From 4100eec3ab57f256c915866b71df1dfa40ddc593 Mon Sep 17 00:00:00 2001 From: Sam Thursfield Date: Wed, 6 Jul 2011 02:01:40 +0100 Subject: [PATCH] client library: Use local exception handling; correct API --- libmoonshot/libmoonshot-msrpc.c | 273 ++++++++++++++++++++++++---------------- libmoonshot/moonshot-msrpc.idl | 6 +- src/moonshot-server.vala | 11 +- tests/basic.c | 5 +- 4 files changed, 183 insertions(+), 112 deletions(-) diff --git a/libmoonshot/libmoonshot-msrpc.c b/libmoonshot/libmoonshot-msrpc.c index 73185d4..df29b2f 100644 --- a/libmoonshot/libmoonshot-msrpc.c +++ b/libmoonshot/libmoonshot-msrpc.c @@ -40,10 +40,24 @@ #include "libmoonshot-common.h" #include "moonshot-msrpc.h" +#include + #define MOONSHOT_ENDPOINT_NAME "/org/janet/Moonshot" #define MOONSHOT_INSTALL_PATH_KEY "Software\\Moonshot" +static MoonshotError *moonshot_error_new_from_status (MoonshotErrorCode code, + DWORD status) +{ + MoonshotError *error = malloc (sizeof (MoonshotError)); + error->code = code; + error->message = malloc (256); + + FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM, NULL, status, 0, (LPSTR)error->message, 255, NULL); + + return error; +} + static void launch_server (MoonshotError **error) { HKEY key = NULL; STARTUPINFO startup_info = { 0 }; @@ -102,51 +116,79 @@ static void launch_server (MoonshotError **error) { } } -/*static void dbus_call_complete_cb (DBusGProxy *proxy, - DBusGProxyCall *call_id, - void *user_data) +static void bind_rpc (MoonshotError **error) { - GError *error = NULL; - GSimpleAsyncResult *token; - MoonshotIdentityData *identity_data; - gboolean success; - - token = G_SIMPLE_ASYNC_RESULT (user_data); - identity_data = moonshot_identity_data_new (); - - dbus_g_proxy_end_call (moonshot_dbus_proxy, - call_id, - &error, - G_TYPE_STRING, &identity_data->nai, - G_TYPE_STRING, &identity_data->password, - G_TYPE_STRING, &identity_data->server_certificate_hash, - G_TYPE_STRING, &identity_data->ca_certificate, - G_TYPE_STRING, &identity_data->subject_name_constraint, - G_TYPE_STRING, &identity_data->subject_alt_name_constraint, - G_TYPE_BOOLEAN, &success, - G_TYPE_INVALID); - - if (error != NULL) { - g_simple_async_result_set_from_error (token, error); - } - else - if (success == FALSE) { - error = g_error_new (MOONSHOT_ERROR, - MOONSHOT_ERROR_NO_IDENTITY_SELECTED, - "No matching identity was available"); - g_simple_async_result_set_from_error (token, error); - g_error_free (error); + DWORD status; + int i; + + status = rpc_client_bind (&moonshot_binding_handle, + MOONSHOT_ENDPOINT_NAME, + RPC_PER_USER); + + if (status != RPC_S_OK) { + *error = moonshot_error_new_from_status (MOONSHOT_ERROR_IPC_ERROR, + status); + return; } - else { - g_simple_async_result_set_op_res_gpointer (token, - identity_data, - moonshot_identity_data_free); + + status = RpcMgmtIsServerListening (moonshot_binding_handle); + + if (status == RPC_S_NOT_LISTENING) { + //launch_server (error); + + /* Allow 5 seconds for the server to launch before we time out */ + //for (i=0; i<50; i++) { + // Sleep (100); /* ms */ +/* + status = RpcMgmtIsServerListening (moonshot_binding_handle); + + if (status == RPC_S_OK) + return; + + if (status != RPC_S_NOT_LISTENING) + break; + }*/ } - g_simple_async_result_complete (token); - g_object_unref (token); + if (status != RPC_S_OK) + *error = moonshot_error_new_from_status (MOONSHOT_ERROR_IPC_ERROR, + status); +} + +static void init_rpc (MoonshotError **error) +{ + static volatile LONG binding_init_flag = 2; + int status; + + /* Hack to avoid requiring a moonshot_init() function. Windows does not + * provide any synchronisation primitives that can be statically init'ed, + * but we can use its atomic variable access functions to achieve the same. + * See: http://msdn.microsoft.com/en-us/library/ms684122%28v=vs.85%29.aspx + */ + + if (binding_init_flag == 0) + return; + + if (InterlockedCompareExchange (&binding_init_flag, 1, 2) == 2) { + bind_rpc (error); + + /* We'll handle all exceptions locally to avoid interfering with any + * other RPC/other exception handling that goes on in the process, + * and so we can store the problem in a MooshotError instead of + * aborting. + */ + rpc_set_global_exception_handler_enable (FALSE); + + if (InterlockedCompareExchange (&binding_init_flag, 0, 1) != 1) { + /* This should never happen */ + fprintf (stderr, "moonshot: Internal synchronisation error"); + } + } else { + while (binding_init_flag != 0) + Sleep (100); /* ms */ + } } -*/ + int moonshot_get_identity (const char *nai, const char *password, @@ -159,78 +201,55 @@ int moonshot_get_identity (const char *nai, char **subject_alt_name_constraint_out, MoonshotError **error) { - int status; - - status = rpc_client_bind (&moonshot_binding_handle, - MOONSHOT_ENDPOINT_NAME, - RPC_PER_USER); - - printf ("RPC status: %i\n", status); + int success; + RpcAsyncCall call; - /*DBusGProxyCall *call_id; - GSimpleAsyncResult *result; - GError *error = NULL; + init_rpc (error); - if (moonshot_dbus_proxy == NULL) - moonshot_dbus_proxy = dbus_connect (&error); + if (*error != NULL) + return FALSE; - if (moonshot_dbus_proxy == NULL) { - result = g_simple_async_result_new (NULL, - callback, - user_data, - moonshot_get_identity); - g_simple_async_result_set_from_error (result, error); - g_simple_async_result_complete_in_idle (result); - g_error_free (error); - return; + rpc_async_call_init (&call); + + nai_out = NULL; + password_out = NULL; + server_certificate_hash_out = NULL; + ca_certificate_out = NULL; + subject_name_constraint_out = NULL; + subject_alt_name_constraint_out = NULL; + + RPC_TRY_EXCEPT { + moonshot_get_identity_rpc (&call, + nai, + password, + service, + nai_out, + password_out, + server_certificate_hash_out, + ca_certificate_out, + subject_name_constraint_out, + subject_alt_name_constraint_out); + + success = rpc_async_call_complete_int (&call); } + RPC_EXCEPT { + *error = moonshot_error_new_from_status (MOONSHOT_ERROR_IPC_ERROR, + RPC_GET_EXCEPTION_CODE ()); + } + RPC_END_EXCEPT - g_return_if_fail (DBUS_IS_G_PROXY (moonshot_dbus_proxy)); - - result = g_simple_async_result_new (NULL, - callback, - user_data, - moonshot_get_identity); - - call_id = dbus_g_proxy_begin_call (moonshot_dbus_proxy, - "GetIdentity", - dbus_call_complete_cb, - result, NULL, - G_TYPE_STRING, nai, - G_TYPE_STRING, password, - G_TYPE_STRING, service);*/ -} - -/*gboolean moonshot_get_identity_finish (GAsyncResult *result, - char **nai, - char **password, - char **server_certificate_hash, - char **ca_certificate, - char **subject_name_constraint, - char **subject_alt_name_constraint, - GError **error) -{ - MoonshotIdentityData *identity; - - g_return_val_if_fail (g_simple_async_result_is_valid (result, - NULL, - moonshot_get_identity), - FALSE); - - if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result), error)) + if (*error != NULL) return FALSE; - identity = g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (result)); - - *nai = identity->nai; - *password = identity->password; - *server_certificate_hash = identity->server_certificate_hash; - *ca_certificate = identity->ca_certificate; - *subject_name_constraint = identity->subject_name_constraint; - *subject_alt_name_constraint = identity->subject_alt_name_constraint; + if (success == FALSE) { + *error = moonshot_error_new (MOONSHOT_ERROR_NO_IDENTITY_SELECTED, + "No identity was returned by the Moonshot " + "user interface."); + return FALSE; + } return TRUE; -}*/ +} int moonshot_get_default_identity (char **nai_out, @@ -241,11 +260,49 @@ int moonshot_get_default_identity (char **nai_out, char **subject_alt_name_constraint_out, MoonshotError **error) { - int status; + int success; + RpcAsyncCall call; - status = rpc_client_bind (&moonshot_binding_handle, - MOONSHOT_ENDPOINT_NAME, - RPC_PER_USER); + init_rpc (error); + + if (*error != NULL) + return FALSE; + + rpc_async_call_init (&call); + + nai_out = NULL; + password_out = NULL; + server_certificate_hash_out = NULL; + ca_certificate_out = NULL; + subject_name_constraint_out = NULL; + subject_alt_name_constraint_out = NULL; + + RPC_TRY_EXCEPT { + moonshot_get_default_identity_rpc (&call, + nai_out, + password_out, + server_certificate_hash_out, + ca_certificate_out, + subject_name_constraint_out, + subject_alt_name_constraint_out); + + success = rpc_async_call_complete_int (&call); + } + RPC_EXCEPT { + *error = moonshot_error_new_from_status (MOONSHOT_ERROR_IPC_ERROR, + RPC_GET_EXCEPTION_CODE ()); + } + RPC_END_EXCEPT + + if (*error != NULL) + return FALSE; + + if (success == FALSE) { + *error = moonshot_error_new (MOONSHOT_ERROR_NO_IDENTITY_SELECTED, + "No identity was returned by the Moonshot " + "user interface."); + return FALSE; + } - printf ("RPC status: %i\n", status); + return TRUE; }; diff --git a/libmoonshot/moonshot-msrpc.idl b/libmoonshot/moonshot-msrpc.idl index 8055713..e02ff2c 100644 --- a/libmoonshot/moonshot-msrpc.idl +++ b/libmoonshot/moonshot-msrpc.idl @@ -15,6 +15,10 @@ interface moonshot [out, string] char **subject_alt_name_constraint); int moonshot_get_default_identity_rpc ([out, string] char **nai_out, - [out, string] char **password_out); + [out, string] char **password_out, + [out, string] char **server_certificate_hash, + [out, string] char **ca_certificate, + [out, string] char **subject_name_constraint, + [out, string] char **subject_alt_name_constraint); } diff --git a/src/moonshot-server.vala b/src/moonshot-server.vala index 145d6bf..02d9edf 100644 --- a/src/moonshot-server.vala +++ b/src/moonshot-server.vala @@ -185,7 +185,11 @@ public class MoonshotServer : Object { [CCode (cname = "moonshot_get_default_identity_rpc")] public static void get_default_identity (Rpc.AsyncCall call, ref string nai_out, - ref string password_out) + ref string password_out, + ref string server_certificate_hash, + ref string ca_certificate, + ref string subject_name_constraint, + ref string subject_alt_name_constraint) { bool result; @@ -202,11 +206,16 @@ public class MoonshotServer : Object { nai_out = ""; password_out = ""; + server_certificate_hash = ""; + ca_certificate = ""; + subject_name_constraint = ""; + subject_alt_name_constraint = ""; if (request.id_card != null) { nai_out = request.id_card.nai; password_out = request.id_card.password; + server_certificate_hash = "certificate"; return_if_fail (nai_out != null); return_if_fail (password_out != null); diff --git a/tests/basic.c b/tests/basic.c index 0d1e127..25a4945 100644 --- a/tests/basic.c +++ b/tests/basic.c @@ -27,7 +27,8 @@ gpointer test_func (gpointer data) &subject_alt_name_constraint, error); - g_print ("Got id: %s %s\n", nai, password); + if (success) + g_print ("Got id: %s %s\n", nai, password); return GINT_TO_POINTER (success); } @@ -91,7 +92,7 @@ int main (int argc, char *argv[]) g_test_init (&argc, &argv, NULL); g_test_add_func ("/basic/connect", test_connect); - g_test_add_func ("/basic/multithread", test_multithread); + //g_test_add_func ("/basic/multithread", test_multithread); g_test_run (); } -- 2.1.4