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