aboutsummaryrefslogtreecommitdiff
path: root/src/windows/identity/kmq/msgtype.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/windows/identity/kmq/msgtype.c')
-rw-r--r--src/windows/identity/kmq/msgtype.c357
1 files changed, 357 insertions, 0 deletions
diff --git a/src/windows/identity/kmq/msgtype.c b/src/windows/identity/kmq/msgtype.c
new file mode 100644
index 0000000..eb44eec
--- /dev/null
+++ b/src/windows/identity/kmq/msgtype.c
@@ -0,0 +1,357 @@
+/*
+ * Copyright (c) 2004 Massachusetts Institute of Technology
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+/* $Id$ */
+
+#include<kmqinternal.h>
+
+CRITICAL_SECTION cs_kmq_types;
+
+kmq_msg_type *msg_types[KMQ_MSG_TYPE_MAX + 1];
+kmq_msg_type *all_msg_types = NULL;
+
+/*! \internal
+ \brief Initializes the message type data structures
+ \note called with cs_mkq_global held */
+void kmqint_init_msg_types(void) {
+ ZeroMemory(msg_types, sizeof(kmq_msg_type *) * (KMQ_MSG_TYPE_MAX + 1));
+ InitializeCriticalSection(&cs_kmq_types);
+}
+
+/*! \internal
+ \brief Frees up the message type data structures
+ \note called with cs_mkq_global held */
+void kmqint_exit_msg_types(void) {
+ int i;
+
+ EnterCriticalSection(&cs_kmq_types);
+ for(i=0;i<KMQ_MSG_TYPE_MAX;i++) {
+ if(msg_types[i])
+ kmqint_free_msg_type(i);
+ }
+ LeaveCriticalSection(&cs_kmq_types);
+ DeleteCriticalSection(&cs_kmq_types);
+}
+
+/*! \internal
+ \brief Notifies that the message has completed
+
+ \return Zero if the completion handling is done. Nonzero if the
+ handling is queued.
+ */
+int kmqint_notify_msg_completion(kmq_message * m) {
+ kmq_msg_type * mt;
+ kmq_msg_completion_handler h;
+
+ /* doing it this way to elude race conditions without
+ obtaining a lock */
+
+ mt = msg_types[m->type];
+ if(mt == NULL)
+ return 0;
+ h = mt->completion_handler;
+
+ /* handler is set to NULL before freeing type */
+ if(h == NULL || msg_types[m->type] == NULL)
+ return 0;
+
+ return kmqint_call_completion_handler(h,m);
+}
+
+/* called with cs_mkq_global && cs_kmq_types held */
+void kmqint_free_msg_type(int t) {
+ /*TODO: free the message type*/
+ /* must set handler to NULL before freeing type */
+ /* must set msg_type[t] = NULL before starting to free type */
+}
+
+/*! \internal
+ \brief Create a message type
+ \note Obtains ::cs_kmq_types
+ */
+void kmqint_msg_type_create(int t) {
+ if(t < 0 || t > KMQ_MSG_TYPE_MAX)
+ return;
+
+ EnterCriticalSection(&cs_kmq_types);
+ if(!msg_types[t]) {
+ kmq_msg_type * mt;
+ mt = malloc(sizeof(kmq_msg_type));
+ ZeroMemory(mt, sizeof(kmq_msg_type));
+ mt->id = t;
+ LINIT(mt);
+ mt->subs = NULL;
+ msg_types[t] = mt;
+
+ LPUSH(&all_msg_types, mt);
+ }
+ LeaveCriticalSection(&cs_kmq_types);
+}
+
+KHMEXP khm_int32 KHMAPI kmq_register_type(wchar_t * name,
+ khm_int32 * new_id)
+{
+ int i;
+ khm_int32 rv = KHM_ERROR_SUCCESS;
+ BOOL registered = FALSE;
+ int first_free = 0;
+ size_t sz;
+
+ if(FAILED(StringCbLength(name, KMQ_MAXCB_TYPE_NAME, &sz)) ||
+ sz == 0)
+ return KHM_ERROR_INVALID_PARM;
+ sz += sizeof(wchar_t);
+
+ EnterCriticalSection(&cs_kmq_types);
+ for(i=KMSGBASE_USER; i <= KMQ_MSG_TYPE_MAX; i++) {
+ if(msg_types[i] == NULL) {
+ if(first_free == 0)
+ first_free = i;
+ } else {
+ if(msg_types[i]->name != NULL &&
+ !wcscmp(msg_types[i]->name, name))
+ registered = TRUE;
+ }
+ }
+
+ if(registered) {
+ rv = KHM_ERROR_EXISTS;
+ } else if(first_free == 0) {
+ rv = KHM_ERROR_NO_RESOURCES;
+ } else {
+ kmqint_msg_type_create(first_free);
+ msg_types[first_free]->name = malloc(sz);
+ StringCbCopy(msg_types[first_free]->name, sz, name);
+
+ if(new_id != NULL)
+ *new_id = first_free;
+ }
+ LeaveCriticalSection(&cs_kmq_types);
+
+ return rv;
+}
+
+KHMEXP khm_int32 KHMAPI kmq_find_type(wchar_t * name, khm_int32 * id)
+{
+ int i;
+
+ EnterCriticalSection(&cs_kmq_types);
+ for(i=KMSGBASE_USER; i <= KMQ_MSG_TYPE_MAX; i++) {
+ if(msg_types[i] != NULL && msg_types[i]->name != NULL) {
+ if(!wcscmp(msg_types[i]->name, name))
+ break;
+ }
+ }
+ LeaveCriticalSection(&cs_kmq_types);
+
+ if(i <= KMQ_MSG_TYPE_MAX) {
+ if(id != NULL)
+ *id = i;
+ return KHM_ERROR_SUCCESS;
+ }
+
+ return KHM_ERROR_NOT_FOUND;
+
+}
+
+KHMEXP khm_int32 KHMAPI kmq_unregister_type(khm_int32 id)
+{
+ khm_int32 rv = KHM_ERROR_SUCCESS;
+
+ if(id < KMSGBASE_USER || id > KMQ_MSG_TYPE_MAX)
+ return KHM_ERROR_INVALID_PARM;
+
+ EnterCriticalSection(&cs_kmq_types);
+ if(msg_types[id] != NULL) {
+ EnterCriticalSection(&cs_kmq_global);
+ kmqint_free_msg_type(id);
+ LeaveCriticalSection(&cs_kmq_global);
+ } else {
+ rv = KHM_ERROR_NOT_FOUND;
+ }
+ LeaveCriticalSection(&cs_kmq_types);
+
+ return rv;
+}
+
+/*! \internal
+ \brief Adds a subscription to a message type
+ \note Obtains ::cs_kmq_types
+ */
+void kmqint_msg_type_add_sub(int t, kmq_msg_subscription *s) {
+ kmq_msg_subscription * ts;
+
+ if(t < 0 || t > KMQ_MSG_TYPE_MAX)
+ return;
+
+ if(!msg_types[t])
+ kmqint_msg_type_create(t);
+
+ EnterCriticalSection(&cs_kmq_types);
+ s->type = t;
+ /* check if we already have this subscription */
+ ts = msg_types[t]->subs;
+ while(ts) {
+ if((ts->rcpt_type == s->rcpt_type) &&
+ (((ts->rcpt_type == KMQ_RCPTTYPE_CB) && (ts->recipient.cb == s->recipient.cb)) ||
+ ((ts->rcpt_type == KMQ_RCPTTYPE_HWND) && (ts->recipient.hwnd == s->recipient.hwnd))))
+ break;
+ ts = LNEXT(ts);
+ }
+ /* add it if we didn't find it */
+ if(!ts) {
+ LPUSH(&msg_types[t]->subs, s);
+ }
+ LeaveCriticalSection(&cs_kmq_types);
+}
+
+/*! \internal
+ \brief Delete a subscription
+ \note Obtains ::cs_kmq_types
+ */
+void kmqint_msg_type_del_sub(kmq_msg_subscription *s) {
+ int t = s->type;
+
+ EnterCriticalSection(&cs_kmq_types);
+ if(msg_types[t]) {
+ LDELETE(&msg_types[t]->subs,s);
+ }
+ LeaveCriticalSection(&cs_kmq_types);
+}
+
+/*! \internal
+ \brief Deletes a window subscription from a message type
+ \note Obtains ::cs_kmq_types
+*/
+kmq_msg_subscription * kmqint_msg_type_del_sub_hwnd(khm_int32 t, HWND hwnd) {
+ kmq_msg_subscription *s;
+
+ if(t < 0 || t > KMQ_MSG_TYPE_MAX)
+ return NULL;
+
+ EnterCriticalSection(&cs_kmq_types);
+ if(msg_types[t]) {
+ s = msg_types[t]->subs;
+ while(s) {
+ kmq_msg_subscription * n = LNEXT(s);
+ if(s->rcpt_type == KMQ_RCPTTYPE_HWND && s->recipient.hwnd == hwnd) {
+ /*TODO: do more here? */
+ LDELETE(&msg_types[t]->subs, s);
+ break;
+ }
+ s = n;
+ }
+ }
+ LeaveCriticalSection(&cs_kmq_types);
+
+ return s;
+}
+
+/*! \internal
+ \brief Delete a callback from a message type
+ \note Obtains ::cs_kmq_types, ::cs_kmq_global
+ */
+kmq_msg_subscription * kmqint_msg_type_del_sub_cb(khm_int32 t, kmq_callback_t cb) {
+ kmq_msg_subscription *s;
+ kmq_queue *q;
+
+ if(t < 0 || t > KMQ_MSG_TYPE_MAX)
+ return NULL;
+
+ if(!msg_types[t])
+ return NULL;
+
+ q = kmqint_get_thread_queue();
+
+ EnterCriticalSection(&cs_kmq_types);
+ s = msg_types[t]->subs;
+ while(s) {
+ kmq_msg_subscription * n = LNEXT(s);
+ if(s->rcpt_type == KMQ_RCPTTYPE_CB && s->recipient.cb == cb && s->queue == q) {
+ /*TODO: do more here? */
+ LDELETE(&msg_types[t]->subs, s);
+ break;
+ }
+ s = n;
+ }
+ LeaveCriticalSection(&cs_kmq_types);
+
+ return s;
+}
+
+/*! \internal
+ \brief Publish a message
+ \note Obtains ::cs_kmq_types, ::cs_kmq_msg_ref, kmq_queue::cs, ::cs_kmq_msg
+ */
+khm_int32 kmqint_msg_publish(kmq_message * m, khm_boolean try_send) {
+ khm_int32 rv = KHM_ERROR_SUCCESS;
+ if(msg_types[m->type]) {
+ kmq_msg_type *t;
+ kmq_msg_subscription * s;
+
+ EnterCriticalSection(&cs_kmq_types);
+ EnterCriticalSection(&cs_kmq_msg);
+ t = msg_types[m->type];
+ s = t->subs;
+ while(s) {
+ kmqint_post(s, m, try_send);
+ s = LNEXT(s);
+ }
+
+ if(m->nCompleted + m->nFailed == m->nSent) {
+ kmqint_put_message(m);
+ }
+
+ LeaveCriticalSection(&cs_kmq_msg);
+ LeaveCriticalSection(&cs_kmq_types);
+
+ } else {
+ EnterCriticalSection(&cs_kmq_msg);
+ kmqint_put_message(m);
+ LeaveCriticalSection(&cs_kmq_msg);
+ }
+ return rv;
+}
+
+/*! \internal
+ \brief Sets the completion handler for a message type
+ \note Obtains ::cs_kmq_types
+ */
+khm_int32 kmqint_msg_type_set_handler(khm_int32 type, kmq_msg_completion_handler handler) {
+
+ if (type == KMSG_SYSTEM)
+ return KHM_ERROR_INVALID_PARM;
+
+ if(!msg_types[type])
+ kmqint_msg_type_create(type);
+
+ if(!msg_types[type])
+ return KHM_ERROR_NO_RESOURCES;
+
+ EnterCriticalSection(&cs_kmq_types);
+ msg_types[type]->completion_handler = handler;
+ LeaveCriticalSection(&cs_kmq_types);
+
+ return KHM_ERROR_SUCCESS;
+}