/*
 * nasd_pdrive_client_msgq.c
 *
 * RPC-specific client code for colocating with drive via message queues
 *
 * 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_pdrive_client.h>
#include <nasd/nasd_pdrive_client_msgq.h>
#include <nasd/nasd_pipe.h>
#include <nasd/nasd_pipe_shm.h>
#include <nasd/nasd_mem.h>
#include <nasd/nasd_mq.h>
#include <nasd/nasd_types.h>
#include <nasd/nasd_security.h>
#include <nasd/nasd_types_marshall.h>

#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include <ctype.h>
#include <string.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <sys/shm.h>

#define NASD_MSGQ_OP_SETUP(_op_) { \
  nasd_key_t integrity_key; \
  mb.mtype = _op_; \
  mb.sec_param = *sec_param; \
  if(capability) { \
    nasd_capability_t_marshall(capability, mb.capability_otw); \
    mb.capability_valid = 1; \
  } else \
    mb.capability_valid = 0; \
  nasd_sec_integrity_key(in_key, integrity_key); \
  nasd_gettime(&now); \
  nasd_sec_fill_nonce(sec_param, in_key, integrity_key, \
                      NULL, 0, args, sizeof(*args), \
                      &now, mb.digest_otw, NULL); \
}

#define NASD_MSGQ_SHM_SETUP(_len_) { \
  rc = nasd_shmpipe_create((_len_), &shmid, status); \
  if(rc) { \
    res->nasd_status = rc; \
    return; \
  } \
  rc = nasd_shmpipe_setup_cs(shmid, &shmbuf, status); \
  if(rc) { \
    nasd_shmpipe_complete_cs(shmid, NULL, &status2); \
    res->nasd_status = rc; \
    return; \
  } \
  MSG(&mb).shmid = shmid; \
}


nasd_status_t
nasd_cl_msgq_bind(
  nasd_drive_handle_t   handle,
  char                 *drive_name,
  char                 *portnum,
  int                   binding_type,
  void                 *binding_param,
  int                   binding_param_len)
{
  nasd_drive_handle_msgq_t *rpch;
  int mqid;

  /* bail if the drive name doesn't refer to the local machine. */
  if (nasd_hostlocal(drive_name) != NASD_SUCCESS) { return(NASD_FAIL); }

  rpch = (nasd_drive_handle_msgq_t *)handle->rpc_specific_handle;

  /* get id for drive's queue */
  mqid = msgget(NASD_MSGQ_KEY, 0);
  if (mqid < 0)
    return NASD_OFFLINE;

  rpch->fd = mqid;

  /* create a queue for replies from drive */
  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_cl_msgq_unbind(
  nasd_drive_handle_t  handle)
{
  nasd_drive_handle_msgq_t *rpch;
  int ret;

  rpch = (nasd_drive_handle_msgq_t *)handle->rpc_specific_handle;

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

  return(NASD_SUCCESS);
}

nasd_status_t
nasd_cl_msgq_docall(nasd_drive_handle_msgq_t *rpch, nasd_msgq_buf_t *mb,
                    nasd_rpc_status_t *status)
{
  int seqnum;
  int ret;

  NASD_LOCK_MUTEX(rpch->seqlock);
  seqnum = MSG(mb).seqnum = rpch->seqnum++;
  NASD_UNLOCK_MUTEX(rpch->seqlock);

  MSG(mb).replyq = rpch->replyq;
  ret = msgsnd(rpch->fd, (struct msgbuf *) mb, NASD_MSGQ_MSGLEN, 0);
  if(ret) {
    *status = errno;
    return NASD_RPC_LOCAL_FAIL;
  }

  ret = msgrcv(rpch->replyq, (struct msgbuf *) mb, NASD_MSGQ_MSGLEN,
               seqnum, 0);
  if(ret != NASD_MSGQ_MSGLEN) {
    *status = 0;
    return NASD_RPC_LOCAL_FAIL;
  }

  *status = 0;
  return NASD_SUCCESS;
}

void
nasd_cl_msgq_null_dr(
  nasd_drive_handle_t   handle,
  nasd_res_t           *res,
  nasd_rpc_status_t    *status)
{
  nasd_drive_handle_msgq_t *rpch;
  nasd_msgq_buf_t mb;
  nasd_status_t rc;

  rpch = (nasd_drive_handle_msgq_t *)handle->rpc_specific_handle;

  mb.mtype = NASD_MSGQ_NULL;
  rc = nasd_cl_msgq_docall(rpch, &mb, status);
  if(rc) {
    res->nasd_status = rc;
    return;
  }
  res->nasd_status = mb.op.nasd_status;
}

