/*
 * nasd_edrfs_srpc.c
 *
 * RPC layer for SRPC for EDRFS
 *
 * Author: Jim Zelenka
 */
/*
 * Copyright (c) of Carnegie Mellon University, 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>

#if NASD_RPC_PACKAGE == NASD_RPC_PACKAGE_SRPC

#include <nasd/nasd_types.h>
#include <nasd/nasd_edrfs_types.h>
#include <nasd/nasd_itypes.h>
#include <nasd/nasd_mem.h>
#include <nasd/nasd_common.h>
#include <nasd/nasd_edrfs_server_internal.h>
#include <nasd/nasd_timer.h>
#include <nasd/nasd_edrfs_rpc.h>
#include <nasd/nasd_timeout.h>
#include <nasd/nasd_pipe.h>
#include <nasd/nasd_srpc_types.h>
#include <nasd/nasd_srpc.h>
#include <nasd/nasd_marshall.h>
#include <nasd/nasd_edrfs_server.h>
#include <nasd/nasd_edrfs_server_sstub.h>

/* Don't use __FILE__ here to avoid getting kernel-mangled names */
#define NASD_EDRFS_RPC_RETURN(_statval_) { \
  return(_statval_); \
}
#define DOBEGIN(_opname_) NASD_EDRFS_RPC_DOBEGIN(_opname_,"nasd_edrfs_srpc.c")
#define DORETURN(_opname_) NASD_EDRFS_RPC_DORETURN(_opname_,"nasd_edrfs_srpc.c")

nasd_edrfs_lookup_res_t nasd_edrfs_srpc_lookup_failmem;

/*
 * RPC callbacks
 */

nasd_srpc_status_t
nasd_null_fm_server(
  nasd_srpc_listener_t      *listener,
  nasd_srpc_conn_t          *conn,
  nasd_srpc_server_call_t   *call,
  nasd_res_otw_t             out_res_otw)
{
  nasd_res_t res;
  NASD_EDRFS_RPC_OP_STATS_DECL

  DOBEGIN(null);
  res.nasd_status = NASD_SUCCESS;
  nasd_res_t_marshall(&res, out_res_otw);
  DORETURN(null);
}

nasd_srpc_status_t
nasd_mount_fm_server(
  nasd_srpc_listener_t         *listener,
  nasd_srpc_conn_t             *conn,
  nasd_srpc_server_call_t      *call,
  nasd_edrfs_mount_args_otw_t   in_args_otw,
  nasd_edrfs_mount_res_otw_t    out_res_otw)
{
  nasd_edrfs_mount_args_t args;
  nasd_edrfs_mount_res_t res;

  NASD_EDRFS_RPC_OP_STATS_DECL

  DOBEGIN(mount);

  nasd_edrfs_mount_args_t_unmarshall(in_args_otw, &args);

  args.in_dirpath[NASD_EDRFS_MAX_NAME_LEN-1] = '\0';

  nasd_edrfs_real_mount(args.in_credential,
                        (char *)args.in_dirpath,
                        NASD_EDRFS_DRIVE_LIST_LEN,
                        res.out_drivelist,
                        &res.out_listlen,
                        &res.out_cookie,
                        &res.out_identifier,
                        &res.nasd_status);

  nasd_edrfs_mount_res_t_marshall(&res, out_res_otw);

  DORETURN(mount);
}

nasd_srpc_status_t
nasd_fsstat_fm_server(
  nasd_srpc_listener_t          *listener,
  nasd_srpc_conn_t              *conn,
  nasd_srpc_server_call_t       *call,
  nasd_edrfs_fsstat_args_otw_t   in_args_otw,
  nasd_edrfs_fsstat_res_otw_t    out_res_otw)
{
  nasd_edrfs_fsstat_args_t args;
  nasd_edrfs_fsstat_res_t res;

  NASD_EDRFS_RPC_OP_STATS_DECL

  DOBEGIN(fsstat);

  nasd_edrfs_fsstat_args_t_unmarshall(in_args_otw, &args);

  nasd_edrfs_real_fsstat(args.in_cookie,
                         args.in_identifier,
                         args.in_credential,
                         &res.out_stat,
                         &res.out_attribute,
                         &res.nasd_status);

  nasd_edrfs_fsstat_res_t_marshall(&res, out_res_otw);

  DORETURN(fsstat);
}

