1 /* -*-Mode: C;-*-
2 * $Id: edsio.c 1.1 Sun, 28 Jan 2007 10:02:26 -0800 jmacd $
3 *
4 * Copyright (C) 1998, 1999, Josh MacDonald.
5 * All Rights Reserved.
6 *
7 * Author: Josh MacDonald <jmacd@CS.Berkeley.EDU>
8 */
9
10 #include "edsio.h"
11 #include <stdio.h>
12
13 #if TIME_WITH_SYS_TIME
14 # include <sys/time.h>
15 # include <time.h>
16 #else
17 # if HAVE_SYS_TIME_H
18 # include <sys/time.h>
19 # else
20 # include <time.h>
21 # endif
22 #endif
23
24 #include "maketime.h"
25
26 /*#define DEBUG_PROPS*/
27
28 /* Event delivery
29 */
30
31 static GHashTable* all_event_defs = NULL;
32
33 static GPtrArray* all_event_watchers = NULL;
34
35 typedef struct _ErrorDeliveryWatcher ErrorDeliveryWatcher;
36 typedef struct _DelayedEvent DelayedEvent;
37
38 struct _ErrorDeliveryWatcher {
39 ErrorDeliveryFunc deliver;
40 };
41
42 struct _DelayedEvent {
43 GenericEvent ev;
44 GenericEventDef *def;
45 const char *msg;
46 };
47
48 void
eventdelivery_initialize_event_def(gint code,gint level,gint flags,const char * name,const char * oneline,const char * (* field_to_string)(GenericEvent * ev,gint field))49 eventdelivery_initialize_event_def (gint code,
50 gint level,
51 gint flags,
52 const char* name,
53 const char* oneline,
54 const char * (* field_to_string) (GenericEvent* ev, gint field))
55 {
56 GenericEventDef* def = g_new0 (GenericEventDef, 1);
57
58 if (! all_event_defs)
59 all_event_defs = g_hash_table_new (g_int_hash, g_int_equal);
60
61 def->code = code;
62 def->level = level;
63 def->flags = flags;
64 def->name = name;
65 def->oneline = oneline;
66 def->field_to_string = field_to_string;
67
68 g_hash_table_insert (all_event_defs, & def->code, def);
69 }
70
71 void
eventdelivery_event_watch_all(ErrorDeliveryFunc func)72 eventdelivery_event_watch_all (ErrorDeliveryFunc func)
73 {
74 ErrorDeliveryWatcher* w = g_new0 (ErrorDeliveryWatcher, 1);
75
76 w->deliver = func;
77
78 if (! all_event_watchers)
79 all_event_watchers = g_ptr_array_new ();
80
81 g_ptr_array_add (all_event_watchers, w);
82 }
83
84 GenericEventDef*
eventdelivery_event_lookup(gint code)85 eventdelivery_event_lookup (gint code)
86 {
87 return g_hash_table_lookup (all_event_defs, & code);
88 }
89
90 void
eventdelivery_event_deliver(GenericEvent * e)91 eventdelivery_event_deliver (GenericEvent* e)
92 {
93 static gint in_call = FALSE;
94 static GQueue* queued = NULL;
95 static GPtrArray* free_strings = NULL;
96
97 if (! queued)
98 {
99 queued = g_queue_new ();
100 free_strings = g_ptr_array_new ();
101 }
102
103 in_call += 1;
104
105 g_assert (e);
106
107 edsio_edsio_init ();
108
109 if (all_event_defs)
110 {
111 GenericEventDef* def = g_hash_table_lookup (all_event_defs, & e->code);
112
113 if (def)
114 {
115 GString* out;
116 const char* oneline = def->oneline;
117 char c;
118
119 out = g_string_new (NULL);
120
121 while ((c = *oneline++))
122 {
123 switch (c)
124 {
125 case '$':
126 {
127 const char* field;
128 char *end;
129 int f;
130
131 if ((*oneline++) != '{')
132 goto badevent;
133
134 f = strtol (oneline, &end, 10);
135
136 if (f < 0 || !end || end[0] != '}')
137 goto badevent;
138
139 oneline = end+1;
140
141 g_assert (def->field_to_string);
142
143 field = def->field_to_string (e, f);
144
145 if (field)
146 {
147 g_string_append (out, field);
148
149 g_free ((void*) field);
150 }
151 else
152 goto badevent;
153 }
154 break;
155 default:
156 g_string_append_c (out, c);
157 }
158 }
159
160 if (! all_event_watchers)
161 {
162 fprintf (stderr, "%s:%d: %s\n", e->srcfile, e->srcline, out->str);
163
164 g_string_free (out, TRUE);
165 }
166 else if (in_call == 1)
167 {
168 gint i;
169
170 for (i = 0; i < all_event_watchers->len; i += 1)
171 {
172 ErrorDeliveryWatcher* w = all_event_watchers->pdata[i];
173
174 if (! w->deliver (e, def, out->str))
175 {
176 g_warning ("%s:%d: An error delivery routine failed: %s\n", e->srcfile, e->srcline, out->str);
177 in_call = 0;
178 return;
179 }
180 }
181
182 while (g_queue_get_length (queued) > 0)
183 {
184 DelayedEvent* de = g_queue_pop_head (queued);
185
186 for (i = 0; i < all_event_watchers->len; i += 1)
187 {
188 ErrorDeliveryWatcher* w = all_event_watchers->pdata[i];
189
190 if (! w->deliver (& de->ev, de->def, de->msg))
191 {
192 g_warning ("%s:%d: An error delivery routine failed: %s\n", e->srcfile, e->srcline, out->str);
193 in_call = 0;
194 return;
195 }
196 }
197 }
198
199 for (i = 0; i < free_strings->len; i += 1)
200 g_string_free (free_strings->pdata[i], TRUE);
201
202 g_ptr_array_set_size (free_strings, 0);
203
204 g_string_free (out, TRUE);
205 }
206 else
207 {
208 DelayedEvent* de = g_new (DelayedEvent, 1);
209
210 de->ev = *e;
211 de->def = def;
212 de->msg = out->str;
213
214 g_queue_push_tail (queued, de);
215
216 g_ptr_array_add (free_strings, out);
217 }
218
219 in_call -= 1;
220
221 return;
222 }
223 }
224
225 g_warning ("%s:%d: Unrecognized event delivered (code=%d)\n", e->srcfile, e->srcline, e->code);
226
227 in_call -= 1;
228
229 return;
230
231 badevent:
232
233 g_warning ("%s:%d: An malformed error could not print here (code=%d)\n", e->srcfile, e->srcline, e->code);
234
235 in_call -= 1;
236
237 return;
238 }
239
240 const char*
eventdelivery_int_to_string(int x)241 eventdelivery_int_to_string (int x)
242 {
243 return g_strdup_printf ("%d", x);
244 }
245
246 const char*
eventdelivery_string_to_string(const char * x)247 eventdelivery_string_to_string (const char* x)
248 {
249 return g_strdup (x);
250 }
251
252 const char*
eventdelivery_source_to_string(SerialSource * x)253 eventdelivery_source_to_string (SerialSource* x)
254 {
255 return g_strdup ("@@@SerialSource");
256 }
257
258 const char*
eventdelivery_sink_to_string(SerialSink * x)259 eventdelivery_sink_to_string (SerialSink* x)
260 {
261 return g_strdup ("@@@SerialSink");
262 }
263
264 const char*
eventdelivery_handle_to_string(FileHandle * x)265 eventdelivery_handle_to_string (FileHandle* x)
266 {
267 g_return_val_if_fail (x, g_strdup ("*error*"));
268
269 return x->table->table_handle_name (x);
270 }
271
272 /* Misc crap.
273 */
274
275 gboolean
edsio_time_of_day(SerialGenericTime * setme)276 edsio_time_of_day (SerialGenericTime* setme)
277 {
278 #if HAVE_GETTIMEOFDAY
279
280 struct timeval tv;
281
282 if (gettimeofday (& tv, NULL))
283 {
284 edsio_generate_errno_event (EC_EdsioGetTimeOfDayFailure);
285 goto bail;
286 }
287
288 if (setme)
289 {
290 setme->nanos = tv.tv_usec * 1000;
291 setme->seconds = tv.tv_sec;
292 }
293
294 #else
295
296 struct timeval tv;
297 time_t t = time (NULL);
298
299 if (t < 0)
300 {
301 edsio_generate_errno_event (EC_EdsioTimeFailure);
302 goto bail;
303 }
304
305 if (setme)
306 {
307 setme->nanos = 0;
308 setme->seconds = tv.tv_sec;
309 }
310
311 #endif
312
313 return TRUE;
314
315 bail:
316
317 setme->nanos = 0;
318 setme->seconds = 10;
319
320 return FALSE;
321 }
322
323 gchar*
edsio_time_to_iso8601(SerialGenericTime * tp)324 edsio_time_to_iso8601 (SerialGenericTime *tp)
325 {
326 return edsio_time_t_to_iso8601 (tp->seconds);
327 }
328
329 gchar*
edsio_time_t_to_iso8601(GTime t0)330 edsio_time_t_to_iso8601 (GTime t0)
331 {
332 static char timebuf[64];
333 time_t t = t0;
334
335 struct tm lt = *localtime(&t);
336 int utc_offset = difftm(<, gmtime(&t));
337 char sign = utc_offset < 0 ? '-' : '+';
338 int minutes = abs (utc_offset) / 60;
339 int hours = minutes / 60;
340
341 sprintf(timebuf,
342 "%d-%02d-%02d %02d:%02d:%02d%c%02d%02d",
343 lt.tm_year + 1900,
344 lt.tm_mon + 1,
345 lt.tm_mday,
346 lt.tm_hour,
347 lt.tm_min,
348 lt.tm_sec,
349 sign,
350 hours,
351 minutes % 60);
352
353 return timebuf;
354 }
355
356 static gboolean
strtosl_checked(const char * str,long * l,const char * errmsg)357 strtosl_checked (const char* str, long* l, const char* errmsg)
358 {
359 char* end;
360
361 (*l) = strtol (str, &end, 10);
362
363 if (!end || end[0])
364 {
365 if (errmsg)
366 edsio_generate_stringstring_event (EC_EdsioInvalidIntegerString, errmsg, str);
367
368 (*l) = 0;
369 return FALSE;
370 }
371
372 return TRUE;
373 }
374
375 gboolean
strtosi_checked(const char * str,gint32 * i,const char * errmsg)376 strtosi_checked (const char* str, gint32* i, const char* errmsg)
377 {
378 long l;
379
380 if (! strtosl_checked (str, &l, errmsg))
381 {
382 (*i) = 0;
383 return FALSE;
384 }
385
386 if (l > G_MAXINT || l < G_MININT)
387 {
388 if (errmsg)
389 edsio_generate_stringstring_event (EC_EdsioIntegerOutOfRange, errmsg, str);
390
391 (*i) = 0;
392 return FALSE;
393 }
394
395 (*i) = l;
396
397 return TRUE;
398 }
399
400 gboolean
strtoss_checked(const char * str,gint16 * i,const char * errmsg)401 strtoss_checked (const char* str, gint16* i, const char* errmsg)
402 {
403 long l;
404
405 if (! strtosl_checked (str, &l, errmsg))
406 {
407 (*i) = 0;
408 return FALSE;
409 }
410
411 if (l > G_MAXSHORT || l < G_MINSHORT)
412 {
413 if (errmsg)
414 edsio_generate_stringstring_event (EC_EdsioIntegerOutOfRange, errmsg, str);
415
416 (*i) = 0;
417 return FALSE;
418 }
419
420 (*i) = l;
421
422 return TRUE;
423 }
424
425 gboolean
strtoui_checked(const char * str,guint32 * i,const char * errmsg)426 strtoui_checked (const char* str, guint32* i, const char* errmsg)
427 {
428 long l;
429
430 if (! strtosl_checked (str, &l, errmsg))
431 {
432 (*i) = 0;
433 return FALSE;
434 }
435
436 if (l < 0)
437 {
438 if (errmsg)
439 edsio_generate_stringstring_event (EC_EdsioInvalidIntegerSign, errmsg, str);
440
441 (*i) = 0;
442 return FALSE;
443 }
444
445 (*i) = l;
446
447 if (l != (*i))
448 {
449 if (errmsg)
450 edsio_generate_stringstring_event (EC_EdsioIntegerOutOfRange, errmsg, str);
451
452 (*i) = 0;
453 return FALSE;
454 }
455
456 return TRUE;
457 }
458
459 gboolean
strtous_checked(const char * str,guint16 * i,const char * errmsg)460 strtous_checked (const char* str, guint16* i, const char* errmsg)
461 {
462 long l;
463
464 if (! strtosl_checked (str, &l, errmsg))
465 {
466 (*i) = 0;
467 return FALSE;
468 }
469
470 if (l < 0)
471 {
472 if (errmsg)
473 edsio_generate_stringstring_event (EC_EdsioInvalidIntegerSign, errmsg, str);
474
475 (*i) = 0;
476 return FALSE;
477 }
478
479 (*i) = l;
480
481 if (l != (*i))
482 {
483 if (errmsg)
484 edsio_generate_stringstring_event (EC_EdsioIntegerOutOfRange, errmsg, str);
485
486 (*i) = 0;
487 return FALSE;
488 }
489
490 return TRUE;
491 }
492
493 gint
edsio_md5_equal(gconstpointer v,gconstpointer v2)494 edsio_md5_equal (gconstpointer v,
495 gconstpointer v2)
496 {
497 return memcmp (v, v2, 16) == 0;
498 }
499
500 guint
edsio_md5_hash(gconstpointer v)501 edsio_md5_hash (gconstpointer v)
502 {
503 guint8* md5 = (guint8*) v;
504 guint x = 0;
505 gint i, j;
506
507 for (i = 0, j = 0; i < 16; i += 1, j += 1, j %= sizeof (guint32))
508 x ^= md5[i] << (8*j);
509
510 return x;
511 }
512
513 void
serializeio_print_bytes(const guint8 * bytes,guint len0)514 serializeio_print_bytes (const guint8* bytes, guint len0)
515 {
516 char buf[100];
517 int i;
518 guint len;
519
520 len = MIN (len0, 32);
521
522 for (i = 0; i < len; i += 1)
523 sprintf (buf + 2*i, "%02x", bytes[i]);
524
525 if (len0 > len)
526 strcat (buf, "...");
527
528 g_print ("%s\n", buf);
529 }
530
531 void
edsio_md5_to_string(const guint8 * md5,char buf[33])532 edsio_md5_to_string (const guint8* md5, char buf[33])
533 {
534 gint i;
535
536 for (i = 0; i < 16; i += 1)
537 sprintf (buf + 2*i, "%02x", md5[i]);
538 }
539
540 static gboolean
from_hex(char c,int * x,const char * ctx)541 from_hex (char c, int* x, const char* ctx)
542 {
543 char buf[2];
544
545 if (c >= '0' && c <= '9')
546 {
547 (*x) = c - '0';
548 return TRUE;
549 }
550 else if (c >= 'A' && c <= 'F')
551 {
552 (*x) = c - 'A' + 10;
553 return TRUE;
554 }
555 else if (c >= 'a' && c <= 'f')
556 {
557 (*x) = c - 'a' + 10;
558 return TRUE;
559 }
560
561 buf[0] = c;
562 buf[1] = 0;
563
564 edsio_generate_stringstring_event (EC_EdsioInvalidHexDigit, buf, ctx);
565 return FALSE;
566 }
567
568 gboolean
edsio_md5_from_string(guint8 * md5,const char buf[33])569 edsio_md5_from_string (guint8* md5, const char buf[33])
570 {
571 gint i;
572 gint l = strlen (buf);
573
574 if (l < 32)
575 {
576 edsio_generate_string_event (EC_EdsioMD5StringShort, buf);
577 return FALSE;
578 }
579 else if (l > 32)
580 {
581 edsio_generate_string_event (EC_EdsioMD5StringLong, buf);
582 return FALSE;
583 }
584
585 for (i = 0; i < 16; i += 1)
586 {
587 char c1 = buf[(2*i)];
588 char c2 = buf[(2*i)+1];
589 int x1, x2;
590
591 if (! from_hex (c1, &x1, buf))
592 return FALSE;
593
594 if (! from_hex (c2, &x2, buf))
595 return FALSE;
596
597 md5[i] = (x1 << 4) | x2;
598 }
599
600 return TRUE;
601 }
602
603 /* Strings
604 */
605
edsio_intern_string(const char * str)606 const char* edsio_intern_string (const char* str)
607 {
608 static GStringChunk* chunk = NULL;
609
610 if (! chunk)
611 chunk = g_string_chunk_new (256);
612
613 return g_string_chunk_insert_const (chunk, str);
614 }
615
616 /* Properties
617 */
618
619 typedef struct _EdsioHostType EdsioHostType;
620 typedef struct _EdsioPropertyType EdsioPropertyType;
621
622 struct _EdsioPropertyType {
623 const char *type_name;
624 PropFreeFunc freer;
625 PropGSFunc getter;
626 PropGSFunc setter;
627 PropSerialize serialize;
628 PropUnserialize unserialize;
629 };
630
631 struct _EdsioHostType {
632 const char *host_name;
633 PropertyTableFunc ptable;
634 PersistSourceFunc source;
635 PersistSinkFunc sink;
636 PersistIssetFunc isset;
637 PersistUnsetFunc unset;
638 };
639
640 struct _EdsioProperty {
641 guint32 prop_code;
642 const char *prop_name;
643 guint32 prop_flags;
644 EdsioPropertyType *type;
645 EdsioHostType *host;
646 };
647
648 union _EdsioPropertyEntry {
649 guint32 as_uint32;
650 SerialEdsioBytes as_bytes;
651 gpointer as_vptr;
652 const char* as_string;
653 };
654
655 struct _EdsioGenericProperty
656 {
657 guint32 code;
658 };
659
660 static GHashTable* all_property_types = NULL;
661 static GHashTable* all_host_types = NULL;
662 static GHashTable* all_properties = NULL;
663 static GHashTable* all_property_codes = NULL;
664 static guint32 property_code_sequence = 0;
665
666 void
edsio_initialize_property_type(const char * t,PropFreeFunc freer,PropGSFunc getter,PropGSFunc setter,PropSerialize ser,PropUnserialize unser)667 edsio_initialize_property_type (const char* t, PropFreeFunc freer, PropGSFunc getter, PropGSFunc setter, PropSerialize ser, PropUnserialize unser)
668 {
669 EdsioPropertyType* type;
670
671 t = edsio_intern_string (t);
672
673 if (! all_property_types)
674 all_property_types = g_hash_table_new (g_direct_hash, g_direct_equal);
675
676 if ((type = g_hash_table_lookup (all_property_types, t)) != NULL)
677 {
678 if (getter != type->getter ||
679 setter != type->setter ||
680 ser != type->serialize ||
681 unser != type->unserialize)
682 edsio_generate_string_event (EC_EdsioDuplicatePropertyTypeRegistered, t);
683 return;
684 }
685
686 type = g_new0 (EdsioPropertyType, 1);
687
688 type->type_name = t;
689 type->freer = freer;
690 type->getter = getter;
691 type->setter = setter;
692 type->serialize = ser;
693 type->unserialize = unser;
694
695 g_hash_table_insert (all_property_types, (gpointer) t, type);
696 }
697
698 void
edsio_initialize_host_type(const char * ph,PropertyTableFunc ptable,PersistSourceFunc source,PersistSinkFunc sink,PersistIssetFunc isset,PersistUnsetFunc unset)699 edsio_initialize_host_type (const char* ph,
700 PropertyTableFunc ptable,
701 PersistSourceFunc source,
702 PersistSinkFunc sink,
703 PersistIssetFunc isset,
704 PersistUnsetFunc unset)
705 {
706 EdsioHostType* host;
707
708 ph = edsio_intern_string (ph);
709
710 if (! all_host_types)
711 all_host_types = g_hash_table_new (g_direct_hash, g_direct_equal);
712
713 if (g_hash_table_lookup (all_host_types, ph))
714 {
715 edsio_generate_string_event (EC_EdsioDuplicateHostTypeRegistered, ph);
716 return;
717 }
718
719 host = g_new0 (EdsioHostType, 1);
720
721 host->host_name = ph;
722 host->ptable = ptable;
723 host->source = source;
724 host->sink = sink;
725 host->isset = isset;
726 host->unset = unset;
727
728 g_hash_table_insert (all_host_types, (gpointer) ph, host);
729
730 }
731
732 gboolean
edsio_new_property(const char * name,const char * ph,const char * t,guint32 flags,EdsioGenericProperty * ret_prop)733 edsio_new_property (const char* name, const char* ph, const char* t, guint32 flags, EdsioGenericProperty *ret_prop)
734 {
735 EdsioProperty* prop;
736 EdsioPropertyType* type;
737 EdsioHostType* host;
738
739 name = edsio_intern_string (name);
740 ph = edsio_intern_string (ph);
741 t = edsio_intern_string (t);
742
743 g_assert (all_property_types);
744
745 if (! all_properties)
746 {
747 all_properties = g_hash_table_new (g_direct_hash, g_direct_equal);
748 all_property_codes = g_hash_table_new (g_int_hash, g_int_equal);
749 }
750
751 if ((prop = g_hash_table_lookup (all_properties, name)) != NULL)
752 {
753 edsio_generate_string_event (EC_EdsioDuplicatePropertyNameRegistered, name);
754 ret_prop->code = prop->prop_code;
755 return TRUE;
756 }
757
758 if ((type = g_hash_table_lookup (all_property_types, t)) == NULL)
759 {
760 edsio_generate_string_event (EC_EdsioNoSuchPropertyType, t);
761 return FALSE;
762 }
763
764 if ((host = g_hash_table_lookup (all_host_types, ph)) == NULL)
765 {
766 edsio_generate_string_event (EC_EdsioNoSuchHostType, ph);
767 return FALSE;
768 }
769
770 if (flags & PF_Persistent && ! host->isset)
771 {
772 edsio_generate_stringstring_event (EC_EdsioPersistenceUnavailable, name, ph);
773 return FALSE;
774 }
775
776 prop = g_new0 (EdsioProperty, 1);
777
778 prop->prop_code = ++property_code_sequence;
779 prop->prop_name = name;
780 prop->prop_flags = flags;
781 prop->type = type;
782 prop->host = host;
783
784 g_hash_table_insert (all_properties, (gpointer) name, prop);
785 g_hash_table_insert (all_property_codes, & prop->prop_code, prop);
786
787 ret_prop->code = prop->prop_code;
788
789 return TRUE;
790 }
791
792 static EdsioProperty*
edsio_property_find(const char * ph,const char * t,guint32 code)793 edsio_property_find (const char* ph, const char* t, guint32 code)
794 {
795 EdsioProperty* prop;
796
797 ph = edsio_intern_string (ph);
798 t = edsio_intern_string (t);
799
800 if (code <= 0 || code > property_code_sequence)
801 {
802 edsio_generate_int_event (EC_EdsioNoSuchProperty, code);
803 return NULL;
804 }
805
806 if (! (prop = g_hash_table_lookup (all_property_codes, & code)))
807 {
808 edsio_generate_int_event (EC_EdsioNoSuchProperty, code);
809 return NULL;
810 }
811
812 if (prop->host->host_name != ph)
813 {
814 edsio_generate_stringstringstring_event (EC_EdsioWrongHostType, prop->prop_name, ph, prop->host->host_name);
815 return NULL;
816 }
817
818 if (prop->type->type_name != t)
819 {
820 edsio_generate_stringstringstring_event (EC_EdsioWrongDataType, prop->prop_name, t, prop->type->type_name);
821 return NULL;
822 }
823
824 return prop;
825 }
826
827 EdsioPropertyEntry*
edsio_property_get(gpointer obj,EdsioProperty * prop)828 edsio_property_get (gpointer obj, EdsioProperty* prop)
829 {
830 EdsioPropertyEntry* ent;
831 GHashTable* table = * prop->host->ptable (obj);
832 gboolean persist = prop->prop_flags & PF_Persistent;
833
834 #ifdef DEBUG_PROPS
835 g_print ("get %p.%s\n", obj, prop->prop_name);
836 #endif
837
838 if (table && (ent = g_hash_table_lookup (table, & prop->prop_code)) != NULL)
839 return ent;
840
841 if (persist)
842 {
843 SerialSource* src;
844
845 if (! (src = prop->host->source (obj, prop->prop_name)))
846 return NULL;
847
848 g_assert (prop->type->unserialize);
849
850 if (! prop->type->unserialize (src, & ent))
851 return NULL;
852
853 g_assert (ent);
854
855 if (! src->source_close (src))
856 return NULL;
857
858 src->source_free (src);
859
860 if (! table)
861 table = (* prop->host->ptable (obj)) = g_hash_table_new (g_int_hash, g_int_equal);
862
863 g_hash_table_insert (table, & prop->prop_code, ent);
864
865 return ent;
866 }
867
868 edsio_generate_string_event (EC_EdsioPropertyNotSet, prop->prop_name);
869 return NULL;
870 }
871
872 gboolean
edsio_property_set(gpointer obj,EdsioProperty * prop,EdsioPropertyEntry * set)873 edsio_property_set (gpointer obj, EdsioProperty* prop, EdsioPropertyEntry* set)
874 {
875 EdsioPropertyEntry* ent;
876 gboolean persist = prop->prop_flags & PF_Persistent;
877 GHashTable* table = * prop->host->ptable (obj);
878
879 #ifdef DEBUG_PROPS
880 g_print ("set %p.%s\n", obj, prop->prop_name);
881 #endif
882
883 if (! table)
884 table = (* prop->host->ptable (obj)) = g_hash_table_new (g_int_hash, g_int_equal);
885
886 ent = g_hash_table_lookup (table, & prop->prop_code);
887
888 if (ent)
889 {
890 g_hash_table_remove (table, & prop->prop_code);
891 prop->type->freer (ent);
892 }
893
894 g_hash_table_insert (table, & prop->prop_code, set);
895
896 if (persist)
897 {
898 SerialSink* sink;
899
900 if (! (sink = prop->host->sink (obj, prop->prop_name)))
901 return FALSE;
902
903 g_assert (prop->type->serialize);
904
905 if (! prop->type->serialize (sink, set))
906 return FALSE;
907
908 if (! sink->sink_close (sink))
909 return FALSE;
910
911 sink->sink_free (sink);
912 }
913
914 return TRUE;
915 }
916
917 gboolean
edsio_property_isset(const char * ph,const char * t,guint32 code,gpointer obj)918 edsio_property_isset (const char* ph, const char* t, guint32 code, gpointer obj)
919 {
920 EdsioProperty* prop;
921 GHashTable* table;
922 gboolean persist;
923 gboolean result = FALSE;
924
925 if (! (prop = edsio_property_find (ph, t, code)))
926 goto done;
927
928 persist = prop->prop_flags & PF_Persistent;
929
930 table = * prop->host->ptable (obj);
931
932 if (persist)
933 {
934 PersistIssetFunc issetfunc = prop->host->isset;
935 if (issetfunc(obj, prop->prop_name))
936 {
937 if (! edsio_property_get (obj, prop))
938 goto done;
939
940 table = * prop->host->ptable (obj);
941 }
942 }
943
944 if (! table)
945 goto done;
946
947 result = (g_hash_table_lookup (table, & code) != NULL);
948
949 done:
950
951 #ifdef DEBUG_PROPS
952 g_print ("isset %p.%s = %s\n", obj, prop->prop_name, result ? "true" : "false");
953 #endif
954
955 return result;
956 }
957
958 gboolean
edsio_property_unset(const char * ph,const char * t,guint32 code,gpointer obj)959 edsio_property_unset (const char* ph, const char* t, guint32 code, gpointer obj)
960 {
961 EdsioProperty* prop;
962 gboolean persist;
963 GHashTable* table;
964
965 if (! (prop = edsio_property_find (ph, t, code)))
966 return FALSE;
967
968 #ifdef DEBUG_PROPS
969 g_print ("unset %p.%s\n", obj, prop->prop_name);
970 #endif
971
972 persist = prop->prop_flags & PF_Persistent;
973 table = * prop->host->ptable (obj);
974
975 if (table)
976 {
977 EdsioPropertyEntry* ent;
978
979 ent = g_hash_table_lookup (table, & code);
980
981 g_hash_table_remove (table, & code);
982
983 if (g_hash_table_size (table) == 0)
984 {
985 g_hash_table_destroy (table);
986 table = (* prop->host->ptable (obj)) = NULL;
987 }
988
989 /*g_free (ent);*/
990 }
991
992 if (persist)
993 {
994 if (! prop->host->unset (obj, prop->prop_name))
995 return FALSE;
996 }
997
998 return TRUE;
999 }
1000
1001 static gboolean
edsio_false()1002 edsio_false ()
1003 {
1004 return FALSE;
1005 }
1006
1007 PropGSFunc
edsio_property_getter(const char * ph,const char * t,guint32 code,EdsioProperty ** ep)1008 edsio_property_getter (const char* ph, const char* t, guint32 code, EdsioProperty** ep)
1009 {
1010 if (! ((*ep) = edsio_property_find (ph, t, code)))
1011 return & edsio_false;
1012
1013 return (* ep)->type->getter;
1014 }
1015
1016 PropGSFunc
edsio_property_setter(const char * ph,const char * t,guint32 code,EdsioProperty ** ep)1017 edsio_property_setter (const char* ph, const char* t, guint32 code, EdsioProperty** ep)
1018 {
1019 if (! ((* ep) = edsio_property_find (ph, t, code)))
1020 return & edsio_false;
1021
1022 return (* ep)->type->setter;
1023 }
1024
1025 /* Primitive type serializers
1026 */
1027
1028 /* integer
1029 */
1030 gboolean
edsio_property_uint_getter(gpointer obj,EdsioProperty * prop,guint32 * get)1031 edsio_property_uint_getter (gpointer obj, EdsioProperty* prop, guint32* get)
1032 {
1033 EdsioPropertyEntry *ent;
1034
1035 if (! (ent = edsio_property_get (obj, prop)))
1036 return FALSE;
1037
1038 (*get) = ent->as_uint32;
1039
1040 return TRUE;
1041 }
1042
1043 gboolean
edsio_property_uint_setter(gpointer obj,EdsioProperty * prop,guint32 set)1044 edsio_property_uint_setter (gpointer obj, EdsioProperty* prop, guint32 set)
1045 {
1046 EdsioPropertyEntry *ent = g_new (EdsioPropertyEntry, 1);
1047
1048 ent->as_uint32 = set;
1049
1050 return edsio_property_set (obj, prop, ent);
1051 }
1052
1053 void
edsio_property_uint_free(gpointer obj)1054 edsio_property_uint_free (gpointer obj)
1055 {
1056 g_free (obj);
1057 }
1058
1059 gboolean
unserialize_uint(SerialSource * source,guint32 ** x)1060 unserialize_uint (SerialSource *source, guint32** x)
1061 {
1062 SerialEdsioUint *s;
1063 guint32 *n;
1064
1065 if (! unserialize_edsiouint (source, & s))
1066 return FALSE;
1067
1068 n = g_new (guint32, 1);
1069
1070 (* x) = n;
1071
1072 (* n) = s->val;
1073
1074 g_free (s);
1075
1076 return TRUE;
1077 }
1078
1079 gboolean
serialize_uint_obj(SerialSink * sink,guint32 * x)1080 serialize_uint_obj (SerialSink *sink, guint32* x)
1081 {
1082 return serialize_edsiouint (sink, *x);
1083 }
1084
1085 /* String
1086 */
1087
1088 void
edsio_property_string_free(gpointer obj)1089 edsio_property_string_free (gpointer obj)
1090 {
1091 g_free (obj);
1092 }
1093
1094 gboolean
edsio_property_string_getter(gpointer obj,EdsioProperty * prop,const char ** get)1095 edsio_property_string_getter (gpointer obj, EdsioProperty* prop, const char** get)
1096 {
1097 if (! ((*get) = (const char*) edsio_property_get (obj, prop)))
1098 return FALSE;
1099
1100 return TRUE;
1101 }
1102
1103 gboolean
edsio_property_string_setter(gpointer obj,EdsioProperty * prop,const char * set)1104 edsio_property_string_setter (gpointer obj, EdsioProperty* prop, const char* set)
1105 {
1106 return edsio_property_set (obj, prop, (EdsioPropertyEntry*) set);
1107 }
1108
1109 gboolean
unserialize_string(SerialSource * source,const char ** x)1110 unserialize_string (SerialSource *source, const char** x)
1111 {
1112 SerialEdsioString *s;
1113
1114 if (! unserialize_edsiostring (source, & s))
1115 return FALSE;
1116
1117 (*x) = g_strdup (s->val);
1118
1119 g_free (s);
1120
1121 return TRUE;
1122 }
1123
1124 gboolean
serialize_string_obj(SerialSink * sink,const char * x)1125 serialize_string_obj (SerialSink *sink, const char* x)
1126 {
1127 return serialize_edsiostring (sink, x);
1128 }
1129
1130 /* Bytes
1131 */
1132
1133 gboolean
unserialize_bytes(SerialSource * source,SerialEdsioBytes ** x)1134 unserialize_bytes (SerialSource *source, SerialEdsioBytes** x)
1135 {
1136 return unserialize_edsiobytes (source, x);
1137 }
1138
1139 gboolean
serialize_bytes_obj(SerialSink * sink,SerialEdsioBytes * x)1140 serialize_bytes_obj (SerialSink *sink, SerialEdsioBytes *x)
1141 {
1142 return serialize_edsiobytes_obj (sink, x);
1143 }
1144
1145 gboolean
edsio_property_bytes_getter(gpointer obj,EdsioProperty * prop,guint8 ** get,guint32 * get_len)1146 edsio_property_bytes_getter (gpointer obj, EdsioProperty* prop, guint8** get, guint32* get_len)
1147 {
1148 EdsioPropertyEntry *ent;
1149
1150 if (! (ent = edsio_property_get (obj, prop)))
1151 return FALSE;
1152
1153 (* get) = (gpointer) ent->as_bytes.val;
1154 (* get_len) = ent->as_bytes.val_len;
1155
1156 return TRUE;
1157 }
1158
1159 gboolean
edsio_property_bytes_setter(gpointer obj,EdsioProperty * prop,guint8 * set,guint32 set_len)1160 edsio_property_bytes_setter (gpointer obj, EdsioProperty* prop, guint8* set, guint32 set_len)
1161 {
1162 EdsioPropertyEntry *ent = g_new (EdsioPropertyEntry, 1);
1163
1164 ent->as_bytes.val = set;
1165 ent->as_bytes.val_len = set_len;
1166
1167 return edsio_property_set (obj, prop, ent);
1168 }
1169
1170 void
edsio_property_bytes_free(gpointer obj)1171 edsio_property_bytes_free (gpointer obj)
1172 {
1173 g_free (obj);
1174 }
1175
1176 /* Vptr
1177 */
1178
1179 gboolean
edsio_property_vptr_getter(gpointer obj,EdsioProperty * prop,void ** get)1180 edsio_property_vptr_getter (gpointer obj, EdsioProperty* prop, void** get)
1181 {
1182 if (! ((*get) = edsio_property_get (obj, prop)))
1183 return FALSE;
1184
1185 return TRUE;
1186 }
1187
1188 gboolean
edsio_property_vptr_setter(gpointer obj,EdsioProperty * prop,void * set)1189 edsio_property_vptr_setter (gpointer obj, EdsioProperty* prop, void* set)
1190 {
1191 return edsio_property_set (obj, prop, (EdsioPropertyEntry*) set);
1192 }
1193
1194 void
edsio_property_vptr_free(gpointer obj)1195 edsio_property_vptr_free (gpointer obj)
1196 {
1197 /* nothing */
1198 }
1199
1200 /* Testing
1201 */
1202
1203 #ifdef DEBUG_LIBEDSIO
1204
1205 GHashTable**
edsio_proptest_property_table(PropTest * pt)1206 edsio_proptest_property_table (PropTest *pt)
1207 {
1208 return & pt->_edsio_property_table;
1209 }
1210
1211 SerialSource*
edsio_persist_proptest_source(PropTest * pt,const char * prop_name)1212 edsio_persist_proptest_source (PropTest *pt, const char* prop_name)
1213 {
1214 GByteArray* array;
1215
1216 if (! pt->ptable)
1217 {
1218 g_warning ("can't get persist property, no table\n");
1219 return NULL;
1220 }
1221
1222 if (! (array = g_hash_table_lookup (pt->ptable, prop_name)))
1223 {
1224 g_warning ("can't lookup persist property\n");
1225 return NULL;
1226 }
1227
1228 return edsio_simple_source (array->data, array->len, SBF_None);
1229 }
1230
1231 static void
pt_success(gpointer data,GByteArray * result)1232 pt_success (gpointer data, GByteArray* result)
1233 {
1234 PropTest* pt = data;
1235
1236 GByteArray* old;
1237
1238 if (! pt->ptable)
1239 pt->ptable = g_hash_table_new (g_str_hash, g_str_equal);
1240
1241 old = g_hash_table_lookup (pt->ptable, (gpointer) pt->kludge);
1242
1243 if (old)
1244 g_byte_array_free (old, TRUE);
1245
1246 g_hash_table_insert (pt->ptable, (gpointer) pt->kludge, result);
1247 }
1248
1249 SerialSink*
edsio_persist_proptest_sink(PropTest * pt,const char * prop_name)1250 edsio_persist_proptest_sink (PropTest *pt, const char* prop_name)
1251 {
1252 pt->kludge = prop_name;
1253
1254 return edsio_simple_sink (pt, SBF_None, FALSE, pt_success, NULL);
1255 }
1256
1257 gboolean
edsio_persist_proptest_isset(PropTest * pt,const char * prop_name)1258 edsio_persist_proptest_isset (PropTest *pt, const char* prop_name)
1259 {
1260 if (! pt->ptable)
1261 return FALSE;
1262
1263 return g_hash_table_lookup (pt->ptable, prop_name) != NULL;
1264 }
1265
1266 gboolean
edsio_persist_proptest_unset(PropTest * pt,const char * prop_name)1267 edsio_persist_proptest_unset (PropTest *pt, const char* prop_name)
1268 {
1269 GByteArray* old;
1270
1271 if (! pt->ptable)
1272 return FALSE;
1273
1274 old = g_hash_table_lookup (pt->ptable, prop_name);
1275
1276 if (old)
1277 {
1278 g_byte_array_free (old, TRUE);
1279 g_hash_table_remove (pt->ptable, prop_name);
1280 return TRUE;
1281 }
1282
1283 return FALSE;
1284 }
1285
1286 #endif
1287
1288 /* Misc source/sink stuff
1289 */
1290
1291 SerialSink*
serializeio_gzip_sink(SerialSink * sink)1292 serializeio_gzip_sink (SerialSink* sink)
1293 {
1294 /* @@@ not implemented */
1295 return sink;
1296 }
1297
1298 SerialSource*
serializeio_gzip_source(SerialSource * source)1299 serializeio_gzip_source (SerialSource* source)
1300 {
1301 /* @@@ not implemented */
1302 return source;
1303 }
1304
1305 /* Checksum sink
1306 */
1307 typedef struct _ChecksumSink ChecksumSink;
1308
1309 static gboolean checksum_sink_close (SerialSink* sink);
1310 static gboolean checksum_sink_write (SerialSink* sink, const guint8 *ptr, guint32 len);
1311 static void checksum_sink_free (SerialSink* sink);
1312 static gboolean checksum_sink_quantum (SerialSink* sink);
1313
1314 struct _ChecksumSink
1315 {
1316 SerialSink sink;
1317
1318 SerialSink* out;
1319
1320 EdsioMD5Ctx ctx;
1321 guint8 md5[16];
1322 gboolean md5_done;
1323 gboolean md5_written;
1324 };
1325
1326 SerialSink*
serializeio_checksum_sink(SerialSink * out)1327 serializeio_checksum_sink (SerialSink* out)
1328 {
1329 ChecksumSink* it = g_new0 (ChecksumSink, 1);
1330 SerialSink* sink = (SerialSink*) it;
1331
1332 serializeio_sink_init (sink,
1333 NULL,
1334 checksum_sink_close,
1335 checksum_sink_write,
1336 checksum_sink_free,
1337 checksum_sink_quantum);
1338
1339 it->out = out;
1340
1341 edsio_md5_init (& it->ctx);
1342
1343 return sink;
1344 }
1345
1346 gboolean
checksum_sink_write(SerialSink * fsink,const guint8 * ptr,guint32 len)1347 checksum_sink_write (SerialSink* fsink, const guint8 *ptr, guint32 len)
1348 {
1349 ChecksumSink* sink = (ChecksumSink*) fsink;
1350
1351 if (! sink->out->sink_write (sink->out, ptr, len))
1352 return FALSE;
1353
1354 edsio_md5_update (& sink->ctx, ptr, len);
1355
1356 return TRUE;
1357 }
1358
1359 gboolean
checksum_sink_close(SerialSink * fsink)1360 checksum_sink_close (SerialSink* fsink)
1361 {
1362 ChecksumSink* sink = (ChecksumSink*) fsink;
1363
1364 if (! sink->md5_done)
1365 {
1366 edsio_md5_final (sink->md5, & sink->ctx);
1367 sink->md5_done = TRUE;
1368 }
1369
1370 if (! sink->out->sink_write (sink->out, sink->md5, 16))
1371 return FALSE;
1372
1373 if (! sink->out->sink_close (sink->out))
1374 return FALSE;
1375
1376 return TRUE;
1377 }
1378
1379 void
checksum_sink_free(SerialSink * fsink)1380 checksum_sink_free (SerialSink* fsink)
1381 {
1382 ChecksumSink* sink = (ChecksumSink*) fsink;
1383
1384 sink->out->sink_free (sink->out);
1385
1386 g_free (sink);
1387 }
1388
1389 gboolean
checksum_sink_quantum(SerialSink * fsink)1390 checksum_sink_quantum (SerialSink* fsink)
1391 {
1392 ChecksumSink* sink = (ChecksumSink*) fsink;
1393
1394 if (sink->out->sink_quantum)
1395 return sink->out->sink_quantum (sink->out);
1396
1397 return TRUE;
1398 }
1399
1400 /* Checksum source
1401 */
1402
1403 typedef struct _ChecksumSource ChecksumSource;
1404
1405 struct _ChecksumSource {
1406 SerialSource source;
1407
1408 SerialSource *in;
1409
1410 EdsioMD5Ctx ctx;
1411 };
1412
1413 static gboolean checksum_source_close (SerialSource* source);
1414 static gboolean checksum_source_read (SerialSource* source, guint8 *ptr, guint32 len);
1415 static void checksum_source_free (SerialSource* source);
1416
1417 SerialSource*
serializeio_checksum_source(SerialSource * in0)1418 serializeio_checksum_source (SerialSource* in0)
1419 {
1420 ChecksumSource* it = g_new0 (ChecksumSource, 1);
1421 SerialSource* source = (SerialSource*) it;
1422
1423 serializeio_source_init (source,
1424 NULL,
1425 checksum_source_close,
1426 checksum_source_read,
1427 checksum_source_free,
1428 NULL,
1429 NULL);
1430
1431 it->in = in0;
1432
1433 edsio_md5_init (& it->ctx);
1434
1435 return source;
1436 }
1437
1438 gboolean
checksum_source_close(SerialSource * fsource)1439 checksum_source_close (SerialSource* fsource)
1440 {
1441 ChecksumSource* source = (ChecksumSource*) fsource;
1442 guint8 buf1[16];
1443 guint8 buf2[16];
1444
1445 if (! source->in->source_read (source->in, buf1, 16))
1446 return FALSE;
1447
1448 edsio_md5_final (buf2, & source->ctx);
1449
1450 if (memcmp (buf1, buf2, 16) != 0)
1451 {
1452 edsio_generate_void_event (EC_EdsioInvalidStreamChecksum);
1453 return FALSE;
1454 }
1455
1456 if (! source->in->source_close (source->in))
1457 return FALSE;
1458
1459 return TRUE;
1460 }
1461
1462 gboolean
checksum_source_read(SerialSource * fsource,guint8 * ptr,guint32 len)1463 checksum_source_read (SerialSource* fsource, guint8 *ptr, guint32 len)
1464 {
1465 ChecksumSource* source = (ChecksumSource*) fsource;
1466
1467 if (! source->in->source_read (source->in, ptr, len))
1468 return FALSE;
1469
1470 edsio_md5_update (& source->ctx, ptr, len);
1471
1472 return TRUE;
1473 }
1474
1475 void
checksum_source_free(SerialSource * fsource)1476 checksum_source_free (SerialSource* fsource)
1477 {
1478 ChecksumSource* source = (ChecksumSource*) fsource;
1479
1480 source->in->source_free (source->in);
1481
1482 g_free (source);
1483 }
1484