2 * UDP Gateway utility packet assembly and disassembly layer
3 * Copyright (C) 2004 Jan Kratochvil <project-udpgate@jankratochvil.net>
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; exactly version 2 of June 1991 is required
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 #include <glib/gmessages.h>
23 #include <glib/gstring.h>
24 #include <glib/ghash.h>
25 #include <netinet/in.h>
27 #include <glib/gslist.h>
30 #include "main.h" /* for optarg_verbose */
33 static void packet_assembly_guint32(GString *gstring,guint32 value_guint32)
35 guint32 value_guint32_htonl;
37 g_return_if_fail(gstring!=NULL);
39 value_guint32_htonl=htonl(value_guint32);
40 g_assert(4==sizeof(value_guint32_htonl));
41 g_string_append_len(gstring,(const gchar *)&value_guint32_htonl,sizeof(value_guint32_htonl));
44 static void packet_assembly_guint16(GString *gstring,guint16 value_guint16)
46 guint16 value_guint16_htonl;
48 g_return_if_fail(gstring!=NULL);
50 value_guint16_htonl=htons(value_guint16);
51 g_assert(2==sizeof(value_guint16_htonl));
52 g_string_append_len(gstring,(const gchar *)&value_guint16_htonl,sizeof(value_guint16_htonl));
55 static void packet_assembly_data_guint32(GString *gstring,guint32 value_guint32)
57 g_return_if_fail(gstring!=NULL);
59 g_assert(4==sizeof(value_guint32));
60 packet_assembly_guint32(gstring,sizeof(value_guint32));
61 packet_assembly_guint32(gstring,value_guint32);
64 static void packet_assembly_data_guint16(GString *gstring,guint16 value_guint16)
66 g_return_if_fail(gstring!=NULL);
68 g_assert(2==sizeof(value_guint16));
69 packet_assembly_guint32(gstring,sizeof(value_guint16));
70 packet_assembly_guint16(gstring,value_guint16);
73 static void packet_assembly_data_string(GString *gstring,const gchar *string)
76 #ifndef G_DISABLE_ASSERT
77 size_t gstring_length_orig;
78 #endif /* !G_DISABLE_ASSERT */
80 g_return_if_fail(gstring!=NULL);
81 g_return_if_fail(string!=NULL);
83 string_length=strlen(string);
84 packet_assembly_guint32(gstring,string_length);
85 #ifndef G_DISABLE_ASSERT
86 gstring_length_orig=gstring->len;
87 #endif /* !G_DISABLE_ASSERT */
88 g_string_append(gstring,string);
89 #ifndef G_DISABLE_ASSERT
90 g_assert(gstring_length_orig+string_length==gstring->len);
91 #endif /* !G_DISABLE_ASSERT */
94 static void packet_assembly_foreach(gpointer elem_type_gpointer,gpointer value,GString *gstring /* user_data */) /* GHFunc */
96 guint32 elem_type_uint32;
98 g_return_if_fail(gstring!=NULL);
100 elem_type_uint32=GPOINTER_TO_UINT(elem_type_gpointer);
101 packet_assembly_guint32(gstring,elem_type_uint32);
103 switch (elem_type_uint32) {
104 case PACKET_ELEM_TYPE_PROGRAM_VERSION:
105 packet_assembly_data_string(gstring,value);
107 g_message(_("Assembled PROGRAM_VERSION: %s"),(const char *)value);
109 case PACKET_ELEM_TYPE_CLIENT_INADDR:
110 packet_assembly_data_guint32(gstring,GPOINTER_TO_UINT(value));
112 g_message(_("Assembled CLIENT_INADDR: %s"),HOSTIP_GUINT32_TO_STRING(GPOINTER_TO_UINT(value)));
114 case PACKET_ELEM_TYPE_DATA_GUINT32:
115 packet_assembly_data_guint32(gstring,GPOINTER_TO_UINT(value));
117 g_message(_("Assembled DATA_GUINT32: 0x%08X"),(unsigned)GPOINTER_TO_UINT(value));
119 case PACKET_ELEM_TYPE_CLIENT_PORT:
120 packet_assembly_data_guint16(gstring,GPOINTER_TO_UINT(value));
122 g_message(_("Assembled CLIENT_PORT: %d"),(int)GPOINTER_TO_UINT(value));
125 g_assert_not_reached();
129 void *packet_assembly(size_t *packet_length_pointer,GHashTable *values)
133 g_return_val_if_fail(packet_length_pointer!=NULL,NULL);
134 g_return_val_if_fail(values!=NULL,NULL);
137 g_message(_("Assembling packet..."));
139 gstring=g_string_new(NULL);
141 g_string_append(gstring,PACKET_HEADER);
143 packet_assembly_foreach(GINT_TO_POINTER(PACKET_ELEM_TYPE_PROGRAM_VERSION),VERSION,gstring);
144 g_hash_table_foreach(
145 values, /* hash_table */
146 (GHFunc)packet_assembly_foreach, /* func */
147 gstring); /* user_data */
150 g_message(_("Packet assembly done."));
152 *packet_length_pointer=gstring->len;
153 return g_string_free(gstring,
154 FALSE); /* free_segment */
157 static gboolean packet_disassembly_guint32
158 (guint32 *elem_type_guint32_pointer,gconstpointer *packet_pointer,gconstpointer packet_end)
160 g_return_val_if_fail(elem_type_guint32_pointer!=NULL,FALSE);
161 g_return_val_if_fail(packet_pointer!=NULL,FALSE);
162 g_return_val_if_fail(packet_end!=NULL,FALSE);
163 g_return_val_if_fail(*packet_pointer<=packet_end,FALSE);
165 if ((*packet_pointer)+sizeof(*elem_type_guint32_pointer)>packet_end)
168 *elem_type_guint32_pointer=ntohl(*((guint32 *)*packet_pointer));
169 (*packet_pointer)+=sizeof(*elem_type_guint32_pointer);
173 static void packet_disassembly_value_destroy_func(gpointer data) /* GDestroyNotify */
178 /* map: (GHashTable *) -> (GSList *) */
179 static GHashTable *packet_disassembly_destroy_registry;
181 static void packet_disassembly_destroy_key_destroy_func(GHashTable *hash) /* GDestroyNotify */
183 g_return_if_fail(hash!=NULL);
185 g_hash_table_destroy(hash);
188 static void packet_disassembly_destroy_value_destroy_func(GSList *items) /* GDestroyNotify */
190 /* 'items' may be NULL */
194 (GFunc)g_free, /* func */
195 NULL); /* user_data */
198 static void packet_disassembly_destroy_registry_init(void)
200 if (!packet_disassembly_destroy_registry) {
201 packet_disassembly_destroy_registry=g_hash_table_new_full(
202 g_direct_hash, /* hash_func */
203 g_direct_equal, /* key_equal_func */
204 (GDestroyNotify)packet_disassembly_destroy_key_destroy_func, /* key_destroy_func */
205 (GDestroyNotify)packet_disassembly_destroy_value_destroy_func); /* value_destroy_func */
209 void packet_disassembly_destroy(GHashTable *hash)
211 gboolean errgboolean;
213 g_return_if_fail(hash!=NULL);
215 packet_disassembly_destroy_registry_init();
217 errgboolean=g_hash_table_remove(packet_disassembly_destroy_registry,hash);
218 g_assert(errgboolean==TRUE);
221 static gboolean packet_disassembly_data_string
222 (gpointer *value_pointer,gconstpointer elem_data,guint32 elem_data_length_guint32,GSList **items_pointer)
226 g_return_val_if_fail(value_pointer!=NULL,FALSE);
227 g_return_val_if_fail(elem_data!=NULL,FALSE);
228 g_return_val_if_fail(items_pointer!=NULL,FALSE);
230 udpgate_newn(string,elem_data_length_guint32+1);
231 *items_pointer=g_slist_prepend(*items_pointer,string);
232 memcpy(string,elem_data,elem_data_length_guint32);
233 string[elem_data_length_guint32]='\0';
234 *value_pointer=string;
239 static gboolean packet_disassembly_data_guint32
240 (gpointer *value_pointer,gconstpointer elem_data,guint32 elem_data_length_guint32,GSList **items_pointer)
242 guint32 value_guint32;
244 g_return_val_if_fail(value_pointer!=NULL,FALSE);
245 g_return_val_if_fail(elem_data!=NULL,FALSE);
246 g_return_val_if_fail(items_pointer!=NULL,FALSE);
248 g_assert(4==sizeof(value_guint32));
249 if (elem_data_length_guint32!=sizeof(value_guint32))
252 value_guint32=ntohl(*(guint32 *)elem_data);
253 *value_pointer=GUINT_TO_POINTER(value_guint32);
258 static gboolean packet_disassembly_data_guint16
259 (gpointer *value_pointer,gconstpointer elem_data,guint32 elem_data_length_guint32,GSList **items_pointer)
261 guint16 value_guint16;
263 g_return_val_if_fail(value_pointer!=NULL,FALSE);
264 g_return_val_if_fail(elem_data!=NULL,FALSE);
265 g_return_val_if_fail(items_pointer!=NULL,FALSE);
267 g_assert(2==sizeof(value_guint16));
268 if (elem_data_length_guint32!=sizeof(value_guint16))
271 value_guint16=ntohs(*(guint16 *)elem_data);
272 *value_pointer=GUINT_TO_POINTER((guint)value_guint16);
277 gboolean packet_recognized(gconstpointer packet,size_t packet_length)
279 if (strlen(PACKET_HEADER)>packet_length)
281 if (memcmp(packet,PACKET_HEADER,strlen(PACKET_HEADER)))
286 GHashTable *packet_disassembly(gconstpointer packet,size_t packet_length)
289 gconstpointer packet_end;
292 g_return_val_if_fail(packet!=NULL,NULL);
295 g_message(_("Decoding packet..."));
297 r=g_hash_table_new_full(
298 g_direct_hash, /* hash_func */
299 g_direct_equal, /* key_equal_func */
300 NULL, /* key_destroy_func */
301 packet_disassembly_value_destroy_func); /* value_destroy_func */
302 packet_end=packet+packet_length;
304 if (packet+strlen(PACKET_HEADER)>packet_end) {
305 err_g_hash_table_destroy_r:
306 g_hash_table_destroy(r);
309 if (memcmp(packet,PACKET_HEADER,strlen(PACKET_HEADER)))
310 goto err_g_hash_table_destroy_r;
311 packet+=strlen(PACKET_HEADER);
314 while (packet<packet_end) {
315 guint32 elem_type_guint32;
316 guint32 elem_data_length_guint32;
317 gconstpointer elem_data;
320 if (!packet_disassembly_guint32(&elem_type_guint32,&packet,packet_end)) {
321 err_packet_disassembly_destroy_value_destroy_func_items:
322 /* 'items' are not yet registered in 'packet_disassembly_destroy_registry' */
323 packet_disassembly_destroy_value_destroy_func(items);
324 goto err_g_hash_table_destroy_r;
326 if (!packet_disassembly_guint32(&elem_data_length_guint32,&packet,packet_end))
327 goto err_packet_disassembly_destroy_value_destroy_func_items;
329 packet+=elem_data_length_guint32;
331 switch (elem_type_guint32) {
332 case PACKET_ELEM_TYPE_PROGRAM_VERSION:
333 if (!packet_disassembly_data_string(&value,elem_data,elem_data_length_guint32,&items))
334 goto err_packet_disassembly_destroy_value_destroy_func_items;
336 g_message(_("Decoded PROGRAM_VERSION: %s"),(const char *)value);
338 case PACKET_ELEM_TYPE_CLIENT_INADDR:
339 if (!packet_disassembly_data_guint32(&value,elem_data,elem_data_length_guint32,&items))
340 goto err_packet_disassembly_destroy_value_destroy_func_items;
342 g_message(_("Decoded CLIENT_INADDR: %s"),HOSTIP_GUINT32_TO_STRING(GPOINTER_TO_UINT(value)));
344 case PACKET_ELEM_TYPE_DATA_GUINT32:
345 if (!packet_disassembly_data_guint32(&value,elem_data,elem_data_length_guint32,&items))
346 goto err_packet_disassembly_destroy_value_destroy_func_items;
348 g_message(_("Decoded DATA_GUINT32: 0x%08X"),(unsigned)GPOINTER_TO_UINT(value));
350 case PACKET_ELEM_TYPE_CLIENT_PORT:
351 if (!packet_disassembly_data_guint16(&value,elem_data,elem_data_length_guint32,&items))
352 goto err_packet_disassembly_destroy_value_destroy_func_items;
354 g_message(_("Decoded CLIENT_PORT: %d"),GPOINTER_TO_UINT(value));
357 if (elem_type_guint32&PACKET_ELEM_ATTR_MANDATORY) {
359 g_message(_("Decoding failed on ATTR_MANDATORY ELEM code 0x%08X"),(unsigned)elem_type_guint32);
360 goto err_packet_disassembly_destroy_value_destroy_func_items;
364 g_message(_("Decoding ignores ATTR_OPTIONAL ELEM code 0x%08X"),(unsigned)elem_type_guint32);
368 g_hash_table_insert(r,GUINT_TO_POINTER(elem_type_guint32),value);
370 g_assert(packet==packet_end);
372 packet_disassembly_destroy_registry_init();
373 g_hash_table_insert(packet_disassembly_destroy_registry,r,items);
376 g_message(_("Decoding done."));