--- a/src/protocols/sametime/meanwhile/srvc_store.c Fri Jan 20 00:19:53 2006 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,608 +0,0 @@ - -/* - Meanwhile - Unofficial Lotus Sametime Community Client Library - Copyright (C) 2004 Christopher (siege) O'Brien - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License as published by the Free Software Foundation; either - version 2 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 - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with this library; if not, write to the Free - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -#include <glib/glist.h> - -#include "mw_channel.h" -#include "mw_debug.h" -#include "mw_error.h" -#include "mw_message.h" -#include "mw_service.h" -#include "mw_session.h" -#include "mw_srvc_store.h" - - -#define PROTOCOL_TYPE 0x00000025 -#define PROTOCOL_VER 0x00000001 - - -enum storage_action { - action_load = 0x0004, - action_loaded = 0x0005, - action_save = 0x0006, - action_saved = 0x0007, -}; - - -struct mwStorageUnit { - /** key by which data is referenced in service - @see mwStorageKey */ - guint32 key; - - /** Data associated with key in service */ - struct mwOpaque data; -}; - - -struct mwStorageReq { - guint32 id; /**< unique id for this request */ - guint32 result_code; /**< result code for completed request */ - enum storage_action action; /**< load or save */ - struct mwStorageUnit *item; /**< the key/data pair */ - mwStorageCallback cb; /**< callback to notify upon completion */ - gpointer data; /**< user data to pass with callback */ - GDestroyNotify data_free; /**< optionally frees user data */ -}; - - -struct mwServiceStorage { - struct mwService service; - - /** collection of mwStorageReq */ - GList *pending; - - /** current service channel */ - struct mwChannel *channel; - - /** keep track of the counter */ - guint32 id_counter; -}; - - -static void request_get(struct mwGetBuffer *b, struct mwStorageReq *req) { - guint32 id, count, junk; - - if(mwGetBuffer_error(b)) return; - - guint32_get(b, &id); - guint32_get(b, &req->result_code); - - if(req->action == action_loaded) { - guint32_get(b, &count); - - if(count > 0) { - guint32_get(b, &junk); - guint32_get(b, &req->item->key); - - mwOpaque_clear(&req->item->data); - mwOpaque_get(b, &req->item->data); - } - } -} - - -static void request_put(struct mwPutBuffer *b, struct mwStorageReq *req) { - - guint32_put(b, req->id); - guint32_put(b, 1); - - if(req->action == action_save) { - guint32_put(b, 20 + req->item->data.len); /* ugh, offset garbage */ - guint32_put(b, req->item->key); - mwOpaque_put(b, &req->item->data); - - } else { - guint32_put(b, req->item->key); - } -} - - -static int request_send(struct mwChannel *chan, struct mwStorageReq *req) { - struct mwPutBuffer *b; - struct mwOpaque o = { 0, 0 }; - int ret; - - b = mwPutBuffer_new(); - request_put(b, req); - - mwPutBuffer_finalize(&o, b); - ret = mwChannel_send(chan, req->action, &o); - mwOpaque_clear(&o); - - if(! ret) { - if(req->action == action_save) { - req->action = action_saved; - } else if(req->action == action_load) { - req->action = action_loaded; - } - } - - return ret; -} - - -static struct mwStorageReq *request_find(struct mwServiceStorage *srvc, - guint32 id) { - GList *l; - - for(l = srvc->pending; l; l = l->next) { - struct mwStorageReq *r = l->data; - if(r->id == id) return r; - } - - return NULL; -} - - -static const char *action_str(enum storage_action act) { - switch(act) { - case action_load: return "load"; - case action_loaded: return "loaded"; - case action_save: return "save"; - case action_saved: return "saved"; - default: return "UNKNOWN"; - } -} - - -static void request_trigger(struct mwServiceStorage *srvc, - struct mwStorageReq *req) { - - struct mwStorageUnit *item = req->item; - - g_message("storage request %s: key = 0x%x, result = 0x%x, length = %u", - action_str(req->action), - item->key, req->result_code, (guint) item->data.len); - - if(req->cb) - req->cb(srvc, req->result_code, item, req->data); -} - - -static void request_free(struct mwStorageReq *req) { - if(req->data_free) { - req->data_free(req->data); - req->data = NULL; - req->data_free = NULL; - } - - mwStorageUnit_free(req->item); - g_free(req); -} - - -static void request_remove(struct mwServiceStorage *srvc, - struct mwStorageReq *req) { - - srvc->pending = g_list_remove_all(srvc->pending, req); - request_free(req); -} - - -static const char *get_name(struct mwService *srvc) { - return "User Storage"; -} - - -static const char *get_desc(struct mwService *srvc) { - return "Stores user data and settings on the server"; -} - - -static struct mwChannel *make_channel(struct mwServiceStorage *srvc) { - struct mwSession *session; - struct mwChannelSet *cs; - struct mwChannel *chan; - - session = mwService_getSession(MW_SERVICE(srvc)); - cs = mwSession_getChannels(session); - chan = mwChannel_newOutgoing(cs); - - mwChannel_setService(chan, MW_SERVICE(srvc)); - mwChannel_setProtoType(chan, PROTOCOL_TYPE); - mwChannel_setProtoVer(chan, PROTOCOL_VER); - - return mwChannel_create(chan)? NULL: chan; -} - - -static void start(struct mwService *srvc) { - struct mwServiceStorage *srvc_store; - struct mwChannel *chan; - - g_return_if_fail(srvc != NULL); - srvc_store = (struct mwServiceStorage *) srvc; - - chan = make_channel(srvc_store); - if(chan) { - srvc_store->channel = chan; - } else { - mwService_stopped(srvc); - } -} - - -static void stop(struct mwService *srvc) { - - struct mwServiceStorage *srvc_store; - GList *l; - - g_return_if_fail(srvc != NULL); - srvc_store = (struct mwServiceStorage *) srvc; - - if(srvc_store->channel) { - mwChannel_destroy(srvc_store->channel, ERR_SUCCESS, NULL); - srvc_store->channel = NULL; - } - -#if 1 - /* the new way */ - /* remove pending requests. Sometimes we can crash the storage - service, and when that happens, we end up resending the killer - request over and over again, and the service never stays up */ - for(l = srvc_store->pending; l; l = l->next) - request_free(l->data); - - g_list_free(srvc_store->pending); - srvc_store->pending = NULL; - - srvc_store->id_counter = 0; - -#else - /* the old way */ - /* reset all of the started requests to their unstarted states */ - for(l = srvc_store->pending; l; l = l->next) { - struct mwStorageReq *req = l->data; - - if(req->action == action_loaded) { - req->action = action_load; - } else if(req->action == action_saved) { - req->action = action_save; - } - } -#endif - - mwService_stopped(srvc); -} - - -static void recv_channelAccept(struct mwService *srvc, - struct mwChannel *chan, - struct mwMsgChannelAccept *msg) { - - struct mwServiceStorage *srvc_stor; - GList *l; - - g_return_if_fail(srvc != NULL); - srvc_stor = (struct mwServiceStorage *) srvc; - - g_return_if_fail(chan != NULL); - g_return_if_fail(chan == srvc_stor->channel); - - /* send all pending requests */ - for(l = srvc_stor->pending; l; l = l->next) { - struct mwStorageReq *req = l->data; - - if(req->action == action_save || req->action == action_load) { - request_send(chan, req); - } - } - - mwService_started(srvc); -} - - -static void recv_channelDestroy(struct mwService *srvc, - struct mwChannel *chan, - struct mwMsgChannelDestroy *msg) { - - struct mwSession *session; - struct mwServiceStorage *srvc_stor; - - g_return_if_fail(srvc != NULL); - g_return_if_fail(chan != NULL); - - session = mwService_getSession(srvc); - g_return_if_fail(session != NULL); - - srvc_stor = (struct mwServiceStorage *) srvc; - srvc_stor->channel = NULL; - - mwService_stop(srvc); - mwSession_senseService(session, mwService_getType(srvc)); -} - - -static void recv(struct mwService *srvc, struct mwChannel *chan, - guint16 type, struct mwOpaque *data) { - - /* process into results, trigger callbacks */ - - struct mwGetBuffer *b; - struct mwServiceStorage *srvc_stor; - struct mwStorageReq *req; - guint32 id; - - g_return_if_fail(srvc != NULL); - srvc_stor = (struct mwServiceStorage *) srvc; - - g_return_if_fail(chan != NULL); - g_return_if_fail(chan == srvc_stor->channel); - g_return_if_fail(data != NULL); - - b = mwGetBuffer_wrap(data); - - id = guint32_peek(b); - req = request_find(srvc_stor, id); - - if(! req) { - g_warning("couldn't find request 0x%x in storage service", id); - mwGetBuffer_free(b); - return; - } - - g_return_if_fail(req->action == type); - request_get(b, req); - - if(mwGetBuffer_error(b)) { - mw_mailme_opaque(data, "storage request 0x%x, type: 0x%x", id, type); - - } else { - request_trigger(srvc_stor, req); - } - - mwGetBuffer_free(b); - request_remove(srvc_stor, req); -} - - -static void clear(struct mwService *srvc) { - struct mwServiceStorage *srvc_stor; - GList *l; - - srvc_stor = (struct mwServiceStorage *) srvc; - - for(l = srvc_stor->pending; l; l = l->next) - request_free(l->data); - - g_list_free(srvc_stor->pending); - srvc_stor->pending = NULL; - - srvc_stor->id_counter = 0; -} - - -struct mwServiceStorage *mwServiceStorage_new(struct mwSession *session) { - struct mwServiceStorage *srvc_store; - struct mwService *srvc; - - srvc_store = g_new0(struct mwServiceStorage, 1); - srvc = MW_SERVICE(srvc_store); - - mwService_init(srvc, session, mwService_STORAGE); - srvc->get_name = get_name; - srvc->get_desc = get_desc; - srvc->recv_accept = recv_channelAccept; - srvc->recv_destroy = recv_channelDestroy; - srvc->recv = recv; - srvc->start = start; - srvc->stop = stop; - srvc->clear = clear; - - return srvc_store; -} - - -struct mwStorageUnit *mwStorageUnit_new(guint32 key) { - struct mwStorageUnit *u; - - u = g_new0(struct mwStorageUnit, 1); - u->key = key; - - return u; -} - - -struct mwStorageUnit *mwStorageUnit_newOpaque(guint32 key, - struct mwOpaque *data) { - struct mwStorageUnit *u; - - u = g_new0(struct mwStorageUnit, 1); - u->key = key; - - if(data) - mwOpaque_clone(&u->data, data); - - return u; -} - - -struct mwStorageUnit *mwStorageUnit_newBoolean(guint32 key, - gboolean val) { - - return mwStorageUnit_newInteger(key, (guint32) val); -} - - -struct mwStorageUnit *mwStorageUnit_newInteger(guint32 key, - guint32 val) { - struct mwStorageUnit *u; - struct mwPutBuffer *b; - - u = g_new0(struct mwStorageUnit, 1); - u->key = key; - - b = mwPutBuffer_new(); - guint32_put(b, val); - mwPutBuffer_finalize(&u->data, b); - - return u; -} - - -struct mwStorageUnit *mwStorageUnit_newString(guint32 key, - const char *str) { - struct mwStorageUnit *u; - struct mwPutBuffer *b; - - u = g_new0(struct mwStorageUnit, 1); - u->key = key; - - b = mwPutBuffer_new(); - mwString_put(b, str); - mwPutBuffer_finalize(&u->data, b); - - return u; -} - - -guint32 mwStorageUnit_getKey(struct mwStorageUnit *item) { - g_return_val_if_fail(item != NULL, 0x00); /* feh, unsafe */ - return item->key; -} - - -gboolean mwStorageUnit_asBoolean(struct mwStorageUnit *item, - gboolean val) { - - return !! mwStorageUnit_asInteger(item, (guint32) val); -} - - -guint32 mwStorageUnit_asInteger(struct mwStorageUnit *item, - guint32 val) { - struct mwGetBuffer *b; - guint32 v; - - g_return_val_if_fail(item != NULL, val); - - b = mwGetBuffer_wrap(&item->data); - - guint32_get(b, &v); - if(! mwGetBuffer_error(b)) val = v; - mwGetBuffer_free(b); - - return val; -} - - -char *mwStorageUnit_asString(struct mwStorageUnit *item) { - struct mwGetBuffer *b; - char *c = NULL; - - g_return_val_if_fail(item != NULL, NULL); - - b = mwGetBuffer_wrap(&item->data); - - mwString_get(b, &c); - - if(mwGetBuffer_error(b)) - g_debug("error obtaining string value from opaque"); - - mwGetBuffer_free(b); - - return c; -} - - -struct mwOpaque *mwStorageUnit_asOpaque(struct mwStorageUnit *item) { - g_return_val_if_fail(item != NULL, NULL); - return &item->data; -} - - -void mwStorageUnit_free(struct mwStorageUnit *item) { - if(! item) return; - - mwOpaque_clear(&item->data); - g_free(item); -} - - -static struct mwStorageReq *request_new(struct mwServiceStorage *srvc, - struct mwStorageUnit *item, - mwStorageCallback cb, - gpointer data, GDestroyNotify df) { - - struct mwStorageReq *req = g_new0(struct mwStorageReq, 1); - - req->id = ++srvc->id_counter; - req->item = item; - req->cb = cb; - req->data = data; - req->data_free = df; - - return req; -} - - -void mwServiceStorage_load(struct mwServiceStorage *srvc, - struct mwStorageUnit *item, - mwStorageCallback cb, - gpointer data, GDestroyNotify d_free) { - - /* - construct a request - - put request at end of pending - - if channel is open and connected - - compose the load message - - send message - - set request to sent - - else - - start service - */ - - struct mwStorageReq *req; - - req = request_new(srvc, item, cb, data, d_free); - req->action = action_load; - - srvc->pending = g_list_append(srvc->pending, req); - - if(MW_SERVICE_IS_STARTED(MW_SERVICE(srvc))) - request_send(srvc->channel, req); -} - - -void mwServiceStorage_save(struct mwServiceStorage *srvc, - struct mwStorageUnit *item, - mwStorageCallback cb, - gpointer data, GDestroyNotify d_free) { - - /* - construct a request - - put request at end of pending - - if channel is open and connected - - compose the save message - - send message - - set request to sent - - else - - start service - */ - - struct mwStorageReq *req; - - req = request_new(srvc, item, cb, data, d_free); - req->action = action_save; - - srvc->pending = g_list_append(srvc->pending, req); - - if(MW_SERVICE_IS_STARTED(MW_SERVICE(srvc))) - request_send(srvc->channel, req); -} -