#if HAVE_CONFIG_H
#include <config.h>
#endif
#include <dce/rpc.h>
#include <dce/stubbase.h>
#include <lsysdep.h>
#include <dce/uuid.h>
#include <ctxeertl.h>
#ifndef DEBUG_VERBOSE
# define NDEBUG
#endif
#include <assert.h>
#ifdef PERFMON
#include <dce/idl_log.h>
#endif
#ifdef CTXEETEST
# include <stdio.h>
# define DPRINT(ARGS) printf ARGS
#else
# define DPRINT(ARGS)
#endif
ndr_boolean rpc_ss_context_is_set_up = ndr_false;
static RPC_SS_THREADS_ONCE_T context_once = RPC_SS_THREADS_ONCE_INIT;
RPC_SS_THREADS_MUTEX_T rpc_ss_context_table_mutex;
static void rpc_ss_init_context(
void
)
{
RPC_SS_THREADS_MUTEX_CREATE( &rpc_ss_context_table_mutex );
rpc_ss_init_callee_ctx_tables();
}
void rpc_ss_init_context_once(
void
)
{
RPC_SS_THREADS_INIT;
RPC_SS_THREADS_ONCE( &context_once, rpc_ss_init_context );
rpc_ss_context_is_set_up = ndr_true;
}
#define CALLEE_CONTEXT_TABLE_SIZE 256
static callee_context_entry_t *context_table = NULL;
void rpc_ss_init_callee_ctx_tables(
void
)
{
#ifdef PERFMON
RPC_SS_INIT_CALLEE_CTX_TABLES_N;
#endif
assert(!context_table);
context_table = (callee_context_entry_t *)malloc(
CALLEE_CONTEXT_TABLE_SIZE * sizeof(callee_context_entry_t)
);
if (!context_table)
DCETHREAD_RAISE(rpc_x_no_memory);
memset (context_table, 0,
CALLEE_CONTEXT_TABLE_SIZE * sizeof(callee_context_entry_t));
rpc_ss_init_callee_client_table();
#ifdef PERFMON
RPC_SS_INIT_CALLEE_CTX_TABLES_X;
#endif
}
void rpc_ss_create_callee_context
(
rpc_ss_context_t callee_context,
idl_uuid_t *p_uuid,
handle_t h,
ctx_rundown_fn_p_t ctx_rundown,
error_status_t *result
)
{
rpc_client_handle_t ctx_client;
callee_context_entry_t *this_link, *next_link, * volatile new_link;
ndr_boolean is_new_client;
#ifdef PERFMON
RPC_SS_CREATE_CALLEE_CONTEXT_N;
#endif
RPC_SS_INIT_CONTEXT
rpc_binding_inq_client(h, &ctx_client, (error_status_t *) result);
if (*result != error_status_ok) return;
RPC_SS_THREADS_MUTEX_LOCK(&rpc_ss_context_table_mutex);
DPRINT(("Seized context tables\n"));
this_link = &context_table[uuid_hash(p_uuid,(error_status_t *)result)
% CALLEE_CONTEXT_TABLE_SIZE];
if ( uuid_is_nil(&this_link->uuid, (error_status_t *)result) )
{
new_link = this_link;
next_link = NULL;
}
else
{
new_link = (callee_context_entry_t *)
malloc(sizeof(callee_context_entry_t));
if (new_link == NULL)
{
RPC_SS_THREADS_MUTEX_UNLOCK(&rpc_ss_context_table_mutex);
DPRINT(("Released context tables\n"));
DCETHREAD_RAISE( rpc_x_no_memory );
}
next_link = this_link->next_context;
this_link->next_context = new_link;
}
memcpy(
(char *)&new_link->uuid,
(char *)p_uuid,
sizeof(idl_uuid_t)
);
new_link->user_context = callee_context;
new_link->rundown = ctx_rundown;
new_link->next_context = next_link;
DCETHREAD_TRY
rpc_ss_add_to_callee_client(ctx_client,new_link,&is_new_client,
result);
DCETHREAD_FINALLY
RPC_SS_THREADS_MUTEX_UNLOCK(&rpc_ss_context_table_mutex);
DPRINT(("Released context tables\n"));
DCETHREAD_ENDTRY
if ((*result == error_status_ok) && is_new_client)
{
rpc_network_monitor_liveness( h, ctx_client,
rpc_ss_rundown_client,
(error_status_t *) result );
#ifdef PERFMON
RPC_SS_CREATE_CALLEE_CONTEXT_X;
#endif
}
}
void rpc_ss_update_callee_context
(
rpc_ss_context_t callee_context,
idl_uuid_t *p_uuid,
error_status_t *result
)
{
callee_context_entry_t *this_link;
#ifdef PERFMON
RPC_SS_UPDATE_CALLEE_CONTEXT_N;
#endif
RPC_SS_THREADS_MUTEX_LOCK(&rpc_ss_context_table_mutex);
DPRINT(("Seized context tables\n"));
this_link = &context_table[uuid_hash(p_uuid,result)
% CALLEE_CONTEXT_TABLE_SIZE];
while ( ! uuid_equal(p_uuid,&this_link->uuid,result) )
{
this_link = this_link->next_context;
if (this_link == NULL)
{
RPC_SS_THREADS_MUTEX_UNLOCK(&rpc_ss_context_table_mutex);
DPRINT(("Released context tables\n"));
DCETHREAD_RAISE( rpc_x_ss_context_mismatch);
}
}
this_link->user_context = callee_context;
RPC_SS_THREADS_MUTEX_UNLOCK(&rpc_ss_context_table_mutex);
DPRINT(("Released context tables\n"));
*result = error_status_ok;
#ifdef PERFMON
RPC_SS_UPDATE_CALLEE_CONTEXT_X;
#endif
}
void rpc_ss_ee_ctx_from_wire
(
ndr_context_handle *p_wire_context,
rpc_ss_context_t *p_context,
volatile error_status_t *p_st
)
{
idl_uuid_t *p_uuid;
callee_context_entry_t *this_link;
#ifdef PERFMON
RPC_SS_EE_CTX_FROM_WIRE_N;
#endif
p_uuid = &p_wire_context->context_handle_uuid;
#ifdef DEBUGCTX
debug_context_lookup(p_uuid);
debug_context_table();
#endif
*p_st = error_status_ok;
if ( uuid_is_nil(p_uuid, (error_status_t *)p_st) )
{
*p_context = NULL;
#ifdef PERFMON
RPC_SS_EE_CTX_FROM_WIRE_X;
#endif
return;
}
RPC_SS_THREADS_MUTEX_LOCK(&rpc_ss_context_table_mutex);
DPRINT(("Seized context tables\n"));
this_link = &context_table[uuid_hash(p_uuid, (error_status_t *)p_st)
% CALLEE_CONTEXT_TABLE_SIZE];
while ( ! uuid_equal(p_uuid,&this_link->uuid, (error_status_t *)p_st) )
{
this_link = this_link->next_context;
if (this_link == NULL)
{
RPC_SS_THREADS_MUTEX_UNLOCK(&rpc_ss_context_table_mutex);
DPRINT(("Released context tables\n"));
#ifdef PERFMON
RPC_SS_EE_CTX_FROM_WIRE_X;
#endif
DCETHREAD_RAISE( rpc_x_ss_context_mismatch );
return;
}
}
*p_context = this_link->user_context;
RPC_SS_THREADS_MUTEX_UNLOCK(&rpc_ss_context_table_mutex);
DPRINT(("Released context tables\n"));
#ifdef PERFMON
RPC_SS_EE_CTX_FROM_WIRE_X;
#endif
return;
}
void rpc_ss_destroy_callee_context
(
idl_uuid_t *p_uuid,
handle_t h,
error_status_t *result
)
{
rpc_client_handle_t close_client;
#ifdef PERFMON
RPC_SS_DESTROY_CALLEE_CONTEXT_N;
#endif
RPC_SS_THREADS_MUTEX_LOCK(&rpc_ss_context_table_mutex);
DPRINT(("Seized context tables\n"));
rpc_ss_lkddest_callee_context(p_uuid,&close_client,result);
RPC_SS_THREADS_MUTEX_UNLOCK(&rpc_ss_context_table_mutex);
DPRINT(("Released context tables\n"));
if ((*result == error_status_ok) && (close_client != NULL))
{
rpc_network_stop_monitoring(h, close_client, (error_status_t *) result);
}
#ifdef PERFMON
RPC_SS_DESTROY_CALLEE_CONTEXT_X;
#endif
}
void rpc_ss_lkddest_callee_context
(
idl_uuid_t *p_uuid,
rpc_client_handle_t *p_close_client,
error_status_t *result
)
{
callee_context_entry_t *this_link, *next_link, *last_link;
#ifdef PERFMON
RPC_SS_LKDDEST_CALLEE_CONTEXT_N;
#endif
this_link = &context_table[uuid_hash(p_uuid,(error_status_t *) result)
% CALLEE_CONTEXT_TABLE_SIZE];
next_link = this_link->next_context;
if ( uuid_equal(p_uuid,&this_link->uuid, (error_status_t *) result) )
{
rpc_ss_take_from_callee_client(this_link,p_close_client,result);
if (next_link == NULL)
{
uuid_create_nil(&this_link->uuid, (error_status_t *) result);
}
else
{
memcpy(
(char *)&this_link->uuid,
(char *)&next_link->uuid,
sizeof(idl_uuid_t)
);
this_link->user_context = next_link->user_context;
this_link->rundown = next_link->rundown;
this_link->p_client_entry = next_link->p_client_entry;
this_link->prev_in_client = next_link->prev_in_client;
if (this_link->prev_in_client == NULL)
{
(this_link->p_client_entry)->first_context = this_link;
}
else
{
(this_link->prev_in_client)->next_in_client = this_link;
}
this_link->next_in_client = next_link->next_in_client;
if (this_link->next_in_client == NULL)
{
(this_link->p_client_entry)->last_context = this_link;
}
else
{
(this_link->next_in_client)->prev_in_client = this_link;
}
this_link->next_context = next_link->next_context;
free((char_p_t)next_link);
}
#ifdef PERFMON
RPC_SS_LKDDEST_CALLEE_CONTEXT_X;
#endif
return;
}
else
{
while (next_link != NULL)
{
last_link = this_link;
this_link = next_link;
next_link = this_link->next_context;
if ( uuid_equal(p_uuid,&this_link->uuid,(error_status_t *)result) )
{
rpc_ss_take_from_callee_client(this_link,p_close_client,result);
last_link->next_context = next_link;
free((char_p_t)this_link);
#ifdef PERFMON
RPC_SS_LKDDEST_CALLEE_CONTEXT_X;
#endif
return;
}
}
RPC_SS_THREADS_MUTEX_UNLOCK(&rpc_ss_context_table_mutex);
DPRINT(("Released context tables\n"));
DCETHREAD_RAISE( rpc_x_ss_context_mismatch);
}
}
#ifdef CTXEETEST
void dump_context_table()
{
int i;
callee_context_entry_t *this_link;
callee_client_entry_t *this_client;
error_status_t status;
for (i=0; i<CALLEE_CONTEXT_TABLE_SIZE; i++)
{
if ( ! uuid_is_nil(&context_table[i].uuid, &status) )
{
this_link = &context_table[i];
printf("Context chain for context_slot %d\n",i);
while (this_link != NULL)
{
printf("\t %s %lx ",
&this_link->uuid,
this_link->user_context);
this_client = this_link->p_client_entry;
printf("Client %lx %d\n",
this_client->client,
this_client->count);
this_link = this_link->next_context;
}
}
}
}
#endif
#ifdef DEBUGCTX
static ndr_boolean debug_file_open = ndr_false;
static char *debug_file = "ctxee.dmp";
static FILE *debug_fid;
static int debug_context_lookup(uuid_p)
unsigned char *uuid_p;
{
int j;
unsigned long k;
if (!debug_file_open)
{
debug_fid = fopen(debug_file, "w");
debug_file_open = ndr_true;
}
fprintf(debug_fid, "L");
for (j=0; j<sizeof(idl_uuid_t); j++)
{
k = *uuid_p++;
fprintf(debug_fid, " %02x", k);
}
fprintf(debug_fid, "\n");
}
static int debug_context_add(user_context)
long user_context;
{
if (!debug_file_open)
{
debug_fid = fopen(debug_file, "w");
debug_file_open = ndr_true;
}
fprintf(debug_fid, "N %lx\n", user_context);
}
static int debug_context_table()
{
int i, j;
unsigned long k;
ndr_boolean at_home;
unsigned char *uuid_p;
callee_context_entry_t *this_link;
callee_client_entry_t *this_client;
error_status_t status;
if (!debug_file_open)
{
debug_fid = fopen(debug_file, "w");
debug_file_open = ndr_true;
}
for (i=0; i<CALLEE_CONTEXT_TABLE_SIZE; i++)
{
if ( ! uuid_is_nil(&context_table[i].uuid, &status) )
{
at_home = ndr_true;
this_link = &context_table[i];
while (this_link != NULL)
{
if (at_home)
{
at_home = ndr_false;
fprintf(debug_fid, "%4d:", i);
}
else
fprintf(debug_fid, " C:", i);
uuid_p = (unsigned char *)&this_link->uuid;
for (j=0; j<sizeof(this_link->uuid); j++)
{
k = *uuid_p++;
fprintf(debug_fid, " %02x", k);
}
this_client = this_link->p_client_entry;
fprintf(debug_fid, " client %lx %d\n",
this_client->client,
this_client->count);
this_link = this_link->next_context;
}
}
}
}
#endif
void rpc_ss_ee_ctx_to_wire
(
rpc_ss_context_t callee_context,
ndr_context_handle *p_wire_context,
handle_t h,
ctx_rundown_fn_p_t ctx_rundown,
ndr_boolean in_out,
volatile error_status_t *p_st
)
{
#ifdef DEBUGCTX
debug_context_add(callee_context);
#endif
int wire, context;
p_wire_context->context_handle_attributes = 0;
#ifdef PERFMON
RPC_SS_EE_CTX_TO_WIRE_N;
#endif
wire = in_out && !uuid_is_nil(
&p_wire_context->context_handle_uuid, (error_status_t *)p_st
)? 4: 0;
context = callee_context? 2: 0;
in_out = in_out? 1: 0;
switch (wire | context | in_out) {
case 0:
uuid_create_nil(
&p_wire_context->context_handle_uuid, (error_status_t *)p_st
);
break;
case 1:
*p_st = error_status_ok;
break;
case 2:
case 3:
uuid_create(
&p_wire_context->context_handle_uuid, (error_status_t *)p_st
);
rpc_ss_create_callee_context(
callee_context, &p_wire_context->context_handle_uuid, h,
ctx_rundown, (error_status_t *)p_st
);
break;
case 5:
rpc_ss_destroy_callee_context(
&p_wire_context->context_handle_uuid, h, (error_status_t *)p_st
);
if (*p_st != error_status_ok) break;
uuid_create_nil(
&p_wire_context->context_handle_uuid, (error_status_t *)p_st
);
break;
case 7:
rpc_ss_update_callee_context(
callee_context, &p_wire_context->context_handle_uuid,
(error_status_t *)p_st
);
break;
default:
assert(!(wire | context | in_out));
break;
}
#ifdef DEBUGCTX
debug_context_table();
#endif
#ifdef PERFMON
RPC_SS_EE_CTX_TO_WIRE_X;
#endif
}