/*
 * nasd_edrfs_client_mq.c
 *
 * Message queue dispatch functions for NASD EDRFS client
 *
 * Author: Marc Unangst
 */
/*
 * 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.
 */


#include <nasd/nasd_options.h>
#include <nasd/nasd_freelist.h>
#include <nasd/nasd_edrfs_client.h>
#include <nasd/nasd_edrfs_client_msgq.h>
#include <nasd/nasd_mem.h>
#include <nasd/nasd_edrfs_mq.h>
#include <nasd/nasd_msg.h>
#include <nasd/nasd_marshall.h>
#include <nasd/nasd_pipe_shm.h>

#include <errno.h>

/* I am, in all likelihood, going to go to hell for these macros. */

#define NASD_EDRFSMQ_DEFINE_VARS(msgtype, msgfield, reptype, repfield)	\
        nasd_edrfs_mq_buf_t mb;						\
	msgtype *msg = &(mb.un.msgfield);				\
	reptype *rep = &(mb.un.repfield);				\
        nasd_edrfscli_handle_msgq_t *rpch =				\
          (nasd_edrfscli_handle_msgq_t *)handle->rpc_specific_handle;	\
        int seqnum;							\
        int rc;

#define NASD_EDRFSMQ_INC_SEQNUM() \
        NASD_LOCK_MUTEX(rpch->seqlock);\
        msg->seqnum = seqnum = rpch->seqnum++;\
        NASD_UNLOCK_MUTEX(rpch->seqlock);

#define NASD_EDRFSMQ_DOCALL(n) \
        mb.mtype = n;\
        msg->replyq = rpch->replyq;\
        rc = nasd_msg_msgsnd(rpch->fd, (struct msgbuf *) &mb, NASD_EDRFS_MQ_MSGLEN, 0);\
        if(rc) {\
                res->nasd_status = NASD_RPC_TRAP;\
                *op_status = errno;\
                return;\
        }\
        rc = nasd_msg_msgrcv(rpch->replyq, (struct msgbuf *) &mb, NASD_EDRFS_MQ_MSGLEN, seqnum, 0);\
        if(rc != NASD_EDRFS_MQ_MSGLEN) {\
                res->nasd_status = NASD_RPC_TRAP;\
                *op_status = errno;\
                return;\
        }\
        *op_status = rep->op_status;

#define NASD_EDRFSMQ_MARSHALL(msgfield, argstype)  bcopy(args, &mb.un.msgfield.args, sizeof(argstype))
#define NASD_EDRFSMQ_UNMARSHALL(repfield, restype) bcopy(&mb.un.repfield.res, res, sizeof(restype))

nasd_status_t
nasd_edrfsmq_bind(
  nasd_edrfs_handle_t   handle,
  char               *server_name,
  char               *portnum,
  int                 binding_type,
  void               *binding_param,
  int                 binding_param_len)
{
  nasd_edrfscli_handle_msgq_t *rpch;
  int mqid;

  rpch = (nasd_edrfscli_handle_msgq_t *)handle->rpc_specific_handle;

  /* get id for file manager's queue */
  mqid = msgget(NASD_EDRFS_MQ_KEY, 0);
  if (mqid < 0)
    return NASD_FAIL;

  rpch->fd = mqid;

  /* create a queue for replies from file manager */
  mqid = msgget(IPC_PRIVATE, IPC_CREAT | 0666);
  if (mqid < 0)
    return NASD_FAIL;
  rpch->replyq = mqid;

  /* initialize sequence numbers */
  nasd_mutex_init(&rpch->seqlock);
  rpch->seqnum = 1;

  return(NASD_SUCCESS);
}

nasd_status_t
nasd_edrfsmq_unbind(
  nasd_edrfs_handle_t  handle)
{
  nasd_edrfscli_handle_msgq_t *rpch;
  int ret;

  rpch = (nasd_edrfscli_handle_msgq_t *)handle->rpc_specific_handle;

  ret = msgctl(rpch->replyq, IPC_RMID, NULL);
  if (ret)
    return(NASD_FAIL);

  return(NASD_SUCCESS);
}