void
nasd_cl_msgq_sync_dr(
  nasd_drive_handle_t   handle,
  nasd_res_t           *res,
  nasd_rpc_status_t    *status)
{
  nasd_drive_handle_msgq_t *rpch;
  nasd_msgq_buf_t mb;
  nasd_status_t rc;

  rpch = (nasd_drive_handle_msgq_t *)handle->rpc_specific_handle;

  mb.mtype = NASD_MSGQ_SYNC;
  rc = nasd_cl_msgq_docall(rpch, &mb, status);
  if(rc) {
    res->nasd_status = rc;
    return;
  }
  res->nasd_status = mb.op.nasd_status;
}

void
nasd_cl_msgq_part_creat_dr(
  nasd_drive_handle_t           handle,
  nasd_key_t                    in_key,
  nasd_security_param_t        *sec_param,
  nasd_capability_t            *capability,
  nasd_p_part_creat_dr_args_t  *args,
  nasd_p_part_creat_dr_res_t   *res,
  nasd_rpc_status_t            *status)
{
  nasd_drive_handle_msgq_t *rpch;
  nasd_msgq_buf_t mb;
  nasd_status_t rc;
  nasd_timespec_t now;

  rpch = (nasd_drive_handle_msgq_t *)handle->rpc_specific_handle;

  NASD_MSGQ_OP_SETUP(NASD_MSGQ_PCRPART);
  mb.op.part_creat_args = *args;
  rc = nasd_cl_msgq_docall(rpch, &mb, status);
  if(rc) {
    res->nasd_status = rc;
    return;
  }
  res->nasd_status = mb.op.nasd_status;
}

/* Alas, we can't use the otw buffer because the message queue routines
   require that the entire message be contiguous in memory. */
void
nasd_cl_msgq_create_dr__otw_provided(
  nasd_drive_handle_t       handle,
  nasd_key_t                in_key,
  nasd_security_param_t    *sec_param,
  nasd_capability_t        *capability,
  nasd_p_create_dr_args_t  *args,
  nasd_p_create_dr_res_t   *res,
  nasd_cl_p_otw_buf_t      *otw,
  nasd_rpc_status_t        *status)
{
  nasd_drive_handle_msgq_t *rpch;
  nasd_msgq_buf_t mb;
  nasd_status_t rc;
  nasd_timespec_t now;

  rpch = (nasd_drive_handle_msgq_t *)handle->rpc_specific_handle;

  NASD_MSGQ_OP_SETUP(NASD_MSGQ_PCREATE);
  mb.op.create_args = *args;
  rc = nasd_cl_msgq_docall(rpch, &mb, status);
  if(rc) {
    res->nasd_status = rc;
    return;
  }
  *res = mb.op.create_res;
}

void
nasd_cl_msgq_getattr_dr(
  nasd_drive_handle_t        handle,
  nasd_key_t                 in_key,
  nasd_security_param_t     *sec_param,
  nasd_capability_t         *capability,
  nasd_p_getattr_dr_args_t  *args,
  nasd_p_getattr_dr_res_t   *res,
  nasd_rpc_status_t         *status)
{
  nasd_drive_handle_msgq_t *rpch;
  nasd_msgq_buf_t mb;
  nasd_timespec_t now;
  nasd_status_t rc;

  rpch = (nasd_drive_handle_msgq_t *)handle->rpc_specific_handle;

  NASD_MSGQ_OP_SETUP(NASD_MSGQ_PGETATTR);
  mb.op.getattr_args = *args;
  rc = nasd_cl_msgq_docall(rpch, &mb, status);
  if(rc) {
    res->nasd_status = rc;
    return;
  }
  *res = mb.op.getattr_res;
}