nasd_srpc_status_t
nasd_fsinfo_fm_server(
  nasd_srpc_listener_t          *listener,
  nasd_srpc_conn_t              *conn,
  nasd_srpc_server_call_t       *call,
  nasd_edrfs_fsinfo_args_otw_t   in_args_otw,
  nasd_edrfs_fsinfo_res_otw_t    out_res_otw)
{
  nasd_edrfs_fsinfo_args_t args;
  nasd_edrfs_fsinfo_res_t res;

  NASD_EDRFS_RPC_OP_STATS_DECL

  DOBEGIN(fsinfo);

  nasd_edrfs_fsinfo_args_t_unmarshall(in_args_otw, &args);

  nasd_edrfs_real_fsinfo(args.in_cookie,
                         args.in_identifier,
                         args.in_credential,
                         &res.out_info,
                         &res.out_attribute,
                         &res.nasd_status);

  nasd_edrfs_fsinfo_res_t_marshall(&res, out_res_otw);

  DORETURN(fsinfo);
}

nasd_srpc_status_t
nasd_lookup_fm_server(
  nasd_srpc_listener_t          *listener,
  nasd_srpc_conn_t              *conn,
  nasd_srpc_server_call_t       *call,
  nasd_edrfs_lookup_args_otw_t   in_args_otw,
  nasd_edrfs_lookup_res_otw_t    out_res_otw)
{
  nasd_status_t rc;
  nasd_edrfs_lookupstuff_t *lus;
  nasd_edrfs_rpc_basic_t res;
  NASD_EDRFS_RPC_OP_STATS_DECL

  DOBEGIN(lookup);

  lus = nasd_edrfs_get_lookupstuff();
  if (lus == NULL) {
    /* marshall a failure */
    nasd_edrfs_lookup_res_t_marshall(&nasd_edrfs_srpc_lookup_failmem, out_res_otw);
    goto really_done_lookup;
  }

  nasd_edrfs_lookup_args_t_unmarshall(in_args_otw, &lus->in_args);

  lus->in_args.in_dirpath[NASD_EDRFS_MAX_NAME_LEN-1] = '\0';

  nasd_edrfs_real_lookup(lus->in_args.in_cookie,
                         lus->in_args.in_identifier,
                         lus->in_args.in_credential,
                         (char *)lus->in_args.in_dirpath,
                         &lus->out_res.out_cookie,
                         &lus->out_res.out_identifier,
                         &lus->out_res.out_attribute,
                         &lus->out_res.post_attribute,
                         &rc);
  lus->out_res.nasd_status = rc;

  nasd_edrfs_lookup_res_t_marshall(&lus->out_res, out_res_otw);

really_done_lookup:
#if (DEBUG_LOOKUP_DETAIL > 0) || (DEBUG_RPC_ERR_DETAIL > 0)
  if (lus == NULL) {
    nasd_printf("lookup complete lus NULL\n");
  }
  else if (rc) {
    nasd_printf("lookup returning nasd status 0x%x (%s) for in_dirpath=\"%s\"\n", rc, nasd_error_string(rc), (char *)lus->in_args.in_dirpath);
  }
#if DEBUG_LOOKUP_DETAIL > 0
  else if (lus->out_res.out_attribute.valid != NASD_EDRFS_ATTRIBUTE_VALID) {
    nasd_printf("lookup Successful with invalid attribute for in_dirpath=\"%s\" nasdid 0x%"
           NASD_ID_FMT "\n",
      (char *)lus->in_args.in_dirpath,
      lus->out_res.out_identifier.nasd_identifier);
    if (lus->out_res.out_attribute.valid == NASD_EDRFS_ATTRIBUTE_INVALID) {
      nasd_printf("lus->out_res.out_attribute.valid = INVALID\n");
    }
    else {
      nasd_printf("lus->out_res.out_attribute.valid = 0x%x\n", ((int)lus->out_res.out_attribute.valid)&0xff);
    }
  }
  else {
    nasd_printf("lookup_otw Successful for in_dirpath=\"%s\" nasdid 0x%"
           NASD_ID_FMT "\n%s attributes: ",
           (char *)lus->in_args.in_dirpath,
           lus->out_res.out_identifier.nasd_identifier,
           (char *)lus->in_args.in_dirpath);
    nasd_dump_edrfs_attributes_otw((nasd_otw_base_t *)lus->out_res.out_attribute.attribute.fs_specific);
    nasd_printf("\n");
#ifndef KERNEL
    fflush(stdout);
#endif /* !KERNEL */
  }
#endif /* DEBUG_LOOKUP_DETAIL > 0 */
#endif /* (DEBUG_LOOKUP_DETAIL > 0) || (DEBUG_RPC_ERR_DETAIL > 0) */

  if (lus) {
    nasd_edrfs_free_lookupstuff(lus);
  }

  res.nasd_status = rc;
  DORETURN(lookup);
}