void
nasd_edrfsmq_null(
  nasd_edrfs_handle_t   handle,
  nasd_res_t         *res,
  nasd_rpc_status_t  *op_status)
{
  NASD_EDRFSMQ_DEFINE_VARS(NASDMQ_edrfs_null_msg_t, null_msg, NASDMQ_edrfs_null_rep_t, null_rep);
  NASD_EDRFSMQ_INC_SEQNUM();
  NASD_EDRFSMQ_DOCALL(NASD_EDRFS_MQ_NULL);
  res->nasd_status = mb.un.null_rep.nasd_status;
}


void
nasd_edrfsmq_mount(
  nasd_edrfs_handle_t       handle,
  nasd_edrfs_mount_args_t  *args,
  nasd_edrfs_mount_res_t   *res,
  nasd_rpc_status_t      *op_status)
{
  NASD_EDRFSMQ_DEFINE_VARS(NASDMQ_edrfs_mount_msg_t, mount_msg, NASDMQ_edrfs_mount_rep_t, mount_rep);
  NASD_EDRFSMQ_INC_SEQNUM();
  NASD_EDRFSMQ_MARSHALL(mount_msg, nasd_edrfs_mount_args_t);
  NASD_EDRFSMQ_DOCALL(NASD_EDRFS_MQ_MOUNT);
  NASD_EDRFSMQ_UNMARSHALL(mount_rep, nasd_edrfs_mount_res_t);
}


void
nasd_edrfsmq_fsstat(
  nasd_edrfs_handle_t        handle,
  nasd_edrfs_fsstat_args_t  *args,
  nasd_edrfs_fsstat_res_t   *res,
  nasd_rpc_status_t       *op_status)
{
  NASD_EDRFSMQ_DEFINE_VARS(NASDMQ_edrfs_fsstat_msg_t, fsstat_msg, NASDMQ_edrfs_fsstat_rep_t, fsstat_rep);
  NASD_EDRFSMQ_INC_SEQNUM();
  NASD_EDRFSMQ_MARSHALL(fsstat_msg, nasd_edrfs_fsstat_args_t);
  NASD_EDRFSMQ_DOCALL(NASD_EDRFS_MQ_FSSTAT);
  NASD_EDRFSMQ_UNMARSHALL(fsstat_rep, nasd_edrfs_fsstat_res_t);
}


void
nasd_edrfsmq_fsinfo(
  nasd_edrfs_handle_t     handle,
  nasd_edrfs_fsinfo_args_t  *args,
  nasd_edrfs_fsinfo_res_t   *res,
  nasd_rpc_status_t          *op_status)
{
  NASD_EDRFSMQ_DEFINE_VARS(NASDMQ_edrfs_fsinfo_msg_t, fsinfo_msg, NASDMQ_edrfs_fsinfo_rep_t, fsinfo_rep);
  NASD_EDRFSMQ_INC_SEQNUM();
  NASD_EDRFSMQ_MARSHALL(fsinfo_msg, nasd_edrfs_fsinfo_args_t);
  NASD_EDRFSMQ_DOCALL(NASD_EDRFS_MQ_FSINFO);
  NASD_EDRFSMQ_UNMARSHALL(fsinfo_rep, nasd_edrfs_fsinfo_res_t);
}


void
nasd_edrfsmq_lookup(
  nasd_edrfs_handle_t     handle,
  nasd_edrfs_lookup_args_t  *args,
  nasd_edrfs_lookup_res_t   *res,
  nasd_rpc_status_t          *op_status)
{
  NASD_EDRFSMQ_DEFINE_VARS(NASDMQ_edrfs_lookup_msg_t, lookup_msg, NASDMQ_edrfs_lookup_rep_t, lookup_rep);
  NASD_EDRFSMQ_INC_SEQNUM();
  NASD_EDRFSMQ_MARSHALL(lookup_msg, nasd_edrfs_lookup_args_t);
  NASD_EDRFSMQ_DOCALL(NASD_EDRFS_MQ_LOOKUP);
  NASD_EDRFSMQ_UNMARSHALL(lookup_rep, nasd_edrfs_lookup_res_t);
}


void
nasd_edrfsmq_lookup_otw_provided(
  nasd_edrfs_handle_t     handle,
  nasd_edrfs_lookup_args_t  *args,
  nasd_edrfs_lookup_res_t   *res,
  nasd_otw_base_t         *args_otw_p,
  nasd_otw_base_t         *res_otw_p,
  nasd_rpc_status_t          *op_status)
{
  nasd_edrfsmq_lookup(handle, args, res, op_status);
}