void
nasd_cl_msgq_read_simple_dr(
  nasd_drive_handle_t        handle,
  nasd_key_t                 in_key,
  nasd_security_param_t     *sec_param,
  nasd_capability_t         *capability,
  int                        is_read2,
  nasd_p_smpl_op_dr_args_t  *args,
  void                      *buf,
  nasd_p_fastread_dr_res_t  *res,
  nasd_rpc_status_t         *status)
{
  nasd_drive_handle_msgq_t *rpch;
  nasd_msgq_buf_t mb;
  nasd_timespec_t now;
  nasd_status_t rc;
  int shmid;
  nasd_byte_t *shmbuf;
  nasd_rpc_status_t status2;

  rpch = (nasd_drive_handle_msgq_t *)handle->rpc_specific_handle;

  NASD_MSGQ_SHM_SETUP(args->in_len);
  if(is_read2) {
    NASD_MSGQ_OP_SETUP(NASD_MSGQ_PREAD2_SIMPLE);
  } else {
    NASD_MSGQ_OP_SETUP(NASD_MSGQ_PREAD_SIMPLE);
  }
  mb.op.smpl_op_args = *args;
  rc = nasd_cl_msgq_docall(rpch, &mb, status);
  if(rc) {
    res->nasd_status = rc;
    return;
  }
  *res = mb.op.fastread_res;

  bcopy(shmbuf, buf, args->in_len);
  rc = nasd_shmpipe_complete_cs(shmid, shmbuf, status);
  if(rc)
    res->nasd_status = rc;
}

void
nasd_cl_msgq_tread_simple_dr(
  nasd_drive_handle_t        handle,
  nasd_key_t                 in_key,
  nasd_security_param_t     *sec_param,
  nasd_capability_t         *capability,
  int                        is_read2,
  nasd_p_thrtl_op_dr_args_t *args,
  void                      *buf,
  nasd_p_fastread_dr_res_t  *res,
  nasd_rpc_status_t         *status)
{
  nasd_drive_handle_msgq_t *rpch;
  nasd_msgq_buf_t mb;
  nasd_timespec_t now;
  nasd_status_t rc;
  int shmid;
  nasd_byte_t *shmbuf;
  nasd_rpc_status_t status2;

  rpch = (nasd_drive_handle_msgq_t *)handle->rpc_specific_handle;

  NASD_MSGQ_SHM_SETUP(args->in_len);
  NASD_MSGQ_OP_SETUP(NASD_MSGQ_PTREAD_SIMPLE);
  mb.op.thrtl_op_args = *args;
  rc = nasd_cl_msgq_docall(rpch, &mb, status);
  if(rc) {
    res->nasd_status = rc;
    return;
  }
  *res = mb.op.fastread_res;

  bcopy(shmbuf, buf, args->in_len);
  rc = nasd_shmpipe_complete_cs(shmid, shmbuf, status);
  if(rc)
    res->nasd_status = rc;
}

void
nasd_cl_msgq_write_simple_dr(
  nasd_drive_handle_t         handle,
  nasd_key_t                  in_key,
  nasd_security_param_t      *sec_param,
  nasd_capability_t          *capability,
  nasd_p_smpl_op_dr_args_t   *args,
  void                       *buf,
  nasd_p_fastwrite_dr_res_t  *res,
  nasd_rpc_status_t          *status)
{
  nasd_drive_handle_msgq_t *rpch;
  nasd_msgq_buf_t mb;
  nasd_timespec_t now;
  nasd_status_t rc;
  int shmid;
  nasd_byte_t *shmbuf;
  nasd_rpc_status_t status2;

  rpch = (nasd_drive_handle_msgq_t *)handle->rpc_specific_handle;

  NASD_MSGQ_SHM_SETUP(args->in_len);
  bcopy(buf, shmbuf, args->in_len);
  NASD_MSGQ_OP_SETUP(NASD_MSGQ_PWRITE_SIMPLE);
  mb.op.smpl_op_args = *args;
  rc = nasd_cl_msgq_docall(rpch, &mb, status);
  if(rc) {
    res->nasd_status = rc;
    return;
  }
  *res = mb.op.fastwrite_res;

  rc = nasd_shmpipe_complete_cs(shmid, shmbuf, status);
  if(rc)
    res->nasd_status = rc;
}

void
nasd_cl_msgq_setattr_dr__otw_provided(
  nasd_drive_handle_t        handle,
  nasd_key_t                 in_key,
  nasd_security_param_t     *sec_param,
  nasd_capability_t         *capability,
  nasd_p_setattr_dr_args_t  *args,
  nasd_p_setattr_dr_res_t   *res,
  nasd_cl_p_otw_buf_t       *otw,
  nasd_rpc_status_t         *status)
{
  nasd_drive_handle_msgq_t *rpch;
  nasd_msgq_buf_t mb;
  nasd_timespec_t now;
  nasd_status_t rc;

  rpch = (nasd_drive_handle_msgq_t *)handle->rpc_specific_handle;

  NASD_MSGQ_OP_SETUP(NASD_MSGQ_PSETATTR);
  mb.op.setattr_args = *args;
  rc = nasd_cl_msgq_docall(rpch, &mb, status);
  if(rc) {
    res->nasd_status = rc;
    return;
  }
  *res = mb.op.setattr_res;
}

