/* -*- 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 POA funcitons. * */ #include #include "orbit.h" #include "orbit_poa_type.h" #include "orbit_poa.h" static void ORBit_POAManager_release(PortableServer_POAManager poa_mgr, CORBA_Environment *ev); static void ORBit_POA_release(PortableServer_POA poa, CORBA_Environment *ev); static PortableServer_Servant ORBit_POA_ServantManager_use_servant(PortableServer_POA poa, GIOPRecvBuffer *recv_buffer, PortableServer_ServantLocator_Cookie *the_cookie, CORBA_Environment *ev); static void ORBit_POA_ServantManager_unuse_servant(PortableServer_Servant servant, PortableServer_POA poa, GIOPRecvBuffer *recv_buffer, PortableServer_ServantLocator_Cookie cookie, CORBA_Environment *ev); static const ORBit_RootObject_Interface CORBA_POAManager_epv = { (gpointer)ORBit_POAManager_release, }; static const ORBit_RootObject_Interface CORBA_POA_epv = { (gpointer)ORBit_POA_release, }; guint g_sequence_octet_hash(CORBA_sequence_octet *so) { guint retval = 0, i, n; n = so->_length/4; for(i = 0; i < n; i++) retval ^= ((CORBA_unsigned_long *)so->_buffer)[i]; return retval; } gint g_sequence_octet_compare(CORBA_sequence_octet *s1, CORBA_sequence_octet *s2) { if(s2->_length != s1->_length) return FALSE; return !memcmp(s1->_buffer, s2->_buffer, s1->_length); } PortableServer_POAManager ORBit_POAManager_new(CORBA_Environment *ev) { PortableServer_POAManager poa_mgr; poa_mgr = g_new0(struct PortableServer_POAManager_type, 1); if(poa_mgr == NULL) { CORBA_exception_set_system(ev, ex_CORBA_NO_MEMORY, CORBA_COMPLETED_NO); goto error; } /* Initialise poa manager */ ORBit_pseudo_object_init(ORBIT_PSEUDO_OBJECT(poa_mgr), ORBIT_PSEUDO_POAMANAGER, ev); ORBIT_ROOT_OBJECT(poa_mgr)->refs = 0; ORBit_RootObject_set_interface(ORBIT_ROOT_OBJECT(poa_mgr), (gpointer)&CORBA_POAManager_epv, ev); poa_mgr->poa_collection = NULL; poa_mgr->state = PortableServer_POAManager_HOLDING; return poa_mgr; error: if(poa_mgr != NULL){ ORBit_POAManager_release(poa_mgr, ev); } return NULL; } static void ORBit_POAManager_release(PortableServer_POAManager poa_mgr, CORBA_Environment *ev) { if(--(ORBIT_ROOT_OBJECT(poa_mgr)->refs) > 0) return; if(poa_mgr != NULL) { if(poa_mgr->poa_collection != NULL) { g_slist_free(poa_mgr->poa_collection); poa_mgr->poa_collection = NULL; } g_free(poa_mgr); poa_mgr = NULL; } } static void ORBit_POAManager_register_poa(PortableServer_POAManager poa_mgr, PortableServer_POA poa, CORBA_Environment *ev) { poa_mgr->poa_collection = g_slist_remove(poa_mgr->poa_collection, poa); poa_mgr->poa_collection = g_slist_append(poa_mgr->poa_collection, poa); } static void ORBit_POAManager_unregister_poa(PortableServer_POAManager poa_mgr, PortableServer_POA poa, CORBA_Environment *ev) { poa_mgr->poa_collection = g_slist_remove(poa_mgr->poa_collection, poa); } static void ORBit_POA_set_policy(PortableServer_POA poa, CORBA_Policy policy, CORBA_Environment *ev) { switch(policy->policy_type) { case PortableServer_THREAD_POLICY_ID: poa->thread = ((PortableServer_ThreadPolicy)policy)->value; break; case PortableServer_LIFESPAN_POLICY_ID: poa->lifespan = ((PortableServer_LifespanPolicy)policy)->value; break; case PortableServer_ID_UNIQUENESS_POLICY_ID: poa->id_uniqueness = ((PortableServer_IdUniquenessPolicy)policy)->value; break; case PortableServer_ID_ASSIGNMENT_POLICY_ID: poa->id_assignment = ((PortableServer_IdAssignmentPolicy)policy)->value; break; case PortableServer_IMPLICIT_ACTIVATION_POLICY_ID: poa->implicit_activation = ((PortableServer_ImplicitActivationPolicy)policy)->value; break; case PortableServer_SERVANT_RETENTION_POLICY_ID: poa->servant_retention = ((PortableServer_ServantRetentionPolicy)policy)->value; break; case PortableServer_REQUEST_PROCESSING_POLICY_ID: poa->request_processing = ((PortableServer_ServantRetentionPolicy)policy)->value; break; default: g_warning("Unknown policy type, cannot set it on this POA"); } } static void ORBit_POA_check_policy_conflicts(PortableServer_POA poa, CORBA_Environment *ev) { /* Check for those policy combinations that aren't allowed */ if ((poa->servant_retention == PortableServer_NON_RETAIN && poa->request_processing == PortableServer_USE_ACTIVE_OBJECT_MAP_ONLY) || (poa->request_processing == PortableServer_USE_DEFAULT_SERVANT && poa->id_uniqueness == PortableServer_UNIQUE_ID) || (poa->implicit_activation == PortableServer_IMPLICIT_ACTIVATION && (poa->id_assignment == PortableServer_USER_ID || poa->servant_retention == PortableServer_NON_RETAIN)) ) { CORBA_exception_set(ev, CORBA_USER_EXCEPTION, ex_PortableServer_POA_InvalidPolicy, NULL); } } static void ORBit_POA_set_policylist(PortableServer_POA poa, CORBA_PolicyList *policies, CORBA_Environment *ev) { CORBA_unsigned_long i; for(i = 0; i < policies->_length; i++) { if(ev->_major != CORBA_NO_EXCEPTION) break; ORBit_POA_set_policy(poa, policies->_buffer[i], ev); } } PortableServer_POA ORBit_POA_new(CORBA_ORB orb, CORBA_char *adapter_name, PortableServer_POAManager the_POAManager, CORBA_PolicyList *policies, CORBA_Environment *ev) { PortableServer_POA poa; /* Create the object */ poa = (PortableServer_POA) g_new0(struct PortableServer_POA_type, 1); if(poa == NULL) { CORBA_exception_set_system(ev, ex_CORBA_NO_MEMORY, CORBA_COMPLETED_NO); goto error; } ORBit_pseudo_object_init(ORBIT_PSEUDO_OBJECT(poa), ORBIT_PSEUDO_POA, ev); ORBIT_ROOT_OBJECT(poa)->refs = 0; ORBit_RootObject_set_interface(ORBIT_ROOT_OBJECT(poa), (gpointer)&CORBA_POA_epv, ev); if(ev->_major != CORBA_NO_EXCEPTION) goto error; /* If no POAManager was specified, create one */ if(the_POAManager == NULL) { the_POAManager = ORBit_POAManager_new(ev); } /* Register this poa with the poa manager */ if(the_POAManager != NULL) ORBit_POAManager_register_poa(the_POAManager,poa,ev); if(ev->_major != CORBA_NO_EXCEPTION) goto error; /* Wire up the poa_manager */ poa->the_POAManager = the_POAManager; /* Initialise the child poas table */ poa->child_POAs = NULL; /* initialise the slist */ poa->held_requests = NULL; poa->poaID = orb->poas->len; g_ptr_array_set_size(orb->poas, orb->poas->len + 1); g_ptr_array_index(orb->poas, poa->poaID) = poa; poa->orb = orb; g_return_val_if_fail(ev->_major == CORBA_NO_EXCEPTION, NULL); /* Need to initialise poa policies etc.. here */ poa->thread = PortableServer_ORB_CTRL_MODEL; poa->lifespan = PortableServer_TRANSIENT; poa->id_uniqueness = PortableServer_UNIQUE_ID; poa->id_assignment = PortableServer_SYSTEM_ID; poa->servant_retention = PortableServer_RETAIN; poa->request_processing = PortableServer_USE_ACTIVE_OBJECT_MAP_ONLY; poa->implicit_activation = PortableServer_NO_IMPLICIT_ACTIVATION; if (policies) { ORBit_POA_set_policylist(poa, policies, ev); ORBit_POA_check_policy_conflicts(poa, ev); if(ev->_major != CORBA_NO_EXCEPTION) goto error; } /* copy the name */ poa->the_name = CORBA_string_dup(adapter_name); poa->active_object_map = g_hash_table_new((GHashFunc)g_sequence_octet_hash, (GCompareFunc)g_sequence_octet_compare); poa->objnum_to_obj = g_ptr_array_new(); g_ptr_array_set_size(poa->objnum_to_obj, 1); g_ptr_array_index(poa->objnum_to_obj, 0) = NULL; return poa; error: if(poa && poa->the_name){ CORBA_free(poa->the_name); } if(poa != NULL){ ORBit_POA_release(poa, NULL); } return NULL; } static void ORBit_POA_release(PortableServer_POA poa, CORBA_Environment *ev) { ORBIT_ROOT_OBJECT_UNREF(poa); if(ORBIT_ROOT_OBJECT(poa)->refs <= 0) { CORBA_free(poa->the_name); g_slist_foreach(poa->child_POAs, (GFunc)CORBA_Object_release, ev); if(poa->parent_poa) ORBit_POA_remove_child(poa->parent_poa, poa, ev); ORBit_POAManager_unregister_poa(poa->the_POAManager, poa, ev); g_ptr_array_index(poa->orb->poas, poa->poaID) = NULL; g_free(poa); } } void ORBit_POA_add_child(PortableServer_POA poa, PortableServer_POA child_poa, CORBA_Environment *ev) { g_return_if_fail(poa != NULL); g_return_if_fail(child_poa != NULL); poa->child_POAs = g_slist_prepend(poa->child_POAs, child_poa); } void ORBit_POA_remove_child(PortableServer_POA poa, PortableServer_POA child_poa, CORBA_Environment *ev) { g_return_if_fail(poa != NULL); g_return_if_fail(child_poa != NULL); poa->child_POAs = g_slist_remove(poa->child_POAs, child_poa); } void ORBit_POA_handle_request(GIOPRecvBuffer *recv_buffer, PortableServer_POA poa) { PortableServer_ServantBase *servant; PortableServer_ServantLocator_Cookie cookie; ORBit_POAObject *obj_impl; ORBitSkeleton skel; gpointer imp; CORBA_Environment ev; GIOPSendBuffer *send_buffer; g_assert(poa); g_assert(recv_buffer); CORBA_exception_init(&ev); g_assert(poa); switch(poa->the_POAManager->state) { case PortableServer_POAManager_HOLDING: poa->held_requests = g_slist_prepend(poa->held_requests, recv_buffer); return; break; case PortableServer_POAManager_DISCARDING: send_buffer = giop_send_reply_buffer_use(GIOP_MESSAGE_BUFFER(recv_buffer)->connection, NULL, recv_buffer->message.u.request.request_id, CORBA_SYSTEM_EXCEPTION); CORBA_exception_set_system(&ev, ex_CORBA_TRANSIENT, CORBA_COMPLETED_NO); ORBit_send_system_exception(send_buffer, &ev); giop_send_buffer_write(send_buffer); giop_recv_buffer_unuse(recv_buffer); giop_send_buffer_unuse(send_buffer); CORBA_exception_free(&ev); return; break; case PortableServer_POAManager_INACTIVE: send_buffer = giop_send_reply_buffer_use(GIOP_MESSAGE_BUFFER(recv_buffer)->connection, NULL, recv_buffer->message.u.request.request_id, CORBA_SYSTEM_EXCEPTION); CORBA_exception_set_system(&ev, ex_CORBA_OBJ_ADAPTER, CORBA_COMPLETED_NO); ORBit_send_system_exception(send_buffer, &ev); giop_send_buffer_write(send_buffer); giop_recv_buffer_unuse(recv_buffer); giop_send_buffer_unuse(send_buffer); CORBA_exception_free(&ev); return; break; case PortableServer_POAManager_ACTIVE: default: break; } servant = NULL; if(poa->servant_retention == PortableServer_RETAIN) { gpointer nptr; CORBA_unsigned_long onum; if(recv_buffer->message.u.request.object_key._length != sizeof(CORBA_unsigned_long) * 2) { CORBA_exception_set_system(&ev, ex_CORBA_OBJECT_NOT_EXIST, CORBA_COMPLETED_NO); goto errout; } nptr = recv_buffer->message.u.request.object_key._buffer; onum = *((CORBA_unsigned_long *)((guchar *)nptr + sizeof(CORBA_unsigned_long))); obj_impl = g_ptr_array_index(poa->objnum_to_obj, onum); if(obj_impl && GPOINTER_TO_UINT(obj_impl) > poa->objnum_to_obj->len) servant = obj_impl->servant; } if(!servant) { switch(poa->request_processing) { case PortableServer_USE_SERVANT_MANAGER: servant = ORBit_POA_ServantManager_use_servant(poa, recv_buffer, &cookie, &ev); break; case PortableServer_USE_DEFAULT_SERVANT: servant = poa->default_servant; if(servant == NULL) CORBA_exception_set_system(&ev, ex_CORBA_OBJ_ADAPTER, CORBA_COMPLETED_NO); break; case PortableServer_USE_ACTIVE_OBJECT_MAP_ONLY: default: CORBA_exception_set_system(&ev, ex_CORBA_OBJECT_NOT_EXIST, CORBA_COMPLETED_NO); goto errout; } } g_assert(poa); g_assert(servant); skel = ORBIT_OBJECT_KEY(servant->_private)->class_info->relay_call(servant, recv_buffer, &imp); skel(servant, recv_buffer, &ev, imp); if(poa->request_processing == PortableServer_USE_SERVANT_MANAGER) { ORBit_POA_ServantManager_unuse_servant(servant, poa, recv_buffer, cookie, &ev); } errout: /* XXX send an exception back */ CORBA_exception_free(&ev); } PortableServer_POA ORBit_POA_find_POA_for_object_key(PortableServer_POA root_poa, CORBA_sequence_octet *key) { CORBA_unsigned_long pid; pid = *((CORBA_unsigned_long *)key->_buffer); if(pid < root_poa->orb->poas->len) return g_ptr_array_index(root_poa->orb->poas, pid); else return NULL; } void ORBit_POA_find_object_key_for_oid(PortableServer_POA poa, ORBit_POAObject *obj, CORBA_sequence_octet *retval) { g_return_if_fail(poa && obj); retval->_length = sizeof(CORBA_unsigned_long) * 2; retval->_buffer = CORBA_octet_allocbuf(retval->_length); CORBA_sequence_set_release(retval, CORBA_TRUE); *((CORBA_unsigned_long *)retval->_buffer) = poa->poaID; *((CORBA_unsigned_long *)(retval->_buffer + sizeof(CORBA_unsigned_long))) = obj->objnum; } DEFINE_LOCK(id_assignment_counter); static int id_assignment_counter = 0; PortableServer_ObjectId * ORBit_POA_allocate_oid(PortableServer_POA poa, const char *basis) { PortableServer_ObjectId *new_objid; char buf[512]; int len; new_objid = (PortableServer_ObjectId *)CORBA_sequence_octet__alloc(); GET_LOCK(id_assignment_counter); g_snprintf(buf, sizeof(buf), "%s%d", basis?basis:"Object", id_assignment_counter); id_assignment_counter++; RELEASE_LOCK(id_assignment_counter); len = strlen(buf)+1; new_objid->_buffer = CORBA_octet_allocbuf(len); new_objid->_length = len; new_objid->_release = CORBA_TRUE; strcpy(new_objid->_buffer, buf); return new_objid; } static PortableServer_Servant ORBit_POA_ServantManager_use_servant(PortableServer_POA poa, GIOPRecvBuffer *recv_buffer, PortableServer_ServantLocator_Cookie *the_cookie, CORBA_Environment *ev) { PortableServer_ObjectId oid; memcpy(&oid, &recv_buffer->message.u.request.object_key, sizeof(oid)); oid._buffer += sizeof(CORBA_unsigned_long); oid._length -= sizeof(CORBA_unsigned_long); if(poa->servant_retention == PortableServer_RETAIN) { POA_PortableServer_ServantActivator *sm; POA_PortableServer_ServantActivator__epv *epv; sm = (POA_PortableServer_ServantActivator *)poa->servant_manager; epv = sm->vepv->PortableServer_ServantActivator_epv; return epv->incarnate(sm, &oid, poa, ev); } else { POA_PortableServer_ServantLocator *sm; POA_PortableServer_ServantLocator__epv *epv; sm = (POA_PortableServer_ServantLocator *)poa->servant_manager; epv = sm->vepv->PortableServer_ServantLocator_epv; return epv->preinvoke(sm, &oid, poa, recv_buffer->message.u.request.operation, the_cookie, ev); } } static void ORBit_POA_ServantManager_unuse_servant(PortableServer_Servant servant, PortableServer_POA poa, GIOPRecvBuffer *recv_buffer, PortableServer_ServantLocator_Cookie cookie, CORBA_Environment *ev) { PortableServer_ObjectId oid; POA_PortableServer_ServantLocator *sm; POA_PortableServer_ServantLocator__epv *epv; if(poa->servant_retention != PortableServer_NON_RETAIN) return; memcpy(&oid, &recv_buffer->message.u.request.object_key, sizeof(oid)); oid._buffer += sizeof(CORBA_unsigned_long); oid._length -= sizeof(CORBA_unsigned_long); sm = (POA_PortableServer_ServantLocator *)poa->servant_manager; epv = sm->vepv->PortableServer_ServantLocator_epv; epv->postinvoke(sm, &oid, poa, recv_buffer->message.u.request.operation, cookie, servant, ev); } typedef struct { PortableServer_POA poa; CORBA_Environment *ev; } EtherealizeInfo; void ORBit_POA_etherealize_object(PortableServer_ObjectId *oid, ORBit_POAObject *obj_impl, EtherealizeInfo *ei) { POA_PortableServer_ServantActivator__epv *epv; POA_PortableServer_ServantActivator *sm; g_assert(ei->poa->servant_manager); g_hash_table_remove(ei->poa->active_object_map, obj_impl->object_id); sm = (POA_PortableServer_ServantActivator *)ei->poa->servant_manager; epv = sm->vepv->PortableServer_ServantActivator_epv; epv->etherealize(sm, obj_impl->object_id, ei->poa, obj_impl->servant, CORBA_TRUE, CORBA_FALSE, ei->ev); } void ORBit_POA_etherealize_objects(PortableServer_POA poa, CORBA_Environment *ev) { EtherealizeInfo ei; ei.poa = poa; ei.ev = ev; if(poa->servant_retention == PortableServer_RETAIN && poa->request_processing == PortableServer_USE_SERVANT_MANAGER) { g_hash_table_foreach(poa->active_object_map, (GHFunc)ORBit_POA_etherealize_object, &ei); } }