void
nasd_edrfsmq_readdir(
  nasd_edrfs_handle_t      handle,
  nasd_edrfs_readdir_args_t  *args,
  nasd_edrfs_dirent_t        *out_entries,
  nasd_edrfs_readdir_res_t   *res,
  nasd_rpc_status_t           *op_status)
{
  NASD_EDRFSMQ_DEFINE_VARS(NASDMQ_edrfs_readdir_msg_t, readdir_msg, NASDMQ_edrfs_readdir_rep_t, readdir_rep);
  nasd_byte_t *shmbuf;
  int shmid;
  nasd_len_t len;
  nasd_rpc_status_t status2;

  len = args->in_count * sizeof(nasd_edrfs_dirent_t);

  rc = nasd_shmpipe_create(len, &shmid, op_status);
  if(rc) {
    res->nasd_status = NASD_RPC_TRAP;
    return;
  }

  msg->shmid = shmid;
  rc = nasd_shmpipe_setup_cs(shmid, &shmbuf, op_status);
  if(rc) {
    res->nasd_status = NASD_RPC_TRAP;
    nasd_shmpipe_complete_cs(shmid, shmbuf, &status2);
    return;
  }

  NASD_EDRFSMQ_INC_SEQNUM();
  NASD_EDRFSMQ_MARSHALL(readdir_msg, nasd_edrfs_readdir_args_t);
  NASD_EDRFSMQ_DOCALL(NASD_EDRFS_MQ_READDIR);
  NASD_EDRFSMQ_UNMARSHALL(readdir_rep, nasd_edrfs_readdir_res_t);
  bcopy(shmbuf, out_entries, len);
  rc = nasd_shmpipe_complete_cs(shmid, shmbuf, op_status);
  if(rc)
    res->nasd_status = NASD_RPC_TRAP;
}


void
nasd_edrfsmq_access(
  nasd_edrfs_handle_t     handle,
  nasd_edrfs_access_args_t  *args,
  nasd_edrfs_access_res_t   *res,
  nasd_rpc_status_t          *op_status)
{
  NASD_EDRFSMQ_DEFINE_VARS(NASDMQ_edrfs_access_msg_t, access_msg, NASDMQ_edrfs_access_rep_t, access_rep);
  NASD_EDRFSMQ_INC_SEQNUM();
  NASD_EDRFSMQ_MARSHALL(access_msg, nasd_edrfs_access_args_t);
  NASD_EDRFSMQ_DOCALL(NASD_EDRFS_MQ_ACCESS);
  NASD_EDRFSMQ_UNMARSHALL(access_rep, nasd_edrfs_access_res_t);
}


void
nasd_edrfsmq_setattr(
  nasd_edrfs_handle_t      handle,
  nasd_edrfs_setattr_args_t  *args,
  nasd_edrfs_setattr_res_t   *res,
  nasd_rpc_status_t           *op_status)
{
  NASD_EDRFSMQ_DEFINE_VARS(NASDMQ_edrfs_setattr_msg_t, setattr_msg, NASDMQ_edrfs_setattr_rep_t, setattr_rep);
  NASD_EDRFSMQ_INC_SEQNUM();
  NASD_EDRFSMQ_MARSHALL(setattr_msg, nasd_edrfs_setattr_args_t);
  NASD_EDRFSMQ_DOCALL(NASD_EDRFS_MQ_SETATTR);
  NASD_EDRFSMQ_UNMARSHALL(setattr_rep, nasd_edrfs_setattr_res_t);
}


void
nasd_edrfsmq_create(
  nasd_edrfs_handle_t     handle,
  nasd_edrfs_create_args_t  *args,
  nasd_edrfs_create_res_t   *res,
  nasd_rpc_status_t          *op_status)
{
  NASD_EDRFSMQ_DEFINE_VARS(NASDMQ_edrfs_create_msg_t, create_msg, NASDMQ_edrfs_create_rep_t, create_rep);
  NASD_EDRFSMQ_INC_SEQNUM();
  NASD_EDRFSMQ_MARSHALL(create_msg, nasd_edrfs_create_args_t);
  NASD_EDRFSMQ_DOCALL(NASD_EDRFS_MQ_CREATE);
  NASD_EDRFSMQ_UNMARSHALL(create_rep, nasd_edrfs_create_res_t);
}