nasd_srpc_status_t
nasd_readdir_fm_server(
  nasd_srpc_listener_t            *listener,
  nasd_srpc_conn_t                *conn,
  nasd_srpc_server_call_t         *call,
  nasd_edrfs_readdir_args_otw_t    in_args_otw,
  nasd_edrfs_readdir_res_otw_t     out_res_otw,
  nasd_srpc_server_pipestate_t    *byte_pipe)
{
  nasd_edrfs_readdir_args_t args;
  nasd_edrfs_readdir_res_t res;
  nasd_edrfs_dirent_otw_t dirent_otw;
  nasd_procpipe_t procpipe;

  NASD_EDRFS_RPC_OP_STATS_DECL

  DOBEGIN(readdir);

  nasd_edrfs_readdir_args_t_unmarshall(in_args_otw, &args);

  procpipe.state = byte_pipe;
  procpipe.push = nasd_srpc_server_procpipe_push;
  procpipe.pull = NULL;

  nasd_edrfs_real_readdir(args.in_cookie,
                          args.in_identifier,
                          args.in_credential,
                          args.in_marker,
                          args.in_markerv,
                          args.in_count,
                          &res.out_marker,
                          &res.out_markerv,
                          &res.out_count,
                          &res.out_eof,
                          &procpipe,
                          &res.post_attribute,
                          &res.nasd_status);

  if (res.nasd_status != NASD_RPC_TRAP) {
    procpipe.push(procpipe.state, dirent_otw, 0, NULL, NULL, NULL);
  }

  nasd_edrfs_readdir_res_t_marshall(&res, out_res_otw);
  DORETURN(readdir);
}

nasd_srpc_status_t
nasd_access_fm_server(
  nasd_srpc_listener_t          *listener,
  nasd_srpc_conn_t              *conn,
  nasd_srpc_server_call_t       *call,
  nasd_edrfs_access_args_otw_t   in_args_otw,
  nasd_edrfs_access_res_otw_t    out_res_otw)
{
  nasd_edrfs_access_args_t args;
  nasd_edrfs_access_res_t res;

  NASD_EDRFS_RPC_OP_STATS_DECL

  DOBEGIN(access);

  nasd_edrfs_access_args_t_unmarshall(in_args_otw, &args);

  nasd_edrfs_real_access(args.in_cookie,
                         args.in_identifier,
                         args.in_credential,
                         args.in_access,
                         &res.out_access,
                         &res.post_attribute,
                         &res.nasd_status);

  nasd_edrfs_access_res_t_marshall(&res, out_res_otw);

  DORETURN(access);
}

nasd_srpc_status_t
nasd_setattr_fm_server(
  nasd_srpc_listener_t           *listener,
  nasd_srpc_conn_t               *conn,
  nasd_srpc_server_call_t        *call,
  nasd_edrfs_setattr_args_otw_t   in_args_otw,
  nasd_edrfs_setattr_res_otw_t    out_res_otw)
{
  nasd_edrfs_setattr_args_t args;
  nasd_edrfs_setattr_res_t res;

  NASD_EDRFS_RPC_OP_STATS_DECL

  DOBEGIN(setattr);

  nasd_edrfs_setattr_args_t_unmarshall(in_args_otw, &args);

  nasd_edrfs_real_setattr(args.in_cookie,
                          args.in_identifier,
                          args.in_credential,
                          args.in_attribute,
                          args.in_fieldmask,
                          args.in_guard,
                          &res.out_attribute,
                          &res.nasd_status);

  nasd_edrfs_setattr_res_t_marshall(&res, out_res_otw);

  DORETURN(setattr);
}

