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(&lt, 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