void
nasd_edrfsmq_create_otw_provided(
  nasd_edrfs_handle_t     handle,
  nasd_edrfs_create_args_t  *args,
  nasd_edrfs_create_res_t   *res,
  nasd_otw_base_t         *args_otw_p,
  nasd_otw_base_t         *res_otw_p,
  nasd_rpc_status_t          *op_status)
{
  nasd_edrfsmq_create(handle, args, res, op_status);
}


void
nasd_edrfsmq_symlink(
  nasd_edrfs_handle_t      handle,
  nasd_edrfs_symlink_args_t  *args,
  nasd_edrfs_symlink_res_t   *res,
  nasd_rpc_status_t           *op_status)
{
  NASD_EDRFSMQ_DEFINE_VARS(NASDMQ_edrfs_symlink_msg_t, symlink_msg, NASDMQ_edrfs_symlink_rep_t, symlink_rep);
  NASD_EDRFSMQ_INC_SEQNUM();
  NASD_EDRFSMQ_MARSHALL(symlink_msg, nasd_edrfs_symlink_args_t);
  NASD_EDRFSMQ_DOCALL(NASD_EDRFS_MQ_SYMLINK);
  NASD_EDRFSMQ_UNMARSHALL(symlink_rep, nasd_edrfs_symlink_res_t);
}


void
nasd_edrfsmq_remove(
  nasd_edrfs_handle_t     handle,
  nasd_edrfs_remove_args_t  *args,
  nasd_edrfs_remove_res_t   *res,
  nasd_rpc_status_t          *op_status)
{
  NASD_EDRFSMQ_DEFINE_VARS(NASDMQ_edrfs_remove_msg_t, remove_msg, NASDMQ_edrfs_remove_rep_t, remove_rep);
  NASD_EDRFSMQ_INC_SEQNUM();
  NASD_EDRFSMQ_MARSHALL(remove_msg, nasd_edrfs_remove_args_t);
  NASD_EDRFSMQ_DOCALL(NASD_EDRFS_MQ_REMOVE);
  NASD_EDRFSMQ_UNMARSHALL(remove_rep, nasd_edrfs_remove_res_t);
}


void
nasd_edrfsmq_mkdir(
  nasd_edrfs_handle_t    handle,
  nasd_edrfs_mkdir_args_t  *args,
  nasd_edrfs_mkdir_res_t   *res,
  nasd_rpc_status_t         *op_status)
{
  NASD_EDRFSMQ_DEFINE_VARS(NASDMQ_edrfs_mkdir_msg_t, mkdir_msg, NASDMQ_edrfs_mkdir_rep_t, mkdir_rep);
  NASD_EDRFSMQ_INC_SEQNUM();
  NASD_EDRFSMQ_MARSHALL(mkdir_msg, nasd_edrfs_mkdir_args_t);
  NASD_EDRFSMQ_DOCALL(NASD_EDRFS_MQ_MKDIR);
  NASD_EDRFSMQ_UNMARSHALL(mkdir_rep, nasd_edrfs_mkdir_res_t);
}


void
nasd_edrfsmq_rmdir(
  nasd_edrfs_handle_t    handle,
  nasd_edrfs_rmdir_args_t  *args,
  nasd_edrfs_rmdir_res_t   *res,
  nasd_rpc_status_t         *op_status)
{
  NASD_EDRFSMQ_DEFINE_VARS(NASDMQ_edrfs_rmdir_msg_t, rmdir_msg, NASDMQ_edrfs_rmdir_rep_t, rmdir_rep);
  NASD_EDRFSMQ_INC_SEQNUM();
  NASD_EDRFSMQ_MARSHALL(rmdir_msg, nasd_edrfs_rmdir_args_t);
  NASD_EDRFSMQ_DOCALL(NASD_EDRFS_MQ_RMDIR);
  NASD_EDRFSMQ_UNMARSHALL(rmdir_rep, nasd_edrfs_rmdir_res_t);
}


void
nasd_edrfsmq_newcookie(
  nasd_edrfs_handle_t        handle,
  nasd_edrfs_newcookie_args_t  *args,
  nasd_edrfs_newcookie_res_t   *res,
  nasd_rpc_status_t             *op_status)
{
  NASD_EDRFSMQ_DEFINE_VARS(NASDMQ_edrfs_newcookie_msg_t, newcookie_msg, NASDMQ_edrfs_newcookie_rep_t, newcookie_rep);
  NASD_EDRFSMQ_INC_SEQNUM();
  NASD_EDRFSMQ_MARSHALL(newcookie_msg, nasd_edrfs_newcookie_args_t);
  NASD_EDRFSMQ_DOCALL(NASD_EDRFS_MQ_NEWCOOKIE);
  NASD_EDRFSMQ_UNMARSHALL(newcookie_rep, nasd_edrfs_newcookie_res_t);
}


