/*
* 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:
*
* session-default.c
*
* Abstract:
*
* Session management API
* Default session manager implementation
*
* Authors: Brian Koropoff (bkoropoff@likewisesoftware.com)
*
*/
#include "session-private.h"
#include "util-private.h"
#include
#include
#include
typedef struct DefaultSession
{
LWMsgSession base;
/* Remote session identifier */
LWMsgSessionID rsmid;
/* Security token of session creator */
LWMsgSecurityToken* sec_token;
/* Reference count */
size_t refs;
/* Pointer to linked list of handles */
struct DefaultHandle* handles;
/* Number of handles */
size_t num_handles;
/* Links to other sessions in the manager */
struct DefaultSession* next, *prev;
/* User data pointer */
void* data;
/* Destruct function */
LWMsgSessionDestructFunction destruct;
} DefaultSession;
typedef struct DefaultHandle
{
/* Handle type */
const char* type;
/* Handle refcount */
size_t refs;
/* Validity bit */
LWMsgBool valid;
/* Handle pointer */
void* pointer;
/* Handle locality */
LWMsgHandleType locality;
/* Handle id */
unsigned long hid;
/* Handle cleanup function */
void (*cleanup)(void*);
/* Links to other handles in the session */
struct DefaultHandle* next, *prev;
} DefaultHandle;
typedef struct DefaultManager
{
LWMsgSessionManager base;
DefaultSession* sessions;
unsigned long next_hid;
} DefaultManager;
#define DEFAULT_MANAGER(obj) ((DefaultManager*) (obj))
#define DEFAULT_SESSION(obj) ((DefaultSession*) (obj))
static void
default_free_handle(
DefaultHandle* entry
)
{
if (entry->cleanup)
{
entry->cleanup(entry->pointer);
}
if (entry->prev)
{
entry->prev->next = entry->next;
}
if (entry->next)
{
entry->next->prev = entry->prev;
}
free(entry);
}
static
LWMsgStatus
default_add_handle(
DefaultSession* session,
const char* type,
LWMsgHandleType locality,
void* pointer,
unsigned long hid,
void (*cleanup)(void*),
DefaultHandle** out_handle
)
{
LWMsgStatus status = LWMSG_STATUS_SUCCESS;
DefaultHandle* handle = NULL;
handle = calloc(1, sizeof(*handle));
if (!handle)
{
BAIL_ON_ERROR(status = LWMSG_STATUS_MEMORY);
}
handle->type = type;
handle->valid = LWMSG_TRUE;
handle->refs = 1;
handle->pointer = pointer ? pointer : handle;
handle->cleanup = cleanup;
handle->hid = hid;
handle->locality = locality;
handle->next = session->handles;
if (session->handles)
{
session->handles->prev = handle;
}
session->handles = handle;
session->num_handles++;
*out_handle = handle;
error:
return status;
}
static
DefaultSession*
default_find_session(
DefaultManager* priv,
const LWMsgSessionID* rsmid
)
{
DefaultSession* entry = NULL;
for (entry = priv->sessions; entry; entry = entry->next)
{
if (!memcmp(rsmid->bytes, entry->rsmid.bytes, sizeof(rsmid->bytes)))
{
return entry;
}
}
return NULL;
}
static
void
default_free_session(
DefaultSession* session
)
{
DefaultHandle* handle, *next;
for (handle = session->handles; handle; handle = next)
{
next = handle->next;
default_free_handle(handle);
}
if (session->destruct && session->data)
{
session->destruct(session->sec_token, session->data);
}
if (session->sec_token)
{
lwmsg_security_token_delete(session->sec_token);
}
free(session);
}
static
void
default_delete(
LWMsgSessionManager* manager
)
{
DefaultManager* priv = DEFAULT_MANAGER(manager);
DefaultSession* entry, *next;
for (entry = priv->sessions; entry; entry = next)
{
next = entry->next;
default_free_session(entry);
}
free(manager);
}
static
LWMsgStatus
default_enter_session(
LWMsgSessionManager* manager,
const LWMsgSessionID* rsmid,
LWMsgSecurityToken* rtoken,
LWMsgSessionConstructFunction construct,
LWMsgSessionDestructFunction destruct,
void* construct_data,
LWMsgSession** out_session
)
{
LWMsgStatus status = LWMSG_STATUS_SUCCESS;
DefaultManager* priv = DEFAULT_MANAGER(manager);
DefaultSession* session = default_find_session(priv, rsmid);
if (session)
{
if (!session->sec_token || !lwmsg_security_token_can_access(session->sec_token, rtoken))
{
session = NULL;
BAIL_ON_ERROR(status = LWMSG_STATUS_SECURITY);
}
session->refs++;
}
else
{
session = calloc(1, sizeof(*session));
if (!session)
{
BAIL_ON_ERROR(status = LWMSG_STATUS_MEMORY);
}
session->base.manager = manager;
memcpy(session->rsmid.bytes, rsmid->bytes, sizeof(rsmid->bytes));
if (rtoken)
{
BAIL_ON_ERROR(status = lwmsg_security_token_copy(rtoken, &session->sec_token));
}
session->refs = 1;
session->destruct = destruct;
if (construct)
{
BAIL_ON_ERROR(status = construct(
session->sec_token,
construct_data,
&session->data));
}
if (priv->sessions)
{
priv->sessions->prev = session;
}
session->next = priv->sessions;
priv->sessions = session;
}
*out_session = LWMSG_SESSION(session);
done:
return status;
error:
if (session)
{
default_free_session(session);
}
goto done;
}
static
LWMsgStatus
default_leave_session(
LWMsgSessionManager* manager,
LWMsgSession* session
)
{
LWMsgStatus status = LWMSG_STATUS_SUCCESS;
DefaultManager* priv = DEFAULT_MANAGER(manager);
DefaultSession* my_session = DEFAULT_SESSION(session);
my_session->refs--;
if (my_session->refs == 0)
{
if (priv->sessions == my_session)
{
priv->sessions = priv->sessions->next;
}
if (my_session->next)
{
my_session->next->prev = my_session->prev;
}
if (my_session->prev)
{
my_session->prev->next = my_session->next;
}
default_free_session(my_session);
}
return status;
}
static
void
default_retain_session(
LWMsgSessionManager* manager,
LWMsgSession* session
)
{
DefaultSession* my_session = DEFAULT_SESSION(session);
my_session->refs++;
}
static
LWMsgSecurityToken*
default_get_session_peer_security_token (
LWMsgSessionManager* manager,
LWMsgSession* session
)
{
DefaultSession* my_session = DEFAULT_SESSION(session);
return my_session->sec_token;
}
static
LWMsgStatus
default_register_handle_remote(
LWMsgSessionManager* manager,
LWMsgSession* session,
const char* type,
LWMsgHandleID hid,
void (*cleanup)(void* ptr),
void** ptr)
{
LWMsgStatus status = LWMSG_STATUS_SUCCESS;
DefaultHandle* handle = NULL;
BAIL_ON_ERROR(status = default_add_handle(
DEFAULT_SESSION(session),
type,
LWMSG_HANDLE_REMOTE,
NULL,
hid,
cleanup,
&handle));
if (ptr)
{
*ptr = handle->pointer;
}
error:
return status;
}
static
LWMsgStatus
default_register_handle_local(
LWMsgSessionManager* manager,
LWMsgSession* session,
const char* type,
void* pointer,
void (*cleanup)(void* ptr),
LWMsgHandleID* hid
)
{
LWMsgStatus status = LWMSG_STATUS_SUCCESS;
DefaultManager* priv = DEFAULT_MANAGER(manager);
DefaultHandle* handle = NULL;
BAIL_ON_ERROR(status = default_add_handle(
DEFAULT_SESSION(session),
type,
LWMSG_HANDLE_LOCAL,
pointer,
priv->next_hid++,
cleanup,
&handle));
if (hid)
{
*hid = handle->hid;
}
error:
return status;
}
static
LWMsgStatus
default_retain_handle(
LWMsgSessionManager* manager,
LWMsgSession* session,
void* ptr
)
{
LWMsgStatus status = LWMSG_STATUS_SUCCESS;
DefaultHandle* handle = NULL;
DefaultSession* my_session = DEFAULT_SESSION(session);
if (!my_session)
{
BAIL_ON_ERROR(status = LWMSG_STATUS_NOT_FOUND);
}
for (handle = my_session->handles; handle; handle = handle->next)
{
if (handle->pointer == ptr)
{
handle->refs++;
goto done;
}
}
BAIL_ON_ERROR(status = LWMSG_STATUS_INVALID_HANDLE);
done:
return status;
error:
goto done;
}
static
LWMsgStatus
default_release_handle(
LWMsgSessionManager* manager,
LWMsgSession* session,
void* ptr
)
{
LWMsgStatus status = LWMSG_STATUS_SUCCESS;
DefaultHandle* handle = NULL;
DefaultSession* my_session = DEFAULT_SESSION(session);
if (!my_session)
{
BAIL_ON_ERROR(status = LWMSG_STATUS_NOT_FOUND);
}
for (handle = my_session->handles; handle; handle = handle->next)
{
if (handle->pointer == ptr)
{
if (--handle->refs == 0)
{
if (handle == my_session->handles)
{
my_session->handles = my_session->handles->next;
}
default_free_handle(handle);
my_session->num_handles--;
}
goto done;
}
}
BAIL_ON_ERROR(status = LWMSG_STATUS_INVALID_HANDLE);
done:
return status;
error:
goto done;
}
static
LWMsgStatus
default_unregister_handle(
LWMsgSessionManager* manager,
LWMsgSession* session,
void* ptr
)
{
LWMsgStatus status = LWMSG_STATUS_SUCCESS;
DefaultHandle* handle = NULL;
DefaultSession* my_session = DEFAULT_SESSION(session);
if (!my_session)
{
BAIL_ON_ERROR(status = LWMSG_STATUS_NOT_FOUND);
}
for (handle = my_session->handles; handle; handle = handle->next)
{
if (handle->pointer == ptr)
{
if (!handle->valid)
{
BAIL_ON_ERROR(status = LWMSG_STATUS_INVALID_HANDLE);
}
handle->valid = LWMSG_FALSE;
if (--handle->refs == 0)
{
if (handle == my_session->handles)
{
my_session->handles = my_session->handles->next;
}
default_free_handle(handle);
my_session->num_handles--;
}
goto done;
}
}
BAIL_ON_ERROR(status = LWMSG_STATUS_INVALID_HANDLE);
done:
return status;
error:
goto done;
}
static
LWMsgStatus
default_handle_pointer_to_id(
LWMsgSessionManager* manager,
LWMsgSession* session,
void* pointer,
const char** type,
LWMsgHandleType* htype,
LWMsgHandleID* hid
)
{
LWMsgStatus status = LWMSG_STATUS_SUCCESS;
DefaultHandle* handle = NULL;
DefaultSession* my_session = DEFAULT_SESSION(session);
if (!my_session)
{
BAIL_ON_ERROR(status = LWMSG_STATUS_NOT_FOUND);
}
for (handle = my_session->handles; handle; handle = handle->next)
{
if (handle->pointer == pointer)
{
if (!handle->valid)
{
BAIL_ON_ERROR(status = LWMSG_STATUS_NOT_FOUND);
}
if (type)
{
*type = handle->type;
}
if (htype)
{
*htype = handle->locality;
}
if (hid)
{
*hid = handle->hid;
}
goto done;
}
}
BAIL_ON_ERROR(status = LWMSG_STATUS_NOT_FOUND);
done:
return status;
error:
goto done;
}
static
LWMsgStatus
default_handle_id_to_pointer(
LWMsgSessionManager* manager,
LWMsgSession* session,
const char* type,
LWMsgHandleType htype,
LWMsgHandleID hid,
void** pointer
)
{
LWMsgStatus status = LWMSG_STATUS_SUCCESS;
DefaultHandle* handle = NULL;
DefaultSession* my_session = DEFAULT_SESSION(session);
for (handle = my_session->handles; handle; handle = handle->next)
{
if (handle->hid == hid && handle->locality == htype)
{
if (!handle->valid)
{
BAIL_ON_ERROR(status = LWMSG_STATUS_NOT_FOUND);
}
if (type && strcmp(type, handle->type))
{
BAIL_ON_ERROR(status = LWMSG_STATUS_NOT_FOUND);
}
*pointer = handle->pointer;
handle->refs++;
goto done;
}
}
BAIL_ON_ERROR(status = LWMSG_STATUS_NOT_FOUND);
done:
return status;
error:
goto done;
}
static
void*
default_get_session_data (
LWMsgSessionManager* manager,
LWMsgSession* session
)
{
return DEFAULT_SESSION(session)->data;
}
static
const LWMsgSessionID*
default_get_session_id(
LWMsgSessionManager* manager,
LWMsgSession* session
)
{
return &DEFAULT_SESSION(session)->rsmid;
}
static
size_t
default_get_session_assoc_count(
LWMsgSessionManager* manager,
LWMsgSession* session
)
{
return DEFAULT_SESSION(session)->refs;
}
static
size_t
default_get_session_handle_count(
LWMsgSessionManager* manager,
LWMsgSession* session
)
{
return DEFAULT_SESSION(session)->num_handles;
}
static LWMsgSessionManagerClass default_class =
{
.delete = default_delete,
.enter_session = default_enter_session,
.leave_session = default_leave_session,
.retain_session = default_retain_session,
.register_handle_local = default_register_handle_local,
.register_handle_remote = default_register_handle_remote,
.retain_handle = default_retain_handle,
.release_handle = default_release_handle,
.unregister_handle = default_unregister_handle,
.handle_pointer_to_id = default_handle_pointer_to_id,
.handle_id_to_pointer = default_handle_id_to_pointer,
.get_session_data = default_get_session_data,
.get_session_id = default_get_session_id,
.get_session_assoc_count = default_get_session_assoc_count,
.get_session_handle_count = default_get_session_handle_count,
.get_session_peer_security_token = default_get_session_peer_security_token
};
LWMsgStatus
lwmsg_default_session_manager_new(
LWMsgSessionManager** manager
)
{
LWMsgStatus status = LWMSG_STATUS_SUCCESS;
DefaultManager* my_manager = NULL;
BAIL_ON_ERROR(status = LWMSG_ALLOC(&my_manager));
BAIL_ON_ERROR(status = lwmsg_session_manager_init(&my_manager->base, &default_class));
*manager = LWMSG_SESSION_MANAGER(my_manager);
done:
return status;
error:
if (my_manager)
{
free(my_manager);
}
goto done;
}