nasd_srpc_status_t
nasd_create_fm_server(
  nasd_srpc_listener_t          *listener,
  nasd_srpc_conn_t              *conn,
  nasd_srpc_server_call_t       *call,
  nasd_edrfs_create_args_otw_t   in_args_otw,
  nasd_edrfs_create_res_otw_t    out_res_otw)
{
  nasd_edrfs_create_args_t args;
  nasd_edrfs_create_res_t res;

  NASD_EDRFS_RPC_OP_STATS_DECL

  DOBEGIN(create);

  nasd_edrfs_create_args_t_unmarshall(in_args_otw, &args);

  args.in_dirpath[NASD_EDRFS_MAX_NAME_LEN-1] = '\0';

  nasd_edrfs_real_create(args.in_cookie,
                         args.in_directory,
                         args.in_credential,
                         (char *)args.in_dirpath,
                         args.in_attribute,
                         args.in_fieldmask,
                         &res.out_cookie,
                         &res.out_identifier,
                         &res.out_attribute,
                         &res.post_attribute,
                         &res.nasd_status);
  
  nasd_edrfs_create_res_t_marshall(&res, out_res_otw);

  DORETURN(create);
}

nasd_srpc_status_t
nasd_symlink_fm_server(
  nasd_srpc_listener_t           *listener,
  nasd_srpc_conn_t               *conn,
  nasd_srpc_server_call_t        *call,
  nasd_edrfs_symlink_args_otw_t   in_args_otw,
  nasd_edrfs_symlink_res_otw_t    out_res_otw)
{
  nasd_edrfs_symlink_args_t args;
  nasd_edrfs_symlink_res_t res;

  NASD_EDRFS_RPC_OP_STATS_DECL

  DOBEGIN(symlink);

  nasd_edrfs_symlink_args_t_unmarshall(in_args_otw, &args);

  args.in_dirpath[NASD_EDRFS_MAX_NAME_LEN-1] = '\0';
  args.in_symlink[NASD_EDRFS_MAX_NAME_LEN-1] = '\0';

  nasd_edrfs_real_symlink(args.in_cookie,
                          args.in_directory,
                          args.in_credential,
                          (char *)args.in_dirpath,
                          (char *)args.in_symlink,
                          args.in_attribute,
                          &res.out_cookie,
                          &res.out_identifier,
                          &res.out_attribute,
                          &res.post_attribute,
                          &res.nasd_status);

  nasd_edrfs_symlink_res_t_marshall(&res, out_res_otw);

  DORETURN(symlink);
}

nasd_srpc_status_t
nasd_remove_fm_server(
  nasd_srpc_listener_t          *listener,
  nasd_srpc_conn_t              *conn,
  nasd_srpc_server_call_t       *call,
  nasd_edrfs_remove_args_otw_t   in_args_otw,
  nasd_edrfs_remove_res_otw_t    out_res_otw)
{
  nasd_edrfs_remove_args_t args;
  nasd_edrfs_remove_res_t res;

  NASD_EDRFS_RPC_OP_STATS_DECL

  DOBEGIN(remove);

  nasd_edrfs_remove_args_t_unmarshall(in_args_otw, &args);

  args.in_dirpath[NASD_EDRFS_MAX_NAME_LEN-1] = '\0';

  nasd_edrfs_real_remove(args.in_cookie,
                         args.in_directory,
                         args.in_credential,
                         (char *)args.in_dirpath,
                         &res.nasd_status);

  nasd_edrfs_remove_res_t_marshall(&res, out_res_otw);

  DORETURN(remove);
}

nasd_srpc_status_t
nasd_mkdir_fm_server(
  nasd_srpc_listener_t         *listener,
  nasd_srpc_conn_t             *conn,
  nasd_srpc_server_call_t      *call,
  nasd_edrfs_mkdir_args_otw_t   in_args_otw,
  nasd_edrfs_mkdir_res_otw_t    out_res_otw)
{
  nasd_edrfs_mkdir_args_t args;
  nasd_edrfs_mkdir_res_t res;

  NASD_EDRFS_RPC_OP_STATS_DECL

  DOBEGIN(mkdir);

  nasd_edrfs_mkdir_args_t_unmarshall(in_args_otw, &args);

  args.in_dirpath[NASD_EDRFS_MAX_NAME_LEN-1] = '\0';

  nasd_edrfs_real_mkdir(args.in_cookie,
                        args.in_directory, 
                        args.in_credential,
                        (char *)args.in_dirpath,
                        args.in_attribute,
                        args.in_fieldmask,
                        &res.out_cookie,
                        &res.out_identifier,
                        &res.out_attribute,
                        &res.post_attribute,
                        &res.nasd_status);

  nasd_edrfs_mkdir_res_t_marshall(&res, out_res_otw);

  DORETURN(mkdir);
}

