/* * Copyright (c) Likewise Software. All rights Reserved. * * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 2.1 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 Lesser * General Public License for more details. You should have received a copy * of the GNU Lesser General Public License along with this program. If * not, see . * * LIKEWISE SOFTWARE MAKES THIS SOFTWARE AVAILABLE UNDER OTHER LICENSING * TERMS AS WELL. IF YOU HAVE ENTERED INTO A SEPARATE LICENSE AGREEMENT * WITH LIKEWISE SOFTWARE, THEN YOU MAY ELECT TO USE THE SOFTWARE UNDER THE * TERMS OF THAT SOFTWARE LICENSE AGREEMENT INSTEAD OF THE TERMS OF THE GNU * LESSER GENERAL PUBLIC LICENSE, NOTWITHSTANDING THE ABOVE NOTICE. IF YOU * HAVE QUESTIONS, OR WISH TO REQUEST A COPY OF THE ALTERNATE LICENSING * TERMS OFFERED BY LIKEWISE SOFTWARE, PLEASE CONTACT LIKEWISE SOFTWARE AT * license@likewisesoftware.com */ /* * Module Name: * * assoc.c * * Abstract: * * Association API * Primary entry points * * Authors: Brian Koropoff (bkoropoff@likewisesoftware.com) * */ #include #include #include #include "assoc-private.h" #include "util-private.h" #include "protocol-private.h" #include "session-private.h" LWMsgStatus lwmsg_assoc_register_handle( LWMsgAssoc* assoc, const char* typename, void* handle, LWMsgHandleCleanupFunction free ) { LWMsgStatus status = LWMSG_STATUS_SUCCESS; LWMsgSessionManager* manager = NULL; LWMsgSession* session = NULL; BAIL_ON_ERROR(status = lwmsg_assoc_get_session_manager(assoc, &manager)); BAIL_ON_ERROR(status = assoc->aclass->get_session(assoc, &session)); BAIL_ON_ERROR(status = lwmsg_session_manager_register_handle_local( manager, session, typename, handle, free, NULL)); error: return status; } LWMsgStatus lwmsg_assoc_retain_handle( LWMsgAssoc* assoc, void* handle ) { LWMsgStatus status = LWMSG_STATUS_SUCCESS; LWMsgSessionManager* manager = NULL; LWMsgSession* session = NULL; BAIL_ON_ERROR(status = lwmsg_assoc_get_session_manager(assoc, &manager)); BAIL_ON_ERROR(status = assoc->aclass->get_session(assoc, &session)); BAIL_ON_ERROR(status = lwmsg_session_manager_retain_handle( manager, session, handle )); error: return status; } LWMsgStatus lwmsg_assoc_release_handle( LWMsgAssoc* assoc, void* handle ) { LWMsgStatus status = LWMSG_STATUS_SUCCESS; LWMsgSessionManager* manager = NULL; LWMsgSession* session = NULL; BAIL_ON_ERROR(status = lwmsg_assoc_get_session_manager(assoc, &manager)); BAIL_ON_ERROR(status = assoc->aclass->get_session(assoc, &session)); BAIL_ON_ERROR(status = lwmsg_session_manager_release_handle( manager, session, handle )); error: return status; } LWMsgStatus lwmsg_assoc_unregister_handle( LWMsgAssoc* assoc, void* handle ) { LWMsgStatus status = LWMSG_STATUS_SUCCESS; LWMsgSessionManager* manager = NULL; LWMsgSession* session = NULL; BAIL_ON_ERROR(status = lwmsg_assoc_get_session_manager(assoc, &manager)); BAIL_ON_ERROR(status = assoc->aclass->get_session(assoc, &session)); BAIL_ON_ERROR(status = lwmsg_session_manager_unregister_handle( manager, session, handle )); error: return status; } LWMsgStatus lwmsg_assoc_get_handle_location( LWMsgAssoc* assoc, void* handle, LWMsgHandleType* location ) { LWMsgStatus status = LWMSG_STATUS_SUCCESS; LWMsgSessionManager* manager = NULL; LWMsgSession* session = NULL; BAIL_ON_ERROR(status = lwmsg_assoc_get_session_manager(assoc, &manager)); BAIL_ON_ERROR(status = assoc->aclass->get_session(assoc, &session)); BAIL_ON_ERROR(status = lwmsg_session_manager_handle_pointer_to_id( manager, session, handle, NULL, location, NULL)); error: return status; } static LWMsgStatus lwmsg_assoc_context_get_data( const char* key, void** out_data, void* data ) { if (!strcmp(key, "assoc")) { *out_data = data; return LWMSG_STATUS_SUCCESS; } else { return LWMSG_STATUS_NOT_FOUND; } } LWMsgStatus lwmsg_assoc_new( const LWMsgContext* context, LWMsgProtocol* prot, LWMsgAssocClass* aclass, size_t size, LWMsgAssoc** out_assoc ) { LWMsgStatus status = LWMSG_STATUS_SUCCESS; LWMsgAssoc* assoc = calloc(1, size); if (!assoc) { BAIL_ON_ERROR(status = LWMSG_STATUS_MEMORY); } assoc->prot = prot; assoc->aclass = aclass; lwmsg_context_setup(&assoc->context, context); lwmsg_context_set_data_function(&assoc->context, lwmsg_assoc_context_get_data, assoc); BAIL_ON_ERROR(status = lwmsg_assoc_call_init(&assoc->call)); if (aclass->construct) { aclass->construct(assoc); } *out_assoc = assoc; error: return status; } void lwmsg_assoc_delete( LWMsgAssoc* assoc ) { lwmsg_context_cleanup(&assoc->context); if (assoc->aclass->destruct) { assoc->aclass->destruct(assoc); } if (assoc->manager && assoc->manager_is_private) { lwmsg_session_manager_delete(assoc->manager); } free(assoc); } LWMsgProtocol* lwmsg_assoc_get_protocol( LWMsgAssoc* assoc ) { return assoc->prot; } LWMsgStatus lwmsg_assoc_send_message( LWMsgAssoc* assoc, LWMsgMessage* message ) { LWMsgStatus status = LWMSG_STATUS_SUCCESS; BAIL_ON_ERROR(status = assoc->aclass->send_msg(assoc, message)); error: return status; } LWMsgStatus lwmsg_assoc_recv_message( LWMsgAssoc* assoc, LWMsgMessage* message ) { LWMsgStatus status = LWMSG_STATUS_SUCCESS; BAIL_ON_ERROR(status = assoc->aclass->recv_msg(assoc, message)); error: return status; } LWMsgStatus lwmsg_assoc_send_message_transact( LWMsgAssoc* assoc, LWMsgMessage* send_message, LWMsgMessage* recv_message ) { LWMsgStatus status = LWMSG_STATUS_SUCCESS; BAIL_ON_ERROR(status = assoc->aclass->send_msg(assoc, send_message)); BAIL_ON_ERROR(status = assoc->aclass->recv_msg(assoc, recv_message)); error: return status; } LWMsgStatus lwmsg_assoc_recv_message_transact( LWMsgAssoc* assoc, LWMsgAssocDispatchFunction dispatch, void* data ) { LWMsgStatus status = LWMSG_STATUS_SUCCESS; LWMsgMessage recv_message = LWMSG_MESSAGE_INITIALIZER; LWMsgMessage send_message = LWMSG_MESSAGE_INITIALIZER; BAIL_ON_ERROR(status = assoc->aclass->recv_msg(assoc, &recv_message)); BAIL_ON_ERROR(status = dispatch(assoc, &recv_message, &send_message, data)); BAIL_ON_ERROR(status = assoc->aclass->send_msg(assoc, &send_message)); error: if (recv_message.tag != -1 && recv_message.data) { lwmsg_assoc_destroy_message(assoc, &recv_message); } if (send_message.tag != -1 && send_message.data) { lwmsg_assoc_destroy_message(assoc, &send_message); } return status; } LWMsgStatus lwmsg_assoc_send( LWMsgAssoc* assoc, LWMsgTag type, void* object ) { LWMsgMessage message = LWMSG_MESSAGE_INITIALIZER; message.tag = type; message.data = object; return lwmsg_assoc_send_message(assoc, &message); } LWMsgStatus lwmsg_assoc_recv( LWMsgAssoc* assoc, LWMsgTag* out_type, void** out_object ) { LWMsgStatus status = LWMSG_STATUS_SUCCESS; LWMsgMessage message = LWMSG_MESSAGE_INITIALIZER; BAIL_ON_ERROR(status = lwmsg_assoc_recv_message(assoc, &message)); *out_type = message.tag; *out_object = message.data; error: return status; } LWMsgStatus lwmsg_assoc_send_transact( LWMsgAssoc* assoc, LWMsgTag in_type, void* in_object, LWMsgTag* out_type, void** out_object ) { LWMsgStatus status = LWMSG_STATUS_SUCCESS; LWMsgMessage in_message = LWMSG_MESSAGE_INITIALIZER; LWMsgMessage out_message = LWMSG_MESSAGE_INITIALIZER; in_message.tag = in_type; in_message.data = in_object; BAIL_ON_ERROR(status = lwmsg_assoc_send_message_transact(assoc, &in_message, &out_message)); *out_type = out_message.tag; *out_object = out_message.data; error: return status; } LWMsgStatus lwmsg_assoc_get_peer_security_token( LWMsgAssoc* assoc, LWMsgSecurityToken** out_token ) { LWMsgStatus status = LWMSG_STATUS_SUCCESS; BAIL_ON_ERROR(status = assoc->aclass->get_peer_security_token(assoc, out_token)); error: return status; } LWMsgStatus lwmsg_assoc_get_peer_session_id( LWMsgAssoc* assoc, LWMsgSessionID* id ) { LWMsgStatus status = LWMSG_STATUS_SUCCESS; LWMsgSession* session = NULL; const LWMsgSessionID* my_id = NULL; BAIL_ON_ERROR(status = assoc->aclass->get_session(assoc, &session)); my_id = lwmsg_session_manager_get_session_id(assoc->manager, session); memcpy(id->bytes, my_id->bytes, sizeof(id->bytes)); error: return status; } LWMsgStatus lwmsg_assoc_get_session( LWMsgAssoc* assoc, LWMsgSession** session ) { return assoc->aclass->get_session(assoc, session); } LWMsgStatus lwmsg_assoc_close( LWMsgAssoc* assoc ) { LWMsgStatus status = LWMSG_STATUS_SUCCESS; BAIL_ON_ERROR(status = assoc->aclass->close(assoc)); error: return status; } LWMsgStatus lwmsg_assoc_reset( LWMsgAssoc* assoc ) { LWMsgStatus status = LWMSG_STATUS_SUCCESS; BAIL_ON_ERROR(status = assoc->aclass->reset(assoc)); error: return status; } LWMsgStatus lwmsg_assoc_destroy_message( LWMsgAssoc* assoc, LWMsgMessage* message ) { LWMsgStatus status = LWMSG_STATUS_SUCCESS; LWMsgTypeSpec* type = NULL; LWMsgDataContext* context = NULL; if (message->tag != -1) { BAIL_ON_ERROR(status = lwmsg_protocol_get_message_type(assoc->prot, message->tag, &type)); if (type != NULL) { BAIL_ON_ERROR(status = lwmsg_data_context_new(&assoc->context, &context)); BAIL_ON_ERROR(status = lwmsg_data_free_graph(context, type, message->data)); } message->tag = -1; message->data = NULL; } error: if (context) { lwmsg_data_context_delete(context); } return status; } LWMsgStatus lwmsg_assoc_free_graph( LWMsgAssoc* assoc, LWMsgTag mtype, void* object ); LWMsgStatus lwmsg_assoc_free_graph( LWMsgAssoc* assoc, LWMsgTag mtype, void* object ) { LWMsgStatus status = LWMSG_STATUS_SUCCESS; LWMsgTypeSpec* type = NULL; LWMsgDataContext* context = NULL; BAIL_ON_ERROR(status = lwmsg_protocol_get_message_type(assoc->prot, mtype, &type)); BAIL_ON_ERROR(status = lwmsg_data_context_new(&assoc->context, &context)); BAIL_ON_ERROR(status = lwmsg_data_free_graph(context, type, object)); error: if (context) { lwmsg_data_context_delete(context); } return status; } const char* lwmsg_assoc_get_error_message( LWMsgAssoc* assoc, LWMsgStatus status ) { return lwmsg_context_get_error_message(&assoc->context, status); } LWMsgStatus lwmsg_assoc_set_session_manager( LWMsgAssoc* assoc, LWMsgSessionManager* manager ) { if (assoc->manager && assoc->manager_is_private) { lwmsg_session_manager_delete(assoc->manager); assoc->manager_is_private = LWMSG_FALSE; } assoc->manager = manager; return LWMSG_STATUS_SUCCESS; } LWMsgStatus lwmsg_assoc_get_session_manager( LWMsgAssoc* assoc, LWMsgSessionManager** out_manager ) { LWMsgStatus status = LWMSG_STATUS_SUCCESS; if (!assoc->manager) { BAIL_ON_ERROR(status = lwmsg_default_session_manager_new(&assoc->manager)); assoc->manager_is_private = LWMSG_TRUE; } *out_manager = assoc->manager; error: return status; } LWMsgAssocState lwmsg_assoc_get_state( LWMsgAssoc* assoc ) { return assoc->aclass->get_state(assoc); } LWMsgStatus lwmsg_assoc_get_session_data( LWMsgAssoc* assoc, void** data ) { LWMsgStatus status = LWMSG_STATUS_SUCCESS; LWMsgSession* session = NULL; if (!assoc->manager) { BAIL_ON_ERROR(status = LWMSG_STATUS_INVALID_STATE); } if (assoc->aclass->get_session(assoc, &session)) { BAIL_ON_ERROR(status = LWMSG_STATUS_INVALID_STATE); } *data = lwmsg_session_manager_get_session_data(assoc->manager, session); error: return status; } LWMsgStatus lwmsg_assoc_set_timeout( LWMsgAssoc* assoc, LWMsgTimeout type, LWMsgTime* value ) { return assoc->aclass->set_timeout(assoc, type, value); } LWMsgStatus lwmsg_assoc_establish( LWMsgAssoc* assoc ) { return assoc->aclass->establish( assoc, assoc->construct, assoc->destruct, assoc->construct_data); } LWMsgStatus lwmsg_assoc_finish( LWMsgAssoc* assoc, LWMsgMessage** message ) { return assoc->aclass->finish(assoc, message); } LWMsgStatus lwmsg_assoc_set_nonblock( LWMsgAssoc* assoc, LWMsgBool nonblock ) { return assoc->aclass->set_nonblock(assoc, nonblock); } LWMsgStatus lwmsg_assoc_set_session_functions( LWMsgAssoc* assoc, LWMsgSessionConstructFunction construct, LWMsgSessionDestructFunction destruct, void* data ) { LWMsgStatus status = LWMSG_STATUS_SUCCESS; assoc->construct = construct; assoc->destruct = destruct; assoc->construct_data = data; return status; } LWMsgStatus lwmsg_assoc_print_message_alloc( LWMsgAssoc* assoc, LWMsgMessage* message, char** result ) { LWMsgStatus status = LWMSG_STATUS_SUCCESS; LWMsgDataContext* context = NULL; LWMsgTypeSpec* type = NULL; char* payload_result = NULL; char* my_result = NULL; const char* tag_name = NULL; BAIL_ON_ERROR(status = lwmsg_data_context_new(&assoc->context, &context)); BAIL_ON_ERROR(status = lwmsg_protocol_get_message_name(assoc->prot, message->tag, &tag_name)); BAIL_ON_ERROR(status = lwmsg_protocol_get_message_type(assoc->prot, message->tag, &type)); if (type) { BAIL_ON_ERROR(status = lwmsg_data_print_graph_alloc(context, type, message->data, &payload_result)); my_result = lwmsg_format("%s: %s", tag_name, payload_result); } else { my_result = lwmsg_format("%s", tag_name); } if (!my_result) { BAIL_ON_ERROR(status = LWMSG_STATUS_MEMORY); } *result = my_result; cleanup: if (context) { lwmsg_data_context_delete(context); } if (payload_result) { lwmsg_context_free(&assoc->context, payload_result); } return status; error: *result = NULL; if (my_result) { lwmsg_context_free(&assoc->context, my_result); } goto cleanup; } LWMsgStatus lwmsg_assoc_acquire_call( LWMsgAssoc* assoc, LWMsgCall** call ) { LWMsgStatus status = LWMSG_STATUS_SUCCESS; if (assoc->call.in_use) { BAIL_ON_ERROR(status = LWMSG_STATUS_BUSY); } else { switch (lwmsg_assoc_get_state(assoc)) { case LWMSG_ASSOC_STATE_IDLE: break; case LWMSG_ASSOC_STATE_NOT_ESTABLISHED: BAIL_ON_ERROR(status = lwmsg_assoc_establish(assoc)); break; default: BAIL_ON_ERROR(status = LWMSG_STATUS_INVALID_STATE); } assoc->call.in_use = LWMSG_TRUE; *call = LWMSG_CALL(&assoc->call); } error: return status; }