/* * Copyright (c) 2010-2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of Apple Inc. ("Apple") nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * Portions of this software have been released under the following terms: * * (c) Copyright 1989-1993 OPEN SOFTWARE FOUNDATION, INC. * (c) Copyright 1989-1993 HEWLETT-PACKARD COMPANY * (c) Copyright 1989-1993 DIGITAL EQUIPMENT CORPORATION * * To anyone who acknowledges that this file is provided "AS IS" * without any express or implied warranty: * permission to use, copy, modify, and distribute this file for any * purpose is hereby granted without fee, provided that the above * copyright notices and this notice appears in all source code copies, * and that none of the names of Open Software Foundation, Inc., Hewlett- * Packard Company or Digital Equipment Corporation be used * in advertising or publicity pertaining to distribution of the software * without specific, written prior permission. Neither Open Software * Foundation, Inc., Hewlett-Packard Company nor Digital * Equipment Corporation makes any representations about the suitability * of this software for any purpose. * * Copyright (c) 2007, Novell, Inc. All rights reserved. * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of Novell Inc. nor the names of its contributors * may be used to endorse or promote products derived from this * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * @APPLE_LICENSE_HEADER_END@ */ /* ** ** NAME ** ** combind.c ** ** FACILITY: ** ** Remote Procedure Call (RPC) ** ** ABSTRACT: ** ** Definition of the Binding Services for the Common Communication ** Services component. These routines are called by applications to ** manipulate Binding Rep data structures required by the runtime. ** ** */ #include /* Common declarations for all RPC runtime */ #include /* Common communications services */ #include /* Private communications services */ #include /* I18N codesets definitions */ #include /* **++ ** ** ROUTINE NAME: rpc__binding_free ** ** SCOPE: PRIVATE - declared in com.h ** ** DESCRIPTION: ** ** This routine will really free the Binding Rep memory - this routine ** should not be called directly; RPC_BINDING_RELEASE() should be used. ** Since a Binding Rep's size is RPC Protocol Service-specific the RPC ** Protocol Service is called to do the actual free. ** ** INPUTS: ** ** binding_rep The binding rep pointer which points to the binding ** rep data structure to be freed. ** ** INPUTS/OUTPUTS: none ** ** OUTPUTS: ** ** status A value indicating the status of the routine. ** ** rpc_s_ok The call was successful. ** ** IMPLICIT INPUTS: none ** ** IMPLICIT OUTPUTS: none ** ** FUNCTION VALUE: void ** ** SIDE EFFECTS: none ** **-- **/ PRIVATE void rpc__binding_free ( rpc_binding_rep_p_t *binding_rep_p, unsigned32 *status ) { rpc_binding_rep_p_t binding_rep = *binding_rep_p; unsigned32 temp_status = rpc_s_ok; rpc_cs_method_eval_p_t method_p ATTRIBUTE_UNUSED; rpc_cs_tags_eval_p_t tags_p ATTRIBUTE_UNUSED; CODING_ERROR (status); /* * The handle must be locked so that we can "atomically" * free it. */ RPC_LOCK_ASSERT(0); /* * see if an RPC address exists in this binding */ if (binding_rep->rpc_addr != NULL) { /* * if so, ask the NAF extension service to free the RPC address */ (*rpc_g_naf_id[binding_rep->rpc_addr->sa.family].epv ->naf_addr_free) (&(binding_rep->rpc_addr), status); if (*status != rpc_s_ok) return; } /* * see if we have a protocol version */ if (binding_rep->protocol_version != NULL) { rpc__binding_prot_version_free(&(binding_rep->protocol_version)); } #ifdef PD_BUILD /* * check code sets I14Y */ if (binding_rep->extended_bind_flag == RPC_C_BH_EXTENDED_CODESETS) { /* Release codesets relating binding information. * Determine the data structure */ switch (binding_rep->cs_eval.key) { case RPC_CS_EVAL_METHOD: method_p = &binding_rep->cs_eval.tagged_union.method_key; if (method_p->server != NULL) rpc_ns_mgmt_free_codesets ( &(method_p->server), &temp_status ); if (method_p->client != NULL) rpc_ns_mgmt_free_codesets ( &(method_p->client), &temp_status ); break; case RPC_CS_EVAL_TAGS: break; default: temp_status = rpc_s_ss_invalid_codeset_tag; break; } } #endif /* * if we have any authentication info, free it up now. */ rpc__auth_info_binding_release(binding_rep); /* * if we have transport information, free it up now */ if (binding_rep->transport_info) { rpc__transport_info_release(binding_rep->transport_info); } /* * Free the name service-specific part of the binding. */ if (binding_rep->ns_specific != NULL) (*rpc_g_ns_specific_free_fn) (&binding_rep->ns_specific); /* * then ask the protocol service to free the binding rep and * NULL the reference. */ (*rpc_g_protocol_id[binding_rep->protocol_id].binding_epv ->binding_free) (binding_rep_p, status); if ((temp_status != rpc_s_ok) && (*status == rpc_s_ok)) *status = temp_status; } /* **++ ** ** ROUTINE NAME: rpc_binding_free ** ** SCOPE: PUBLIC - declared in rpc.idl ** ** DESCRIPTION: ** ** This routine will release the reference on the Binding Rep and free ** the rep when no more references exist. A NULL pointer will be ** returned. Most runtime internal operations that want to release a binding ** handle reference should probably use RPC_BINDING_RELEASE(), not this ** routine. ** ** INPUTS: none ** ** INPUTS/OUTPUTS: ** ** binding_h The binding handle which points to the binding ** rep data structure to be freed. ** ** OUTPUTS: ** ** status A value indicating the status of the routine. ** ** rpc_s_ok The call was successful. ** rpc_s_invalid_binding ** RPC Protocol ID in binding handle was invalid. ** rpc_s_coding_error ** ** IMPLICIT INPUTS: none ** ** IMPLICIT OUTPUTS: none ** ** FUNCTION VALUE: void ** ** SIDE EFFECTS: none ** **-- **/ PUBLIC void rpc_binding_free ( rpc_binding_handle_t *binding_h, unsigned32 *status ) { rpc_binding_rep_p_t binding_rep = (rpc_binding_rep_p_t) *binding_h; assert(binding_rep != NULL); CODING_ERROR (status); RPC_VERIFY_INIT (); RPC_BINDING_VALIDATE_CLIENT(binding_rep, status); if (*status != rpc_s_ok) return; /* * We need to lock the handle so that we can "atomically" * release it. */ RPC_LOCK(0); /* * Release and NULL the reference (possibly free the handle). */ RPC_BINDING_RELEASE((rpc_binding_rep_p_t *) binding_h, status); RPC_UNLOCK(0); } /* **++ ** ** ROUTINE NAME: rpc_binding_vector_free ** ** SCOPE: PUBLIC - declared in rpc.idl ** ** DESCRIPTION: ** ** This routine will free the Binding Rep pointed to by each non-NULL ** entry in the vector array. The vector memory itself is then freed. ** ** INPUTS: none ** ** INPUTS/OUTPUTS: ** ** binding_vec A vector of pointers to binding rep structures. ** ** OUTPUTS: ** ** status A value indicating the status of the routine. ** ** rpc_s_ok The call was successful. ** rpc_s_coding_error ** rpc_s_invalid_arg ** ** IMPLICIT INPUTS: none ** ** IMPLICIT OUTPUTS: none ** ** FUNCTION VALUE: void ** ** SIDE EFFECTS: none ** **-- **/ PUBLIC void rpc_binding_vector_free ( rpc_binding_vector_p_t *binding_vec, unsigned32 *status ) { unsigned32 i; CODING_ERROR (status); RPC_VERIFY_INIT (); /* * check to see if binding_vec is NULL, and if so, * return with an error status */ if (binding_vec == NULL) { *status = rpc_s_invalid_arg; return; } /* * free each element in the vector array (that's non-NULL) */ for (i = 0; i < (*binding_vec)->count; i++) { if ((*binding_vec)->binding_h[i] != NULL) { rpc_binding_free (&(*binding_vec)->binding_h[i], status); if (*status != rpc_s_ok) return; } } /* * now free the vector memory itself */ RPC_MEM_FREE (*binding_vec, RPC_C_MEM_BINDING_VEC); *binding_vec = NULL; *status = rpc_s_ok; } /* **++ ** ** ROUTINE NAME: rpc_binding_set_object ** ** SCOPE: PUBLIC - declared in rpc.idl ** ** DESCRIPTION: ** ** This routine will set the object UUID field in the Binding Rep to the ** object UUID given. The RPC Protocol Service identified by the RPC ** Protocol ID in the Binding Rep will be notified that the Binding Rep ** has changed. ** ** INPUTS: ** ** binding_h The binding handle which points to the binding ** rep data structure to be modified. ** ** object_uuid The unique identifier of an object to which an RPC ** may be made. ** ** INPUTS/OUTPUTS: none ** ** OUTPUTS: ** ** status A value indicating the status of the routine. ** ** rpc_s_ok The call was successful. ** rpc_s_invalid_binding ** RPC Protocol ID in binding handle was invalid. ** rpc_s_coding_error ** ** IMPLICIT INPUTS: none ** ** IMPLICIT OUTPUTS: none ** ** FUNCTION VALUE: void ** ** SIDE EFFECTS: none ** **-- **/ PUBLIC void rpc_binding_set_object ( rpc_binding_handle_t binding_h, uuid_p_t object_uuid, unsigned32 *status ) { rpc_binding_rep_p_t binding_rep = (rpc_binding_rep_p_t) binding_h; assert(binding_rep != NULL); CODING_ERROR (status); RPC_VERIFY_INIT (); RPC_BINDING_VALIDATE_CLIENT(binding_rep, status); if (*status != rpc_s_ok) return; /* * copy the new object UUID into the binding rep * (note: a NULL object uuid pointer is treated as a nil uuid) */ if (object_uuid != NULL) { binding_rep->obj = *object_uuid; } else { uuid_create_nil (&(binding_rep->obj), status); } /* * notify the protocol service that the binding has changed */ (*rpc_g_protocol_id[binding_rep->protocol_id].binding_epv ->binding_changed) (binding_rep, status); } /* **++ ** ** ROUTINE NAME: rpc_binding_inq_object ** ** SCOPE: PUBLIC - declared in rpc.idl ** ** DESCRIPTION: ** ** This routine will inquire what the object UUID is in a Binding Rep. ** ** INPUTS: ** ** binding_h The binding handle which points to the binding ** rep data structure to be read. ** ** INPUTS/OUTPUTS: none ** ** OUTPUTS: ** ** object_uuid The unique identifier of an object to which an RPC ** may be made. ** ** status A value indicating the status of the routine. ** ** rpc_s_ok The call was successful. ** rpc_s_invalid_binding ** RPC Protocol ID in binding handle was invalid. ** rpc_s_coding_error ** ** IMPLICIT INPUTS: none ** ** IMPLICIT OUTPUTS: none ** ** FUNCTION VALUE: void ** ** SIDE EFFECTS: none ** **-- **/ PUBLIC void rpc_binding_inq_object ( rpc_binding_handle_t binding_h, idl_uuid_t *object_uuid, unsigned32 *status ) { rpc_binding_rep_p_t binding_rep = (rpc_binding_rep_p_t) binding_h; assert(binding_rep != NULL); CODING_ERROR (status); RPC_VERIFY_INIT (); RPC_BINDING_VALIDATE(binding_rep, status); if (*status != rpc_s_ok) return; *object_uuid = binding_rep->obj; *status = rpc_s_ok; } /* **++ ** ** ROUTINE NAME: rpc_binding_reset ** ** SCOPE: PUBLIC - declared in rpc.idl ** ** DESCRIPTION: ** ** This routine will clear the endpoint in the RPC address of the Binding ** Rep. The Network Address Family Extension Service identified by the ** NAF ID in the RPC address will be called to actually clear the endpoint ** since its format is NAF-specific. Finally the RPC Protocol Service ** identifed by the RPC Protocol ID in the Binding Rep will be notified ** that the Binding Rep has changed. ** ** INPUTS: ** ** binding_h The binding handle which points to the binding ** rep data structure to be modified. ** ** INPUTS/OUTPUTS: none ** ** OUTPUTS: ** ** status A value indicating the status of the routine. ** ** rpc_s_ok The call was successful. ** rpc_s_invalid_binding ** RPC Protocol ID in binding handle was invalid. ** rpc_s_coding_error ** ** IMPLICIT INPUTS: none ** ** IMPLICIT OUTPUTS: none ** ** FUNCTION VALUE: void ** ** SIDE EFFECTS: none ** **-- **/ PUBLIC void rpc_binding_reset ( rpc_binding_handle_t binding_h, unsigned32 *status ) { rpc_binding_rep_p_t binding_rep = (rpc_binding_rep_p_t) binding_h; assert(binding_rep != NULL); CODING_ERROR (status); RPC_VERIFY_INIT (); RPC_BINDING_VALIDATE_CLIENT(binding_rep, status); if (*status != rpc_s_ok) return; /* * There is no longer a server instance associated with the binding. */ RPC_LOCK(0); binding_rep->bound_server_instance = false; RPC_UNLOCK(0); /* * if binding endpoint is not set, don't do anything */ if (!binding_rep->addr_has_endpoint) { *status = rpc_s_ok; return; } assert(binding_rep->rpc_addr != NULL); /* * Tell the NAF extension service to clear the endpoint. A zero * length string *must* be passed in to naf_addr_set_endpoint to * clear the endpoint. Do *not* pass in NULL. This will generate a * dynamic endpoint in certain nafs. */ (*rpc_g_naf_id[binding_rep->rpc_addr->sa.family].epv ->naf_addr_set_endpoint) ((unsigned_char_p_t) "", &(binding_rep->rpc_addr), status); if (*status != rpc_s_ok) return; /* * clear the endpoint flag in the binding rep */ binding_rep->addr_has_endpoint = false; /* * notify the protocol service that the binding rep has been reset */ (*rpc_g_protocol_id[binding_rep->protocol_id].binding_epv ->binding_reset) (binding_rep, status); } /* **++ ** ** ROUTINE NAME: rpc_binding_copy ** ** SCOPE: PUBLIC - declared in rpc.idl ** ** DESCRIPTION: ** ** This routine will allocate a new Binding Rep through the RPC Protocol ** Service. The common part of the Binding Rep will then be filled in and ** the RPC Protocol Service will be called to initialize the RPC Protocol ** Service-specific part of the Binding Rep. ** ** INPUTS: ** ** src_binding_h The binding handle which points to the source ** binding rep data structure to be copied. ** ** INPUTS/OUTPUTS: none ** ** OUTPUTS: ** ** dst_binding_h The binding handle which points to the destination ** binding rep data structure to be created. ** ** status A value indicating the status of the routine. ** ** rpc_s_ok The call was successful. ** rpc_s_invalid_binding ** RPC Protocol ID in binding handle was invalid. ** rpc_s_coding_error ** ** IMPLICIT INPUTS: none ** ** IMPLICIT OUTPUTS: none ** ** FUNCTION VALUE: void ** ** SIDE EFFECTS: none ** **-- **/ PUBLIC void rpc_binding_copy ( rpc_binding_handle_t src_binding_h, rpc_binding_handle_t *dst_binding_h, unsigned32 *status ) { rpc_binding_rep_p_t src_binding_rep = (rpc_binding_rep_p_t) src_binding_h; rpc_binding_rep_p_t dst_binding_rep; rpc_addr_p_t rpc_addr; unsigned32 tmp_status; boolean have_addr = false; rpc_cs_method_eval_p_t method_s_p; rpc_cs_method_eval_p_t method_d_p; rpc_cs_tags_eval_p_t tags_s_p; rpc_cs_tags_eval_p_t tags_d_p; if (src_binding_rep == NULL) { *status = rpc_s_invalid_arg; return; } CODING_ERROR (status); RPC_VERIFY_INIT (); RPC_BINDING_VALIDATE_CLIENT(src_binding_rep, status); if (*status != rpc_s_ok) return; if (src_binding_rep->rpc_addr == NULL) { *status = rpc_s_invalid_arg; return; } (*rpc_g_naf_id[src_binding_rep->rpc_addr->sa.family].epv ->naf_addr_copy) (src_binding_rep->rpc_addr, &rpc_addr, status); if (*status != rpc_s_ok) return; have_addr = true; /* * allocate a binding rep to hold the copy and init it from the source */ dst_binding_rep = rpc__binding_alloc ( (boolean)src_binding_rep->is_server, &src_binding_rep->obj, src_binding_rep->protocol_id, rpc_addr, status); if (*status != rpc_s_ok) goto CLEANUP; /* * copy other common parts of the binding rep from the source to dest */ dst_binding_rep->timeout = src_binding_rep->timeout; dst_binding_rep->call_timeout_time = src_binding_rep->call_timeout_time; dst_binding_rep->addr_is_dynamic = src_binding_rep->addr_is_dynamic; dst_binding_rep->bound_server_instance = src_binding_rep->bound_server_instance; dst_binding_rep->extended_bind_flag = src_binding_rep->extended_bind_flag; /* * Copy the auth info. */ if (src_binding_rep->auth_info != NULL) { rpc__auth_info_reference (src_binding_rep->auth_info); dst_binding_rep->auth_info = src_binding_rep->auth_info; } /* * Copy transport information */ if (src_binding_rep->transport_info != NULL) { rpc__transport_info_retain(src_binding_rep->transport_info); dst_binding_rep->transport_info = src_binding_rep->transport_info; } /* * Copy the protocol version */ if (src_binding_rep->protocol_version != NULL) { rpc__binding_prot_version_alloc( &(dst_binding_rep->protocol_version), src_binding_rep->protocol_version->major_version, src_binding_rep->protocol_version->minor_version, status); if (*status != rpc_s_ok) goto CLEANUP; } /* * Copy the ns_specific. */ if (src_binding_rep->ns_specific != NULL) { /* NOTE * This needs to be replaced with the real copy. * For now set the field to NULL so later we don't improperly * try to free the field. * * When we get around to doing this, see how this field is * freed in rpc_binding_free for a hint on doing this. * You'll probably need to add a similar entry point in nsinit.c */ dst_binding_rep->ns_specific = NULL; } /* * Copy the extended code set i14y information */ if (src_binding_rep->extended_bind_flag == RPC_C_BH_EXTENDED_CODESETS) { /* Copy codesets relating binding information. * Determine the data structure */ switch (src_binding_rep->cs_eval.key) { case RPC_CS_EVAL_METHOD: method_s_p = &src_binding_rep->cs_eval.tagged_union.method_key; method_d_p = &dst_binding_rep->cs_eval.tagged_union.method_key; dst_binding_rep->cs_eval.key = src_binding_rep->cs_eval.key; method_d_p->method = method_s_p->method; method_d_p->tags.stag = method_s_p->tags.stag; method_d_p->tags.drtag = method_s_p->tags.drtag; method_d_p->tags.stag_max_bytes = method_s_p->tags.stag_max_bytes; method_d_p->tags.client_tag = method_s_p->tags.client_tag; method_d_p->tags.client_max_bytes = method_s_p->tags.client_max_bytes; method_d_p->tags.type_handle = method_d_p->tags.type_handle; method_d_p->fixed = method_s_p->fixed; method_d_p->cs_stub_eval_func = method_s_p->cs_stub_eval_func; method_s_p->server = NULL; method_d_p->client = NULL; break; case RPC_CS_EVAL_TAGS: tags_s_p = &src_binding_rep->cs_eval.tagged_union.tags_key; tags_d_p = &dst_binding_rep->cs_eval.tagged_union.tags_key; dst_binding_rep->cs_eval.key = src_binding_rep->cs_eval.key; tags_d_p->stag = tags_s_p->stag; tags_d_p->drtag = tags_s_p->drtag; tags_d_p->stag_max_bytes = tags_s_p->stag_max_bytes; tags_d_p->client_tag = tags_s_p->client_tag; tags_d_p->client_max_bytes = tags_s_p->client_max_bytes; tags_d_p->type_handle = tags_d_p->type_handle; break; default: *status = rpc_s_ss_invalid_codeset_tag; break; } } /* * return the destination binding rep as a binding handle */ *dst_binding_h = (rpc_binding_handle_t) dst_binding_rep; /* * let the protocol service copy any stuff it wants to */ (*rpc_g_protocol_id[src_binding_rep->protocol_id].binding_epv ->binding_copy) (src_binding_rep, dst_binding_rep, status); CLEANUP: if (*status != rpc_s_ok && have_addr) rpc__naf_addr_free (&rpc_addr, &tmp_status); } /* **++ ** ** ROUTINE NAME: rpc_binding_to_string_binding ** ** SCOPE: PUBLIC - declared in rpc.idl ** ** DESCRIPTION: ** ** This routine will convert a Binding Rep data structure to its string ** represenation, which is called a "string binding". It will first convert ** the object UUID contained in the Binding Rep to string format. The string ** format of the Protocol Sequence ID contained in the RPC Address will be ** looked up in the RPC Protocol Sequence ID table. It will the call the ** appropriate Network Address Family Extension Service to return the ** endpoint, network address and network options form the RPC Address in the ** Binding Rep. ** ** INPUTS: ** ** binding_h The binding handle which points to the binding ** rep data structure to be converted. ** ** INPUTS/OUTPUTS: none ** ** OUTPUTS: ** ** string_binding A string representation of the binding rep data ** structure. ** ** status A value indicating the status of the routine. ** ** rpc_s_ok The call was successful. ** rpc_s_invalid_binding ** RPC Protocol ID in binding handle was invalid. ** rpc_s_coding_error ** ** IMPLICIT INPUTS: none ** ** IMPLICIT OUTPUTS: none ** ** FUNCTION VALUE: void ** ** SIDE EFFECTS: none ** **-- **/ PUBLIC void rpc_binding_to_string_binding ( rpc_binding_handle_t binding_h, unsigned_char_p_t *string_binding, unsigned32 *status ) { rpc_binding_rep_p_t binding_rep = (rpc_binding_rep_p_t) binding_h; rpc_addr_p_t rpc_addr = NULL; unsigned_char_p_t object_uuid = NULL; unsigned_char_p_t endpoint = NULL; unsigned_char_p_t netaddr = NULL; unsigned_char_p_t network_options = NULL; unsigned32 temp_status; assert(binding_rep != NULL); CODING_ERROR (status); RPC_VERIFY_INIT (); /* * if the output argument is NULL, don't do anything */ if (string_binding == NULL) { *status = rpc_s_ok; return; } RPC_BINDING_VALIDATE(binding_rep, status); if (*status != rpc_s_ok) return; /* * convert the object UUID in the binding rep to string format * (if it is non-nil - otherwise, keep it as a NULL pointer) */ if (!uuid_is_nil (&(binding_rep->obj), status)) { uuid_to_string (&(binding_rep->obj), &object_uuid, status); if (*status != uuid_s_ok) { goto CLEANUP; } } /* * if the RPC address in the binding is NULL, get one from protocol service */ if (binding_rep->rpc_addr == NULL) { /* * get the RPC address from the protocol service */ (*rpc_g_protocol_id[binding_rep->protocol_id].binding_epv ->binding_inq_addr) (binding_rep, &rpc_addr, status); if (*status != rpc_s_ok) { goto CLEANUP; } } else { /* * otherwise use the RPC address in the binding rep */ rpc_addr = binding_rep->rpc_addr; } /* * get the endpoint from the network address family extension */ (*rpc_g_naf_id[rpc_addr->sa.family].epv->naf_addr_inq_endpoint) (rpc_addr, &endpoint, status); if (*status != rpc_s_ok) { goto CLEANUP; } /* * get the network address from the network address family extension */ (*rpc_g_naf_id[rpc_addr->sa.family].epv->naf_addr_inq_netaddr) (rpc_addr, &netaddr, status); if (*status != rpc_s_ok) { goto CLEANUP; } /* * get the network options from the network address family extension */ (*rpc_g_naf_id[rpc_addr->sa.family].epv->naf_addr_inq_options) (rpc_addr, &network_options, status); if (*status != rpc_s_ok) { goto CLEANUP; } /* * got everything - now build the whole string * (note: if the object uuid was nil, a NULL will be passed here, * and it won't appear in the string binding; also note, we'll * return at this point with the status of rpc_string_binding_compose) */ rpc_string_binding_compose ( object_uuid, rpc_g_protseq_id[rpc_addr->rpc_protseq_id].rpc_protseq, netaddr, endpoint, network_options, string_binding, status); CLEANUP: /* * if anything failed along the way, or we got here succesfully, * cleanup local buffers and return with the last meaningful status */ if (object_uuid != NULL) { rpc_string_free (&object_uuid, &temp_status); } if (endpoint != NULL) { rpc_string_free (&endpoint, &temp_status); } if (netaddr != NULL) { rpc_string_free (&netaddr, &temp_status); } if (network_options != NULL) { rpc_string_free (&network_options, &temp_status); } } /* **++ ** ** ROUTINE NAME: rpc_binding_from_string_binding ** ** SCOPE: PUBLIC - declared in rpc.idl ** ** DESCRIPTION: ** ** This routine converts a string binding to a Binding Rep data structure. ** It will strip the object UUID, RPC Protocol Sequence string, endpoint, ** network address and network options out of the string binding provided. ** A Binding Rep will then be allocated through the RPC Protocol Service ** identified in the RPC Protocol Sequence. An RPC Address will be allocated ** through the Network Address Family Extension Service identified in the ** RPC Protocol Sequence. The common fields of the Binding Rep will be set ** to defaults and the RPC Prtotcol Service will be called to initialize ** the RPC Protocol Service-specific part of the Binding Rep. ** ** ** If the string binding contains an endpoint, the addr_is_dynamic field ** in the binding rep is set to false, indicating a well-known endpoint. ** (This field is initialized to true in rpc__binding_alloc.) ** ** INPUTS: ** ** string_binding A string representation of the binding rep data ** structure. ** ** INPUTS/OUTPUTS: none ** ** OUTPUTS: ** ** binding_h The binding handle which points to the binding ** rep data structure to be created. ** ** status A value indicating the status of the routine. ** ** rpc_s_ok The call was successful. ** uuid_s_invalid_string_uuid ** Object UUID in string binding was invalid. ** rpc_s_invalid_string_binding ** String binding was invalid. ** rpc_s_coding_error ** ** IMPLICIT INPUTS: none ** ** IMPLICIT OUTPUTS: none ** ** FUNCTION VALUE: void ** ** SIDE EFFECTS: none ** **-- **/ PUBLIC void rpc_binding_from_string_binding ( unsigned_char_p_t string_binding, rpc_binding_handle_t *binding_h, unsigned32 *status ) { rpc_binding_rep_p_t binding_rep; idl_uuid_t obj_uuid; rpc_addr_p_t rpc_addr = NULL; unsigned_char_p_t string_object_uuid = NULL; unsigned_char_p_t protseq = NULL; unsigned_char_p_t endpoint = NULL; unsigned_char_p_t netaddr = NULL; unsigned_char_p_t network_options = NULL; rpc_protseq_id_t protseq_id; rpc_protocol_id_t protocol_id; rpc_naf_id_t naf_id = 0; unsigned32 temp_status; CODING_ERROR (status); RPC_VERIFY_INIT (); /* * extract the various fields from the string binding */ rpc_string_binding_parse (string_binding, &string_object_uuid, &protseq, &netaddr, &endpoint, &network_options, status); if (*status != rpc_s_ok) { goto CLEANUP; } /* * Convert the protocol sequence string to and protseq ID. */ protseq_id = rpc__network_pseq_id_from_pseq (protseq, status); if (*status != rpc_s_ok) { goto CLEANUP; } if (rpc_g_protseq_id[protseq_id].supported == false) { *status = rpc_s_protseq_not_supported; goto CLEANUP; } protocol_id = rpc_g_protseq_id[protseq_id].rpc_protocol_id; naf_id = rpc_g_protseq_id[protseq_id].naf_id; /* * set the object UUID to the one given in the string * - if the string is empty, none was given - use the nil uuid */ if (*string_object_uuid != '\0') { uuid_from_string (string_object_uuid, &obj_uuid, status); } else { uuid_create_nil (&obj_uuid, status); } if (*status != uuid_s_ok) { goto CLEANUP; } /* * A NULL network address means to bind to the local host. * Otherwise, get an RPC address from the Network Address Family * Extension Service. */ if (*netaddr == '\0') { rpc__network_inq_local_addr (protseq_id, endpoint, &rpc_addr, status); } else { (*rpc_g_naf_id[naf_id].epv->naf_addr_alloc) (protseq_id, naf_id, endpoint, netaddr, network_options, &rpc_addr, status); } if (*status != rpc_s_ok) { rpc_addr = NULL; goto CLEANUP; } /* * allocate a binding rep and initialize it */ binding_rep = rpc__binding_alloc ((boolean)false, &obj_uuid, protocol_id, rpc_addr, status); if (*status != rpc_s_ok) goto CLEANUP; /* * A non-NULL endpoint means that the endpoint is well-known, so set * the addr_is_dynamic field to false. */ if (*endpoint != '\0') { binding_rep->addr_is_dynamic = false; } /* * cast the binding handle to a binding rep pointer */ *binding_h = (rpc_binding_handle_t) binding_rep; *status = rpc_s_ok; CLEANUP: if (string_object_uuid != NULL) { rpc_string_free (&string_object_uuid, &temp_status); } if (protseq != NULL) { rpc_string_free (&protseq, &temp_status); } if (endpoint != NULL) { rpc_string_free (&endpoint, &temp_status); } if (netaddr != NULL) { rpc_string_free (&netaddr, &temp_status); } if (network_options != NULL) { rpc_string_free (&network_options, &temp_status); } if (*status != rpc_s_ok) { unsigned32 tstatus; if (rpc_addr != NULL) { (*rpc_g_naf_id[naf_id].epv->naf_addr_free) (&rpc_addr, &tstatus); } if (*status == rpc_s_invalid_binding) { *status = rpc_s_invalid_string_binding; } *binding_h = NULL; } } PRIVATE void rpc__string_netaddr_escape ( unsigned_char_p_t netaddr, unsigned_char_p_t *escaped_netaddr, unsigned32 *status ) { unsigned_char_p_t saved_netaddr; unsigned_char_p_t escaped_netaddr_ptr; size_t escaped_string_size = 1; /* include null at end */ CODING_ERROR (status); /* * if the output argument is NULL, don't do anything */ if (escaped_netaddr == NULL) { *status = rpc_s_ok; return; } /* * if the input argument is NULL, return NULL */ if (netaddr == NULL) { *escaped_netaddr = NULL; *status = rpc_s_ok; return; } /* * calculate total size of the string including escaped out chars */ saved_netaddr = netaddr; while (*netaddr != '\0') { switch (*netaddr) { case ' ': case '@': case ':': case '[': case ']': case ',': case '\\': /* have to add one more char due to adding '\' */ escaped_string_size += 2; break; default: escaped_string_size += 1; break; } netaddr++; } /* * heap allocate storage for the escaped string */ RPC_MEM_ALLOC (*escaped_netaddr, unsigned_char_p_t, escaped_string_size, RPC_C_MEM_STRING, RPC_C_MEM_WAITOK); escaped_netaddr_ptr = *escaped_netaddr; /* make sure string ends in null */ memset(escaped_netaddr_ptr, 0, escaped_string_size); /* * copy chars and escape as needed */ netaddr = saved_netaddr; while (*netaddr != '\0') { switch (*netaddr) { case ' ': case '@': case ':': case '[': case ']': case ',': case '\\': /* add escape char of '\' followed by the char */ *(escaped_netaddr_ptr++) = '\\'; *(escaped_netaddr_ptr++) = *(netaddr++); break; default: /* no need to escape, just copy the char */ *(escaped_netaddr_ptr++) = *(netaddr++); break; } } *status = rpc_s_ok; return; } PRIVATE void rpc__string_netaddr_unescape ( unsigned_char_p_t escaped_netaddr, unsigned_char_p_t *netaddr, unsigned32 *status ) { unsigned_char_p_t netaddr_ptr; size_t escaped_string_size; unsigned_char_p_t p1, p2; CODING_ERROR (status); /* * if the output argument is NULL, don't do anything */ if (netaddr == NULL) { *status = rpc_s_ok; return; } /* * if the input argument is NULL, return NULL */ if (escaped_netaddr == NULL) { *netaddr = NULL; *status = rpc_s_ok; return; } /* * The unescaped string will be the same length or shorter than * the escaped string so allocate same size as the escaped string. */ escaped_string_size = strlen ((char*) escaped_netaddr); /* * heap allocate storage for the unescaped string */ RPC_MEM_ALLOC (*netaddr, unsigned_char_p_t, escaped_string_size + 1, RPC_C_MEM_STRING, RPC_C_MEM_WAITOK); netaddr_ptr = *netaddr; /* make sure string ends in null */ memset(netaddr_ptr, 0, escaped_string_size + 1); /* * copy the string, filtering out escape chars */ p2 = netaddr_ptr; p1 = escaped_netaddr; while (*p1 != '\0') { switch (*p1) { case '\\': /* skip escape char of '\' and just copy the char */ if (p1[1] != '\0') { p1++; *(p2++) = *(p1++); } else { /* must be at end of escaped string so just copy the '\' */ *(p2++) = *(p1++); } break; default: /* no need to unescape, just copy the char */ *(p2++) = *(p1++); break; } } *status = rpc_s_ok; return; } /* **++ ** ** ROUTINE NAME: rpc_string_binding_parse ** ** SCOPE: PUBLIC - declared in rpc.idl ** ** DESCRIPTION: ** ** This routine will split the string binding provided into multiple ** components. ** ** INPUTS: ** ** string_binding A string representation of the binding rep data ** structure. ** ** INPUTS/OUTPUTS: none ** ** OUTPUTS: ** ** string_obj_uuid A string representation of an object UUID. ** ** protseq An RPC Protocol Sequence. ** ** netaddr A Network Address. ** ** endpoint An RPC Endpoint. ** ** network_options A string of Network Options. ** ** status A value indicating the status of the routine. ** ** rpc_s_ok The call was successful. ** rpc_s_invalid_string_binding ** The string binding could not be parsed ** rpc_s_coding_error ** ** IMPLICIT INPUTS: none ** ** IMPLICIT OUTPUTS: none ** ** FUNCTION VALUE: void ** ** SIDE EFFECTS: none ** **-- **/ PUBLIC void rpc_string_binding_parse ( unsigned_char_p_t string_binding, unsigned_char_p_t *string_object_uuid, unsigned_char_p_t *protseq, unsigned_char_p_t *netaddr, unsigned_char_p_t *endpoint, unsigned_char_p_t *network_options, unsigned32 *status ) { #define RPC_C_NETWORK_OPTIONS_MAX 1024 unsigned_char_p_t binding_ptr; unsigned_char_p_t option_ptr = NULL; size_t count; boolean get_endpoint; unsigned32 temp_status; size_t len; unsigned_char_p_t escaped_netaddr; CODING_ERROR (status); RPC_VERIFY_INIT (); /* * make sure we have something to start with */ if (string_binding == NULL) { *status = rpc_s_invalid_string_binding; return; } /* * Initialize netaddr, endpoint and network_options if pointers are non-NULL */ if (netaddr != NULL) { *netaddr = NULL; } if (endpoint != NULL) { *endpoint = NULL; } if (network_options != NULL) { *network_options = NULL; } binding_ptr = string_binding; /* * get in the object UUID and protocol sequence */ count = rpc__strcspn (binding_ptr, "@"); if (string_object_uuid != NULL) { { RPC_MEM_ALLOC ( *string_object_uuid, unsigned_char_p_t, count + 1, RPC_C_MEM_STRING, RPC_C_MEM_WAITOK); if (count > 0) { rpc__strncpy (*string_object_uuid, binding_ptr, count - 1); } else { **string_object_uuid = '\0'; } } } /* * In any case, advance the pointer. */ binding_ptr += count; count = rpc__strcspn (binding_ptr, ":"); if (protseq != NULL) { { RPC_MEM_ALLOC ( *protseq, unsigned_char_p_t, count + 1, RPC_C_MEM_STRING, RPC_C_MEM_WAITOK); if (count > 0) { rpc__strncpy (*protseq, binding_ptr, count - 1); } else { **protseq = '\0'; } } } /* * In any case, advance the pointer. */ binding_ptr += count; /* * see if there are options after the network address */ if ((count = rpc__strcspn (binding_ptr, "[")) == 0) { /* * if there was no '[' terminator, maybe there are no options - * but there still might be a network address - go for it! */ if (netaddr != NULL) { len = strlen ((char *) binding_ptr); RPC_MEM_ALLOC ( *netaddr, unsigned_char_p_t, len + 1, RPC_C_MEM_STRING, RPC_C_MEM_WAITOK); /* * Note: we are counting on null termination here, even if len == 0 */ rpc__strncpy (*netaddr, binding_ptr, len); } } else { /* * if there are options, first get the network address */ if (netaddr != NULL) { RPC_MEM_ALLOC ( *netaddr, unsigned_char_p_t, count, RPC_C_MEM_STRING, RPC_C_MEM_WAITOK); rpc__strncpy (*netaddr, binding_ptr, count - 1); } binding_ptr += count; /* * then get the entries in the options list one by one */ if (network_options != NULL) { /* * we've got to allocate enough space to catch all of the * network options that might conceivably be here - a lot * will probably be wasted, but we have no way of knowing at * this time exactly how much, but we know it can be no more than * the length of what remains of this string binding. */ /* * Allocate one byte more than we need to cover bug - * see modification history for 21-may-91. */ RPC_MEM_ALLOC ( *network_options, unsigned_char_p_t, strlen ((char *)binding_ptr) + 1, RPC_C_MEM_STRING, RPC_C_MEM_WAITOK); option_ptr = *network_options; *option_ptr = '\0'; } while ((count > 0) && (*binding_ptr != '\0')) { get_endpoint = false; /* * first see if there's an option tag */ count = rpc__strcspn (binding_ptr, "=,"); if (count == 0 || *(binding_ptr + count - 1) != '=') { /* * if there's no option tag, this must be an endpoint */ get_endpoint = true; } else { /* * see if the tag is an endpoint specifier - * but skip over any leading white space */ for (; (*binding_ptr == ' ' || *binding_ptr == '\t') && *binding_ptr != '\0'; binding_ptr++, count--); if ((strncmp ((char *) binding_ptr, "endpoint", (count-1))) == 0) { /* * if the tag was "endpoint", skip to the equal sign */ get_endpoint = true; binding_ptr += count; } } /* * if this is an endpoint, collect it */ if (get_endpoint && endpoint != NULL) { size_t token_end; /* * We want to return an error if there is more than one * endpoint specified (this will also catch an endpoint * specified with extra brackets, like "[[foo]]" as a side * effect). */ if (*endpoint != NULL) { *status = rpc_s_invalid_string_binding; goto CLEANUP; } token_end = rpc__get_token(binding_ptr, '\\', ",]", endpoint, status); if(*status != rpc_s_ok) goto CLEANUP; /* * We want to return an error if there is no closing ']'; */ if (binding_ptr[token_end] == '\0') { *status = rpc_s_invalid_string_binding; goto CLEANUP; } binding_ptr += token_end + 1; } else if (get_endpoint && endpoint == NULL) /* * Skip over the endpoint */ { size_t token_end = rpc__get_token(binding_ptr, '\\', ",]", NULL, status); binding_ptr += token_end + 1; } else { count = rpc__strcspn (binding_ptr, ",]"); /* * If this is the last token, make sure the string is properly terminated. */ if ((count == 0) && ((strlen ((char *) binding_ptr)) != 0)) { *status = rpc_s_invalid_string_binding; goto CLEANUP; } /* * if not an endpoint, collect the option tag and value */ if (network_options != NULL) { /* * We can have any number of network options, but we'll * lose the last one if the string doesn't have a * terminator. * (this code is probably redundant, now) */ if (count == 0) { *status = rpc_s_invalid_string_binding; goto CLEANUP; } rpc__strncpy (option_ptr, binding_ptr, count); option_ptr += count; } /* * advance to the next token in the string. */ binding_ptr += count; } } } /* * if component strings were created, compress white space out of the * results - otherwise, return empty strings for things that were wanted * but not found */ if (string_object_uuid != NULL) { if (*string_object_uuid != NULL) { rpc__strsqz (*string_object_uuid); } else { RPC_MEM_ALLOC ( *string_object_uuid, unsigned_char_p_t, 1, RPC_C_MEM_STRING, RPC_C_MEM_WAITOK); **string_object_uuid = '\0'; } } if (protseq != NULL) { if (*protseq != NULL) { rpc__strsqz (*protseq); } else { RPC_MEM_ALLOC ( *protseq, unsigned_char_p_t, 1, RPC_C_MEM_STRING, RPC_C_MEM_WAITOK); **protseq = '\0'; } } if (netaddr != NULL) { if (*netaddr != NULL) { /* * call rpc__strsqz before unescaping so that dont lose any escaped * spaces */ rpc__strsqz (*netaddr); /* unescape the netaddr before returning it */ escaped_netaddr = *netaddr; rpc__string_netaddr_unescape(escaped_netaddr, netaddr, &temp_status); if (temp_status == rpc_s_ok) { /* free the escaped netaddr */ rpc_string_free (&escaped_netaddr, &temp_status); } else { /* error occurred so restore original netaddr */ *netaddr = escaped_netaddr; } } else { RPC_MEM_ALLOC ( *netaddr, unsigned_char_p_t, 1, RPC_C_MEM_STRING, RPC_C_MEM_WAITOK); **netaddr = '\0'; } } if (endpoint != NULL) { if (*endpoint != NULL) { rpc__strsqz (*endpoint); } else { RPC_MEM_ALLOC ( *endpoint, unsigned_char_p_t, 1, RPC_C_MEM_STRING, RPC_C_MEM_WAITOK); **endpoint = '\0'; } } if (network_options != NULL) { if (*network_options != NULL) { rpc__strsqz (*network_options); /* * clip the trailing separator off the network options string * to be neat */ if ((count = strlen ((char *) *network_options)) > 0) { (*network_options)[count - 1] = '\0'; } } else { RPC_MEM_ALLOC ( *network_options, unsigned_char_p_t, 1, RPC_C_MEM_STRING, RPC_C_MEM_WAITOK); **network_options = '\0'; } } *status = rpc_s_ok; return; CLEANUP: /* * free any buffers that have been allocated */ if (string_object_uuid != NULL && *string_object_uuid != NULL) { rpc_string_free (string_object_uuid, &temp_status); } if (protseq != NULL && *protseq != NULL) { rpc_string_free (protseq, &temp_status); } if (netaddr != NULL && *netaddr != NULL) { rpc_string_free (netaddr, &temp_status); } if (endpoint != NULL && *endpoint != NULL) { rpc_string_free (endpoint, &temp_status); } if (network_options != NULL && *network_options != NULL) { rpc_string_free (network_options, &temp_status); } return; } /* **++ ** ** ROUTINE NAME: rpc_string_binding_compose ** ** SCOPE: PUBLIC - declared in rpc.idl ** ** DESCRIPTION: ** ** This routine will combine the components of a string binding and ** return a formatted string binding. ** ** INPUTS: ** ** string_obj_uuid A string representation of an object UUID. ** ** protseq An RPC Protocol Sequence. ** ** netaddr A Network Address. ** ** endpoint An RPC Endpoint. ** ** network_options A string of Network Options. ** ** INPUTS/OUTPUTS: none ** ** OUTPUTS: ** ** string_binding A string representation of the binding rep data ** structure. ** ** status A value indicating the status of the routine. ** ** rpc_s_ok The call was successful. ** rpc_s_invalid_binding ** RPC Protocol ID in binding handle was invalid. ** rpc_s_coding_error ** ** IMPLICIT INPUTS: none ** ** IMPLICIT OUTPUTS: none ** ** FUNCTION VALUE: void ** ** SIDE EFFECTS: none ** **-- **/ PUBLIC void rpc_string_binding_compose ( unsigned_char_p_t string_object_uuid, unsigned_char_p_t protseq, unsigned_char_p_t netaddr, unsigned_char_p_t endpoint, unsigned_char_p_t network_options, unsigned_char_p_t *string_binding, unsigned32 *status ) { unsigned_char_p_t string_binding_ptr; unsigned32 string_binding_size = 1; unsigned_char_p_t escaped_netaddr = NULL; unsigned_char_p_t temp_netaddr = NULL; CODING_ERROR (status); RPC_VERIFY_INIT (); /* * if the output argument is NULL, don't do anything */ if (string_binding == NULL) { *status = rpc_s_ok; return; } /* * calculate the total size of the resulting string binding - the sum * of the lengths of all the non-null input strings, plus space for * any delimiters that might possibly be needed (and the requisite * null terminator) */ if ((string_object_uuid != NULL) && (*string_object_uuid != '\0')) { string_binding_size += strlen ((char *) string_object_uuid) + 1; } if (protseq != NULL) { string_binding_size += strlen ((char *) protseq) + 1; } if (netaddr != NULL) { /* escape out the netaddr string */ rpc__string_netaddr_escape(netaddr, &escaped_netaddr, status); if (*status == rpc_s_ok) { /* add in the len of the escaped string */ string_binding_size += strlen ((char *) escaped_netaddr) + 1; } else { /* error occurred so add in the len of netaddr */ string_binding_size += strlen ((char *) netaddr) + 1; } } if (endpoint != NULL) { string_binding_size += strlen ((char *) endpoint) + 2; } if (network_options != NULL) { string_binding_size += strlen ((char *) network_options) + 2; } /* * heap allocate storage for the string binding */ RPC_MEM_ALLOC ( *string_binding, unsigned_char_p_t, string_binding_size, RPC_C_MEM_STRING, RPC_C_MEM_WAITOK); string_binding_ptr = *string_binding; /* * fill in the object UUID */ if ((string_object_uuid != NULL) && (*string_object_uuid != '\0')) { while (*string_object_uuid != '\0') { *(string_binding_ptr++) = *(string_object_uuid++); } *(string_binding_ptr++) = '@'; } /* * fill in the protocol sequence */ if (protseq != NULL) { while (*protseq != '\0') { *(string_binding_ptr++) = *(protseq++); } *(string_binding_ptr++) = ':'; } /* * fill in the network address */ if (escaped_netaddr != NULL) { temp_netaddr = escaped_netaddr; while (*temp_netaddr != '\0') { *(string_binding_ptr++) = *(temp_netaddr++); } rpc_string_free (&escaped_netaddr, status); } else { /* * maybe an error occurred when trying to escape the netaddr? * try to copy in the original netaddr */ if (netaddr != NULL) { while (*netaddr != '\0') { *(string_binding_ptr++) = *(netaddr++); } } } if (endpoint != NULL || network_options != NULL) { *(string_binding_ptr++) = '['; /* * fill in the endpoint */ if (endpoint != NULL) { while (*endpoint != '\0') { *(string_binding_ptr++) = *(endpoint++); } if (network_options != NULL && *network_options != '\0') { *(string_binding_ptr++) = ','; } } /* * fill in any other options that might be specified */ if (network_options != NULL) { while (*network_options != '\0') { *(string_binding_ptr++) = *(network_options++); } } *(string_binding_ptr++) = ']'; } /* * terminate the string */ *(string_binding_ptr) = '\0'; *status = rpc_s_ok; return; } /* **++ ** ** ROUTINE NAME: rpc__binding_alloc ** ** SCOPE: PRIVATE - declared in combind.h ** ** DESCRIPTION: ** ** This routine will allocate the memory for a Binding Rep data structure ** through the RPC Protocol Service identified in the input arguments. ** All the common fields of the Binding Rep will be initialized using ** defaults and the input arguments to this routine. The RPC Protocol ** Service will then be called to initialize the RPC Protocol Service ** specific parts of the Binding Rep. ** ** INPUTS: ** ** is_server T => a server-side binding handle should be created ** ** object_uuid The unique identifier of an object to which an ** RPC may be made. ** ** protocol_id The identifier of an RPC Protocol Service through ** which an RPC may be made. Since this is an internal ** routine it assumes this has been checked by the ** caller to see if it is a valid identifier. ** ** rpc_addr The location of the remote half of the RPC. ** ** INPUTS/OUTPUTS: none ** ** OUTPUTS: ** ** status A value indicating the status of the routine. ** ** rpc_s_ok The call was successful. ** rpc_s_coding_error ** ** IMPLICIT INPUTS: none ** ** IMPLICIT OUTPUTS: none ** ** FUNCTION VALUE: ** ** binding_rep A Binding Rep data structure containing the object ** UUID of an RPC as well as the location of the remote ** half of the RPC. ** ** SIDE EFFECTS: none ** **-- **/ PRIVATE rpc_binding_rep_t *rpc__binding_alloc ( boolean32 is_server, uuid_p_t object_uuid, rpc_protocol_id_t protocol_id, rpc_addr_p_t rpc_addr, unsigned32 *status ) { rpc_binding_rep_p_t binding_rep; unsigned_char_p_t endpoint = NULL; unsigned32 temp_status; CODING_ERROR (status); /* * get protocol service to allocate an empty binding rep */ binding_rep = (*rpc_g_protocol_id[protocol_id].binding_epv ->binding_alloc) (is_server, status); /* * Initialize the common part of the binding rep. */ binding_rep->is_server = is_server; binding_rep->protocol_id = protocol_id; binding_rep->obj = *object_uuid; binding_rep->timeout = rpc_c_binding_default_timeout; binding_rep->ns_specific = NULL; binding_rep->auth_info = NULL; binding_rep->transport_info = NULL; binding_rep->bound_server_instance = false; binding_rep->addr_has_endpoint = false; binding_rep->refcnt = 1; /* the reference we are returning */ binding_rep->calls_in_progress = 0; binding_rep->call_timeout_time = 0; binding_rep->fork_count = rpc_g_fork_count; binding_rep->protocol_version = NULL; binding_rep->extended_bind_flag = RPC_C_BH_EXTENDED_NONE; /* * By default, created bindings are declared to have dynamic * addresses; *this* default state is important. Callers of * binding_alloc that know they're associating a non-dynamic * addr with the binding can change this state. */ binding_rep->addr_is_dynamic = true; if (rpc_addr != NULL) { /* * find out if the RPC address contains an endpoint */ (*rpc_g_naf_id[rpc_addr->sa.family].epv->naf_addr_inq_endpoint) (rpc_addr, &endpoint, status); /* * If the addr has an endpoint, tell everyone. */ if (*status != rpc_s_ok) { /* * then ask the protocol service to free the binding rep and * NULL the reference. */ (*rpc_g_protocol_id[protocol_id].binding_epv->binding_free) (&binding_rep, &temp_status); /* mdn 23.10.1999: FIXME if I am wrong * if endpoint was allocated it is not a NULL pointer, so * it must be freed. */ /* return (NULL); */ binding_rep = NULL; goto CLEANUP; } else { if (strlen ((char *) endpoint) != 0) { binding_rep->addr_has_endpoint = true; } } } /* * set the pointer to the specified rpc address in the binding */ binding_rep->rpc_addr = rpc_addr; /* * get the protocol service to initialize the rest of the binding */ (*rpc_g_protocol_id[protocol_id].binding_epv ->binding_init) (binding_rep, status); *status = rpc_s_ok; CLEANUP: if (endpoint != NULL) { rpc_string_free (&endpoint, &temp_status); } return (binding_rep); } /* **++ ** ** ROUTINE NAME: rpc_binding_inq_client ** ** SCOPE: PUBLIC ** ** DESCRIPTION: ** ** This routine returns a protocol service dependent client handle which ** can be used by the stubs to identify a particular instance of a ** particular client process. ** ** INPUTS: ** ** binding_h Server stub binding handle ** ** INPUTS/OUTPUTS: none ** ** OUTPUTS: ** ** client_h Client handle for use with monitor_liveness routine ** ** status A value indicating the status of the routine. ** rpc_s_invalid_binding ** RPC Protocol ID in binding handle was invalid. ** ** ** ** IMPLICIT INPUTS: none ** ** IMPLICIT OUTPUTS: none ** ** FUNCTION VALUE: ** ** void ** ** SIDE EFFECTS: none ** **-- **/ PUBLIC void rpc_binding_inq_client ( rpc_binding_handle_t binding_h, rpc_client_handle_t *client_h, unsigned32 *status ) { rpc_binding_rep_p_t binding_rep = (rpc_binding_rep_p_t) binding_h; assert(binding_rep != NULL); CODING_ERROR (status); RPC_VERIFY_INIT (); RPC_BINDING_VALIDATE_SERVER(binding_rep, status); if (*status != rpc_s_ok) return; /* * Ask the protocol service for a client handle associated with * the client on the other end of the connection specified by this * server binding handle. */ (*rpc_g_protocol_id[binding_rep->protocol_id].binding_epv ->binding_inq_client) (binding_rep, client_h, status); } /* **++ ** ** ROUTINE NAME: rpc_binding_handle_copy ** ** SCOPE: PUBLIC ** ** DESCRIPTION: ** ** This routine creates a duplicate handle to an existing ** (now shared) binding (via bumping a reference count). ** ** INPUTS: ** ** source_binding The binding handle which points to the source ** binding rep data structure to be copied. ** ** INPUTS/OUTPUTS: none ** ** OUTPUTS: ** ** destination_binding ** The binding handle which points to the shared ** binding rep data structure. ** ** status A value indicating the status of the routine. ** ** rpc_s_ok The call was successful. ** rpc_s_invalid_binding ** RPC Protocol ID in binding handle was invalid. ** rpc_s_coding_error ** ** IMPLICIT INPUTS: none ** ** IMPLICIT OUTPUTS: none ** ** FUNCTION VALUE: void ** ** SIDE EFFECTS: none ** **-- **/ void rpc_binding_handle_copy ( rpc_binding_handle_t source_binding, rpc_binding_handle_t *destination_binding, unsigned32 *status ) { rpc_binding_rep_p_t src_binding_rep = (rpc_binding_rep_p_t) source_binding; rpc_binding_rep_p_t *dst_binding_rep = (rpc_binding_rep_p_t *) destination_binding; assert(src_binding_rep != NULL); CODING_ERROR (status); RPC_VERIFY_INIT (); RPC_BINDING_VALIDATE_CLIENT(src_binding_rep, status); if (*status != rpc_s_ok) return; /* * Add a new reference. */ *dst_binding_rep = src_binding_rep; RPC_LOCK(0); RPC_BINDING_REFERENCE(src_binding_rep); RPC_UNLOCK(0); *status = rpc_s_ok; } /* **++ ** ** ROUTINE NAME: rpc_binding_handle_equal ** ** SCOPE: PUBLIC ** ** DESCRIPTION: ** ** This routine compares two binding handles to determine if they ** reference the same binding object. The current external binding handle ** representation (a pointer) doesn't really require the assistance ** of such a function, however, it is anticipated that we will (shortly) ** change the external representation to something that will allow us ** to detect dangling references users will not be able to perform a ** comparison via the C "==" operator. ** ** INPUTS: ** ** binding_h1 One binding handle ref. ** binding_h2 A second binding handle ref. ** ** INPUTS/OUTPUTS: none ** ** OUTPUTS: ** ** status A value indicating the status of the routine. ** ** rpc_s_ok The call was successful. ** ** IMPLICIT INPUTS: none ** ** IMPLICIT OUTPUTS: none ** ** FUNCTION VALUE: ** ** result true if both handle's refer to the same binding rep ** false if they don't ** ** SIDE EFFECTS: none ** **-- **/ PUBLIC boolean32 rpc_binding_handle_equal ( rpc_binding_handle_t binding1, rpc_binding_handle_t binding2, unsigned32 *status ) { CODING_ERROR (status); RPC_VERIFY_INIT (); *status = rpc_s_ok; return (binding1 == binding2); } /* **++ ** ** ROUTINE NAME: rpc_binding_server_to_client ** ** SCOPE: PUBLIC - declared in rpcpvt.idl ** ** DESCRIPTION: ** ** This routine provides compatibility for DCE components that were ** coded prior to the routine name change from rpc_binding_server_to_client() ** to rpc_binding_server_from_client(). ** ** This routine calls through to the rpc_binding_server_from_client() ** API routine. ** ** NOTE: This description uses old terminology. ** ** Convert a server binding handle to a client handle. The new handle's ** endpoint is reset and it has no associated authentication information. ** ** Server binding handles are those created by the runtime and provided ** to the server manager as a result of a [handle_t] RPC parameter. ** ** INPUTS: ** ** src_binding_h The binding handle which points to the (server) ** source binding rep data structure to be converted. ** ** INPUTS/OUTPUTS: none ** ** OUTPUTS: ** ** dst_binding_h The binding handle which points to the converted (client) ** destination binding rep data structure. ** ** status A value indicating the status of the routine. ** ** rpc_s_ok The call was successful. ** rpc_s_invalid_binding ** RPC Protocol ID in binding handle was invalid. ** rpc_s_coding_error ** ** IMPLICIT INPUTS: none ** ** IMPLICIT OUTPUTS: none ** ** FUNCTION VALUE: void ** ** SIDE EFFECTS: none ** **-- **/ PUBLIC void rpc_binding_server_to_client ( rpc_binding_handle_t src_binding_h, rpc_binding_handle_t *dst_binding_h, unsigned32 *status ) { rpc_binding_server_from_client (src_binding_h, dst_binding_h, status); return; } /* **++ ** ** ROUTINE NAME: rpc_binding_server_from_client ** ** SCOPE: PUBLIC - declared in rpc.idl ** ** DESCRIPTION: ** ** NOTE: This description and the code use phrases "server binding ** handle" and "client binding handle" opposite from the way ** these are used in the API documentation. At some point, we ** should change the code to match the documentation. ** ** Convert a server binding handle to a client handle. The new handle's ** endpoint is reset and it has no associated authentication information. ** ** Server binding handles are those created by the runtime and provided ** to the server manager as a result of a [handle_t] RPC parameter. ** ** INPUTS: ** ** src_binding_h The binding handle which points to the (server) ** source binding rep data structure to be converted. ** ** INPUTS/OUTPUTS: none ** ** OUTPUTS: ** ** dst_binding_h The binding handle which points to the converted (client) ** destination binding rep data structure. ** ** status A value indicating the status of the routine. ** ** rpc_s_ok The call was successful. ** rpc_s_invalid_binding ** RPC Protocol ID in binding handle was invalid. ** rpc_s_coding_error ** ** IMPLICIT INPUTS: none ** ** IMPLICIT OUTPUTS: none ** ** FUNCTION VALUE: void ** ** SIDE EFFECTS: none ** **-- **/ PUBLIC void rpc_binding_server_from_client ( rpc_binding_handle_t src_binding_h, rpc_binding_handle_t *dst_binding_h, unsigned32 *status ) { rpc_binding_rep_p_t src_binding_rep = (rpc_binding_rep_p_t) src_binding_h; rpc_binding_rep_p_t dst_binding_rep; rpc_addr_p_t rpc_addr; unsigned32 tmp_status; boolean have_addr = false; assert(src_binding_rep != NULL); CODING_ERROR (status); RPC_VERIFY_INIT (); RPC_BINDING_VALIDATE_SERVER(src_binding_rep, status); if (*status != rpc_s_ok) return; /* * if the RPC address in the source is NULL, get one from protocol service */ if (src_binding_rep->rpc_addr == NULL) { rpc_addr_p_t srpc_addr; (*rpc_g_protocol_id[src_binding_rep->protocol_id].binding_epv ->binding_inq_addr) (src_binding_rep, &srpc_addr, status); if (*status != rpc_s_ok) return; /* * make a copy of the one in the source */ (*rpc_g_naf_id[src_binding_rep->rpc_addr->sa.family].epv ->naf_addr_copy) (src_binding_rep->rpc_addr, &rpc_addr, status); } else { /* * otherwise, make a copy of the one in the source */ (*rpc_g_naf_id[src_binding_rep->rpc_addr->sa.family].epv ->naf_addr_copy) (src_binding_rep->rpc_addr, &rpc_addr, status); if (*status != rpc_s_ok) return; } have_addr = true; /* * The resultant binding's address has no endpoint. It is absolutely * wrong to use the originating client's endpoint. */ rpc__naf_addr_set_endpoint ((unsigned_char_p_t) "", &rpc_addr, status); if (*status != rpc_s_ok) goto CLEANUP; /* * allocate and init a *client* binding rep. */ dst_binding_rep = rpc__binding_alloc ( false, &src_binding_rep->obj, src_binding_rep->protocol_id, rpc_addr, status); if (*status != rpc_s_ok) goto CLEANUP; /* * copy other common parts of the binding rep from the source to dest * * We explicitly leave the dst->auth NULL; the server (using this * new client handle) probably wants to make calls as its own * identity. */ dst_binding_rep->timeout = src_binding_rep->timeout; dst_binding_rep->call_timeout_time = src_binding_rep->call_timeout_time; dst_binding_rep->addr_is_dynamic = src_binding_rep->addr_is_dynamic; /* * return the destination binding rep as a binding handle */ *dst_binding_h = (rpc_binding_handle_t) dst_binding_rep; *status = rpc_s_ok; CLEANUP: if (*status != rpc_s_ok && have_addr) rpc__naf_addr_free (&rpc_addr, &tmp_status); } /* **++ ** ** ROUTINE NAME: rpc__binding_inq_sockaddr ** ** SCOPE: PRIVATE - declared in com.h ** ** DESCRIPTION: ** ** Inquire the sockaddr that is associated with a binding handle. ** ** This is kernel RPC only (private) operation and exists strictly for ** performance reasons. The returned sockaddr pointer points to storage ** directly associated with the binding handle. This pointer can become ** invalid under a number of circumstances (e.g. binding handle ** operations); copy the sa if you need to use it after any binding handle ** operations! ** ** Note: Do NOT remove this routine even though it appears that nothing ** is using it... it is used by Kernel RPC Applications. ** ** INPUTS: ** ** binding_h The binding handle which points to the binding ** rep data structure to be inquired. ** ** INPUTS/OUTPUTS: none ** ** OUTPUTS: ** ** sa A pointer to the sockaddr contained in the binding. ** ** status A value indicating the status of the routine. ** ** rpc_s_ok The call was successful. ** ** IMPLICIT INPUTS: none ** ** IMPLICIT OUTPUTS: none ** ** FUNCTION VALUE: void ** ** SIDE EFFECTS: none ** **-- **/ PRIVATE void rpc__binding_inq_sockaddr ( rpc_binding_handle_t binding_h, sockaddr_p_t *sa, unsigned32 *status ) { *sa = &((rpc_binding_rep_p_t) binding_h)->rpc_addr->sa; *status = rpc_s_ok; } /* **++ ** ** ROUTINE NAME: rpc__binding_cross_fork ** ** SCOPE: PRIVATE - declared in com.h ** ** DESCRIPTION: ** ** Perform whatever actions are required to make a binding handle usable ** in the client of a fork. ** ** Currently there is no common processing performed, and we just pass ** the binding rep to protocol specific routines for processing. ** ** INPUTS: ** ** binding_rep A pointer to a binding rep which is being used ** across a fork. ** ** INPUTS/OUTPUTS: none ** ** OUTPUTS: ** ** status A value indicating the status of the routine. ** ** rpc_s_ok The call was successful. ** ** IMPLICIT INPUTS: none ** ** IMPLICIT OUTPUTS: none ** ** FUNCTION VALUE: void ** ** SIDE EFFECTS: Any state associated with the binding handle is ** dropped so that it is not inherited by the child ** of a fork. ** **-- **/ PRIVATE void rpc__binding_cross_fork ( rpc_binding_rep_p_t binding_rep, unsigned32 * status ) { /* * Servers aren't allowed to fork, so we only allow passing * client binding handles across the fork. */ if (! RPC_BINDING_IS_CLIENT(binding_rep)) { *status = rpc_s_wrong_kind_of_binding; return; } /* * We only want to bring the handle across the fork once. * Take the global lock, then check that the handle still * needs to cross the fork. */ RPC_LOCK(0); if (binding_rep->fork_count != rpc_g_fork_count) { /* * Ask the protocol service to clean up any protocol specific * state that should not survive in the child of a fork. */ (*rpc_g_protocol_id[binding_rep->protocol_id].binding_epv ->binding_cross_fork) (binding_rep, status); /* * Update the handle to the current fork count. */ binding_rep->fork_count = rpc_g_fork_count; } RPC_UNLOCK(0); } /* **++ ** ROUTINE NAME: rpc__binding_prot_version_alloc ** ** SCOPE: PRIVATE ** ** DESCRIPTION: ** ** Allocates and initializes an rpc_protocol_version_t struct. ** ** INPUTS: ** major_version The major version of the protocol ** ** minor_version The minor version of the protocol. ** ** ** OUTPUTS: ** prot_version The allocated protocol_version structure. ** ** status ** rpc_s_ok ** ** ** IMPLICIT INPUTS: none ** ** IMPLICIT OUTPUTS: none ** ** FUNCTION VALUE: void ** ** SIDE EFFECTS: none ** **-- */ PRIVATE void rpc__binding_prot_version_alloc( rpc_protocol_version_p_t *prot_version, unsigned32 major_version, unsigned32 minor_version, unsigned32 *status) { /* * Alocate a version struct */ RPC_MEM_ALLOC(*prot_version, rpc_protocol_version_p_t, sizeof(rpc_protocol_version_t), RPC_C_MEM_PROTOCOL_VERSION, RPC_C_MEM_WAITOK); /* * Initialize data */ (*prot_version)->major_version = major_version; (*prot_version)->minor_version = minor_version; *status = rpc_s_ok; return; } /* **++ ** ROUTINE NAME: rpc__binding_prot_version_free ** ** SCOPE: PRIVATE - declared in com.h ** ** DESCRIPTION: ** ** Free's an rpc_protocol_version_t struct. ** The pointer is set to NULL. ** ** INPUTS: ** protocol_version Pointer to the version stuct. ** ** ** OUTPUTS: none ** ** SIDE EFFECTS: none ** **-- */ PRIVATE void rpc__binding_prot_version_free( rpc_protocol_version_p_t *protocol_version) { RPC_MEM_FREE (*protocol_version, RPC_C_MEM_PROTOCOL_VERSION); *protocol_version = NULL; return; } /* **++ ** ROUTINE NAME: rpc__binding_set_prot_version ** ** SCOPE: PRIVATE - called from nslookup.c ** ** DESCRIPTION: ** ** Sets the protocol version in a binding_rep data structure ** from a protocol tower. ** ** INPUTS: ** binding_h The binding handle which points to the binding ** rep data structure to be modified. ** ** tower_ref The tower to get the protocol version information ** ** OUTPUTS: ** status return status from called routines. ** ** SIDE EFFECTS: none ** **-- */ PRIVATE void rpc__binding_set_prot_version( rpc_binding_handle_t binding_h, rpc_tower_ref_p_t tower_ref, unsigned32 *status) { rpc_binding_rep_p_t binding_rep; rpc_protocol_id_t temp_protocol_id; unsigned32 major_version; unsigned32 minor_version; /* * Get the major and minor version of the tower. */ rpc__tower_flr_to_rpc_prot_id(tower_ref->floor[2], &temp_protocol_id, &major_version, &minor_version, status); if (*status != rpc_s_ok) { return; } /* * Allocate a protocol structure and initialize it. */ binding_rep = (rpc_binding_rep_p_t) binding_h; rpc__binding_prot_version_alloc(&(binding_rep->protocol_version), major_version, minor_version, status); return; } /* **++ ** ROUTINE NAME: rpc_binding_create ** ** SCOPE: PUBLIC ** ** DESCRIPTION: ** ** INPUTS: ** template binding handle template ** ** security security options ** ** options other options ** ** OUTPUTS: ** binding_h binding handle ** ** status return status from called routines. ** ** SIDE EFFECTS: none ** **-- */ PUBLIC void rpc_binding_create( rpc_binding_handle_template_t *template, rpc_binding_handle_security_t *security, rpc_binding_handle_options_t *options, rpc_binding_handle_t *binding_h, unsigned32 *st) { unsigned_char_p_t string_object_uuid = NULL; unsigned_char_p_t string_binding = NULL; rpc_binding_handle_t h = NULL; unsigned32 tmp_st; CODING_ERROR(st); *binding_h = NULL; if (template->version != 1 || (security != NULL && security->version != 1) || (options != NULL && options->version != 1)) { *st = rpc_s_rpc_prot_version_mismatch; /* XXX */ return; } if (!uuid_is_nil(&template->object_uuid, st)) { uuid_to_string(&template->object_uuid, &string_binding, st); if (*st != rpc_s_ok) return; } rpc_string_binding_compose(string_object_uuid, template->protseq, template->network_address, template->string_endpoint, template->reserved, &string_binding, st); rpc_string_free(&string_object_uuid, &tmp_st); if (*st != rpc_s_ok) return; rpc_binding_from_string_binding(string_binding, &h, st); rpc_string_free(&string_binding, &tmp_st); if (*st != rpc_s_ok) return; if (*st == rpc_s_ok && h == NULL) { *st = rpc_s_no_bindings; return; } if (options != NULL) { rpc_mgmt_set_com_timeout(h, options->com_timeout, st); if (*st != rpc_s_ok) { rpc_binding_free(&h, &tmp_st); return; } rpc_mgmt_set_cancel_timeout(options->cancel_timeout, st); if (*st != rpc_s_ok) { rpc_binding_free(&h, &tmp_st); return; } } if (security != NULL) { rpc_binding_set_auth_info(h, security->server_princ_name, security->authn_level, security->authn_protocol, security->auth_identity, security->authz_svc, st); if (*st != rpc_s_ok) { rpc_binding_free(&h, &tmp_st); return; } } *binding_h = h; return; }