nasd_srpc_status_t
nasd_rmdir_fm_server(
  nasd_srpc_listener_t         *listener,
  nasd_srpc_conn_t             *conn,
  nasd_srpc_server_call_t      *call,
  nasd_edrfs_rmdir_args_otw_t   in_args_otw,
  nasd_edrfs_rmdir_res_otw_t    out_res_otw)
{
  nasd_edrfs_rmdir_args_t args;
  nasd_edrfs_rmdir_res_t res;

  NASD_EDRFS_RPC_OP_STATS_DECL

  DOBEGIN(rmdir);

  nasd_edrfs_rmdir_args_t_unmarshall(in_args_otw, &args);

  args.in_dirpath[NASD_EDRFS_MAX_NAME_LEN-1] = '\0';

  nasd_edrfs_real_rmdir(args.in_cookie,
                        args.in_directory,
                        args.in_credential,
                        (char *)args.in_dirpath,
                        &res.nasd_status);

  nasd_edrfs_rmdir_res_t_marshall(&res, out_res_otw);

  DORETURN(rmdir);
}

nasd_srpc_status_t
nasd_newcookie_fm_server(
  nasd_srpc_listener_t             *listener,
  nasd_srpc_conn_t                 *conn,
  nasd_srpc_server_call_t          *call,
  nasd_edrfs_newcookie_args_otw_t   in_args_otw,
  nasd_edrfs_newcookie_res_otw_t    out_res_otw)
{
  nasd_edrfs_newcookie_args_t args;
  nasd_edrfs_newcookie_res_t res;

  NASD_EDRFS_RPC_OP_STATS_DECL

  DOBEGIN(newcookie);
  
  nasd_edrfs_newcookie_args_t_unmarshall(in_args_otw, &args);

  nasd_edrfs_real_newcookie(args.in_identifier,
                            args.in_credential,
                            &res.out_cookie,
                            &res.nasd_status);

  nasd_edrfs_newcookie_res_t_marshall(&res, out_res_otw);

  DORETURN(newcookie);
}

nasd_srpc_status_t
nasd_rename_fm_server(
  nasd_srpc_listener_t          *listener,
  nasd_srpc_conn_t              *conn,
  nasd_srpc_server_call_t       *call,
  nasd_edrfs_rename_args_otw_t   in_args_otw,
  nasd_edrfs_rename_res_otw_t    out_res_otw)
{
  nasd_edrfs_rename_args_t args;
  nasd_edrfs_rename_res_t res;

  NASD_EDRFS_RPC_OP_STATS_DECL

  DOBEGIN(rename);

  nasd_edrfs_rename_args_t_unmarshall(in_args_otw, &args);

  args.in_from_path[NASD_EDRFS_MAX_NAME_LEN-1] = '\0';
  args.in_to_path[NASD_EDRFS_MAX_NAME_LEN-1] = '\0';

  nasd_edrfs_real_rename(args.in_cookie,
                         args.in_from_directory,
                         args.in_credential,
                         (char *)args.in_from_path,
                         args.in_to_directory,
                         (char *)args.in_to_path,
                         &res.post_from_attribute,
                         &res.post_to_attribute,
                         &res.nasd_status);

  nasd_edrfs_rename_res_t_marshall(&res, out_res_otw);

  DORETURN(rename);
}

nasd_srpc_status_t
nasd_getstats_fm_server(
  nasd_srpc_listener_t            *listener,
  nasd_srpc_conn_t                *conn,
  nasd_srpc_server_call_t         *call,
  nasd_edrfs_getstats_res_otw_t    out_res_otw)
{
  nasd_edrfs_getstats_res_t res;

  NASD_EDRFS_RPC_OP_STATS_DECL

  DOBEGIN(getstats);

  nasd_edrfs_real_getstats(&res.out_opstats,
                           &res.out_cachestats,
                           &res.out_opdepths,
                           &res.nasd_status);

  nasd_edrfs_getstats_res_t_marshall(&res, out_res_otw);

  DORETURN(getstats);
}

