The sample server application source compiles a message catalog as well as the required auxiliary .c and .h files from a sams file. In part, the file looks like the following (for the full file, see A Sample Application):
# Part I
component smp
table smp__table
technology dce
####################################################################
# Part II
serviceability table smp_svc_table handle smp_svc_handle
start
subcomponent smp_s_server "server" smp_i_svc_server
subcomponent smp_s_manager "manager" smp_i_svc_manager
subcomponent smp_s_binder
"binder" smp_i_svc_binder
end
####################################################################
# Part III
# Note that
defining the "sub-component" and "attributes" fields
# will result in a convenience macro's being generated for the
# message in question...
start
code sign_on
subcomponent smp_s_server
attributes "svc_c_sev_notice"
text "Starting up"
explanation ""
action "None required."
end
start
code cleanup
subcomponent
smp_s_server
attributes "svc_c_sev_notice"
text "Cleaning up"
explanation "Starting server cleanup"
action
"None required."
end
start
code server_exit
subcomponent smp_s_server
attributes
"svc_c_sev_notice"
text "Exiting"
explanation ""
action "None required."
end
start
code signal_catcher
subcomponent smp_s_server
attributes "svc_c_sev_notice"
text "Spawning signal handler
thread"
explanation ""
action "None required."
end
start
code no_signal_catcher
subcomponent smp_s_server
attributes "svc_c_sev_notice"
text "Spawn signal handler failed"
explanation "RPC runtime
error. pthread_create() failed."
action ""
end
start
code bad_entryname_count
subcomponent
smp_s_server
attributes "svc_c_sev_notice"
text "Bad entryname count"
explanation "Count of entrynames doesn't match count of object
uuids"
action ""
end
start
code cannot_resolve_name
subcomponent smp_s_server
attributes "svc_c_sev_notice"
text "Can't resolve name"
explanation "ACL manager resolver failed to resolve name"
action
"The ACL databases may be corrupt and need to be regenerated."
end
start
code cannot_manage_keys
subcomponent
smp_s_server
attributes "svc_c_sev_notice"
text "Can't spawn key management thread."
explanation "RPC runtime error."
action ""
end
start
code no_acl_dbs
subcomponent smp_s_server
attributes
"svc_c_sev_notice"
text "ACL databases not found, creating them from scratch"
explanation ""
action "None required."
end
start
code exporting_to
subcomponent smp_s_server
attributes "svc_c_sev_notice"
text "Exporting to %s"
explanation "Exporting to CDS entry"
action "None required."
end
start
code unexporting_from
subcomponent smp_s_server
attributes "svc_c_sev_notice"
text
"Unexporting from %s"
explanation "Unexporting from CDS entry"
action "None required."
end
start
code
importing_from
subcomponent smp_s_server
attributes "svc_c_sev_notice"
text "Importing from %s"
explanation
"Importing from CDS entry"
action "None required."
end
start
code auth_set_client
subcomponent smp_s_server
attributes "svc_c_sev_notice"
text "Beginning client authentication setup"
explanation ""
action "None required."
end
start
code bindings_received
subcomponent smp_s_server
attributes "svc_c_sev_notice"
text "Nr of %s bindings received == %d"
explanation "Server diagnostic message."
action
"None required."
end
start
code full_binding
subcomponent smp_s_server
attributes
"svc_c_sev_notice"
text "Full %s binding in string form == %s"
explanation "Server diagnostic message."
action "None required."
end
start
code server_error
subcomponent smp_s_server
attributes "svc_c_sev_fatal"
text "%s: %s"
explanation "general error message"
action "?"
end
start
code
no_permissions
subcomponent smp_s_manager
attributes "svc_c_sev_notice"
text "No permissions"
explanation
"Client does not have permissions for operation"
action "None required."
end
start
code object_not_found
subcomponent smp_s_manager
attributes "svc_c_sev_error"
text "Object not found"
explanation "object was not found in
UUID-indexed database"
action "None required."
end
start
code manager_error
subcomponent
smp_s_manager
attributes "svc_c_sev_fatal"
text "%s: %s"
explanation "general error message"
action "?"
end
start
code binder_error
subcomponent smp_s_binder
attributes "svc_c_sev_fatal"
text "%s: %s"
explanation "general error message"
action "?"
end
####################################################################
# Part IIIa
# Messages for serviceability table
#
# Note that
there has to be one of these for each of
# the subcomponents declared in the second part of
# the file (above)...
start
!intable undocumented
code smp_i_svc_server
text "Sample server"
end
start !intable
undocumented
code smp_i_svc_binder
text "Sample object binder"
end
start !intable undocumented
code smp_i_svc_manager
text "Sample manager"
end
The server main() function then establishes the required serviceability context and defines a message table with the following calls:
/* Set the program name for serviceability messages... */
dce_svc_set_progname(argv[0], &status);
/* Get serviceability handle...
*/
smp_svc_handle = dce_svc_register(smp_svc_table,
(idl_char*)"smp",
&status);
/* Set up in-memory serviceability message table... */
dce_msg_define_msg_table(smp__table,
sizeof
smp__table / sizeof smp__table[0],
&status);
The following fragments illustrate remote error handling using a common status parameter. The .idl file for the sample interface includes the following declarations:
void sample_call(
[in] handle_t binding,
[out] long *status,
[in,out] error_status_t *remote_status);
This is matched in the .acf file by the following:
interface sample
{
sample_call([comm_status,fault_status] remote_status);
}
Then, for example, the server implementation of the sample_call( ) remote call can return the smp_s_no_perms status code on authorization failure:
void
sample_call(
rpc_binding_handle_t binding, /* Client binding. */
idl_long_int *status,
error_status_t
*remote_status)
{
extern uuid_t sample_acl_mgr_uuid, sample_acl_uuid;
boolean32 authorized = 0;
/* We have
to explicitly initialize the remote status value; */
/* otherwise, if no error occurs in the transmission (which */
/* would cause the runtime to assign an
error value to this */
/* variable), its value will be whatever it happened to be */
/* when the RPC was made by the client... */
*remote_status = rpc_s_ok;
DCE_SVC_DEBUG((smp_svc_handle,
smp_s_manager,
svc_c_debug6,
"Entering sample_call()..."));
/* Check whether client is authorized or not... */
DCE_SVC_DEBUG((smp_svc_handle,
smp_s_manager,
svc_c_debug6,
"Calling
dce_acl_is_client_authorized()..."));
dce_acl_is_client_authorized(
binding, /* Client's binding handle. */
&sample_acl_mgr_uuid, /* ACL manager type UUID. */
&sample_acl_uuid, /* The ACL UUID. */
NULL, /* Pointer to owner's UUID. */
NULL, /* Pointer to owner's group's UUID. */
sec_acl_perm_read,
/* The desired privileges. */
&authorized, /* Will be TRUE or FALSE on return. */
remote_status);
if (*remote_status != error_status_ok)
{
print_manager_error("dce_acl_is_client_authorized()",
*remote_status);
return;
}
if (authorized)
{
DCE_SVC_DEBUG((smp_svc_handle,
smp_s_manager,
svc_c_debug8,
"Call authorized"));
/* HERE'S WHERE WE SHOULD ACTUALLY DO SOMETHING! */
*status = error_status_ok;
}
else
{
DCE_SVC_DEBUG((smp_svc_handle,
smp_s_manager,
svc_c_debug8,
"Call
not authorized"));
/* Return no permissions status to client */
*status = no_permissions;
}
DCE_SVC_DEBUG((smp_svc_handle,
smp_s_manager,
svc_c_debug6,
"Successfully exiting sample_call()"));
}
The client making the sample_call( ) remote call can then check both RPC comm and fault status and application-specific status and display any error messages with the same code:
sample_call(binding_h, &rpc_status, &rpc_remote_status);
if (rpc_remote_status != error_status_ok)
{
print_error("sample_call()", rpc_remote_status);
exit(1);
}