void
nasd_cl_msgq_flush_obj_dr(
  nasd_drive_handle_t          handle,
  nasd_key_t                   in_key,
  nasd_security_param_t       *sec_param,
  nasd_capability_t           *capability,
  nasd_p_flush_obj_dr_args_t  *args,
  nasd_p_flush_obj_dr_res_t   *res,
  nasd_rpc_status_t           *status)
{
  nasd_drive_handle_msgq_t *rpch;
  nasd_msgq_buf_t mb;
  nasd_timespec_t now;
  nasd_status_t rc;

  rpch = (nasd_drive_handle_msgq_t *)handle->rpc_specific_handle;

  NASD_MSGQ_OP_SETUP(NASD_MSGQ_PFLUSH_OBJ);
  mb.op.flush_obj_args = *args;
  rc = nasd_cl_msgq_docall(rpch, &mb, status);
  if(rc) {
    res->nasd_status = rc;
    return;
  }
  res->nasd_status = mb.op.nasd_status;
}

void
nasd_cl_msgq_eject_obj_dr(
  nasd_drive_handle_t          handle,
  nasd_key_t                   in_key,
  nasd_security_param_t       *sec_param,
  nasd_capability_t           *capability,
  nasd_p_eject_obj_dr_args_t  *args,
  nasd_p_eject_obj_dr_res_t   *res,
  nasd_rpc_status_t           *status)
{
  nasd_drive_handle_msgq_t *rpch;
  nasd_msgq_buf_t mb;
  nasd_timespec_t now;
  nasd_status_t rc;

  rpch = (nasd_drive_handle_msgq_t *)handle->rpc_specific_handle;

  NASD_MSGQ_OP_SETUP(NASD_MSGQ_PEJECT_OBJ);
  mb.op.eject_obj_args = *args;
  rc = nasd_cl_msgq_docall(rpch, &mb, status);
  if(rc) {
    res->nasd_status = rc;
    return;
  }
  res->nasd_status = mb.op.nasd_status;
}

void
nasd_cl_msgq_remove_dr(
  nasd_drive_handle_t       handle,
  nasd_key_t                in_key,
  nasd_security_param_t    *sec_param,
  nasd_capability_t        *capability,
  nasd_p_remove_dr_args_t  *args,
  nasd_p_remove_dr_res_t   *res,
  nasd_rpc_status_t        *status)
{
  nasd_drive_handle_msgq_t *rpch;
  nasd_msgq_buf_t mb;
  nasd_timespec_t now;
  nasd_status_t rc;

  rpch = (nasd_drive_handle_msgq_t *)handle->rpc_specific_handle;

  NASD_MSGQ_OP_SETUP(NASD_MSGQ_PREMOVE);
  mb.op.remove_args = *args;
  rc = nasd_cl_msgq_docall(rpch, &mb, status);
  if(rc) {
    res->nasd_status = rc;
    return;
  }
  res->nasd_status = mb.op.nasd_status;
}

void
nasd_cl_msgq_initialize_dr(
  nasd_drive_handle_t           handle,
  nasd_p_initialize_dr_args_t  *args,
  nasd_p_initialize_dr_res_t   *res,
  nasd_rpc_status_t            *status)
{
  nasd_drive_handle_msgq_t *rpch;
  nasd_msgq_buf_t mb;
  nasd_status_t rc;

  rpch = (nasd_drive_handle_msgq_t *)handle->rpc_specific_handle;

  mb.mtype = NASD_MSGQ_PINITIALIZE;
  mb.op.initialize_args = *args;
  rc = nasd_cl_msgq_docall(rpch, &mb, status);
  if(rc) {
    res->nasd_status = rc;
    return;
  }
  res->nasd_status = mb.op.nasd_status;
}