nasd_srpc_status_t
nasd_resetstats_fm_server(
  nasd_srpc_listener_t     *listener,
  nasd_srpc_conn_t         *conn,
  nasd_srpc_server_call_t  *call,
  nasd_res_otw_t            out_res_otw)
{
  nasd_res_t res;

  NASD_EDRFS_RPC_OP_STATS_DECL

  DOBEGIN(resetstats);

  nasd_edrfs_real_resetstats(&res.nasd_status);

  nasd_res_t_marshall(&res, out_res_otw);

  DORETURN(resetstats);
}

/*
 * RPC mechanism
 */

nasd_srpc_listener_t *nasd_edrfs_fm_listener;
int nasd_edrfs_fm_srpc_started = 0;
nasd_threadgroup_t nasd_edrfs_fm_listening_group;

void
nasd_od_srpc_kill_listener_group(
  void  *ignored)
{
  nasd_status_t rc;

  rc = nasd_destroy_threadgroup(&nasd_edrfs_fm_listening_group);
  if (rc) {
    nasd_printf("WARNING: got 0x%x (%s) destroying edrfs_fm_listening_group\n",
      rc, nasd_error_string(rc));
  }
}

nasd_status_t
nasd_edrfs_rpc_specific_init()
{
  nasd_status_t rc;

  bzero((char *)&nasd_edrfs_srpc_lookup_failmem, sizeof(nasd_edrfs_srpc_lookup_failmem));
  nasd_edrfs_srpc_lookup_failmem.nasd_status = NASD_NO_MEM;

  rc = nasd_init_threadgroup(&nasd_edrfs_fm_listening_group);
  if (rc)
    return(rc);
  rc = nasd_shutdown_proc(nasd_edrfs_shutdown,
    nasd_od_srpc_kill_listener_group, NULL);
  if (rc) {
    nasd_od_srpc_kill_listener_group(NULL);
    return(rc);
  }

  nasd_edrfs_fm_listener = NULL;
  rc = nasd_srpc_init();

  if (rc == NASD_SUCCESS) {
    nasd_edrfs_fm_srpc_started = 1;
  }

  return(rc);
}

nasd_status_t
nasd_edrfs_rpc_specific_startup()
{
  return(NASD_SUCCESS);
}

void
nasd_edrfs_rpc_specific_stop()
{
  nasd_status_t rc;

  if (nasd_edrfs_fm_listener) {
    rc = nasd_srpc_listener_destroy(nasd_edrfs_fm_listener);
    if (rc) {
      nasd_printf("EDRFS SERVER ERROR: got 0x%x (%s) from "
        "nasd_srpc_listener_destroy()\n",
        rc, nasd_error_string(rc));
    }
    nasd_edrfs_fm_listener = NULL;
  }

  if (nasd_edrfs_fm_srpc_started) {
    /* Go go gadget linux */
    NASD_THREADGROUP_WAIT_START(&nasd_edrfs_fm_listening_group);
    NASD_THREADGROUP_WAIT_STOP(&nasd_edrfs_fm_listening_group);
    nasd_edrfs_fm_srpc_started = 0;
    nasd_srpc_shutdown();
  }
}

nasd_status_t
nasd_edrfs_rpc_specific_listen(
  int          service_threads,
  nasd_uint16  ipport)
{
  nasd_status_t rc;

  rc = nasd_srpc_listener_start(&nasd_edrfs_fm_listener, service_threads, ipport,
    nasd_edrfs_server_demux);
  if (rc)
    return(rc);

  /*
   * Subtle race condition: if we shut down asynchronously between the start
   * and this wait, we lose the memory. If this seems like a problem, we
   * could resolve it by having _start() hand the serial number to us,
   * and waiting only on the serial number.
   */

  NASD_THREADGROUP_STARTED(&nasd_edrfs_fm_listening_group);
  NASD_THREADGROUP_RUNNING(&nasd_edrfs_fm_listening_group);

  rc = nasd_srpc_listener_wait(nasd_edrfs_fm_listener);

  NASD_THREADGROUP_DONE(&nasd_edrfs_fm_listening_group);

  return(rc);
}

nasd_status_t
nasd_edrfs_rpc_specific_set_stacksize(
  int  stacksize)
{
  return(NASD_OP_NOT_SUPPORTED);
}

#endif /* NASD_RPC_PACKAGE == NASD_RPC_PACKAGE_SRPC */

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