/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ /* * ORBit: A CORBA v2.2 ORB * * Copyright (C) 1998 Richard H. Porter and Red Hat Software * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * Author: Phil Dawes * Elliot Lee * */ /* * ORBit specific CORBA_Object functions. * */ #include #include "config.h" #include "../IIOP/iiop-endianP.h" #include "orbit_object_type.h" #include "corba_object_type.h" #include "allocators.h" #include "iop.h" #include static void ORBit_object_try_existing_connections(CORBA_Object obj); static void CORBA_Object_release_fn(CORBA_Object obj, CORBA_Environment *ev); ORBit_RootObject_Interface CORBA_Object_epv = { (gpointer)CORBA_Object_release_fn, }; void ORBit_pseudo_object_init(ORBit_PseudoObject obj, ORBit_PseudoObject_type obj_type, CORBA_Environment *ev) { ORBIT_ROOT_OBJECT(obj)->is_pseudo_object = TRUE; ORBIT_ROOT_OBJECT(obj)->refs = 0; ORBIT_PSEUDO_OBJECT(obj)->pseudo_object_type = obj_type; } static const ORBit_RootObject_Interface CORBA_Policy__epv = { (gpointer)CORBA_Policy_destroy }; void ORBit_policy_object_init(CORBA_Policy obj, CORBA_PolicyType obj_type, CORBA_Environment *ev) { ORBit_pseudo_object_init(ORBIT_PSEUDO_OBJECT(obj), ORBIT_PSEUDO_POLICY, ev); obj->policy_type = obj_type; ORBit_RootObject_set_interface(ORBIT_ROOT_OBJECT(obj), (gpointer)&CORBA_Policy__epv, ev); } void ORBit_object_reference_init(CORBA_Object obj, CORBA_Environment *ev) { ORBIT_ROOT_OBJECT(obj)->is_pseudo_object = FALSE; ORBIT_ROOT_OBJECT(obj)->refs = 0; /* set the interface up */ ORBit_RootObject_set_interface(ORBIT_ROOT_OBJECT(obj),&CORBA_Object_epv,ev); /* initialise the reference count */ ORBIT_ROOT_OBJECT(obj)->refs = 0; } CORBA_Object ORBit_CORBA_Object_new(CORBA_Environment *ev) { CORBA_Object obj; /* Create the object */ obj = ORBIT_CHUNK_ALLOC(CORBA_Object); memset(obj, '\0', sizeof(struct CORBA_Object_struct)); ORBit_object_reference_init(obj, ev); return obj; } void ORBit_set_object_key(ORBit_Object_info *info) { g_assert(info); g_assert(info->object_key._length); info->object_key_data = g_malloc(sizeof(CORBA_unsigned_long) + info->object_key._length); info->object_key_data->_length = info->object_key._length; memcpy(info->object_key_data->_buffer, info->object_key._buffer, info->object_key._length); info->object_key_vec.iov_base = (gpointer)info->object_key_data; info->object_key_vec.iov_len = sizeof(CORBA_unsigned_long) + info->object_key._length; } static void ORBit_free_profile(gpointer item, gpointer data) { ORBit_Object_info *info=(ORBit_Object_info *)item; g_assert(info); g_free(info->object_key_data); CORBA_free(info->object_key._buffer); if(info->profile_type == IOP_TAG_INTERNET_IOP) { g_free(info->tag.iopinfo.host); } else if(info->profile_type == IOP_TAG_ORBIT_SPECIFIC) { g_free(info->tag.orbitinfo.unix_sock_path); } else { g_warning("ORBit_free_profile asked to free type %d", info->profile_type); } g_free(info); /* Check its safe to free the item within a foreach func */ } void ORBit_delete_profiles(GSList *profile_list) { g_slist_foreach(profile_list, ORBit_free_profile, NULL); g_slist_free(profile_list); } /* this function is wired up to the RootObject interface */ void CORBA_Object_release_fn(CORBA_Object obj, CORBA_Environment *ev) { g_assert(obj!=NULL); ORBIT_ROOT_OBJECT_UNREF(obj); if(ORBIT_ROOT_OBJECT(obj)->refs <= 0) { g_hash_table_remove(obj->orb->objrefs, obj); if(obj->connection) giop_connection_unref(obj->connection); g_free(obj->object_id); ORBit_delete_profiles(obj->profile_list); ORBit_delete_profiles(obj->forward_locations); ORBIT_CHUNK_FREE(CORBA_Object, obj); } } /* Sets the interface member in the RootObject to the epv specified*/ void ORBit_RootObject_set_interface(ORBit_RootObject obj, ORBit_RootObject_Interface* epv, CORBA_Environment *ev) { g_assert(obj!=NULL); g_assert(epv!=NULL); obj->interface = epv; } #define GET_ATOM(x) G_STMT_START{ GIOP_RECV_BUFFER(recv_buffer)->decoder(&x, (GIOP_RECV_BUFFER(recv_buffer)->cur), sizeof(x)); ((guchar *)GIOP_RECV_BUFFER(recv_buffer)->cur) += sizeof(x); }G_STMT_END #define ALIGNFOR(x) recv_buffer->cur = ALIGN_ADDRESS(recv_buffer->cur, sizeof(x)) CORBA_Object ORBit_create_object_with_info(GSList *profiles, CORBA_char *type_id, CORBA_ORB orb, CORBA_Environment *ev) { CORBA_Object new; struct CORBA_Object_struct refcheck; if(!type_id || !*type_id) { g_warning("Failing object creation because object has no type"); CORBA_exception_set_system(ev, ex_CORBA_MARSHAL, CORBA_COMPLETED_MAYBE); return CORBA_OBJECT_NIL; } if(g_slist_length(profiles) < 1) { g_warning("Failing object creation because object has no profiles"); CORBA_exception_set_system(ev, ex_CORBA_MARSHAL, CORBA_COMPLETED_MAYBE); return CORBA_OBJECT_NIL; } /* XXX badhack :) */ refcheck.object_id = type_id; refcheck.profile_list = profiles; new = g_hash_table_lookup(orb->objrefs, &refcheck); if(new) { ORBit_delete_profiles(profiles); return CORBA_Object_duplicate(new, ev); } new = ORBit_CORBA_Object_new(ev); new->connection = NULL; new->object_id = g_strdup(type_id); new->orb = (CORBA_ORB)CORBA_Object_duplicate((CORBA_Object)orb, ev); new->profile_list = profiles; new->active_profile = NULL; ORBit_object_try_existing_connections(new); g_hash_table_insert(orb->objrefs, new, new); return CORBA_Object_duplicate(new, ev); } static ORBit_Object_info * ORBit_demarshal_profile(GIOPRecvBuffer *recv_buffer, IOP_ProfileId profile_id) { ORBit_Object_info *object_info; CORBA_unsigned_long subpart_len; CORBA_octet o; CDR_Codec codec_d; CDR_Codec *codec=&codec_d; object_info = g_new0(ORBit_Object_info, 1); switch(profile_id) { case IOP_TAG_INTERNET_IOP: GET_ATOM(subpart_len); /* The length of the embedded sequence */ CDR_codec_init_static(codec); codec->buffer = recv_buffer->cur; codec->release_buffer = CORBA_FALSE; ((guchar *)recv_buffer->cur) += subpart_len; codec->readonly = CORBA_TRUE; codec->host_endian = codec->data_endian = FLAG_ENDIANNESS; codec->buf_len = subpart_len; CDR_get_octet(codec, &o); codec->data_endian = o; object_info->profile_type = IOP_TAG_INTERNET_IOP; CDR_get_octet(codec, &object_info->iiop_major); if(object_info->iiop_major != 1) goto error_exit; /* XXX should we check for a specific minor version? */ CDR_get_octet(codec, &object_info->iiop_minor); CDR_get_string(codec, &object_info->tag.iopinfo.host); CDR_get_ushort(codec, &object_info->tag.iopinfo.port); CDR_get_seq_begin(codec, &object_info->object_key._length); object_info->object_key._buffer = ORBit_alloc(object_info->object_key._length, NULL, NULL); CDR_buffer_gets(codec, object_info->object_key._buffer, object_info->object_key._length); object_info->object_key._maximum = object_info->object_key._release = 0; ORBit_set_object_key(object_info); return(object_info); break; case IOP_TAG_MULTIPLE_COMPONENTS: GET_ATOM(subpart_len); g_warning("IOP_TAG_MULTIPLE_COMPONENTS decoding needs finishing"); object_info->profile_type = IOP_TAG_MULTIPLE_COMPONENTS; ((guchar *)recv_buffer->cur) += subpart_len; return(object_info); break; case IOP_TAG_ORBIT_SPECIFIC: GET_ATOM(subpart_len); CDR_codec_init_static(codec); codec->buffer = recv_buffer->cur; codec->release_buffer = CORBA_FALSE; ((guchar *)recv_buffer->cur) += subpart_len; codec->readonly = CORBA_TRUE; codec->host_endian = codec->data_endian = FLAG_ENDIANNESS; codec->buf_len = subpart_len; CDR_get_octet(codec, &o); codec->data_endian = o; object_info->profile_type = IOP_TAG_ORBIT_SPECIFIC; CDR_get_octet(codec, &object_info->iiop_major); if(object_info->iiop_major != 1) goto error_exit; /* XXX should we check for a specific minor version? */ CDR_get_octet(codec, &object_info->iiop_minor); CDR_get_string(codec, &object_info->tag.orbitinfo.unix_sock_path); CDR_get_ushort(codec, &object_info->tag.orbitinfo.ipv6_port); CDR_get_seq_begin(codec, &object_info->object_key._length); object_info->object_key._buffer = ORBit_alloc(object_info->object_key._length, NULL, NULL); CDR_buffer_gets(codec, object_info->object_key._buffer, object_info->object_key._length); object_info->object_key._maximum = object_info->object_key._release = 0; ORBit_set_object_key(object_info); return(object_info); break; } error_exit: g_message("demarshal_profile(): IIOP major is %d", object_info->iiop_major); g_free(object_info); return(NULL); } GSList *ORBit_demarshal_IOR(GIOPRecvBuffer *recv_buffer) { GSList *profiles=NULL; ORBit_Object_info *object_info; CORBA_unsigned_long len, seq_len; IOP_ProfileId profile_id; int i; /* Get type_id */ ALIGNFOR(CORBA_unsigned_long); GET_ATOM(len); if(len == 0) return(NULL); ((guchar *)recv_buffer->cur) += len; /* Decode the sequence */ ALIGNFOR(CORBA_unsigned_long); GET_ATOM(seq_len); for(i = 0; i < seq_len; i++) { ALIGNFOR(CORBA_unsigned_long); GET_ATOM(profile_id); object_info=ORBit_demarshal_profile(recv_buffer, profile_id); if(object_info==NULL) { goto error_exit; } else { profiles=g_slist_append(profiles, object_info); } } return(profiles); error_exit: ORBit_delete_profiles(profiles); return(NULL); } CORBA_Object ORBit_demarshal_object(GIOPRecvBuffer *recv_buffer, CORBA_ORB orb) { GSList *profiles=NULL; ORBit_Object_info *object_info; CORBA_char *type_id; CORBA_unsigned_long len, seq_len; IOP_ProfileId profile_id; int i; CORBA_Environment ev; CORBA_Object retval; CORBA_exception_init(&ev); /* Get type_id */ ALIGNFOR(CORBA_unsigned_long); GET_ATOM(len); if(len == 0) return CORBA_OBJECT_NIL; type_id = recv_buffer->cur; ((guchar *)recv_buffer->cur) += len; /* Decode the sequence */ ALIGNFOR(CORBA_unsigned_long); GET_ATOM(seq_len); for(i = 0; i < seq_len; i++) { ALIGNFOR(CORBA_unsigned_long); GET_ATOM(profile_id); object_info=ORBit_demarshal_profile(recv_buffer, profile_id); if(object_info==NULL) { g_warning("Doing an error exit because demarshal_profile failed"); goto error_exit; } else { profiles=g_slist_append(profiles, object_info); } } retval = ORBit_create_object_with_info(profiles, type_id, orb, &ev); return retval; error_exit: ORBit_delete_profiles(profiles); CORBA_exception_set_system(&ev, ex_CORBA_MARSHAL, CORBA_COMPLETED_MAYBE); return CORBA_OBJECT_NIL; } static void ORBit_marshal_profile(gpointer item, gpointer data) { ORBit_Object_info *info = (ORBit_Object_info *)item; GIOPSendBuffer *send_buffer = (GIOPSendBuffer *)data; static const CORBA_unsigned_long ioptag = IOP_TAG_INTERNET_IOP, orbittag = IOP_TAG_ORBIT_SPECIFIC; CDR_Codec codec_d; CDR_Codec *codec = &codec_d; CORBA_unsigned_long len; char codecbuf[2048]; static const CORBA_octet oc_endian = FLAG_ENDIANNESS; static const CORBA_octet iiopversion[] = {1,0}; g_assert(info); g_assert(send_buffer); if(info->profile_type == IOP_TAG_INTERNET_IOP) { giop_message_buffer_append_mem(GIOP_MESSAGE_BUFFER(send_buffer), &ioptag, sizeof(ioptag)); CDR_codec_init_static(codec); codec->buffer = codecbuf; codec->buf_len = 2048; codec->release_buffer = CORBA_FALSE; codec->readonly = CORBA_FALSE; codec->data_endian = codec->host_endian = FLAG_ENDIANNESS; CDR_put_octet(codec, oc_endian); CDR_put_octet(codec, iiopversion[0]); CDR_put_octet(codec, iiopversion[1]); CDR_put_string(codec, info->tag.iopinfo.host); CDR_put_ushort(codec, info->tag.iopinfo.port); CDR_put_ulong(codec, info->object_key._length); CDR_put_octets(codec, info->object_key._buffer, info->object_key._length); len = codec->wptr; giop_send_buffer_append_mem_indirect_a(send_buffer, &len, sizeof(len)); giop_send_buffer_append_mem_indirect(send_buffer, codec->buffer, codec->wptr); } else if(info->profile_type==IOP_TAG_ORBIT_SPECIFIC) { giop_message_buffer_append_mem_a(GIOP_MESSAGE_BUFFER(send_buffer), &orbittag, sizeof(orbittag)); CDR_codec_init_static(codec); codec->buffer = codecbuf; codec->release_buffer = CORBA_FALSE; codec->buf_len = 2048; codec->readonly = CORBA_FALSE; codec->data_endian = codec->host_endian = FLAG_ENDIANNESS; CDR_put_octet(codec, oc_endian); CDR_put_octets(codec, (gpointer)iiopversion, sizeof(iiopversion)); CDR_put_string(codec, info->tag.orbitinfo.unix_sock_path); CDR_put_ushort(codec, info->tag.orbitinfo.ipv6_port); CDR_put_ulong(codec, info->object_key._length); CDR_put_octets(codec, info->object_key._buffer, info->object_key._length); len = codec->wptr; giop_send_buffer_append_mem_indirect_a(send_buffer, &len, sizeof(len)); giop_send_buffer_append_mem_indirect(send_buffer, codec->buffer, codec->wptr); } else { g_warning("ORBit_marshal_profile ask to marshal type %d\n", info->profile_type); } } void ORBit_marshal_object(GIOPSendBuffer *send_buffer, CORBA_Object obj) { CORBA_unsigned_long len; if(!obj) { len = 0; giop_send_buffer_append_mem_indirect_a(send_buffer, &len, sizeof(len)); return; } len = strlen(obj->object_id) + 1; giop_send_buffer_append_mem_indirect_a(send_buffer, &len, sizeof(len)); giop_message_buffer_append_mem(GIOP_MESSAGE_BUFFER(send_buffer), obj->object_id, len); len = g_slist_length(obj->profile_list); giop_send_buffer_append_mem_indirect_a(GIOP_SEND_BUFFER(send_buffer), &len, sizeof(len)); /* Marshal active first? */ g_slist_foreach(obj->profile_list, ORBit_marshal_profile, send_buffer); } static void ORBit_test_profile(gpointer item, gpointer data) { ORBit_Object_info *info = (ORBit_Object_info *)item; CORBA_Object obj = (CORBA_Object)data; if(obj->active_profile != NULL) return; /* we already have a good profile */ if(info->profile_type == IOP_TAG_ORBIT_SPECIFIC) { if(!ORBit_parse_unixsock(obj, info->tag.orbitinfo.unix_sock_path, TRUE)) { /* success */ obj->active_profile=info; } } else if(info->profile_type == IOP_TAG_INTERNET_IOP) { if(!ORBit_parse_inet(obj, info->tag.iopinfo.host, info->tag.iopinfo.port, TRUE)) { /* success */ obj->active_profile=info; } } } static void ORBit_object_try_existing_connections(CORBA_Object obj) { g_slist_foreach(obj->profile_list, ORBit_test_profile, obj); } static void ORBit_activate_profile(gpointer item, gpointer data) { ORBit_Object_info *info = (ORBit_Object_info *)item; CORBA_Object obj = (CORBA_Object)data; if(obj->active_profile != NULL) return; /* we already have a good profile */ if(info->profile_type == IOP_TAG_ORBIT_SPECIFIC) { if(!ORBit_parse_unixsock(obj, info->tag.orbitinfo.unix_sock_path, FALSE)) { /* success */ obj->active_profile=info; } } else if(info->profile_type == IOP_TAG_INTERNET_IOP) { if(!ORBit_parse_inet(obj, info->tag.iopinfo.host, info->tag.iopinfo.port, FALSE)) { /* success */ obj->active_profile=info; } } } GIOPConnection * _ORBit_object_get_connection(CORBA_Object obj) { g_return_val_if_fail(obj, NULL); if (obj->connection) { giop_connection_unref(obj->connection); obj->connection = NULL; obj->active_profile = NULL; } g_slist_foreach(obj->profile_list, ORBit_activate_profile, obj); if(obj->active_profile == NULL || !obj->connection) return NULL; obj->connection->orb_data = obj->orb; return obj->connection; } GIOPConnection * ORBit_object_get_forwarded_connection(CORBA_Object obj) { g_return_val_if_fail(obj, NULL); if (obj->connection) { giop_connection_unref(obj->connection); obj->connection = NULL; obj->active_profile = NULL; } g_slist_foreach(obj->forward_locations, ORBit_activate_profile, obj); if(obj->active_profile == NULL || !obj->connection) return NULL; obj->connection->orb_data = obj->orb; return obj->connection; } /* This function is heavily based on the idl stubs output. Any changes there will probably have to be reflected here also. */ void ORBit_object_locate(CORBA_Object obj, CORBA_Environment *ev) { GIOPConnection *cnx; GIOPSendBuffer *send_buffer; GIOPRecvBuffer *recv_buffer; GIOP_unsigned_long request_id; g_return_if_fail(obj!=NULL); g_return_if_fail(ev!=NULL); /* Send a LOCATE_REQUEST, wait for a LOCATE_REPLY. The reply will either say "Object here", or will carry a new location. We set obj->active_profile appropriately */ cnx=ORBit_object_get_connection(obj); if((cnx==NULL) || (obj->active_profile==NULL)) { CORBA_exception_set_system(ev, ex_CORBA_COMM_FAILURE, CORBA_COMPLETED_NO); return; } request_id=giop_get_request_id(); send_buffer=giop_send_locate_request_buffer_use(cnx, request_id, &(obj->active_profile->object_key_vec)); if(!send_buffer) { CORBA_exception_set_system(ev, ex_CORBA_COMM_FAILURE, CORBA_COMPLETED_NO); return; } giop_send_buffer_write(send_buffer); giop_send_buffer_unuse(send_buffer); recv_buffer=giop_recv_locate_reply_buffer_use(request_id, TRUE); if(recv_buffer==NULL || recv_buffer->message_buffer.message_header.message_type!=GIOP_LOCATEREPLY) { CORBA_exception_set_system(ev, ex_CORBA_COMM_FAILURE, CORBA_COMPLETED_MAYBE); if(recv_buffer) giop_recv_buffer_unuse(recv_buffer); return; } ev->_major=CORBA_NO_EXCEPTION; switch(recv_buffer->message.u.locate_reply.locate_status) { case GIOP_UNKNOWN_OBJECT: CORBA_exception_set_system(ev, ex_CORBA_OBJECT_NOT_EXIST, CORBA_COMPLETED_NO); break; case GIOP_OBJECT_HERE: /* No further processing necessary */ break; case GIOP_OBJECT_FORWARD: /* We've been forwarded onto somewhere else. The message body contains the new IOR */ if(obj->forward_locations != NULL) { ORBit_delete_profiles(obj->forward_locations); } obj->forward_locations=ORBit_demarshal_IOR(recv_buffer); /* This will adjust obj->active_profile */ cnx=ORBit_object_get_forwarded_connection(obj); break; default: g_message("Bad Reply in ORBit_locate_object()\n"); break; } giop_recv_buffer_unuse(recv_buffer); }