/* * 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-marshal.c * * Abstract: * * Association API * Marshalling logic for association-specific datatypes * * Authors: Brian Koropoff (bkoropoff@likewisesoftware.com) * */ #include #include #include "convert.h" #include "util-private.h" #include "assoc-private.h" #include "data-private.h" #include #include static LWMsgStatus lwmsg_assoc_marshal_handle( LWMsgDataContext* mcontext, size_t object_size, void* object, LWMsgTypeAttrs* attrs, LWMsgBuffer* buffer, void* data ) { LWMsgStatus status = LWMSG_STATUS_SUCCESS; void* pointer = NULL; LWMsgHandleType location; unsigned long handle; LWMsgAssoc* assoc = NULL; LWMsgSessionManager* manager = NULL; LWMsgSession* session = NULL; unsigned char blob[5]; const char* type = NULL; const LWMsgContext* context = lwmsg_data_context_get_context(mcontext); LWMsgByteOrder byte_order = lwmsg_data_context_get_byte_order(mcontext); BAIL_ON_ERROR(status = lwmsg_context_get_data(context, "assoc", (void**) (void*) &assoc)); BAIL_ON_ERROR(status = lwmsg_assoc_get_session_manager(assoc, &manager)); BAIL_ON_ERROR(status = assoc->aclass->get_session(assoc, &session)); pointer = *(void**) object; if (pointer != NULL) { status = lwmsg_session_manager_handle_pointer_to_id( manager, session, pointer, &type, &location, &handle); switch (status) { case LWMSG_STATUS_NOT_FOUND: status = LWMSG_STATUS_INVALID_HANDLE; default: break; } BAIL_ON_ERROR(status); /* Confirm that the handle is of the expected type */ if (strcmp((const char*) data, type)) { MARSHAL_RAISE_ERROR(mcontext, status = LWMSG_STATUS_INVALID_HANDLE, "Invalid handle 0x%lx(%lu): expected handle of type '%s', " "got '%s'", (unsigned long) pointer, (unsigned long) handle, (const char*) data, type); } /* Confirm that handle origin is correct according to type attributes */ if ((attrs->custom & LWMSG_ASSOC_HANDLE_LOCAL_FOR_RECEIVER && location != LWMSG_HANDLE_REMOTE) || (attrs->custom & LWMSG_ASSOC_HANDLE_LOCAL_FOR_SENDER && location != LWMSG_HANDLE_LOCAL)) { if (location == LWMSG_HANDLE_LOCAL) { MARSHAL_RAISE_ERROR(mcontext, status = LWMSG_STATUS_INVALID_HANDLE, "Invalid handle 0x%lx(%lu): expected handle which is " "local for the receiver", (unsigned long) pointer, (unsigned long) handle); } else { MARSHAL_RAISE_ERROR(mcontext, status = LWMSG_STATUS_INVALID_HANDLE, "Invalid handle 0x%lx(%lu): expected handle which is " "local for the sender", (unsigned long) pointer, (unsigned long) handle); } } blob[0] = (unsigned char) location; BAIL_ON_ERROR(status = lwmsg_convert_integer( &handle, sizeof(handle), LWMSG_NATIVE_ENDIAN, &blob[1], 4, byte_order, LWMSG_UNSIGNED)); BAIL_ON_ERROR(status = lwmsg_buffer_write(buffer, blob, sizeof(blob))); } else { /* If the handle was not supposed to be NULL, raise an error */ if (attrs->nonnull) { MARSHAL_RAISE_ERROR(mcontext, status = LWMSG_STATUS_INVALID_HANDLE, "Invalid handle: expected non-null handle"); } blob[0] = (unsigned char) LWMSG_HANDLE_NULL; BAIL_ON_ERROR(status = lwmsg_buffer_write(buffer, blob, sizeof(blob[0]))); } error: return status; } static LWMsgStatus lwmsg_assoc_unmarshal_handle( LWMsgDataContext* mcontext, LWMsgBuffer* buffer, size_t object_size, LWMsgTypeAttrs* attrs, void* object, void* data ) { LWMsgStatus status = LWMSG_STATUS_SUCCESS; LWMsgAssoc* assoc = NULL; void* pointer = NULL; LWMsgHandleType location; unsigned long handle; char temp[5]; LWMsgSessionManager* manager = NULL; LWMsgSession* session = NULL; const LWMsgContext* context = lwmsg_data_context_get_context(mcontext); LWMsgByteOrder byte_order = lwmsg_data_context_get_byte_order(mcontext); BAIL_ON_ERROR(status = lwmsg_context_get_data(context, "assoc", (void**) (void*) &assoc)); BAIL_ON_ERROR(status = lwmsg_assoc_get_session_manager(assoc, &manager)); BAIL_ON_ERROR(status = assoc->aclass->get_session(assoc, &session)); /* Read handle type */ BAIL_ON_ERROR(status = lwmsg_buffer_read(buffer, &temp[0], sizeof(temp[0]))); location = (LWMsgHandleType) temp[0]; if (location != LWMSG_HANDLE_NULL) { /* Read handle ID */ BAIL_ON_ERROR(status = lwmsg_buffer_read(buffer, &temp[1], sizeof(temp) - sizeof(temp[0]))); /* Invert sense of handle location */ if (location == LWMSG_HANDLE_LOCAL) { location = LWMSG_HANDLE_REMOTE; } else { location = LWMSG_HANDLE_LOCAL; } if ((attrs->custom & LWMSG_ASSOC_HANDLE_LOCAL_FOR_RECEIVER && location != LWMSG_HANDLE_LOCAL) || (attrs->custom & LWMSG_ASSOC_HANDLE_LOCAL_FOR_SENDER && location != LWMSG_HANDLE_REMOTE)) { if (location == LWMSG_HANDLE_LOCAL) { MARSHAL_RAISE_ERROR(mcontext, status = LWMSG_STATUS_INVALID_HANDLE, "Invalid handle (%lu): expected handle which is " "local for the receiver", (unsigned long) pointer, (unsigned long) handle); } else { MARSHAL_RAISE_ERROR(mcontext, status = LWMSG_STATUS_INVALID_HANDLE, "Invalid handle (%lu): expected handle which is " "local for the sender", (unsigned long) pointer, (unsigned long) handle); } } BAIL_ON_ERROR(status = lwmsg_convert_integer( temp + 1, 4, byte_order, &handle, sizeof(handle), LWMSG_NATIVE_ENDIAN, LWMSG_UNSIGNED)); /* Convert handle to pointer */ status = lwmsg_session_manager_handle_id_to_pointer( manager, session, (const char*) data, location, handle, &pointer); switch (status) { case LWMSG_STATUS_NOT_FOUND: if (location == LWMSG_HANDLE_REMOTE) { /* Implicitly register handle seen from the peer for the first time */ BAIL_ON_ERROR(status = lwmsg_session_manager_register_handle_remote( manager, session, (const char*) data, handle, NULL, &pointer)); } else { MARSHAL_RAISE_ERROR(mcontext, status = LWMSG_STATUS_INVALID_HANDLE, "Invalid handle (%lu)", (unsigned long) handle); } break; default: BAIL_ON_ERROR(status); } /* Set pointer on unmarshalled object */ *(void**) object = pointer; } else { if (attrs->nonnull) { MARSHAL_RAISE_ERROR(mcontext, status = LWMSG_STATUS_INVALID_HANDLE, "Invalid handle: expected non-null handle"); } *(void**) object = NULL; } error: return status; } static void lwmsg_assoc_free_handle( const LWMsgContext* context, size_t object_size, LWMsgTypeAttrs* attr, void* object, void* data ) { LWMsgStatus status = LWMSG_STATUS_SUCCESS; LWMsgAssoc* assoc = NULL; void* pointer = NULL; BAIL_ON_ERROR(status = lwmsg_context_get_data(context, "assoc", (void**) (void*) &assoc)); pointer = *(void**) object; if (pointer) { BAIL_ON_ERROR(status = lwmsg_assoc_release_handle(assoc, pointer)); } error: return; } static LWMsgStatus lwmsg_assoc_print_handle( const LWMsgContext* context, size_t object_size, void* object, LWMsgTypeAttrs* attrs, void* data, LWMsgDataPrintFunction print, void* print_data ) { LWMsgStatus status = LWMSG_STATUS_SUCCESS; void* pointer = NULL; LWMsgHandleType location; unsigned long handle; LWMsgAssoc* assoc = NULL; LWMsgSessionManager* manager = NULL; LWMsgSession* session = NULL; const char* type; char* str = NULL; BAIL_ON_ERROR(status = lwmsg_context_get_data(context, "assoc", (void**) (void*) &assoc)); BAIL_ON_ERROR(status = lwmsg_assoc_get_session_manager(assoc, &manager)); BAIL_ON_ERROR(status = assoc->aclass->get_session(assoc, &session)); pointer = *(void**) object; if (pointer != NULL) { status = lwmsg_session_manager_handle_pointer_to_id( manager, session, pointer, &type, &location, &handle); switch (status) { case LWMSG_STATUS_NOT_FOUND: status = LWMSG_STATUS_INVALID_HANDLE; default: break; } BAIL_ON_ERROR(status); /* Confirm that the handle is of the expected type */ if (strcmp((const char*) data, type)) { BAIL_ON_ERROR(status = LWMSG_STATUS_INVALID_HANDLE); } str = lwmsg_format("<%s:%s[%lu]>", type, location == LWMSG_HANDLE_LOCAL ? "local" : "remote", handle); BAIL_ON_ERROR(status = print(str, strlen(str), print_data)); } else { static const char* nullstr = ""; if (attrs->nonnull) { BAIL_ON_ERROR(status = LWMSG_STATUS_INVALID_HANDLE); } BAIL_ON_ERROR(status = print(nullstr, strlen(nullstr), print_data)); } error: if (str) { free(str); } return status; } LWMsgCustomTypeClass lwmsg_handle_type_class = { .is_pointer = LWMSG_TRUE, .marshal = lwmsg_assoc_marshal_handle, .unmarshal = lwmsg_assoc_unmarshal_handle, .free = lwmsg_assoc_free_handle, .print = lwmsg_assoc_print_handle };