#include <strings.h>
#include <stdlib.h>
#include <libmlrpc/ndr.h>
#include <libmlrpc/mlrpc.h>
#include <libmlrpc/mlsvc_util.h>
static int mlsvc_xa_init(struct mlrpc_client *, struct mlrpc_xaction *,
mlrpc_heap_t *);
static int mlsvc_xa_exchange(struct mlrpc_client *, struct mlrpc_xaction *);
static int mlsvc_xa_read(struct mlrpc_client *, struct mlrpc_xaction *);
static int mlsvc_xa_preserve(struct mlrpc_client *, struct mlrpc_xaction *,
mlrpc_heapref_t *);
static int mlsvc_xa_destruct(struct mlrpc_client *, struct mlrpc_xaction *);
static void mlsvc_xa_release(struct mlrpc_client *, mlrpc_heapref_t *heapref);
int
mlsvc_rpc_bind(mlsvc_handle_t *desc,
const struct mlrpc_smb_client * smbcli,
int fid, const char *service)
{
struct mlsvc_rpc_context *context;
int rc;
bzero(&desc->handle, sizeof (ms_handle_t));
context = malloc(sizeof (struct mlsvc_rpc_context));
if ((desc->context = context) == NULL)
return (-1);
bzero(context, sizeof (struct mlsvc_rpc_context));
context->cli.context = context;
mlrpc_binding_pool_initialize(&context->cli.binding_list,
context->binding_pool, CTXT_N_BINDING_POOL);
context->fid = fid;
context->handle = &desc->handle;
context->cli.xa_init = mlsvc_xa_init;
context->cli.xa_exchange = mlsvc_xa_exchange;
context->cli.xa_read = mlsvc_xa_read;
context->cli.xa_preserve = mlsvc_xa_preserve;
context->cli.xa_destruct = mlsvc_xa_destruct;
context->cli.xa_release = mlsvc_xa_release;
context->cli.smbcli = *smbcli;
rc = mlrpc_c_bind(&context->cli, service, &context->binding);
if (MLRPC_DRC_IS_FAULT(rc)) {
free(context);
desc->context = NULL;
return (-1);
}
return (rc);
}
int
mlsvc_rpc_init(mlrpc_heapref_t *heapref)
{
bzero(heapref, sizeof (mlrpc_heapref_t));
if ((heapref->heap = mlrpc_heap_create()) == NULL)
return (-1);
return (0);
}
int
mlsvc_rpc_call(struct mlsvc_rpc_context *context, int opnum, void *params,
mlrpc_heapref_t *heapref)
{
return (mlrpc_c_call(context->binding, opnum, params, heapref));
}
void
mlsvc_rpc_free(struct mlsvc_rpc_context *context, mlrpc_heapref_t *heapref)
{
mlrpc_c_free_heap(context->binding, heapref);
free(context);
}
static int
mlsvc_xa_init(struct mlrpc_client *mcli, struct mlrpc_xaction *mxa,
mlrpc_heap_t *heap)
{
struct mlndr_stream *recv_mlnds = &mxa->recv_mlnds;
struct mlndr_stream *send_mlnds = &mxa->send_mlnds;
if (heap == 0) {
if ((heap = mlrpc_heap_create()) == 0)
return (-1);
}
mxa->heap = heap;
mlnds_initialize(send_mlnds, 0, NDR_MODE_CALL_SEND, heap);
mlnds_initialize(recv_mlnds, 16 * 1024, NDR_MODE_RETURN_RECV, heap);
return (0);
}
static int
mlsvc_xa_exchange(struct mlrpc_client *mcli, struct mlrpc_xaction *mxa)
{
struct mlsvc_rpc_context *context = mcli->context;
struct mlndr_stream *recv_mlnds = &mxa->recv_mlnds;
struct mlndr_stream *send_mlnds = &mxa->send_mlnds;
int rc;
rc = mcli->smbcli.smb_transact(mcli->smbcli.smb_context,
context->fid,
send_mlnds->pdu_base_addr, send_mlnds->pdu_size,
recv_mlnds->pdu_base_addr, recv_mlnds->pdu_max_size);
if (rc < 0)
recv_mlnds->pdu_size = 0;
else
recv_mlnds->pdu_size = rc;
return (rc);
}
static int
mlsvc_xa_read(struct mlrpc_client *mcli, struct mlrpc_xaction *mxa)
{
struct mlsvc_rpc_context *context = mcli->context;
struct mlndr_stream *mlnds = &mxa->recv_mlnds;
int len;
ssize_t rc;
if ((len = (mlnds->pdu_max_size - mlnds->pdu_size)) < 0)
return (-1);
rc = mcli->smbcli.smb_readx(mcli->smbcli.smb_context,
context->fid,
mlnds->pdu_base_addr + mlnds->pdu_size, len);
if (rc < 0) {
return (-1);
}
mlnds->pdu_size += rc;
if (mlnds->pdu_size > mlnds->pdu_max_size) {
mlnds->pdu_size = mlnds->pdu_max_size;
return (-1);
}
return (rc);
}
static int
mlsvc_xa_preserve(struct mlrpc_client *mcli, struct mlrpc_xaction *mxa,
mlrpc_heapref_t *heapref)
{
heapref->state = MLRPC_HRST_PRESERVED;
heapref->heap = mxa->heap;
heapref->recv_pdu_buf = (char *)mxa->recv_mlnds.pdu_base_addr;
heapref->send_pdu_buf = (char *)mxa->send_mlnds.pdu_base_addr;
mxa->heap = NULL;
return (0);
}
static int
mlsvc_xa_destruct(struct mlrpc_client *mcli, struct mlrpc_xaction *mxa)
{
if (mxa->heap) {
mlnds_destruct(&mxa->recv_mlnds);
mlnds_destruct(&mxa->send_mlnds);
mlrpc_heap_destroy(mxa->heap);
mxa->heap = NULL;
}
return (0);
}
static void
mlsvc_xa_release(struct mlrpc_client *mcli, mlrpc_heapref_t *heapref)
{
if (heapref == NULL)
return;
if (heapref->state == MLRPC_HRST_PRESERVED) {
free(heapref->recv_pdu_buf);
free(heapref->send_pdu_buf);
mlrpc_heap_destroy(heapref->heap);
heapref->heap = NULL;
}
}