1 
2 /*
3   Meanwhile - Unofficial Lotus Sametime Community Client Library
4   Copyright (C) 2004  Christopher (siege) O'Brien
5 
6   This library is free software; you can redistribute it and/or
7   modify it under the terms of the GNU Library General Public
8   License as published by the Free Software Foundation; either
9   version 2 of the License, or (at your option) any later version.
10 
11   This library is distributed in the hope that it will be useful,
12   but WITHOUT ANY WARRANTY; without even the implied warranty of
13   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14   Library General Public License for more details.
15 
16   You should have received a copy of the GNU Library General Public
17   License along with this library; if not, write to the Free
18   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19 */
20 
21 #include <glib.h>
22 
23 #include "mw_channel.h"
24 #include "mw_debug.h"
25 #include "mw_error.h"
26 #include "mw_message.h"
27 #include "mw_service.h"
28 #include "mw_session.h"
29 #include "mw_srvc_store.h"
30 
31 
32 #define PROTOCOL_TYPE  0x00000025
33 #define PROTOCOL_VER   0x00000001
34 
35 
36 enum storage_action {
37   action_load    = 0x0004,
38   action_loaded  = 0x0005,
39   action_save    = 0x0006,
40   action_saved   = 0x0007,
41 };
42 
43 
44 struct mwStorageUnit {
45   /** key by which data is referenced in service
46       @see mwStorageKey */
47   guint32 key;
48 
49   /** Data associated with key in service */
50   struct mwOpaque data;
51 };
52 
53 
54 struct mwStorageReq {
55   guint32 id;                  /**< unique id for this request */
56   guint32 result_code;         /**< result code for completed request */
57   enum storage_action action;  /**< load or save */
58   struct mwStorageUnit *item;  /**< the key/data pair */
59   mwStorageCallback cb;        /**< callback to notify upon completion */
60   gpointer data;               /**< user data to pass with callback */
61   GDestroyNotify data_free;    /**< optionally frees user data */
62 };
63 
64 
65 struct mwServiceStorage {
66   struct mwService service;
67 
68   /** collection of mwStorageReq */
69   GList *pending;
70 
71   /** current service channel */
72   struct mwChannel *channel;
73 
74   /** keep track of the counter */
75   guint32 id_counter;
76 };
77 
78 
request_get(struct mwGetBuffer * b,struct mwStorageReq * req)79 static void request_get(struct mwGetBuffer *b, struct mwStorageReq *req) {
80   guint32 id, count, junk;
81 
82   if(mwGetBuffer_error(b)) return;
83 
84   guint32_get(b, &id);
85   guint32_get(b, &req->result_code);
86 
87   if(req->action == action_loaded) {
88     guint32_get(b, &count);
89 
90     if(count > 0) {
91       guint32_get(b, &junk);
92       guint32_get(b, &req->item->key);
93 
94       mwOpaque_clear(&req->item->data);
95       mwOpaque_get(b, &req->item->data);
96     }
97   }
98 }
99 
100 
request_put(struct mwPutBuffer * b,struct mwStorageReq * req)101 static void request_put(struct mwPutBuffer *b, struct mwStorageReq *req) {
102 
103   guint32_put(b, req->id);
104   guint32_put(b, 1);
105 
106   if(req->action == action_save) {
107     guint32_put(b, 20 + req->item->data.len); /* ugh, offset garbage */
108     guint32_put(b, req->item->key);
109     mwOpaque_put(b, &req->item->data);
110 
111   } else {
112     guint32_put(b, req->item->key);
113   }
114 }
115 
116 
request_send(struct mwChannel * chan,struct mwStorageReq * req)117 static int request_send(struct mwChannel *chan, struct mwStorageReq *req) {
118   struct mwPutBuffer *b;
119   struct mwOpaque o = { 0, 0 };
120   int ret;
121 
122   b = mwPutBuffer_new();
123   request_put(b, req);
124 
125   mwPutBuffer_finalize(&o, b);
126   ret = mwChannel_send(chan, req->action, &o);
127   mwOpaque_clear(&o);
128 
129   if(! ret) {
130     if(req->action == action_save) {
131       req->action = action_saved;
132     } else if(req->action == action_load) {
133       req->action = action_loaded;
134     }
135   }
136 
137   return ret;
138 }
139 
140 
request_find(struct mwServiceStorage * srvc,guint32 id)141 static struct mwStorageReq *request_find(struct mwServiceStorage *srvc,
142 					 guint32 id) {
143   GList *l;
144 
145   for(l = srvc->pending; l; l = l->next) {
146     struct mwStorageReq *r = l->data;
147     if(r->id == id) return r;
148   }
149 
150   return NULL;
151 }
152 
153 
action_str(enum storage_action act)154 static const char *action_str(enum storage_action act) {
155   switch(act) {
156   case action_load:    return "load";
157   case action_loaded:  return "loaded";
158   case action_save:    return "save";
159   case action_saved:   return "saved";
160   default:             return "UNKNOWN";
161   }
162 }
163 
164 
request_trigger(struct mwServiceStorage * srvc,struct mwStorageReq * req)165 static void request_trigger(struct mwServiceStorage *srvc,
166 			    struct mwStorageReq *req) {
167 
168   struct mwStorageUnit *item = req->item;
169 
170   g_message("storage request %s: key = 0x%x, result = 0x%x, length = %u",
171 	    action_str(req->action),
172 	    item->key, req->result_code, (guint) item->data.len);
173 
174   if(req->cb)
175     req->cb(srvc, req->result_code, item, req->data);
176 }
177 
178 
request_free(struct mwStorageReq * req)179 static void request_free(struct mwStorageReq *req) {
180   if(req->data_free) {
181     req->data_free(req->data);
182     req->data = NULL;
183     req->data_free = NULL;
184   }
185 
186   mwStorageUnit_free(req->item);
187   g_free(req);
188 }
189 
190 
request_remove(struct mwServiceStorage * srvc,struct mwStorageReq * req)191 static void request_remove(struct mwServiceStorage *srvc,
192 			   struct mwStorageReq *req) {
193 
194   srvc->pending = g_list_remove_all(srvc->pending, req);
195   request_free(req);
196 }
197 
198 
get_name(struct mwService * srvc)199 static const char *get_name(struct mwService *srvc) {
200   return "User Storage";
201 }
202 
203 
get_desc(struct mwService * srvc)204 static const char *get_desc(struct mwService *srvc) {
205   return "Stores user data and settings on the server";
206 }
207 
208 
make_channel(struct mwServiceStorage * srvc)209 static struct mwChannel *make_channel(struct mwServiceStorage *srvc) {
210   struct mwSession *session;
211   struct mwChannelSet *cs;
212   struct mwChannel *chan;
213 
214   session = mwService_getSession(MW_SERVICE(srvc));
215   cs = mwSession_getChannels(session);
216   chan = mwChannel_newOutgoing(cs);
217 
218   mwChannel_setService(chan, MW_SERVICE(srvc));
219   mwChannel_setProtoType(chan, PROTOCOL_TYPE);
220   mwChannel_setProtoVer(chan, PROTOCOL_VER);
221 
222   return mwChannel_create(chan)? NULL: chan;
223 }
224 
225 
start(struct mwService * srvc)226 static void start(struct mwService *srvc) {
227   struct mwServiceStorage *srvc_store;
228   struct mwChannel *chan;
229 
230   g_return_if_fail(srvc != NULL);
231   srvc_store = (struct mwServiceStorage *) srvc;
232 
233   chan = make_channel(srvc_store);
234   if(chan) {
235     srvc_store->channel = chan;
236   } else {
237     mwService_stopped(srvc);
238   }
239 }
240 
241 
stop(struct mwService * srvc)242 static void stop(struct mwService *srvc) {
243 
244   struct mwServiceStorage *srvc_store;
245   GList *l;
246 
247   g_return_if_fail(srvc != NULL);
248   srvc_store = (struct mwServiceStorage *) srvc;
249 
250   if(srvc_store->channel) {
251     mwChannel_destroy(srvc_store->channel, ERR_SUCCESS, NULL);
252     srvc_store->channel = NULL;
253   }
254 
255 #if 1
256   /* the new way */
257   /* remove pending requests. Sometimes we can crash the storage
258      service, and when that happens, we end up resending the killer
259      request over and over again, and the service never stays up */
260   for(l = srvc_store->pending; l; l = l->next)
261     request_free(l->data);
262 
263   g_list_free(srvc_store->pending);
264   srvc_store->pending = NULL;
265 
266   srvc_store->id_counter = 0;
267 
268 #else
269   /* the old way */
270   /* reset all of the started requests to their unstarted states */
271   for(l = srvc_store->pending; l; l = l->next) {
272     struct mwStorageReq *req = l->data;
273 
274     if(req->action == action_loaded) {
275       req->action = action_load;
276     } else if(req->action == action_saved) {
277       req->action = action_save;
278     }
279   }
280 #endif
281 
282   mwService_stopped(srvc);
283 }
284 
285 
recv_channelAccept(struct mwService * srvc,struct mwChannel * chan,struct mwMsgChannelAccept * msg)286 static void recv_channelAccept(struct mwService *srvc,
287 			       struct mwChannel *chan,
288 			       struct mwMsgChannelAccept *msg) {
289 
290   struct mwServiceStorage *srvc_stor;
291   GList *l;
292 
293   g_return_if_fail(srvc != NULL);
294   srvc_stor = (struct mwServiceStorage *) srvc;
295 
296   g_return_if_fail(chan != NULL);
297   g_return_if_fail(chan == srvc_stor->channel);
298 
299   /* send all pending requests */
300   for(l = srvc_stor->pending; l; l = l->next) {
301     struct mwStorageReq *req = l->data;
302 
303     if(req->action == action_save || req->action == action_load) {
304       request_send(chan, req);
305     }
306   }
307 
308   mwService_started(srvc);
309 }
310 
311 
recv_channelDestroy(struct mwService * srvc,struct mwChannel * chan,struct mwMsgChannelDestroy * msg)312 static void recv_channelDestroy(struct mwService *srvc,
313 				struct mwChannel *chan,
314 				struct mwMsgChannelDestroy *msg) {
315 
316   struct mwSession *session;
317   struct mwServiceStorage *srvc_stor;
318 
319   g_return_if_fail(srvc != NULL);
320   g_return_if_fail(chan != NULL);
321 
322   session = mwService_getSession(srvc);
323   g_return_if_fail(session != NULL);
324 
325   srvc_stor = (struct mwServiceStorage *) srvc;
326   srvc_stor->channel = NULL;
327 
328   mwService_stop(srvc);
329   mwSession_senseService(session, mwService_getType(srvc));
330 }
331 
332 
recv(struct mwService * srvc,struct mwChannel * chan,guint16 type,struct mwOpaque * data)333 static void recv(struct mwService *srvc, struct mwChannel *chan,
334 		 guint16 type, struct mwOpaque *data) {
335 
336   /* process into results, trigger callbacks */
337 
338   struct mwGetBuffer *b;
339   struct mwServiceStorage *srvc_stor;
340   struct mwStorageReq *req;
341   guint32 id;
342 
343   g_return_if_fail(srvc != NULL);
344   srvc_stor = (struct mwServiceStorage *) srvc;
345 
346   g_return_if_fail(chan != NULL);
347   g_return_if_fail(chan == srvc_stor->channel);
348   g_return_if_fail(data != NULL);
349 
350   b = mwGetBuffer_wrap(data);
351 
352   id = guint32_peek(b);
353   req = request_find(srvc_stor, id);
354 
355   if(! req) {
356     g_warning("couldn't find request 0x%x in storage service", id);
357     mwGetBuffer_free(b);
358     return;
359   }
360 
361   g_return_if_fail(req->action == type);
362   request_get(b, req);
363 
364   if(mwGetBuffer_error(b)) {
365     mw_mailme_opaque(data, "storage request 0x%x, type: 0x%x", id, type);
366 
367   } else {
368     request_trigger(srvc_stor, req);
369   }
370 
371   mwGetBuffer_free(b);
372   request_remove(srvc_stor, req);
373 }
374 
375 
clear(struct mwService * srvc)376 static void clear(struct mwService *srvc) {
377   struct mwServiceStorage *srvc_stor;
378   GList *l;
379 
380   srvc_stor = (struct mwServiceStorage *) srvc;
381 
382   for(l = srvc_stor->pending; l; l = l->next)
383     request_free(l->data);
384 
385   g_list_free(srvc_stor->pending);
386   srvc_stor->pending = NULL;
387 
388   srvc_stor->id_counter = 0;
389 }
390 
391 
mwServiceStorage_new(struct mwSession * session)392 struct mwServiceStorage *mwServiceStorage_new(struct mwSession *session) {
393   struct mwServiceStorage *srvc_store;
394   struct mwService *srvc;
395 
396   srvc_store = g_new0(struct mwServiceStorage, 1);
397   srvc = MW_SERVICE(srvc_store);
398 
399   mwService_init(srvc, session, mwService_STORAGE);
400   srvc->get_name = get_name;
401   srvc->get_desc = get_desc;
402   srvc->recv_accept = recv_channelAccept;
403   srvc->recv_destroy = recv_channelDestroy;
404   srvc->recv = recv;
405   srvc->start = start;
406   srvc->stop = stop;
407   srvc->clear = clear;
408 
409   return srvc_store;
410 }
411 
412 
mwStorageUnit_new(guint32 key)413 struct mwStorageUnit *mwStorageUnit_new(guint32 key) {
414   struct mwStorageUnit *u;
415 
416   u = g_new0(struct mwStorageUnit, 1);
417   u->key = key;
418 
419   return u;
420 }
421 
422 
mwStorageUnit_newOpaque(guint32 key,struct mwOpaque * data)423 struct mwStorageUnit *mwStorageUnit_newOpaque(guint32 key,
424 					      struct mwOpaque *data) {
425   struct mwStorageUnit *u;
426 
427   u = g_new0(struct mwStorageUnit, 1);
428   u->key = key;
429 
430   if(data)
431     mwOpaque_clone(&u->data, data);
432 
433   return u;
434 }
435 
436 
mwStorageUnit_newBoolean(guint32 key,gboolean val)437 struct mwStorageUnit *mwStorageUnit_newBoolean(guint32 key,
438 					       gboolean val) {
439 
440   return mwStorageUnit_newInteger(key, (guint32) val);
441 }
442 
443 
mwStorageUnit_newInteger(guint32 key,guint32 val)444 struct mwStorageUnit *mwStorageUnit_newInteger(guint32 key,
445 					       guint32 val) {
446   struct mwStorageUnit *u;
447   struct mwPutBuffer *b;
448 
449   u = g_new0(struct mwStorageUnit, 1);
450   u->key = key;
451 
452   b = mwPutBuffer_new();
453   guint32_put(b, val);
454   mwPutBuffer_finalize(&u->data, b);
455 
456   return u;
457 }
458 
459 
mwStorageUnit_newString(guint32 key,const char * str)460 struct mwStorageUnit *mwStorageUnit_newString(guint32 key,
461 					      const char *str) {
462   struct mwStorageUnit *u;
463   struct mwPutBuffer *b;
464 
465   u = g_new0(struct mwStorageUnit, 1);
466   u->key = key;
467 
468   b = mwPutBuffer_new();
469   mwString_put(b, str);
470   mwPutBuffer_finalize(&u->data, b);
471 
472   return u;
473 }
474 
475 
mwStorageUnit_getKey(struct mwStorageUnit * item)476 guint32 mwStorageUnit_getKey(struct mwStorageUnit *item) {
477   g_return_val_if_fail(item != NULL, 0x00); /* feh, unsafe */
478   return item->key;
479 }
480 
481 
mwStorageUnit_asBoolean(struct mwStorageUnit * item,gboolean val)482 gboolean mwStorageUnit_asBoolean(struct mwStorageUnit *item,
483 				 gboolean val) {
484 
485   return !! mwStorageUnit_asInteger(item, (guint32) val);
486 }
487 
488 
mwStorageUnit_asInteger(struct mwStorageUnit * item,guint32 val)489 guint32 mwStorageUnit_asInteger(struct mwStorageUnit *item,
490 				guint32 val) {
491   struct mwGetBuffer *b;
492   guint32 v;
493 
494   g_return_val_if_fail(item != NULL, val);
495 
496   b = mwGetBuffer_wrap(&item->data);
497 
498   guint32_get(b, &v);
499   if(! mwGetBuffer_error(b)) val = v;
500   mwGetBuffer_free(b);
501 
502   return val;
503 }
504 
505 
mwStorageUnit_asString(struct mwStorageUnit * item)506 char *mwStorageUnit_asString(struct mwStorageUnit *item) {
507   struct mwGetBuffer *b;
508   char *c = NULL;
509 
510   g_return_val_if_fail(item != NULL, NULL);
511 
512   b = mwGetBuffer_wrap(&item->data);
513 
514   mwString_get(b, &c);
515 
516   if(mwGetBuffer_error(b))
517     g_debug("error obtaining string value from opaque");
518 
519   mwGetBuffer_free(b);
520 
521   return c;
522 }
523 
524 
mwStorageUnit_asOpaque(struct mwStorageUnit * item)525 struct mwOpaque *mwStorageUnit_asOpaque(struct mwStorageUnit *item) {
526   g_return_val_if_fail(item != NULL, NULL);
527   return &item->data;
528 }
529 
530 
mwStorageUnit_free(struct mwStorageUnit * item)531 void mwStorageUnit_free(struct mwStorageUnit *item) {
532   if(! item) return;
533 
534   mwOpaque_clear(&item->data);
535   g_free(item);
536 }
537 
538 
request_new(struct mwServiceStorage * srvc,struct mwStorageUnit * item,mwStorageCallback cb,gpointer data,GDestroyNotify df)539 static struct mwStorageReq *request_new(struct mwServiceStorage *srvc,
540 					struct mwStorageUnit *item,
541 					mwStorageCallback cb,
542 					gpointer data, GDestroyNotify df) {
543 
544   struct mwStorageReq *req = g_new0(struct mwStorageReq, 1);
545 
546   req->id = ++srvc->id_counter;
547   req->item = item;
548   req->cb = cb;
549   req->data = data;
550   req->data_free = df;
551 
552   return req;
553 }
554 
555 
mwServiceStorage_load(struct mwServiceStorage * srvc,struct mwStorageUnit * item,mwStorageCallback cb,gpointer data,GDestroyNotify d_free)556 void mwServiceStorage_load(struct mwServiceStorage *srvc,
557 			   struct mwStorageUnit *item,
558 			   mwStorageCallback cb,
559 			   gpointer data, GDestroyNotify d_free) {
560 
561   /* - construct a request
562      - put request at end of pending
563      - if channel is open and connected
564        - compose the load message
565        - send message
566        - set request to sent
567      - else
568        - start service
569   */
570 
571   struct mwStorageReq *req;
572 
573   req = request_new(srvc, item, cb, data, d_free);
574   req->action = action_load;
575 
576   srvc->pending = g_list_append(srvc->pending, req);
577 
578   if(MW_SERVICE_IS_STARTED(MW_SERVICE(srvc)))
579     request_send(srvc->channel, req);
580 }
581 
582 
mwServiceStorage_save(struct mwServiceStorage * srvc,struct mwStorageUnit * item,mwStorageCallback cb,gpointer data,GDestroyNotify d_free)583 void mwServiceStorage_save(struct mwServiceStorage *srvc,
584 			   struct mwStorageUnit *item,
585 			   mwStorageCallback cb,
586 			   gpointer data, GDestroyNotify d_free) {
587 
588   /* - construct a request
589      - put request at end of pending
590      - if channel is open and connected
591        - compose the save message
592        - send message
593        - set request to sent
594      - else
595        - start service
596   */
597 
598   struct mwStorageReq *req;
599 
600   req = request_new(srvc, item, cb, data, d_free);
601   req->action = action_save;
602 
603   srvc->pending = g_list_append(srvc->pending, req);
604 
605   if(MW_SERVICE_IS_STARTED(MW_SERVICE(srvc)))
606     request_send(srvc->channel, req);
607 }
608 
609