void
nasd_cl_msgq_strt_iread_dr(
  nasd_drive_handle_t           handle,
  nasd_key_t                    in_key,
  nasd_security_param_t        *sec_param,
  nasd_capability_t            *capability,
  nasd_p_strt_iread_dr_args_t  *args,
  nasd_p_strt_iread_dr_res_t   *res,
  nasd_rpc_status_t            *status)
{
  nasd_drive_handle_msgq_t *rpch;
  nasd_msgq_buf_t mb;
  nasd_timespec_t now;
  nasd_status_t rc;

  rpch = (nasd_drive_handle_msgq_t *)handle->rpc_specific_handle;

  NASD_MSGQ_OP_SETUP(NASD_MSGQ_PSTRT_IREAD);
  mb.op.strt_iread_args = *args;
  rc = nasd_cl_msgq_docall(rpch, &mb, status);
  if(rc) {
    res->nasd_status = rc;
    return;
  }
  *res = mb.op.strt_iread_res;
}

void
nasd_cl_msgq_stop_iread_dr(
  nasd_drive_handle_t           handle,
  nasd_key_t                    in_key,
  nasd_security_param_t        *sec_param,
  nasd_capability_t            *capability,
  nasd_p_stop_iread_dr_args_t  *args,
  nasd_p_stop_iread_dr_res_t   *res,
  nasd_rpc_status_t            *status)
{
  nasd_drive_handle_msgq_t *rpch;
  nasd_msgq_buf_t mb;
  nasd_timespec_t now;
  nasd_status_t rc;

  rpch = (nasd_drive_handle_msgq_t *)handle->rpc_specific_handle;

  NASD_MSGQ_OP_SETUP(NASD_MSGQ_PSTOP_IREAD);
  mb.op.stop_iread_args = *args;
  rc = nasd_cl_msgq_docall(rpch, &mb, status);
  if(rc) {
    res->nasd_status = rc;
    return;
  }
  res->nasd_status = mb.op.nasd_status;
}

void
nasd_cl_msgq_rshutdown_dr(
  nasd_drive_handle_t          handle,
  nasd_key_t                   in_key,
  nasd_security_param_t       *sec_param,
  nasd_capability_t           *capability,
  nasd_p_rshutdown_dr_args_t  *args,
  nasd_p_rshutdown_dr_res_t   *res,
  nasd_rpc_status_t           *status)
{
  nasd_drive_handle_msgq_t *rpch;
  nasd_msgq_buf_t mb;
  nasd_timespec_t now;
  nasd_status_t rc;

  rpch = (nasd_drive_handle_msgq_t *)handle->rpc_specific_handle;

  NASD_MSGQ_OP_SETUP(NASD_MSGQ_PRSHUTDOWN);
  mb.op.rshutdown_args = *args;
  rc = nasd_cl_msgq_docall(rpch, &mb, status);
  if(rc) {
    res->nasd_status = rc;
    return;
  }
  res->nasd_status = mb.op.nasd_status;
}

void
nasd_cl_msgq_remote_attach_dr(
  nasd_drive_handle_t              handle,
  nasd_key_t                      in_key,
  nasd_security_param_t           *sec_param,
  nasd_capability_t               *capability,
  nasd_p_remote_attach_dr_args_t  *args,
  void                            *buf,
  nasd_p_remote_attach_dr_res_t   *res,
  nasd_rpc_status_t               *status)
{
  nasd_drive_handle_msgq_t *rpch;
  nasd_msgq_buf_t mb;
  nasd_timespec_t now;
  nasd_status_t rc;
  int shmid;
  nasd_byte_t *shmbuf;
  nasd_rpc_status_t status2;

  rpch = (nasd_drive_handle_msgq_t*)handle->rpc_specific_handle;
  
  NASD_MSGQ_SHM_SETUP(args->in_args_len);
  bcopy(buf,shmbuf,args->in_args_len);
  NASD_MSGQ_OP_SETUP(NASD_MSGQ_PREMOTE_ATTACH);
  mb.op.remote_attach_args = *args;
  rc = nasd_cl_msgq_docall(rpch, &mb, status);
  if (rc) {
    res->nasd_status = rc;
    return;
  }
  *res = mb.op.remote_attach_res;

  rc = nasd_shmpipe_complete_cs(shmid, shmbuf, status);
  if (rc) 
    res->nasd_status = rc;
}
 
