/*
 * nasd_pipe_shm.c
 *
 * Data pipes that use a shared memory segment.
 *
 * 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>
#ifndef KERNEL
#include <nasd/nasd_types.h>
#include <nasd/nasd_error.h>
#include <nasd/nasd_general.h>
#include <nasd/nasd_pdrive_client.h>
#include <nasd/nasd_pipe_shm.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <errno.h>


/*
 * Pipe routines for userspace colocated drive
 */

nasd_status_t
nasd_shmpipe_create(nasd_len_t len, int *out_shmid,
                    nasd_rpc_status_t *status)
{
  int shmid;

  shmid = shmget(IPC_PRIVATE, len, IPC_CREAT | 0666);
  if(shmid < 0) {
    *status = errno;
    return NASD_RPC_LOCAL_FAIL;
  }

  *out_shmid = shmid;
  *status = 0;
  return NASD_SUCCESS;
}

nasd_status_t
nasd_shmpipe_setup(int shmid, nasd_len_t len,
                   nasd_shm_pipe_state_t *state)
{
  nasd_byte_t *shmbuf;

  shmbuf = shmat(shmid, NULL, 0);
  if(shmbuf == (nasd_byte_t *) -1) {
    return NASD_FAIL;
  }

  state->shmid = shmid;
  state->orig_buf = state->cur_buf = shmbuf;
  state->orig_buf_len = state->buf_len_remain = len;

  return NASD_SUCCESS;
}

nasd_status_t
nasd_shmpipe_setup_cs(int shmid, nasd_byte_t **shmbuf,
                      nasd_rpc_status_t *status)
{
  nasd_byte_t *buf;

  buf = shmat(shmid, NULL, 0);
  if(buf == (nasd_byte_t *) -1) {
    *status = errno;
    return NASD_RPC_LOCAL_FAIL;
  }
  *shmbuf = buf;
  *status = 0;
  return NASD_SUCCESS;
}

nasd_status_t
nasd_shmpipe_complete(nasd_byte_t *buf)
{
  int rc;

  rc = shmdt(buf);
  if(rc)
    return NASD_FAIL;
  return NASD_SUCCESS;
}

nasd_status_t
nasd_shmpipe_complete_cs(int shmid, nasd_byte_t *buf,
                         nasd_rpc_status_t *status)
{
  int rc;

  if(buf) {
    rc = shmdt(buf);
    if(rc) {
      *status = errno;
      return NASD_RPC_LOCAL_FAIL;
    }
  }
  rc = shmctl(shmid, IPC_RMID, NULL);
  if(rc) {
    *status = errno;
    return NASD_RPC_LOCAL_FAIL;
  }
  *status = 0;
  return NASD_SUCCESS;
}


nasd_status_t
nasd_shmpipe_pull(void *state_arg, void *buf, nasd_len_t in_len,
                  nasd_len_t *out_lenp, nasd_digest_t ignored1, int *ignored2,
                  void (*ignored3)(), void *ignored4)
{
  nasd_shm_pipe_state_t *state = (nasd_shm_pipe_state_t *) state_arg;
  nasd_len_t len;

  len = NASD_MIN(in_len, state->buf_len_remain);
  if(len) {
    memcpy(buf, state->cur_buf, len);
    state->buf_len_remain -= len;
    state->cur_buf += len;
  }
  *out_lenp = len;
  return NASD_SUCCESS;
}

nasd_status_t
nasd_shmpipe_push(void *state_arg, void *buf, nasd_len_t in_len,
                  nasd_byte_t *ign1, nasd_byte_t *ign2, int *ign3)
{
  nasd_shm_pipe_state_t *state = (nasd_shm_pipe_state_t *) state_arg;
  nasd_len_t len;

  len = NASD_MIN(in_len, state->buf_len_remain);
  if(len) {
    memcpy(state->cur_buf, buf, len);
    state->buf_len_remain -= len;
    state->cur_buf += len;
  }
  return NASD_SUCCESS;
}

#endif /* !KERNEL */

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