#include "ccs_common.h"
#include "ccs_os_server.h"
cci_uuid_string_t g_server_id = NULL;
ccs_cache_collection_t g_cache_collection = NULL;
ccs_client_array_t g_client_array = NULL;
static void handle_close_sessions(void);
int main (int argc, const char *argv[])
{
cc_int32 err = 0;
if (!err) {
err = ccs_os_server_initialize (argc, argv);
}
if (!err) {
err = cci_identifier_new_uuid (&g_server_id);
}
if (!err) {
err = ccs_cache_collection_new (&g_cache_collection);
}
if (!err) {
err = ccs_client_array_new (&g_client_array);
}
handle_close_sessions();
if (!err) {
err = ccs_os_server_listen_loop (argc, argv);
}
if (!err) {
free (g_server_id);
cci_check_error (ccs_cache_collection_release (g_cache_collection));
cci_check_error (ccs_client_array_release (g_client_array));
err = ccs_os_server_cleanup (argc, argv);
}
return cci_check_error (err) ? 1 : 0;
}
#ifdef TARGET_OS_MAC
#pragma mark -
#endif
cc_int32 ccs_server_new_identifier (cci_identifier_t *out_identifier)
{
return cci_check_error (cci_identifier_new (out_identifier,
g_server_id));
}
#ifdef TARGET_OS_MAC
#pragma mark -
#endif
cc_int32 ccs_server_add_client (ccs_pipe_t in_connection_pipe)
{
cc_int32 err = ccNoError;
ccs_client_t client = NULL;
if (!err) {
err = ccs_client_new (&client, in_connection_pipe);
}
if (!err) {
cci_debug_printf ("%s: Adding client %p.", __FUNCTION__, client);
err = ccs_client_array_insert (g_client_array,
client,
ccs_client_array_count (g_client_array));
}
return cci_check_error (err);
}
cc_int32 ccs_server_remove_client (ccs_pipe_t in_connection_pipe)
{
cc_int32 err = ccNoError;
if (!err) {
cc_uint64 i;
cc_uint64 count = ccs_client_array_count (g_client_array);
cc_uint32 found = 0;
for (i = 0; !err && i < count; i++) {
ccs_client_t client = ccs_client_array_object_at_index (g_client_array, i);
err = ccs_client_uses_pipe (client, in_connection_pipe, &found);
if (!err && found) {
cci_debug_printf ("%s: Removing client %p.", __FUNCTION__, client);
err = ccs_client_array_remove (g_client_array, i);
break;
}
}
if (!err && !found) {
cci_debug_printf ("WARNING %s() didn't find client in client list.",
__FUNCTION__);
}
}
return cci_check_error (err);
}
cc_int32 ccs_server_client_for_pipe (ccs_pipe_t in_client_pipe,
ccs_client_t *out_client)
{
cc_int32 err = ccNoError;
ccs_client_t client_for_pipe = NULL;
if (!ccs_pipe_valid (in_client_pipe)) { err = cci_check_error (ccErrBadParam); }
if (!out_client ) { err = cci_check_error (ccErrBadParam); }
if (!err) {
cc_uint64 i;
cc_uint64 count = ccs_client_array_count (g_client_array);
for (i = 0; !err && i < count; i++) {
ccs_client_t client = ccs_client_array_object_at_index (g_client_array, i);
cc_uint32 uses_pipe = 0;
err = ccs_client_uses_pipe (client, in_client_pipe, &uses_pipe);
if (!err && uses_pipe) {
client_for_pipe = client;
break;
}
}
}
if (!err) {
*out_client = client_for_pipe;
}
return cci_check_error (err);
}
cc_int32 ccs_server_client_is_valid (ccs_pipe_t in_client_pipe,
cc_uint32 *out_client_is_valid)
{
cc_int32 err = ccNoError;
ccs_client_t client = NULL;
if (!ccs_pipe_valid (in_client_pipe)) { err = cci_check_error (ccErrBadParam); }
if (!out_client_is_valid ) { err = cci_check_error (ccErrBadParam); }
if (!err) {
err = ccs_server_client_for_pipe (in_client_pipe, &client);
}
if (!err) {
*out_client_is_valid = (client != NULL);
}
return cci_check_error (err);
}
#ifdef TARGET_OS_MAC
#pragma mark -
#endif
static cc_int32 ccs_server_request_demux (ccs_pipe_t in_client_pipe,
ccs_pipe_t in_reply_pipe,
ccs_cache_collection_t in_cache_collection,
enum cci_msg_id_t in_request_name,
au_asid_t in_sessionid,
cci_identifier_t in_request_identifier,
k5_ipc_stream in_request_data,
cc_uint32 *out_will_block,
k5_ipc_stream *out_reply_data)
{
cc_int32 err = ccNoError;
if (!ccs_pipe_valid (in_reply_pipe)) { err = cci_check_error (ccErrBadParam); }
if (!in_request_data ) { err = cci_check_error (ccErrBadParam); }
if (!out_will_block ) { err = cci_check_error (ccErrBadParam); }
if (!out_reply_data ) { err = cci_check_error (ccErrBadParam); }
if (!err) {
if (in_request_name > cci_context_first_msg_id &&
in_request_name < cci_context_last_msg_id) {
if (!err) {
err = ccs_cache_collection_handle_message (in_client_pipe,
in_reply_pipe,
in_cache_collection,
in_request_name,
in_sessionid,
in_request_data,
out_will_block,
out_reply_data);
}
} else if (in_request_name > cci_ccache_first_msg_id &&
in_request_name < cci_ccache_last_msg_id) {
ccs_ccache_t ccache = NULL;
err = ccs_cache_collection_find_ccache (in_cache_collection,
in_request_identifier,
&ccache);
if (!err) {
err = ccs_ccache_handle_message (in_client_pipe,
in_reply_pipe,
ccache,
in_cache_collection,
in_request_name,
in_request_data,
out_will_block,
out_reply_data);
}
} else if (in_request_name > cci_ccache_iterator_first_msg_id &&
in_request_name < cci_ccache_iterator_last_msg_id) {
ccs_ccache_iterator_t ccache_iterator = NULL;
err = ccs_cache_collection_find_ccache_iterator (in_cache_collection,
in_request_identifier,
&ccache_iterator);
if (!err) {
err = ccs_ccache_iterator_handle_message (ccache_iterator,
in_cache_collection,
in_request_name,
in_request_data,
out_reply_data);
}
if (!err) {
*out_will_block = 0;
}
} else if (in_request_name > cci_credentials_iterator_first_msg_id &&
in_request_name < cci_credentials_iterator_last_msg_id) {
ccs_credentials_iterator_t credentials_iterator = NULL;
ccs_ccache_t ccache = NULL;
err = ccs_cache_collection_find_credentials_iterator (in_cache_collection,
in_request_identifier,
&ccache,
&credentials_iterator);
if (!err) {
err = ccs_credentials_iterator_handle_message (credentials_iterator,
ccache,
in_request_name,
in_request_data,
out_reply_data);
}
if (!err) {
*out_will_block = 0;
}
} else {
err = ccErrBadInternalMessage;
}
}
return cci_check_error (err);
}
#ifdef TARGET_OS_MAC
#pragma mark -
#endif
cc_int32 ccs_server_handle_request (ccs_pipe_t in_client_pipe,
au_asid_t in_sessionid,
ccs_pipe_t in_reply_pipe,
k5_ipc_stream in_request)
{
cc_int32 err = ccNoError;
enum cci_msg_id_t request_name = 0;
cci_identifier_t request_identifier = NULL;
cc_uint32 will_block = 0;
k5_ipc_stream reply_data = NULL;
ccs_server_ref();
if (!ccs_pipe_valid (in_client_pipe)) { err = cci_check_error (ccErrBadParam); }
if (!ccs_pipe_valid (in_reply_pipe) ) { err = cci_check_error (ccErrBadParam); }
if (!in_request ) { err = cci_check_error (ccErrBadParam); }
if (!err) {
err = cci_message_read_request_header (in_request,
&request_name,
&request_identifier);
}
if (!err) {
cc_uint32 server_err = 0;
cc_uint32 valid = 0;
ccs_cache_collection_t cache_collection = g_cache_collection;
server_err = cci_identifier_is_for_server (request_identifier,
g_server_id,
&valid);
if (!server_err && !valid) {
server_err = cci_message_invalid_object_err (request_name);
}
if (!server_err) {
server_err = ccs_server_request_demux (in_client_pipe,
in_reply_pipe,
cache_collection,
request_name,
in_sessionid,
request_identifier,
in_request,
&will_block,
&reply_data);
}
if (server_err || !will_block) {
err = ccs_server_send_reply (in_reply_pipe, server_err, reply_data);
ccs_server_unref();
}
}
cci_identifier_release (request_identifier);
k5_ipc_stream_release (reply_data);
return cci_check_error (err);
}
cc_int32 ccs_server_send_reply (ccs_pipe_t in_reply_pipe,
cc_int32 in_reply_err,
k5_ipc_stream in_reply_data)
{
cc_int32 err = ccNoError;
k5_ipc_stream reply = NULL;
if (!ccs_pipe_valid (in_reply_pipe) ) { err = cci_check_error (ccErrBadParam); }
if (!err) {
err = cci_message_new_reply_header (&reply, in_reply_err);
}
if (!err && in_reply_data && k5_ipc_stream_size (in_reply_data) > 0) {
err = k5_ipc_stream_write (reply,
k5_ipc_stream_data (in_reply_data),
k5_ipc_stream_size (in_reply_data));
}
if (!err) {
err = ccs_os_server_send_reply (in_reply_pipe, reply);
}
k5_ipc_stream_release (reply);
return cci_check_error (err);
}
cc_int32
ccs_server_valid(int *valid)
{
cc_int32 err = ccNoError;
err = ccs_cache_collection_valid(g_cache_collection, valid);
return cci_check_error (err);
}
static unsigned long refcount = 0;
void
ccs_server_ref(void)
{
refcount++;
if (refcount == 0)
abort();
}
void
ccs_server_unref(void)
{
if (refcount == 0)
abort();
refcount--;
}
unsigned long
ccs_server_isrefed(void)
{
return refcount;
}
#include <dispatch/dispatch.h>
#include <sys/event.h>
#include <syslog.h>
static int ked = -1;
void
ccs_session_add(au_asid_t session_id)
{
struct kevent ke;
int ret;
syslog(LOG_DEBUG, "monitor session: %d\n", session_id);
if (ked == -1)
return;
EV_SET(&ke, session_id, EVFILT_SESSION, EV_ADD,
NOTE_AS_END, 0, NULL);
ret = kevent(ked, &ke, 1, NULL, 0, NULL);
if (ret)
syslog(LOG_DEBUG, "kevent failed for session: %d %d\n",
ret, session_id);
}
static void
handle_close_sessions(void)
{
ked = kqueue();
if (ked == -1) {
syslog(LOG_DEBUG, "session monitoring failed: %d", errno);
return;
}
dispatch_source_read_create(ked, NULL, dispatch_get_main_queue(),
^(dispatch_event_t event)
{
au_asid_t session_id;
struct kevent ke;
int ret;
ret = kevent(ked, NULL, 0, &ke, 1, NULL);
syslog(LOG_DEBUG, "got event: %d", ret);
if (ret != 1)
return;
if ((ke.fflags & NOTE_AS_END) == 0) {
syslog(LOG_DEBUG, "not a close, bug ?");
return;
}
session_id = ke.ident;
syslog(LOG_DEBUG, "a close of session: %d", (int)session_id);
EV_SET(&ke, session_id, EVFILT_SESSION, EV_DELETE,
NOTE_AS_END, 0, NULL);
(void)kevent(ked, &ke, 1, NULL, 0, NULL);
dispatch_async(dispatch_get_main_queue(),
^{ ccs_cache_collection_kill_session(g_cache_collection,
session_id); });
});
}