void nasd_cl_msgq_remote_detach_dr (
  nasd_drive_handle_t              handle,
  nasd_key_t                      in_key,
  nasd_security_param_t          *sec_param,
  nasd_capability_t              *capability,
  nasd_p_remote_detach_dr_args_t   *args,
  nasd_p_remote_detach_dr_res_t    *res,
  nasd_rpc_status_t                *status)
{
  nasd_drive_handle_msgq_t *rpch;
  nasd_msgq_buf_t mb;
  nasd_timespec_t now;
  nasd_status_t rc;

  rpch = (nasd_drive_handle_msgq_t *)handle->rpc_specific_handle;

  NASD_MSGQ_OP_SETUP(NASD_MSGQ_PREMOTE_DETACH);
  mb.op.remote_detach_args = *args;
  rc = nasd_cl_msgq_docall(rpch, &mb, status);
  if(rc) {
    res->nasd_status = rc;
    return;
  }
  *res = mb.op.remote_detach_res;
}
 
void nasd_cl_msgq_remote_invoke_dr (
  nasd_drive_handle_t              handle,
  nasd_key_t                       in_key,
  nasd_security_param_t            *sec_param,
  nasd_capability_t                *capability,
  nasd_p_smpl_op_dr_args_t         *args,
  void                             *buf,
  nasd_p_fastread_dr_res_t         *res,
  nasd_rpc_status_t                *status)
{
  nasd_drive_handle_msgq_t *rpch;
  nasd_msgq_buf_t mb;
  nasd_timespec_t now;
  nasd_status_t rc;
  int shmid;
  nasd_byte_t *shmbuf;
  nasd_rpc_status_t status2;

  rpch = (nasd_drive_handle_msgq_t *)handle->rpc_specific_handle;

  NASD_MSGQ_SHM_SETUP(args->in_len);
  NASD_MSGQ_OP_SETUP(NASD_MSGQ_PREMOTE_INVOKE);

  mb.op.smpl_op_args = *args;
  rc = nasd_cl_msgq_docall(rpch, &mb, status);
  if(rc) {
    res->nasd_status = rc;
    return;
  }
  *res = mb.op.fastread_res;

  bcopy(shmbuf, buf, args->in_len);
  rc = nasd_shmpipe_complete_cs(shmid, shmbuf, status);
  if(rc)
    res->nasd_status = rc;
}




void
nasd_cl_msgq_getinfo_dr(
  nasd_drive_handle_t       handle,
  nasd_p_getinfo_dr_res_t  *res,
  nasd_rpc_status_t        *status)
{
  nasd_drive_handle_msgq_t *rpch;
  nasd_msgq_buf_t mb;
  nasd_status_t rc;

  rpch = (nasd_drive_handle_msgq_t *)handle->rpc_specific_handle;

  mb.mtype = NASD_MSGQ_PGETINFO;
  rc = nasd_cl_msgq_docall(rpch, &mb, status);
  if(rc) {
    res->nasd_status = rc;
    return;
  }
  *res = mb.op.getinfo_res;
}

void
nasd_cl_msgq_error_string(
  nasd_drive_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_cl_p_rpcmod_tab_t nasd_cl_msgq_mod = {
  NULL,
  NASD_RPCMOD_INIT_FAIL,

  nasd_cl_msgq_bind,
  nasd_cl_msgq_unbind,

  nasd_cl_msgq_null_dr,
  nasd_cl_msgq_sync_dr,
  nasd_cl_msgq_part_creat_dr,
  nasd_cl_msgq_getattr_dr,
  nasd_cl_msgq_write_simple_dr,
  NULL, /* range_write */
  nasd_cl_msgq_read_simple_dr,
  NULL, /* range_read */
  nasd_cl_msgq_tread_simple_dr,
  NULL, /* range_tread */
  nasd_cl_msgq_flush_obj_dr,
  nasd_cl_msgq_eject_obj_dr,
  nasd_cl_msgq_remove_dr,
  nasd_cl_msgq_initialize_dr,
  nasd_cl_msgq_strt_iread_dr,
  nasd_cl_msgq_stop_iread_dr,
  nasd_cl_msgq_rshutdown_dr,
  nasd_cl_msgq_getinfo_dr,

  nasd_cl_msgq_remote_attach_dr,
  nasd_cl_msgq_remote_detach_dr,
  nasd_cl_msgq_remote_invoke_dr,

  nasd_cl_msgq_create_dr__otw_provided,
  nasd_cl_msgq_setattr_dr__otw_provided,

  nasd_cl_msgq_error_string,

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

  NULL
};

void
nasd_cl_p_msgq_register(
  int  counter_lock_held)
{
  nasd_cl_p_mod_register(&nasd_cl_msgq_mod, counter_lock_held);
}

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