void
nasd_edrfsmq_rename(
  nasd_edrfs_handle_t     handle,
  nasd_edrfs_rename_args_t  *args,
  nasd_edrfs_rename_res_t   *res,
  nasd_rpc_status_t          *op_status)
{
  NASD_EDRFSMQ_DEFINE_VARS(NASDMQ_edrfs_rename_msg_t, rename_msg, NASDMQ_edrfs_rename_rep_t, rename_rep);
  NASD_EDRFSMQ_INC_SEQNUM();
  NASD_EDRFSMQ_MARSHALL(rename_msg, nasd_edrfs_rename_args_t);
  NASD_EDRFSMQ_DOCALL(NASD_EDRFS_MQ_RENAME);
  NASD_EDRFSMQ_UNMARSHALL(rename_rep, nasd_edrfs_rename_res_t);
}


void
nasd_edrfsmq_getstats(
  nasd_edrfs_handle_t         handle,
  nasd_edrfs_getstats_res_t  *res,
  nasd_rpc_status_t           *op_status)
{
  NASD_EDRFSMQ_DEFINE_VARS(NASDMQ_edrfs_getstats_msg_t, getstats_msg, NASDMQ_edrfs_getstats_rep_t, getstats_rep);
  NASD_EDRFSMQ_INC_SEQNUM();
  NASD_EDRFSMQ_DOCALL(NASD_EDRFS_MQ_GETSTATS);
  NASD_EDRFSMQ_UNMARSHALL(getstats_rep, nasd_edrfs_getstats_res_t);
}

void
nasd_edrfsmq_resetstats(
  nasd_edrfs_handle_t   handle,
  nasd_res_t           *res,
  nasd_rpc_status_t    *op_status)
{
  NASD_EDRFSMQ_DEFINE_VARS(NASDMQ_edrfs_resetstats_msg_t, resetstats_msg, NASDMQ_edrfs_resetstats_rep_t, resetstats_rep);
  NASD_EDRFSMQ_INC_SEQNUM();
  NASD_EDRFSMQ_DOCALL(NASD_EDRFS_MQ_RESETSTATS);
  res->nasd_status = mb.un.resetstats_rep.nasd_status;
}

void
nasd_edrfsmq_error_string(
  nasd_edrfs_handle_t     handle,
  nasd_rpc_status_t     status,
  nasd_error_string_t   str,
  char                 *file,
  int                   line)
{
  switch(status) {
    case 0:
      strcpy(str, "Success");
      break;
    default:
      strcpy(str, strerror(status));
      break;
  }
}

nasd_edrfscli_rpcmod_tab_t nasd_edrfscli_msgq_mod = {
  NULL,
  NASD_RPCMOD_INIT_FAIL,

  nasd_edrfsmq_bind,
  nasd_edrfsmq_unbind,

  nasd_edrfsmq_null,
  nasd_edrfsmq_mount,
  nasd_edrfsmq_fsstat,
  nasd_edrfsmq_fsinfo,
  nasd_edrfsmq_lookup,
  nasd_edrfsmq_readdir,
  nasd_edrfsmq_access,
  nasd_edrfsmq_setattr,
  nasd_edrfsmq_create,
  nasd_edrfsmq_symlink,
  nasd_edrfsmq_remove,
  nasd_edrfsmq_mkdir,
  nasd_edrfsmq_rmdir,
  nasd_edrfsmq_newcookie,
  nasd_edrfsmq_rename,
  nasd_edrfsmq_getstats,
  nasd_edrfsmq_resetstats,

  nasd_edrfsmq_lookup_otw_provided,
  nasd_edrfsmq_create_otw_provided,

  nasd_edrfsmq_error_string,

  NASD_BIND_MSGQ,
  "Message Queues",
  sizeof(nasd_edrfscli_handle_msgq_t),

  NULL
};

void
nasd_edrfscli_msgq_register(
  int  counter_lock_held)
{
  nasd_edrfscli_mod_register(&nasd_edrfscli_msgq_mod, counter_lock_held);
}

/* Local Variables:  */
/* indent-tabs-mode: nil */
/* tab-width: 2 */
/* End: */
