Free allocated memory as soon as we're done with it. In many cases,
[obnox/wireshark/wip.git] / packet-giop.c
1 /* packet-giop.c
2  * Routines for CORBA GIOP/IIOP packet disassembly
3  *
4  * Initial Code by,
5  * Laurent Deniel <deniel@worldnet.fr>
6  * Craig Rodrigues <rodrigc@mediaone.net>
7  * 
8  * GIOP API extensions by,
9  * Frank Singleton <frank.singleton@ericsson.com>
10  * Trevor Shepherd <eustrsd@am1.ericsson.se>
11  *
12  * $Id: packet-giop.c,v 1.48 2001/08/28 07:19:47 guy Exp $
13  *
14  * Ethereal - Network traffic analyzer
15  * By Gerald Combs <gerald@ethereal.com>
16  * Copyright 1998 Gerald Combs
17  * 
18  * This program is free software; you can redistribute it and/or
19  * modify it under the terms of the GNU General Public License
20  * as published by the Free Software Foundation; either version 2
21  * of the License, or (at your option) any later version.
22  * 
23  * This program is distributed in the hope that it will be useful,
24  * but WITHOUT ANY WARRANTY; without even the implied warranty of
25  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
26  * GNU General Public License for more details.
27  * 
28  * You should have received a copy of the GNU General Public License
29  * along with this program; if not, write to the Free Software
30  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
31  */
32
33
34 /*
35  * TODO: -- FS
36  * 1. heuristic giop dissector table [started]
37  * 2. GUI options, see 20
38  * 3. Remove unneccessary reply_status in heuristic dissector calls (now 
39  *    part of MessageHeader) [done]
40  * 4. get_CDR_xxx should be passed an alignment offset value
41  *    rather than GIOP_HEADER_SIZE, as alignment can also change in a
42  *    octet stream when eg: encapsulation is used [done]
43  * 5. GIOP users should eventually get there own tvbuff, and
44  *    not rely on the GIOP tvbuff, more robust
45  * 6. get_CDR_string,wchar,wstring etc should handle different 
46  *    GIOP versions [started]
47  * 7. Fix situation where req_id is not unique in a logfile [done, use FN/MFN, needs improving.]
48  *
49  * 8. Keep request_1_2 in step with request_1_1 [started]
50  * 9. Explicit module name dissection [done]
51  * 10. Decode IOR and put in a useful struct [IOR decode started]
52  * 11. Fix encapsulation of IOR etc and boundary [done]
53  * 12. handle get_CDR_typeCode() [started]
54  * 13. Handle different IOR profiles
55  * 14. Change printable_string to RETURN a new string, not to modify the old.
56  *     or, new function, make_printable_string [done, make_printable_string]
57  *
58  * 15. Handle "TCKind", and forget about eg: enum translation to symbolic values
59  *     otherwise need knowledge of sub dissectors data - YUK [done]
60  * 16. Handle multiple RepoId representations, besides IDL:Echo:1.0 (see 13.)
61  * 17. Pass subset of RepoID to explicit dissector.
62  *     eg : If IDL:Mod1/Mod2/Int3:1.0 then pass "Mod1/Mode2/Int3" to sub dissector[done]
63  * 18. Better hashing algorithms
64  * 19. Handle hash collision properly .
65  * 20. Allow users to paste a stringified IOR into the GUI, and tie it
66  *     to a sub_dissector.
67  * 21. Add complete_request_packet_list and complete_reply_packet_hash.[done]
68  * 22. Handle case where users click in any order, AND try and match
69  *     REPLY msg to the correct REQUEST msg when we have a request_id collision.[done]
70  * 23. Clean up memory management for all those g_malloc's etc
71  * 24. register_giop_user_module could return a key for every distinct Module/Interface
72  *     the sub_dissector uses. So, instead of strcmp()'s when  handling the
73  *     namespace of an operation, we could have a lookup table instead.
74  * 25. A few typedefs in the right place.
75  * 26  Improve handling of gchar *  and use const gchar * where possible.
76  * 27. Read/write IOR etc to/from file, allows objkey hash to be built from
77  *     external data [read done, write incomplete]
78  * 28. Call sub dissector only if tvb_offset_exists(). [Done, this is checked
79  *     inside try_explicit_giop_dissector() ]
80  *     
81  * 29. Make add/delete routine for objkey hash as it may be useful when say reading 
82  *     stringified IOR's from a file to add them to our hash. ie: There are other ways
83  *     to populate our object key hash besides REPLY's to RESOLVE(request) [done]
84  *
85  * 30. Add routine to encode/decode stringified IOR's [decode done]
86  * 31. Add routine to read IOR's from file [done]
87  * 32. TypeCode -none-, needs decoding.
88  * 33. Complete dissect_data_for_typecode.
89  * 34. For complex TypeCodes need to check final offset against original offset + sequence length.
90  * 35. Update REQUEST/REPLY 1_2 according to IDL (eg; ServiceContextList etc).
91  * 36. Adding decode_ServiceContextList, incomplete. 
92  * 37. Helper functions should not ALWAYS rely on header to find  current endianess. It should
93  *     be passed from user, eg Use   stream_is_big_endian. [started]
94  * 38. Remove unwanted/unused function parameters, see decode_IOR [started]
95  * 40. Add sequence <IOP::TaggedComponent> components to IIOP IOR profile. Perhaps 
96  *     decode_IOP_TaggedComponents as a helper function. [done - NOT helper]
97  *
98  * 41. Make important field searchable from Message header. ie: Remove add_text_
99  * 42. Use sub-tree for decode_ServiceContextList, looks better.
100  * 43. dissect_reply_body, no exception dissector calls
101  *       - call subdiss directly, as we already have handle.
102  *       - add repoid to heuristic call also.
103  *
104  * 44. typedef using xxx_t in .h file.
105  * 45. Subdissectors should not be passed MessageHeader to find endianness and
106  *     version, they should be passed directly ?
107  * 46. get_CDR_wchar and wstring need wide chars decoded (just dumped in
108  *     any readable form at present, not handled well at all, suggestions welcome -- FS
109  * 47. Change ...add_text to ...add_xxx (ie use hf fields).
110  *
111  * 48. BUG - file load with a GIOP filter set, causes the FN/MFN data struct to be
112  *     not initiated properly. Hit "Reload" as a workaround, til I fix this -- FS
113  *
114  */
115
116
117
118 /*
119  * Intended Decode strategy:
120  * =========================
121  *
122  * Initial Pass
123  * ------------
124  * REQUEST: objkey -> Repo_ID -> Module/Interface -> giop_sub_handle_t
125  *          and populate complete_request_packet_hash
126  *
127  * REPLY:   FN -> MFN (via complete_reply_packet_hash) = Request FN -> giop_sub_handle_t
128  *
129  * User Clicks
130  * -----------
131  *
132  * REQUEST: FN -> giop_sub_handle_t directly (via complete_request_packet_hash)
133  *
134  * REPLY:   FN -> MFN (via complete_reply_packet_hash) = Request FN -> giop_sub_handle_t
135  *                                                                     (via complete_request_packet_hash
136  *
137  *
138  * Limitations. 
139  * ============
140  *
141  * 1. Request_ID's are unique only per connection.
142  *
143  * 2. You must be monitoring the network when the client does
144  *    a REQUEST(resolve), otherwise I have no knowledge of the
145  *    association between object_key and REPOID. I could talk to 
146  *    a Nameserver, but then I would start "generating" packets.
147  *    This is probably not a good thing for a protocol analyser.
148  *    Also, how could I decode logfiles offline.
149  *
150  *    TODO -- Read stringified IORs from an input file.[done]
151  *
152  * 3. User clicks (REQUEST) is currently handle the same as
153  *    the initial pass handling.
154  *
155  *    ie: objkey -> Repo_ID -> Module/Interface -> giop_sub_handle_t
156  */
157
158
159 /*
160  * Important Data Structures:
161  *
162  * giop_module_hash 
163  * ----------------
164  *
165  * This is a hash table that maps IDL Module/Interface Names (Key)
166  * to sub_dissector handles, giop_sub_handle_t. It is populated
167  * by subdissectors, via register_giop_user_module(). This
168  * table is used when we have a REPOID, and explicitly wish to
169  * call the subdissector that has registered responsibility for
170  * that IDL module/interface.
171  *
172  * 
173  * giop_sub_list
174  * -------------
175  *
176  * This singly linked list is used to hold entries for
177  * heuristic based subdissectors. It is populated by sub_dissectors
178  * wishing to be called via heuristic mechanisms. They do this
179  * via the register_giop_user() function.
180  *
181  * 
182  * giop_objkey_hash
183  * ----------------
184  *
185  * This hash table maps object_key's (key) onto REPOID's (val).
186  * Once a client has REQUEST(resolve) an object , it knows about
187  * an object (interface) via its object_key (see IOR). So in order to follow
188  * packets that contain an object_key only, and to be able to forward it
189  * to the correct explicit subdissector, we need this table.
190  *
191  * So, I listen in on REQUEST(resolve) messages between client and
192  * Nameserver, and store the respones (REPLY/Objkey,Repo_ID) here.
193  *
194  * Also, stringified IOR's can be read from a file "IOR.txt" and used
195  * to populate  this hash also.
196  *
197  *
198  * Other Data structures 
199  * =======================
200  *
201  * These structures have  been added to minimise the possibility
202  * of incorrectly interpreted packets when people click all
203  * over the place, in no particular order, when the request_id's are
204  * not unique as captured. If all request_is'd are unique, as captured, then
205  * we would not have to deal with this problem.
206  *
207  *
208  * When the logfile or packets are initially being processed, I will
209  * build 2 structures. The intent is to be able to map a REPLY message
210  * back to the most recent REQUEST message with the same Request_ID
211  * (TODO and matching port and IP address ??)
212  * 
213  * Abbrevs:
214  * --------
215  *
216  * FN  - Frame Number
217  * MFN - Matching Frame Number
218  *
219  *
220  * complete_request_packet_list
221  * ----------------------------
222  *
223  * This is a list that contains ALL the FN's that are REQUEST's, along with 
224  * operation,request_id and giop_sub_handle_t
225  *
226  * complete_reply_packet_hash
227  * --------------------------
228  *
229  * This is a hash table. It is populated with FN (key) and MFN (val).
230  * This allows me to handle the case, where if you click on any REPLY
231  * message, I can lookup the matching request. This can improve
232  * the match rate between REQUEST and REPLY when people click in
233  * any old fashion, but is NOT foolproof. 
234  *
235  * The algorithm I use to populate this hash during initial pass,
236  * is as follows. 
237  *
238  * If packet is a REPLY, note the reqid, and then traverse backwards
239  * through the complete_request_packet_list from its tail, looking
240  * for a FN that has the same Request_id. Once found, take the found FN
241  * from complete_reply_packet_hash, and insert it into the MFN field
242  * of the complete_reply_packet_hash.
243  *
244  *
245  * See TODO for improvements to above algorithm.
246  *
247  * So now when people click on a REQUEST packet, I can call lookup the
248  * giop_sub_handle_t directly from complete_request_packet_list.
249  *
250  * And, when they click on a REPLY, I grab the MFN of this FN from
251  * complete_reply_packet_hash, then look that up in the complete_request_packet_list
252  * and call the sub_dissector directly.
253  *
254  * So, how do I differentiate between the initial processing of incoming
255  * packets, and a user clickin on one ? Good question.
256  *
257  * I leverage the pinfo_fd->flags.visited  on a per frame
258  * basis. 
259  *
260  * To quote from the ever helpful development list
261  *
262  * " When a capture file is initially loaded, all "visited" flags
263  * are 0. Ethereal then makes the first pass through file,
264  * sequentially dissecting each packet. After the packet is
265  * dissected the first time, "visited" is 1. (See the end of
266  * dissect_packet() in epan/packet.c; that's the code that
267  * sets "visited" to 1).
268
269  * By the time a user clicks on a packet, "visited" will already
270  * be 1 because Ethereal will have already done its first pass
271  * through the packets.
272
273  * Reload acts just like a normal Close/Open, except that it
274  * doesn't need to ask for a filename. So yes, the reload button
275  * clears the flags and re-dissects the file, just as if the file
276  * had been "opened".  "
277  *
278  */
279
280
281 #ifdef HAVE_CONFIG_H
282 # include "config.h"
283 #endif
284
285 #ifdef HAVE_SYS_TYPES_H
286 # include <sys/types.h>
287 #endif
288
289 #include <string.h>
290 #include <stdio.h>
291 #include <errno.h>
292 #include <ctype.h>
293 #include <glib.h>
294 #include <math.h>
295 #ifdef NEED_STRERROR_H
296 #include "strerror.h"
297 #endif
298
299 #include "packet.h"
300 #include "packet-giop.h"
301
302 /*
303  * This affects how we handle context_data inside ServiceContext structs.
304  * According to CORBA 2.4.2,  Context data is encapsulated in octet sequences,
305  * but so far I haven't seen the that on the wire. But, maybe its me -- FS 
306  *
307  */
308
309 #define CONTEXT_DATA_IS_ENCAPSULATED  0
310
311
312 /*
313  * Set to 1 for DEBUG output - TODO make this a runtime option
314  */
315
316 #define DEBUG   0
317
318
319
320 /*
321  * ------------------------------------------------------------------------------------------+ 
322  *                                 Private Helper function Declarations
323  * ------------------------------------------------------------------------------------------+
324  */
325
326
327 static void decode_IIOP_IOR_profile(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int *offset,
328                                     guint32 boundary, gboolean new_endianess, gchar *repobuf,
329                                     gboolean store_flag);
330
331 static void decode_ServiceContextList(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int *offset,
332                                       gboolean stream_is_be, guint32 boundary);
333
334 static void decode_TaggedProfile(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int *offset,
335                                  guint32 boundary, gboolean stream_is_big_endian, gchar *repobuf);
336
337 static void decode_IOR(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int *offset,
338                        guint32 boundary, gboolean stream_is_big_endian );
339
340 static void decode_SystemExceptionReplyBody (tvbuff_t *tvb, proto_tree *tree, gint *offset,
341                                              gboolean stream_is_big_endian,
342                                              guint32 boundary);
343
344 static void dissect_tk_objref_params(tvbuff_t *tvb, proto_tree *tree, gint *offset, 
345                                      gboolean stream_is_big_endian, guint32 boundary,
346                                      MessageHeader * header);
347
348 static void dissect_tk_struct_params(tvbuff_t *tvb, proto_tree *tree, gint *offset, 
349                                      gboolean stream_is_big_endian, guint32 boundary,
350                                      MessageHeader * header);
351
352 static void dissect_tk_union_params(tvbuff_t *tvb, proto_tree *tree, gint *offset, 
353                                     gboolean stream_is_big_endian, guint32 boundary,
354                                     MessageHeader * header );
355  
356 static void dissect_tk_enum_params(tvbuff_t *tvb, proto_tree *tree, gint *offset, 
357                                    gboolean stream_is_big_endian, guint32 boundary,
358                                    MessageHeader * header);
359
360 static void dissect_tk_sequence_params(tvbuff_t *tvb, proto_tree *tree, gint *offset, 
361                                        gboolean stream_is_big_endian, guint32 boundary,
362                                        MessageHeader * header);
363
364 static void dissect_tk_array_params(tvbuff_t *tvb, proto_tree *tree, gint *offset, 
365                                     gboolean stream_is_big_endian, guint32 boundary,
366                                     MessageHeader * header);
367
368 static void dissect_tk_alias_params(tvbuff_t *tvb, proto_tree *tree, gint *offset, 
369                                     gboolean stream_is_big_endian, guint32 boundary,
370                                     MessageHeader * header);
371
372 static void dissect_tk_except_params(tvbuff_t *tvb, proto_tree *tree, gint *offset, 
373                                      gboolean stream_is_big_endian, guint32 boundary,
374                                      MessageHeader * header);
375
376 static void dissect_tk_value_params(tvbuff_t *tvb, proto_tree *tree, gint *offset, 
377                                     gboolean stream_is_big_endian, guint32 boundary,
378                                     MessageHeader * header);
379
380 static void dissect_tk_value_box_params(tvbuff_t *tvb, proto_tree *tree, gint *offset, 
381                                         gboolean stream_is_big_endian, guint32 boundary,
382                                         MessageHeader * header);
383
384 static void dissect_tk_native_params(tvbuff_t *tvb, proto_tree *tree, gint *offset, 
385                                      gboolean stream_is_big_endian, guint32 boundary,
386                                      MessageHeader * header);
387
388 static void dissect_tk_abstract_interface_params(tvbuff_t *tvb, proto_tree *tree, gint *offset, 
389                                                  gboolean stream_is_big_endian, guint32 boundary,
390                                                  MessageHeader * header);
391
392
393 static void dissect_typecode_string_param(tvbuff_t *tvb, proto_tree *tree, gint *offset, 
394                                           gboolean new_stream_is_big_endian, guint32 new_boundary, int hf_id );
395
396 static void dissect_data_for_typecode(tvbuff_t *tvb, proto_tree *tree, gint *offset, 
397                                       gboolean stream_is_big_endian, guint32 boundary,
398                                       MessageHeader * header, guint32 data_type );
399
400
401
402
403 /*
404  * ------------------------------------------------------------------------------------------+ 
405  *                                 Data/Variables/Structs
406  * ------------------------------------------------------------------------------------------+
407  */
408
409
410 static int proto_giop = -1;
411 static int hf_giop_message_type = -1;
412 static int hf_giop_message_size = -1;
413 static int hf_giop_repoid = -1;
414 static int hf_giop_string_length = -1;
415 static int hf_giop_sequence_length = -1;
416 static int hf_giop_profile_id = -1;
417 static int hf_giop_type_id = -1;
418 static int hf_giop_iiop_v_maj = -1;
419 static int hf_giop_iiop_v_min = -1;
420 static int hf_giop_endianess = -1; /* esp encapsulations */
421 static int hf_giop_IOR_tag = -1; 
422 static int hf_giop_IIOP_tag = -1;
423
424 static int hf_giop_TCKind = -1;
425 static int hf_giop_typecode_count = -1;
426 static int hf_giop_typecode_default_used = -1;
427 static int hf_giop_typecode_digits = -1;
428 static int hf_giop_typecode_length = -1;
429 static int hf_giop_typecode_max_length = -1;
430 static int hf_giop_typecode_member_name = -1;
431 static int hf_giop_typecode_name = -1;
432 static int hf_giop_typecode_scale = -1;
433 static int hf_giop_typecode_ValueModifier = -1;
434 static int hf_giop_typecode_Visibility = -1;
435
436 static int hf_giop_type_boolean = -1;
437 static int hf_giop_type_char = -1;
438 static int hf_giop_type_double = -1;
439 static int hf_giop_type_enum = -1;
440 static int hf_giop_type_float = -1;
441 static int hf_giop_type_long = -1;
442 static int hf_giop_type_octet = -1;
443 static int hf_giop_type_short = -1;
444 static int hf_giop_type_string = -1;
445 static int hf_giop_type_ulong = -1;
446 static int hf_giop_type_ushort = -1;
447
448 static int hf_giop_iiop_host = -1; 
449 static int hf_giop_iiop_port = -1; 
450 static int hf_giop_iop_vscid = -1;
451 static int hf_giop_iop_scid = -1;
452
453 /*
454  * (sub)Tree declares
455  */
456
457 static gint ett_giop = -1;
458 static gint ett_giop_reply = -1;
459 static gint ett_giop_request = -1;
460 static gint ett_giop_cancel_request = -1;
461 static gint ett_giop_locate_request = -1;
462 static gint ett_giop_locate_reply = -1;
463 static gint ett_giop_fragment = -1;
464
465 static gint ett_giop_scl = -1;  /* ServiceContextList */
466 static gint ett_giop_ior = -1;  /* IOR  */
467
468
469 /* GIOP endianess */
470
471 static const value_string giop_endianess_vals[] = {
472   { 0x0, "Big Endian" },
473   { 0x1, "Little Endian" },
474   { 0, NULL}
475 };
476
477 static const value_string sync_scope[] = {
478         { 0x0, "SYNC_NONE" },
479         { 0x1, "SYNC_WITH_TRANSPORT"},
480         { 0x2, "SYNC_WITH_SERVER"},
481         { 0x3, "SYNC_WITH_TARGET"},
482         { 0, NULL}
483 };
484
485 /* Profile ID's */
486
487 static const value_string profile_id_vals[] = {
488         { 0x0, "TAG_INTERNET_IOP" },
489         { 0x1, "TAG_MULTIPLE_COMPONENTS"},
490         { 0x2, "TAG_SCCP_IOP"},
491         { 0, NULL}
492 };
493
494 static const value_string giop_message_types[] = {
495         { 0x0, "Request" },
496         { 0x1, "Reply"},
497         { 0x2, "CancelRequest"},
498         { 0x3, "LocateRequest"},
499         { 0x4, "LocateReply"},
500         { 0x5, "CloseConnection"},
501         { 0x6, "MessageError"},
502         { 0x7, "Fragment"},
503         { 0, NULL}
504 };
505
506 static const value_string giop_locate_status_types[] = {
507         { 0x0, "Unknown Object" },
508         { 0x1, "Object Here"},
509         { 0x2, "Object Forward"},
510         { 0x3, "Object Forward Perm"},
511         { 0x4, "Loc System Exception"},
512         { 0x5, "Loc Needs Addressing Mode"},
513         { 0, NULL }     
514 };
515
516 static const value_string tckind_vals[] = {
517   { 0, "tk_null"},
518   { 1, "tk_void"},
519   { 2, "tk_short"},
520   { 3, "tk_long"},
521   { 4, "tk_ushort"},
522   { 5, "tk_ulong"},
523   { 6, "tk_float"},
524   { 7, "tk_double"},
525   { 8, "tk_boolean"},
526   { 9, "tk_char"},
527   { 10, "tk_octet"},
528   { 11, "tk_any"},
529   { 12, "tk_TypeCode"},
530   { 13, "tk_Principal"},
531   { 14, "tk_objref"},
532   { 15, "tk_struct"},
533   { 16, "tk_union"},
534   { 17, "tk_enum"},
535   { 18, "tk_string"},
536   { 19, "tk_sequence"},
537   { 20, "tk_array"},
538   { 21, "tk_alias"},
539   { 22, "tk_except"},
540   { 23, "tk_longlong"},
541   { 24, "tk_ulonglong"},
542   { 25, "tk_longdouble"},
543   { 26, "tk_wchar"},
544   { 27, "tk_wstring"},
545   { 28, "tk_fixed"},
546   { 29, "tk_value"},
547   { 30, "tk_value_box"},
548   { 31, "tk_native"},
549   { 32, "tk_abstract_interface"},
550   { 0, NULL }   
551 };
552
553
554
555 #define GIOP_MAGIC       "GIOP"
556
557 /*
558  * TAGS for IOR Profiles
559  *
560  * Chapter 13 Corba 2.4.2
561  *
562  */
563
564 #define IOP_TAG_INTERNET_IOP          0
565 #define IOP_TAG_MULTIPLE_COMPONENTS   1
566
567
568 /* Max Supported versions */
569
570 static const guint GIOP_MAJOR =  1;
571 static const guint GIOP_MINOR =  2;
572
573
574 static const int KeyAddr       = 0;
575 static const int ProfileAddr   = 1;
576 static const int ReferenceAddr = 2;
577
578
579
580 static const value_string reply_status_types[] = { 
581    { NO_EXCEPTION, "No Exception" } ,
582    { USER_EXCEPTION, "User Exception" } ,
583    { SYSTEM_EXCEPTION, "System Exception" } ,
584    { LOCATION_FORWARD, "Location Forward" } ,
585    { LOCATION_FORWARD_PERM, "Location Forward Perm" } ,
586    { NEEDS_ADDRESSING_MODE, "Needs Addressing Mode" } ,
587    { 0, NULL }
588 };
589
590
591
592 typedef enum LocateStatusType
593 {
594   UNKNOWN_OBJECT,
595   OBJECT_HERE,
596   OBJECT_FORWARD,
597   OBJECT_FORWARD_PERM,      /* new value for GIOP 1.2 */
598   LOC_SYSTEM_EXCEPTION,     /* new value for GIOP 1.2 */
599   LOC_NEEDS_ADDRESSING_MODE /* new value for GIOP 1.2 */
600 }
601 LocateStatusType_t;
602
603 typedef struct LocateReplyHeader
604 {
605   guint32 request_id;
606   guint32 locate_status;
607 }
608 LocateReplyHeader_t;
609
610
611 /*
612  * DATA - complete_request_list 
613  */
614
615 static GList *giop_complete_request_list;
616
617 struct comp_req_list_entry {
618   guint32 fn;                   /* frame number */
619   gchar * operation;            /* echo echoString */
620   giop_sub_handle_t *subh;      /* handle to sub dissector */
621   guint32 reqid;                /* request id */  
622   gchar * repoid;               /* repository ID */
623 };
624
625 typedef struct comp_req_list_entry comp_req_list_entry_t;
626
627
628 /*
629  * DATA - complete_reply_hash
630  *
631  * Maps reply FN to request MFN
632  */
633
634 static int complete_reply_hash_count = 1000; /* storage size for our permanent data */
635                                              /* ie: 1000 entries -- needs tweaking -- FS */
636
637 struct complete_reply_hash_key {
638   guint32 fn;                   /* reply frame number  */
639 };
640
641 struct complete_reply_hash_val {
642   guint32 mfn;                  /* matching frame number (request)  */
643 };
644
645 GHashTable *giop_complete_reply_hash = NULL; /* hash */
646 GMemChunk  *giop_complete_reply_keys = NULL; /* key storage */
647 GMemChunk  *giop_complete_reply_vals = NULL; /* val storage */
648
649
650 /*
651  * DATA - Module Hash stuff to store data from register_giop_user_module
652  *
653  * ie: module (or interface ?) name, and ptr to sub_dissector handle
654  *
655  * With this knowledge, we can call a sub dissector directly, 
656  * by :
657  * 
658  * objkey -> repoid -> sub_dissector via registered module/interface
659  *
660  */
661
662
663 static int giop_module_init_count = 100; /* storage size for our permanent data */
664                                          /* ie: 100 entries -- needs tweaking -- FS */
665
666 struct giop_module_key {
667   gchar *module;                /* module (interface?) name  */
668 };
669
670 struct giop_module_val {
671   giop_sub_handle_t *subh;      /* handle to sub dissector */
672 };
673
674 GHashTable *giop_module_hash = NULL; /* hash */
675 GMemChunk  *giop_module_keys = NULL; /* key storage */
676 GMemChunk  *giop_module_vals = NULL; /* val storage */
677
678
679 /*
680  * DATA - GSList to store list of function (dissector) pointers.
681  * for heuristic dissection.
682  *
683  */
684
685 static GSList *giop_sub_list = NULL;
686
687 /*
688  * DATA - Hash stuff to follow request/reply. This is so if we get a REPLY
689  * to a REQUEST (resolve), we can dump/store the RepoId and Object Key.
690  *
691  * With this knowledge, we can call a sub dissector directly later
692  * by :
693  * 
694  * objkey -> repoid -> sub_dissector via registered module/interface
695  *
696  * rather than heuristic calls that do not provide operation context.
697  * (unless we pass the RepoID for a given objkey -- hmmm)
698  *
699  */
700
701 /*
702  * Interesting operation list, add more if you want to save
703  * interesting data.
704  */
705
706 static const char  giop_op_resolve[]           = "resolve";
707 static const char  giop_op_bind_new_context[]  = "bind_new_context";
708 static const char  giop_op_bind[]              = "bind";
709
710 /*
711  * Enums  for interesting local operations, that we may need to monitor
712  * with their subsequent replies
713  * 
714  */
715
716 enum giop_op_val {
717   request_resolve_op_val,            /* REQUEST (resolve) to get RepoID etc*/
718   request_bind_new_context_op_val,   /* bind_new_context */
719   request_bind_op_val,               /* bind */
720   request_get_INIT_op_val,           /* finding Nameserver */
721
722 };
723
724
725 /*
726  * hash for mapping object keys onto object namespaces, so
727  * I can call the correct dissector.
728  *
729  *
730  */
731
732 /*
733  * Where did I get the IOR from.
734  */
735
736 enum ior_src {
737   req_res = 0,                  /* REQUEST (resolve) */
738   file,                         /* stringified IOR' in a file */
739
740 };
741
742 typedef enum ior_src ior_src_t;
743
744
745
746 /*
747  * Enums for my lists and hash's 
748  */
749
750 enum collection_data {
751   cd_heuristic_users = 0,
752   cd_module_hash,
753   cd_objkey_hash,
754   cd_complete_request_list,
755   cd_complete_reply_hash
756 };
757
758 typedef enum collection_data collection_data_t;
759
760
761
762 static int giop_objkey_init_count = 100; /* storage size for our permanent data */
763                                          /* ie: 100 entries -- needs tweaking -- FS */
764
765 struct giop_object_key {
766   guint8 *objkey;               /* ptr to object key */
767   guint32 objkey_len;           /* length */
768 };
769
770 struct giop_object_val { 
771   guint8 *repo_id;              /* ptr to Repository ID string */
772   ior_src_t src;                /* where did Iget this IOR from */
773 };
774
775 GHashTable *giop_objkey_hash = NULL; /* hash */
776 GMemChunk  *giop_objkey_keys = NULL; /* key storage */
777 GMemChunk  *giop_objkey_vals = NULL; /* val storage */
778
779
780
781 /*
782  * ------------------------------------------------------------------------------------------+ 
783  *                                 Private helper functions
784  * ------------------------------------------------------------------------------------------+
785  */
786
787
788
789 /*
790  * Insert FN,reqid,operation and sub handle in list. DOES not check for duplicates yet.
791  */
792
793 static GList *insert_in_comp_req_list(GList *list, guint32 fn, guint32 reqid, gchar * op, giop_sub_handle_t *sh ) {
794   GList * newlist_start;
795   comp_req_list_entry_t * entry = NULL;
796   gchar * opn;
797
798   entry =  g_malloc(sizeof(comp_req_list_entry_t));
799   opn =  g_strdup(op); /* duplicate operation for storage */
800     
801   entry->fn = fn;
802   entry->reqid = reqid;
803   entry->subh = sh;             
804   entry->operation = opn;       
805   entry->repoid = NULL;         /* dont have yet */
806
807   newlist_start = g_list_append (list, entry); /* append */
808
809   return newlist_start;
810 }
811
812
813 /*
814  * Used to find an entry with matching Frame Number FN
815  * in the complete_request_list list.
816  */
817
818 static comp_req_list_entry_t * find_fn_in_list(guint32 fn) {
819
820   GList * element;              /*  entry in list */
821   comp_req_list_entry_t * entry_ptr = NULL;
822   
823   element = g_list_last(giop_complete_request_list); /* start from  last  */
824   
825   while(element) {                      /* valid list entry */
826     entry_ptr = element->data;  /* grab data pointer */
827     if (entry_ptr->fn == fn) {  /* similar FN  */
828       return entry_ptr;
829     }    
830     element = g_list_previous(element); /* try next previous */
831   }
832   
833   return NULL;                  /* no match so return NULL */
834 }
835
836
837 /*
838  * Add/update a sub_dissector handle and repoid to a FN entry in the complete_request_list
839  *
840  * Call this when you know a FN and matching giop_sub_handle_t and repoid
841  *
842  * This is done in say, try_explicit_dissector for example.
843  *
844  */
845
846 static void add_sub_handle_repoid_to_comp_req_list(guint32 fn, giop_sub_handle_t *sh, gchar *repoid ) {
847
848   comp_req_list_entry_t * entry = NULL;
849   entry = find_fn_in_list(fn);  /* grab FN data entry */
850
851   if (entry) {
852     entry->subh = sh;           
853     entry->repoid = g_strdup(repoid); /* copy and store */
854
855   }
856 }
857
858
859
860
861 /* giop_complete_reply_hash  "EQUAL" Functions */
862
863 static gint complete_reply_equal_fn(gconstpointer v, gconstpointer w) {
864   struct complete_reply_hash_key *mk1 = (struct complete_reply_hash_key *)v;
865   struct complete_reply_hash_key *mk2 = (struct complete_reply_hash_key *)w;
866
867   if (mk1->fn == mk2->fn) {    
868     return 1;
869   }
870
871   return 0;                     /* found  differences */
872 }
873
874 /* giop_complete_reply_hash "HASH" Functions */
875
876 static guint32 complete_reply_hash_fn(gconstpointer v) {
877   guint32 val;          /* init hash value */
878   struct complete_reply_hash_key *key = (struct complete_reply_hash_key *)v;
879
880   val = key->fn;                /* simple and unique */
881
882   return val;
883 }
884
885
886 /*
887  * Insert the FN and MFN together in our complete_reply_hash.
888  */
889
890 static void insert_in_complete_reply_hash(guint32 fn, guint32 mfn) {
891
892   struct complete_reply_hash_key key, *new_key;
893   struct complete_reply_hash_val *val = NULL;
894
895   key.fn = fn;
896
897   val = (struct complete_reply_hash_val *)g_hash_table_lookup(giop_complete_reply_hash, &key);
898
899   if (val) {
900     return;                     /* FN collision */
901   }
902
903   new_key = g_mem_chunk_alloc(giop_complete_reply_keys);
904   new_key->fn = fn;             /* save FN */
905
906   val = g_mem_chunk_alloc(giop_complete_reply_vals);
907   val->mfn = mfn;               /* and MFN */
908   
909   g_hash_table_insert(giop_complete_reply_hash, new_key, val);
910
911 }
912
913 /*
914  * Find the MFN values from a given FN key.
915  * Assumes the complete_reply_hash is already populated.
916  */
917
918 static guint32 get_mfn_from_fn(guint32 fn) {
919
920   struct complete_reply_hash_key key;
921   struct complete_reply_hash_val *val = NULL;
922   guint32 mfn = fn;             /* save */
923
924   key.fn = fn;
925   val = (struct complete_reply_hash_val *)g_hash_table_lookup(giop_complete_reply_hash, &key);
926
927   if (val) {
928     mfn = val->mfn;             /* grab it */
929   }
930   
931   return mfn;                   /* mfn or fn if not found */
932
933 }
934
935 /*
936  * Attempt to find the MFN for this FN, and return it.
937  * Return MFN if found, or just FN if not. This is
938  * only used when we are building
939  */
940
941 static guint32 get_mfn_from_fn_and_reqid(guint32 fn, guint32 reqid) {
942
943   GList * element;              /* last entry in list */
944   comp_req_list_entry_t * entry_ptr = NULL;
945
946   /* Need Some pretty snappy code */
947   
948   /* Loop back from current end of complete_request_list looking for */
949   /* a FN with the same reqid -- TODO enhance with port/address checks -- FS */
950
951   /*
952    * As this routine is only called during initial pass of data,
953    * and NOT when a user clicks, it is ok to start from Current
954    * end of complete_request_list when searching for a match.
955    * As that list is bing populated in the same order as FN's
956    * are being read.
957    *
958    * Also, can make check for same reqid more detailed, but I start
959    * with reqid. Could add say port or address checks etc later ??
960    */
961
962
963   element = g_list_last(giop_complete_request_list); /* get last  */
964   
965   while(element) {                      /* valid list entry */
966     entry_ptr = element->data;  /* grab data pointer */
967     if (entry_ptr->reqid == reqid) {    /* similar reqid  */
968       return entry_ptr->fn;     /* return MFN */
969     }    
970     element = g_list_previous(element); /* try next previous */
971   }
972   
973   return fn;                    /* no match so return FN */
974 }
975
976
977 /* Module Hash "EQUAL" Functions */
978
979 static gint giop_hash_module_equal(gconstpointer v, gconstpointer w) {
980   struct giop_module_key *mk1 = (struct giop_module_key *)v;
981   struct giop_module_key *mk2 = (struct giop_module_key *)w;
982   
983   if (!strcmp(mk1->module, mk2->module)) {    
984     return 1;
985   }
986
987   return 0;                     /* found  differences */
988 }
989
990 /* Module Hash "HASH" Functions */
991
992 static guint32 giop_hash_module_hash(gconstpointer v) {
993   
994   int i,len;
995   guint32 val = 0;              /* init hash value */
996
997   struct giop_module_key *key = (struct giop_module_key *)v;
998   
999   /*
1000    * Hmm, try this simple hashing scheme for now.
1001    * ie: Simple summation, FIX later -- FS
1002    *
1003    *
1004    */
1005
1006   len = strlen(key->module);
1007
1008   for (i=0; i<len; i++) {
1009     val += (guint8) key->module[i];
1010   }
1011
1012   return val;
1013
1014 }
1015
1016
1017 /*
1018  * ------------------------------------------------------------------------------------------+ 
1019  *                                 Public Utility functions
1020  * ------------------------------------------------------------------------------------------+
1021  */
1022
1023
1024
1025
1026 /*
1027  * Routine to  allow giop users to register their sub dissector function, name, and
1028  * IDL module/interface name. Store in giop_module_hash. Also pass along their proto_XXX
1029  * value returned from their proto_register_protocol(), so we can enable/disbale it
1030  * through the GUI (edit protocols).
1031  *
1032  * This is used by try_explicit_giop_dissector() to find the
1033  * correct sub-dissector.
1034  *
1035  */
1036
1037 void register_giop_user_module(giop_sub_dissector_t *sub, gchar *name, gchar *module, int sub_proto) {
1038
1039   struct giop_module_key module_key, *new_module_key;
1040   struct giop_module_val *module_val = NULL;
1041
1042   module_key.module = module; /*  module name */
1043   
1044   module_val = (struct giop_module_val *)g_hash_table_lookup(giop_module_hash, &module_key);
1045
1046   if (module_val) {
1047     return;                     /* module name collision */
1048   }
1049   
1050   /* So, passed module name should NOT exist in hash at this point.*/
1051
1052 #if DEBUG    
1053   printf("giop:register_module: Adding Module %s to module hash \n", module);
1054   printf("giop:register_module: Module sub dissector name is %s \n", name);
1055 #endif
1056
1057   new_module_key = g_mem_chunk_alloc(giop_module_keys);
1058   new_module_key->module = module; /* save Module or interface name from IDL */
1059   
1060   module_val = g_mem_chunk_alloc(giop_module_vals);
1061
1062   module_val->subh = g_malloc(sizeof (giop_sub_handle_t)); /* init subh  */
1063
1064   module_val->subh->sub_name = name;    /* save dissector name */
1065   module_val->subh->sub_fn = sub;       /* save subdissector*/
1066   module_val->subh->sub_proto = sub_proto;      /* save subdissector's proto_XXX value */
1067   
1068   g_hash_table_insert(giop_module_hash, new_module_key, module_val);
1069
1070 }
1071
1072
1073
1074
1075 /* Object Key Hash "EQUAL" Functions */
1076
1077 static gint giop_hash_objkey_equal(gconstpointer v, gconstpointer w) {
1078   struct giop_object_key *v1 = (struct giop_object_key *)v;
1079   struct giop_object_key *v2 = (struct giop_object_key *)w;
1080
1081   if (v1->objkey_len != v2->objkey_len)
1082     return 0;                   /* no match because different length */
1083
1084   /* Now do a byte comaprison */
1085
1086   if (!memcmp(v1->objkey,v2->objkey, v1->objkey_len)) {
1087     return 1;           /* compares ok */
1088   }
1089
1090 #if DEBUG
1091   printf("giop:giop_hash_objkey_equal: Objkey's DO NOT match");
1092 #endif
1093
1094   return 0;                     /* found  differences */
1095 }
1096
1097 /* Object Key Hash "HASH" Functions */
1098
1099 static guint32 giop_hash_objkey_hash(gconstpointer v) {
1100   struct giop_object_key *key = (struct giop_object_key *)v;
1101
1102   guint32 i;
1103   guint32 val = 0;              /* init hash value */
1104
1105
1106   /*
1107    * Hmm, try this simple hashing scheme for now.
1108    * ie: Simple summation
1109    *
1110    *
1111    */
1112
1113 #if DEBUG
1114   printf("giop:hash_objkey: Key length = %u \n", key->objkey_len );
1115 #endif
1116
1117   for (i=0; i< key->objkey_len; i++) {
1118     val += (guint8) key->objkey[i];
1119   }
1120
1121   return val;
1122
1123 }
1124
1125 /*
1126  * Routine to take an object key octet sequence, and length, and ptr to
1127  * a (null terminated )repository ID string, and store them in the obect key hash.
1128  *
1129  * Blindly Inserts even if it does exist, See TODO at top for reason.
1130  */
1131
1132 static void insert_in_objkey_hash(GHashTable *hash, gchar *obj, guint32 len, gchar *repoid, ior_src_t src) {
1133
1134   struct giop_object_key objkey_key, *new_objkey_key;
1135   struct giop_object_val *objkey_val = NULL;
1136
1137   objkey_key.objkey_len  = len; /*  length  */
1138   objkey_key.objkey  = obj;     /*  object key octet sequence  */
1139
1140   /* Look it up to see if it exists */
1141
1142   objkey_val = (struct giop_object_val *)g_hash_table_lookup(hash, &objkey_key);
1143
1144   /* CHANGED -- Same reqid, so abandon old entry */
1145
1146   if (objkey_val) {
1147     g_hash_table_remove(hash, &objkey_key);
1148   }
1149   
1150   /* So, passed key should NOT exist in hash at this point.*/
1151     
1152   new_objkey_key = g_mem_chunk_alloc(giop_objkey_keys);
1153   new_objkey_key->objkey_len = len; /* save it */
1154   new_objkey_key->objkey = (guint8 *) g_memdup(obj,len);        /* copy from object and allocate ptr */
1155     
1156   objkey_val = g_mem_chunk_alloc(giop_objkey_vals);
1157   objkey_val->repo_id = g_strdup(repoid); /* duplicate and store Respository ID string */
1158   objkey_val->src = src; /* where IOR came from */
1159
1160
1161 #if DEBUG  
1162   printf("giop: ******* Inserting Objkey with RepoID = %s and key length = %u into hash  \n",
1163          objkey_val->repo_id, new_objkey_key->objkey_len);
1164 #endif
1165
1166   g_hash_table_insert(hash, new_objkey_key, objkey_val);
1167
1168 }
1169
1170
1171
1172 /*
1173  * convert an ascii char representing a hex value,
1174  * to a numeric value.
1175  *
1176  * returns value, or -1 if problem.
1177  *
1178  */
1179
1180 static gint8 hex_char_to_val(guchar c){
1181   gint8 retval ;
1182
1183   if (!isxdigit(c)) {
1184     return -1;
1185   }
1186   if (isdigit(c)) {
1187     retval = c - 48;            /* convert digit */
1188     return retval;
1189   }
1190
1191   c = toupper(c);               /* convert to uppercase */
1192   if (c >= 'A' && c <= 'F') {
1193     retval = c - 55;
1194     return retval;
1195   } 
1196   else {
1197     return -1;
1198   }
1199
1200 }
1201
1202 /*
1203  * Convert from  stringified IOR of the kind IOR:af4f7e459f....
1204  * to an IOR octet sequence.
1205  *
1206  * User must free buffer.
1207  *
1208  * Creates a new tvbuff and call decode_IOR with a NULL tree, just to
1209  * grab repoid etc for our objkey hash. 
1210  *
1211  */
1212
1213 static guint32 string_to_IOR(guchar *in, guint32 in_len, guint8 **out){
1214   gint8 tmpval_lsb;
1215   gint8 tmpval_msb;
1216   gint8 tmpval;         /* complete value */
1217   guint32 i;
1218
1219   *out = g_new0(guint8, in_len); /* allocate buffer */
1220
1221   if (*out == NULL) {
1222     return 0;
1223   }
1224
1225   /* skip past IOR:  and convert character pairs to guint8 */
1226
1227   for (i=4; i<in_len-1; i+=2) {
1228     if ( isxdigit(in[i]) && isxdigit(in[i+1]) ) { /* hex ? */
1229       
1230       if ( (tmpval_msb = hex_char_to_val(in[i])) < 0 ) {
1231         g_warning("giop: Invalid value in IOR %i \n", tmpval_msb);
1232
1233       }
1234       
1235       if ( (tmpval_lsb = hex_char_to_val(in[i+1])) < 0 ) {
1236         g_warning("giop: Invalid value in IOR %i \n", tmpval_lsb);
1237       }
1238       
1239       tmpval = tmpval_msb << 4;
1240       tmpval += tmpval_lsb;
1241       (*out)[(i-4)/2] = (guint8) tmpval;
1242
1243     }
1244     else {
1245       /* hmm  */
1246       break;
1247     }
1248     
1249   }
1250
1251   return (i-4)/2;               /* length  */
1252
1253 }
1254
1255
1256
1257 /*
1258  * Simple getline, copied from somewhere :)
1259  *
1260  */
1261
1262 static int getline(FILE *fp, gchar *line, int maxlen) {
1263
1264   if (fgets(line,maxlen,fp) == NULL)
1265     return 0;
1266   else
1267     return strlen(line);
1268
1269 }
1270
1271
1272 /* 
1273  * Read a list of stringified IOR's from a named file, convert to IOR's
1274  * and store in object key hash
1275  */
1276
1277 static void read_IOR_strings_from_file(gchar *name, int max_iorlen) {
1278   guchar *buf;                  /* NOTE reused for every line */
1279   int len;
1280   int ior_val_len;              /* length after unstringifying. */
1281   FILE *fp;             
1282   guint8 *out;                  /* ptr to unstringified IOR */
1283   tvbuff_t *tvb;                /* temp tvbuff for dissectin IORs */
1284   guint32 my_offset = 0;
1285   gboolean stream_is_big_endian;
1286
1287
1288   fp = fopen(name,"r"); /* open read only */
1289
1290   if (fp == NULL) {
1291     if (errno == EACCES)
1292       fprintf(stderr, "Error opening file IOR.txt for reading: %s\n",strerror(errno));
1293     return;
1294   }
1295
1296   buf = g_malloc0(max_iorlen+1);        /* input buf */
1297
1298   while ((len = getline(fp,buf,max_iorlen+1)) > 0) {
1299     my_offset = 0;              /* reset for every IOR read */
1300
1301     ior_val_len = string_to_IOR(buf,len,&out);  /* convert */
1302
1303     if(ior_val_len>0) {
1304     
1305       /* Combination of tvb_new() and tvb_set_real_data().
1306          Can throw ReportedBoundsError.
1307
1308          XXX - can it throw an exception in this case?  If so, we
1309          need to catch it and clean up, but we really shouldn't allow
1310          it - or "get_CDR_octet()", or "decode_IOR()" - to throw an
1311          exception. */
1312
1313       tvb =  tvb_new_real_data(out,ior_val_len,ior_val_len, "GIOP FILE IOR");
1314
1315       stream_is_big_endian = !get_CDR_octet(tvb,&my_offset);
1316       decode_IOR(tvb, NULL, NULL, &my_offset, 0, stream_is_big_endian);
1317
1318       tvb_free(tvb);
1319
1320     }
1321
1322     g_free(out);
1323
1324   }
1325
1326   fclose(fp);                   /* be nice */
1327
1328   g_free(buf);
1329 }
1330
1331
1332
1333 /*
1334  * Init routine, setup our request hash stuff, or delete old ref's
1335  *
1336  * Cannot setup the module hash here as my init() may not be called before
1337  * users start registering. So I will move the module_hash stuff to
1338  * proto_register_giop, as is done with packet-rpc
1339  *
1340  *
1341  *
1342  * Also, setup our objectkey/repoid hash here.
1343  *
1344  */
1345
1346 static void giop_init(void) {
1347
1348
1349   /*
1350    * Create objkey/repoid  hash, use my "equal" and "hash" functions.
1351    * 
1352    */
1353
1354   if (giop_objkey_hash)
1355     g_hash_table_destroy(giop_objkey_hash);
1356   if (giop_objkey_keys)
1357     g_mem_chunk_destroy(giop_objkey_keys);
1358   if (giop_objkey_vals)
1359     g_mem_chunk_destroy(giop_objkey_vals);
1360
1361
1362   /*
1363    * Create hash, use my "equal" and "hash" functions.
1364    * 
1365    */
1366
1367   giop_objkey_hash = g_hash_table_new(giop_hash_objkey_hash, giop_hash_objkey_equal);
1368
1369   giop_objkey_keys = g_mem_chunk_new("giop_objkey_keys",
1370                                          sizeof(struct giop_object_key),
1371                                          giop_objkey_init_count * sizeof(struct giop_object_key), 
1372                                          G_ALLOC_AND_FREE);
1373
1374   giop_objkey_vals = g_mem_chunk_new("giop_objkey_vals", 
1375                                          sizeof(struct giop_object_val),
1376                                          giop_objkey_init_count * sizeof(struct giop_object_val), 
1377                                          G_ALLOC_AND_FREE);
1378
1379
1380   /*
1381    * Create complete_reply_hash, use my "equal" and "hash" functions.
1382    * 
1383    */
1384
1385   if (giop_complete_reply_hash)
1386     g_hash_table_destroy(giop_complete_reply_hash);
1387   if (giop_complete_reply_keys)
1388     g_mem_chunk_destroy(giop_complete_reply_keys);
1389   if (giop_complete_reply_vals)
1390     g_mem_chunk_destroy(giop_complete_reply_vals);
1391
1392
1393   /*
1394    * Create hash, use my "equal" and "hash" functions.
1395    * 
1396    */
1397
1398   giop_complete_reply_hash = g_hash_table_new(complete_reply_hash_fn, complete_reply_equal_fn);
1399
1400   giop_complete_reply_keys = g_mem_chunk_new("giop_complete_reply_keys",
1401                                          sizeof(struct complete_reply_hash_key),
1402                                          complete_reply_hash_count * sizeof(struct complete_reply_hash_key), 
1403                                          G_ALLOC_AND_FREE);
1404
1405   giop_complete_reply_vals = g_mem_chunk_new("giop_complete_reply_vals", 
1406                                          sizeof(struct complete_reply_hash_val),
1407                                          complete_reply_hash_count * sizeof(struct complete_reply_hash_val), 
1408                                          G_ALLOC_AND_FREE);
1409
1410
1411   
1412   read_IOR_strings_from_file("IOR.txt", 600); /* testing */
1413
1414
1415 }
1416
1417
1418 /* 
1419  * Insert an entry in the GIOP Heuristic User table.
1420  * Uses a GList.
1421  * Uses giop_sub_handle_t to wrap giop user info.
1422  *
1423  */
1424     
1425 void register_giop_user(giop_sub_dissector_t *sub, gchar *name, int sub_proto) {
1426
1427   giop_sub_handle_t *subh;
1428   
1429   subh = g_malloc(sizeof (giop_sub_handle_t));
1430
1431   subh->sub_name = name;
1432   subh->sub_fn = sub;
1433   subh->sub_proto = sub_proto;  /* proto_XXX from sub dissectors's proto_register_protocol() */
1434
1435   giop_sub_list = g_slist_append (giop_sub_list, subh);
1436  
1437 }
1438
1439
1440 /*
1441  * Lookup an object key in our object key hash, and return the corresponding
1442  * Repo Id.
1443  *
1444  */
1445
1446 static gchar * get_repoid_from_objkey(GHashTable *hash, guint8 *obj, guint32 len) {
1447
1448   struct giop_object_key objkey_key;
1449   struct giop_object_val *objkey_val = NULL;
1450
1451   objkey_key.objkey_len  = len; /*  length  */
1452   objkey_key.objkey  = obj;     /*  object key octet sequence  */
1453
1454   /* Look it up to see if it exists */
1455
1456   objkey_val = (struct giop_object_val *)g_hash_table_lookup(hash, &objkey_key);
1457
1458   if (objkey_val) {
1459 #if DEBUG
1460     printf("Lookup of object key returns  RepoId = %s \n",objkey_val->repo_id );
1461 #endif
1462     return objkey_val->repo_id; /* found  */
1463   }
1464
1465 #if DEBUG    
1466   printf("FAILED Lookup of object key \n" );
1467 #endif
1468   
1469   return NULL;                  /* not  found */
1470 }
1471
1472
1473
1474 /*
1475  * Extract top level module/interface from repoid 
1476  *
1477  * eg from -  "IDL:Echo/interface1:1.0"
1478  * get "Echo"
1479  *
1480  * Or, from "IDL:linux.org/Penguin/Teeth:1.0" get
1481  * get linux.org/Penguin/Teeth
1482  * 
1483  *
1484  * User must free returned ptr after use.
1485  *
1486  * TODO -- generalize for other Repoid encodings
1487  */
1488
1489 static gchar * get_modname_from_repoid(gchar *repoid) {
1490
1491   gchar *modname = NULL;
1492   gchar *saved_repoid = NULL;
1493   gchar c = 'a';
1494   guint8 stop_mod;              /* Index of last character of modname in Repoid  */
1495   guint8 start_mod = 4;         /* Index where Module name starts in repoid */
1496   int i;
1497
1498   saved_repoid = g_strdup(repoid); /* make a copy */
1499
1500   /* Must start with IDL: , otherwise I get confused */
1501
1502   if (g_strncasecmp("IDL:",repoid,4))
1503     return NULL;
1504
1505   /* Looks like a RepoID to me, so get Module or interface name */
1506
1507   /* TODO -- put some code here to get Module name */
1508
1509   for(i=4; c != '\0'; i++) {
1510     c = repoid[i];
1511     stop_mod = i;               /* save */
1512     if (c == ':' )              /* delimiters */
1513       break;
1514     
1515   }
1516
1517   /* Now create a new string based on start and stop and \0 */
1518   
1519   modname = g_strndup(repoid+4, stop_mod - start_mod);
1520     
1521   return modname;
1522   
1523 }
1524
1525 /*
1526  * DEBUG CODE
1527  *
1528  */
1529
1530
1531 #if DEBUG
1532
1533 /*
1534  * Display a "module" hash entry
1535  */
1536
1537 static void display_module_hash(gpointer key, gpointer val, gpointer user_data) {
1538
1539   struct giop_module_val *mv = (struct giop_module_val *) val;
1540   struct giop_module_key *mk = (struct giop_module_key *) key;
1541
1542   printf("giop:module: Key = (%s) , Val = (%s) \n", mk->module, mv->subh->sub_name);
1543   
1544   return;
1545
1546 }
1547
1548 /*
1549  * Display a "complete_reply " hash entry
1550  */
1551
1552 static void display_complete_reply_hash(gpointer key, gpointer val, gpointer user_data) {
1553
1554   struct complete_reply_hash_val *mv = (struct complete_reply_hash_val *) val;
1555   struct complete_reply_hash_key *mk = (struct complete_reply_hash_key *) key;
1556
1557   printf("giop:complete_reply: FN (key) = %8u , MFN (val) = %8u \n", mk->fn, mv->mfn);
1558   
1559   return;
1560
1561 }
1562
1563
1564 /*
1565  * Display an "objkey" hash entry
1566  */
1567
1568 static void display_objkey_hash(gpointer key, gpointer val, gpointer user_data) {
1569   guint32 i;
1570   struct giop_object_val *mv = (struct giop_object_val *) val;
1571   struct giop_object_key *mk = (struct giop_object_key *) key;
1572
1573
1574   printf("giop:objkey: Key->objkey_len = %u,  Key->objkey ",  mk->objkey_len);
1575
1576   for (i=0; i<mk->objkey_len; i++) {
1577     printf("%.2x ", mk->objkey[i]);
1578   }
1579
1580   /*
1581    * If read from file, mark it as such..
1582    */
1583
1584   if(mv->src == 0) {
1585     printf(", Repo ID = %s \n", mv->repo_id);
1586   }
1587   else {
1588     printf(", Repo ID = %s , (file) \n", mv->repo_id);    
1589   }
1590   
1591   return;
1592
1593 }
1594
1595 /*
1596  * Display all giop_sub_list (GSList) entries
1597  */
1598
1599 static void display_heuristic_user_list() {
1600   int i;
1601   int len;
1602   giop_sub_handle_t *subh;      /* handle */
1603   
1604   /* Get length of list */
1605   len = g_slist_length(giop_sub_list); /* find length */
1606
1607   if (len == 0)
1608     return;
1609
1610   for (i=0; i<len; i++) {
1611     subh = ( giop_sub_handle_t *) g_slist_nth_data(giop_sub_list,i); /* grab entry */
1612     printf("giop:heuristic_user: Element = %i, Val (user) = %s \n", i, subh->sub_name);
1613   }
1614   
1615 }
1616
1617 /*
1618  * Display all complete_request_list (GList) entries
1619  */
1620
1621 static void display_complete_request_list() {
1622   int i;
1623   int len;
1624   comp_req_list_entry_t *entry;
1625   
1626   /* Get length of list */
1627   len = g_list_length(giop_complete_request_list); /* find length */
1628
1629   if (len == 0)
1630     return;
1631
1632   for (i=0; i<len; i++) {
1633     entry = (comp_req_list_entry_t *) g_list_nth_data(giop_complete_request_list,i); /* grab entry */
1634     printf("giop:Index = %8i , FN = %8i, reqid = %8u , operation = %20s , repoid = %30s \n", i, entry->fn, 
1635            entry->reqid,entry->operation, entry->repoid);
1636   }
1637   
1638 }
1639
1640
1641
1642
1643 /* Dump Hash/List contents 
1644  *
1645  * collection_type specifies the list or hash to dump
1646  *
1647  */
1648
1649 static void giop_dump_collection(collection_data_t collection_type) {
1650
1651   switch(collection_type) {
1652   case cd_heuristic_users:
1653     printf("+----------------------------------------------+ \n");
1654     printf("+-------------- Heuristic User (Begin) --------+ \n");
1655     printf("+----------------------------------------------+ \n");
1656
1657     display_heuristic_user_list();
1658
1659     printf("+----------------------------------------------+ \n");
1660     printf("+-------------- Heuristic User (End) ----------+ \n");
1661     printf("+----------------------------------------------+ \n");
1662
1663     break;
1664
1665   case cd_complete_request_list:
1666     printf("+----------------------------------------------+ \n");
1667     printf("+------------- Complete Request List (Begin) --+ \n");
1668     printf("+----------------------------------------------+ \n");
1669
1670     display_complete_request_list();
1671
1672     printf("+----------------------------------------------+ \n");
1673     printf("+------------ Complete Request List (End) -----+ \n");
1674     printf("+----------------------------------------------+ \n");
1675
1676     break;
1677
1678   case cd_module_hash:
1679     printf("+----------------------------------------------+ \n");
1680     printf("+-------------- Module (Begin) ----------------+ \n");
1681     printf("+----------------------------------------------+ \n");
1682
1683     g_hash_table_foreach(giop_module_hash, display_module_hash, NULL);
1684
1685     printf("+----------------------------------------------+ \n");
1686     printf("+-------------- Module ( End) -----------------+ \n");
1687     printf("+----------------------------------------------+ \n\n");
1688
1689     break;
1690
1691   case cd_objkey_hash:
1692     printf("+----------------------------------------------+ \n");
1693     printf("+-------------- Objkey (Begin) ----------------+ \n");
1694     printf("+----------------------------------------------+ \n");
1695
1696     g_hash_table_foreach(giop_objkey_hash, display_objkey_hash,NULL);
1697
1698     printf("+----------------------------------------------+ \n");
1699     printf("+-------------- Objkey (End) ------------------+ \n");
1700     printf("+----------------------------------------------+ \n\n");
1701   
1702     break;
1703
1704   case cd_complete_reply_hash:
1705     printf("+----------------------------------------------+ \n");
1706     printf("+-------------- Complete_Reply_Hash (Begin) ---+ \n");
1707     printf("+----------------------------------------------+ \n");
1708
1709     g_hash_table_foreach(giop_complete_reply_hash, display_complete_reply_hash, NULL);
1710
1711     printf("+----------------------------------------------+ \n");
1712     printf("+------------- Complete_Reply_Hash (End) ------+ \n");
1713     printf("+----------------------------------------------+ \n");
1714
1715     break;
1716     
1717   default:
1718
1719     printf("giop: giop_dump_collection: Unknown type   \n");
1720
1721   }
1722
1723
1724 }
1725
1726
1727 #endif /* DEBUG */
1728
1729 /*
1730  * Loop through all  subdissectors, and call them until someone
1731  * answers (returns TRUE). This function then returns TRUE, otherwise
1732  * it return FALSE
1733  *
1734  * But skip a subdissector if it has been disabled in GUI "edit protocols".
1735  */
1736
1737 static gboolean try_heuristic_giop_dissector(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int *offset,
1738                 MessageHeader *header, gchar *operation  ) {
1739
1740   int i,len;
1741   gboolean res = FALSE;         /* result of calling a heuristic sub dissector */
1742   giop_sub_handle_t *subh = NULL; 
1743
1744   len = g_slist_length(giop_sub_list); /* find length */
1745
1746   if (len == 0)
1747     return FALSE;
1748
1749   for (i=0; i<len; i++) {
1750     subh = (giop_sub_handle_t *) g_slist_nth_data(giop_sub_list,i); /* grab dissector handle */
1751
1752     if (proto_is_protocol_enabled(subh->sub_proto)) {
1753       res = (subh->sub_fn)(tvb,pinfo,tree,offset,header,operation,NULL); /* callit TODO - replace NULL */
1754       if (res) {
1755         return TRUE;            /* found one, lets return */
1756       }  
1757     } /* protocol_is_enabled */
1758   } /* loop */
1759
1760   return res;                   /* result */
1761
1762 }
1763
1764
1765 /*
1766  * Find the matching repoid in the module hash and call
1767  * the dissector function if offset exists.
1768  * 
1769  *
1770  * Repoid is eg IDL:tux.antarctic/Penguin/Teeth:1.0 but subdissectors 
1771  * will register possibly "tux.antarctic/Penguin" and "tux.antarctic/Penguin/Teeth". 
1772  *
1773  *
1774  *
1775  */
1776
1777 static gboolean try_explicit_giop_dissector(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int *offset,
1778                                             MessageHeader *header, gchar *operation, gchar *repoid ) {
1779
1780   giop_sub_handle_t *subdiss = NULL; /* handle */
1781   gboolean res = FALSE;
1782   gchar *modname = NULL;
1783   struct giop_module_key module_key;
1784   struct giop_module_val *module_val = NULL;
1785
1786
1787   /*
1788    * Get top level module/interface from complete repoid 
1789    */
1790
1791   modname = get_modname_from_repoid(repoid); 
1792   if (modname == NULL) {
1793     return res;                 /* unknown module name */
1794   }
1795
1796
1797   /* Search for Module or interface name */
1798
1799   module_key.module = modname; /*  module name */
1800   module_val = (struct giop_module_val *)g_hash_table_lookup(giop_module_hash, &module_key);
1801
1802   if (module_val == NULL) {
1803     return res;                 /* module not registered */
1804   }
1805   
1806   subdiss = (giop_sub_handle_t *) module_val->subh; /* grab dissector handle */
1807
1808   if (subdiss) {
1809     /* Add giop_sub_handle_t and repoid into complete_request_list, so REPLY can */
1810     /* look it up directly, later ie: FN -> MFN -> giop_sub_handle_t and repoid */
1811     /* but only if user not clicking */
1812
1813     if (!pinfo->fd->flags.visited)
1814       add_sub_handle_repoid_to_comp_req_list(pinfo->fd->num,subdiss,repoid);
1815
1816
1817     /* Call subdissector if current offset exists , and dissector is enabled in GUI "edit protocols" */
1818
1819     if (tvb_offset_exists(tvb, *offset)) {   
1820 #if DEBUG  
1821       printf("giop:try_explicit_dissector calling sub = %s with module = (%s) \n", subdiss->sub_name  , modname);
1822 #endif
1823
1824       if (proto_is_protocol_enabled(subdiss->sub_proto)) {
1825
1826         res = (subdiss->sub_fn)(tvb,pinfo,tree,offset,header,operation, modname); /* callit, TODO replace NULL with idlname */
1827
1828       } /* protocol_is_enabled */
1829     } /* offset exists */
1830   } /* subdiss */
1831   
1832   return res;                   /* return result */
1833 }
1834
1835
1836
1837 /* Take in an array of char and create a new string.
1838  * Replace non-printable characters with periods.
1839  *
1840  * The array may contain \0's so dont use strdup
1841  * The string is \0 terminated, and thus longer than
1842  * the initial sequence. 
1843  * Caller must free the new string.
1844  */
1845
1846 static gchar * make_printable_string (gchar *in, guint32 len) {
1847   guint32 i = 0;
1848   gchar *print_string = NULL;
1849
1850   print_string = (gchar * )g_malloc0(len + 1); /* make some space and zero it */
1851   memcpy(print_string, in, len);        /* and make a copy of input data */
1852   
1853   for(i=0; i < len; i++) {
1854     if( !isprint( (unsigned char)print_string[i] ) ) 
1855       print_string[i] = '.';
1856   }
1857
1858   return print_string;          /* return ptr */
1859 }
1860
1861 /* Determine the byte order from the GIOP MessageHeader */
1862
1863 gboolean is_big_endian (MessageHeader * header) {
1864   gboolean big_endian = FALSE;
1865
1866   switch (header->GIOP_version.minor) {
1867   case 2:
1868   case 1:
1869     if (header->flags & 0x01)
1870       big_endian = FALSE;
1871     else
1872       big_endian = TRUE;
1873     break;
1874   case 0:
1875     if (header->flags)
1876       big_endian = FALSE;
1877     else
1878       big_endian = TRUE;
1879     break;
1880   default:
1881     break;
1882   }
1883   return big_endian;
1884 }
1885
1886
1887
1888 /* 
1889  * Calculate new offset, based on the current offset, and user supplied 
1890  * "offset delta" value, and the alignment requirement.
1891  *
1892  *
1893  *
1894  * eg: Used for GIOP 1.2 where Request and Reply bodies are 
1895  *     aligned on 8 byte boundaries.
1896  */
1897
1898 static void set_new_alignment(int *offset, int delta, int  alignment) {
1899
1900   while( ( (*offset + delta) % alignment) != 0)
1901           ++(*offset);
1902
1903
1904 }
1905
1906
1907
1908 /*
1909  * ------------------------------------------------------------------------------------------+ 
1910  *                                 Public get_CDR_xxx functions.
1911  * ------------------------------------------------------------------------------------------+
1912  */
1913
1914
1915
1916 /*
1917  * Gets data of type any. This is encoded as a TypeCode
1918  * followed by the encoded value.
1919  */
1920
1921 void get_CDR_any(tvbuff_t *tvb, proto_tree *tree, gint *offset, 
1922                  gboolean stream_is_big_endian, int boundary,
1923                  MessageHeader * header ) {
1924   
1925   guint32  TCKind;    /* TypeCode */
1926
1927   /* get TypeCode of any */
1928   TCKind = get_CDR_typeCode(tvb, tree, offset, stream_is_big_endian, boundary, header );
1929
1930   /* dissect data of type TCKind */
1931   dissect_data_for_typecode(tvb, tree, offset, stream_is_big_endian, boundary, header, TCKind );
1932 }
1933
1934
1935 /* Copy a 1 octet sequence from the tvbuff 
1936  * which represents a boolean value, and convert
1937  * it to a boolean value.
1938  * Offset is then incremented by 1, to indicate the 1 octet which
1939  * has been processed.
1940  */
1941
1942 gboolean get_CDR_boolean(tvbuff_t *tvb, int *offset) {
1943   guint8 val;
1944
1945   val = tvb_get_guint8(tvb, *offset); /* easy */
1946   (*offset)++;
1947   return val;
1948 }
1949
1950 /* Copy a 1 octet sequence from the tvbuff 
1951  * which represents a char, and convert
1952  * it to an char value.
1953  * offset is then incremented by 1, to indicate the 1 octet which
1954  * has been processed.
1955  */
1956
1957 guint8 get_CDR_char(tvbuff_t *tvb, int *offset) {
1958   guint8 val;
1959
1960   val = tvb_get_guint8(tvb, *offset); /* easy */
1961   (*offset)++;
1962   return val;
1963 }
1964
1965
1966
1967 /* 
1968  * Floating Point Data Type double IEEE 754-1985 
1969  *
1970  * Copy an 8 octet sequence from the tvbuff 
1971  * which represents a double value, and convert
1972  * it to a double value, taking into account byte order.
1973  * offset is first incremented so that it falls on a proper alignment
1974  * boundary for double values.
1975  * offset is then incremented by 8, to indicate the 8 octets which
1976  * have been processed.
1977  */
1978
1979 gdouble get_CDR_double(tvbuff_t *tvb, int *offset, gboolean stream_is_big_endian, int boundary) {
1980
1981   guint8 sign;
1982   guint8 e1,e2,f1,f2,f3,f4,f5,f6,f7;
1983   gdouble val;
1984   guint16 exp;
1985   guint32 fract0, fract1;
1986   gdouble d_fract;              
1987   
1988
1989   /* double values must be aligned on a 8 byte boundary */
1990
1991   while( ( (*offset + boundary) % 8) != 0)
1992           ++(*offset);
1993
1994
1995   if(stream_is_big_endian) {    
1996     e1  = get_CDR_octet(tvb,offset);
1997     sign = e1 >> 7;                     /* sign value */
1998     e1 &= 0x7f;         /* bottom 7 bits */
1999     f1  = get_CDR_octet(tvb,offset);
2000     e2 = f1 >> 4;
2001     f1 &= 0x0f;         /* bottom 4 bits */
2002     f2  = get_CDR_octet(tvb,offset);
2003     f3  = get_CDR_octet(tvb,offset);
2004     f4  = get_CDR_octet(tvb,offset);
2005     f5  = get_CDR_octet(tvb,offset);
2006     f6  = get_CDR_octet(tvb,offset);
2007     f7  = get_CDR_octet(tvb,offset);
2008
2009   } else {
2010
2011     f7  = get_CDR_octet(tvb,offset);
2012     f6  = get_CDR_octet(tvb,offset);
2013     f5  = get_CDR_octet(tvb,offset);
2014     f4  = get_CDR_octet(tvb,offset);
2015     f3  = get_CDR_octet(tvb,offset);
2016     f2  = get_CDR_octet(tvb,offset);
2017     f1  = get_CDR_octet(tvb,offset);
2018     e2 = f1 >> 4;
2019     f1 &= 0x0f;         /* bottom 4 bits */
2020     e1  = get_CDR_octet(tvb,offset);
2021     sign = e1 >> 7;                     /* sign value */
2022     e1 &= 0x7f;         /* bottom 7 bits */
2023
2024   }
2025
2026   exp = (e1 << 4) + e2;
2027
2028   /* Now lets do some 52 bit math with 32 bit constraint */
2029
2030   fract0 = f7 + (f6 << 8) + (f5 << 16) + (f4 << 24); /* lower 32 bits of fractional part */
2031   fract1 = f3 + (f2 << 8) + (f1 << 16);              /* top 20 bits of fractional part   */
2032
2033   d_fract = (fract1 / (pow(2,20))) + (fract0 / (pow(2,52))); /* 52 bits represent a fraction */
2034
2035   val = pow(-1,sign) * pow(2,(exp - 1023)) * (1 + d_fract);
2036
2037   return val;           /* FIX rounding ?? */
2038
2039 }
2040
2041
2042 /* Copy a 4 octet sequence from the tvbuff 
2043  * which represents an enum value, and convert
2044  * it to an enum value, taking into account byte order.
2045  * offset is first incremented so that it falls on a proper alignment
2046  * boundary for an enum (4)
2047  * offset is then incremented by 4, to indicate the 4 octets which
2048  * have been processed.
2049  *
2050  * Enum values are encoded as unsigned long.
2051  */
2052
2053
2054 guint32 get_CDR_enum(tvbuff_t *tvb, int *offset, gboolean stream_is_big_endian, int boundary) {
2055
2056   return get_CDR_ulong(tvb, offset, stream_is_big_endian, boundary );
2057
2058 }
2059
2060
2061 /*
2062  * Copy an octet sequence from the tvbuff
2063  * which represents a Fixed point decimal type, and create a string representing
2064  * a Fixed point decimal type. There are no alignment restrictions.
2065  * Size and scale of fixed decimal type is determined by IDL.
2066  * 
2067  * digits - IDL specified number of "digits" for this fixed type
2068  * scale  - IDL specified "scale" for this fixed type
2069  *
2070  *
2071  * eg: typedef fixed <5,2> fixed_t;
2072  *     could represent numbers like 123.45, 789.12, 
2073  *
2074  *
2075  * As the fixed type could be any size, I will not try to fit it into our
2076  * simple types like gdouble or glong etc. I will just create a string buffer holding
2077  * a  representation (after scale is applied), and with a decimal point or zero padding
2078  * inserted at the right place if necessary. The string is null terminated
2079  *
2080  * so string may look like 
2081  *
2082  *
2083  *  "+1.234" or "-3456.78" or "1234567309475760377365465897891" or "-2789000000" etc
2084  *
2085  * According to spec, digits <= 31
2086  * and scale is positive (except for constants eg: 1000 has digit=1 and implied scale = -3)
2087  * or <4,0> ?
2088  *
2089  * User must remember to free the buffer
2090  *
2091  */
2092
2093
2094 void get_CDR_fixed(tvbuff_t *tvb, gchar **seq, gint *offset, guint32 digits, gint32 scale) {
2095
2096   guint8 sign;                  /* 0x0c is positive, 0x0d is negative */
2097   guint32 i ;                   /* loop */
2098   guint32 slen;                 /* number of bytes to hold digits + extra 0's if scale <0 */
2099                                 /* this does not include sign, decimal point and \0 */
2100   guint32 sindex = 0;           /* string index */
2101   gchar *tmpbuf;                /* temp buff, holds string without scaling */
2102   guint8 tval;                  /* temp val storage */
2103
2104   /*
2105    * how many bytes to hold digits and scale (if scale <0) 
2106    *
2107    * eg: fixed <5,2> = 5 digits
2108    *     fixed <5,-2> = 7 digits (5 + 2 added 0's)
2109    */
2110
2111 #if DEBUG
2112     printf("giop:get_CDR_fixed() called , digits = %u, scale = %u \n", digits, scale);
2113 #endif
2114
2115   if (scale <0) {
2116     slen = digits - scale;      /* allow for digits + padding 0's for negative scal */
2117   } else {
2118     slen = digits;              /*  digits */
2119   }
2120
2121 #if DEBUG
2122     printf("giop:get_CDR_fixed(): slen =  %.2x \n", slen);
2123 #endif
2124   
2125   tmpbuf = g_new0(gchar, slen); /* allocate temp buffer */ 
2126
2127   /*
2128    * Register a cleanup function in case on of our tvbuff accesses
2129    * throws an exception. We need to clean up tmpbuf.
2130    */
2131   CLEANUP_PUSH(g_free, tmpbuf);
2132
2133   /* If even , grab 1st dig */
2134
2135   if (!(digits & 0x01)) {
2136     tval = get_CDR_octet(tvb,offset);
2137 #if DEBUG
2138     printf("giop:get_CDR_fixed():even: octet = %.2x \n", tval);
2139 #endif
2140     tmpbuf[sindex] = (tval & 0x0f) + 0x30; /* convert top nibble to ascii */
2141     sindex++;
2142   }
2143
2144   /*
2145    * Loop, but stop BEFORE we hit last digit and sign 
2146    * if digits = 1 or 2, then this part is skipped 
2147    */
2148
2149   if (digits>2) {
2150     for(i=0; i< ((digits-1)/2 ); i++) {
2151       tval = get_CDR_octet(tvb,offset);
2152 #if DEBUG
2153       printf("giop:get_CDR_fixed():odd: octet = %.2x \n", tval);
2154 #endif
2155       
2156       tmpbuf[sindex] = ((tval & 0xf0) >> 4) + 0x30; /* convert top nibble to ascii */
2157       sindex++;
2158       tmpbuf[sindex] = (tval & 0x0f)  + 0x30; /* convert bot nibble to ascii */
2159       sindex++;
2160       
2161     }
2162   } /* digits > 3 */
2163
2164 #if DEBUG
2165     printf("giop:get_CDR_fixed(): before last digit \n");
2166 #endif
2167   
2168
2169   /* Last digit and sign if digits >1, or 1st dig and sign if digits = 1 */
2170
2171     tval = get_CDR_octet(tvb,offset);
2172 #if DEBUG
2173     printf("giop:get_CDR_fixed(): octet = %.2x \n", tval);
2174 #endif
2175     tmpbuf[sindex] = (( tval & 0xf0)>> 4) + 0x30; /* convert top nibble to ascii */
2176     sindex++;
2177
2178     sign = tval & 0x0f; /* get sign */
2179
2180     /* So now, we have all digits in an array, and the sign byte 
2181      * so lets generate a printable string, taking into account the scale
2182      * and sign values.
2183      */
2184  
2185     sindex = 0;                         /* reset */
2186     *seq = g_new0(gchar, slen + 3);     /* allocate temp buffer , including space for sign, decimal point and 
2187                                          * \0 -- TODO check slen is reasonable first */
2188 #if DEBUG
2189     printf("giop:get_CDR_fixed(): sign =  %.2x \n", sign);
2190 #endif                                  
2191     
2192     switch(sign) {
2193     case 0x0c:
2194       (*seq)[sindex] = '+';     /* put sign in first string position */
2195       break;                    
2196     case 0x0d:
2197       (*seq)[sindex] = '-';
2198       break;
2199     default:
2200       g_warning("giop: Unknown sign value in fixed type %u \n", sign);
2201       (*seq)[sindex] = '*';     /* flag as sign unkown */
2202       break;
2203     }
2204
2205     sindex++;
2206
2207     /* Add decimal point or padding 0's, depending if scale is positive or
2208      * negative, respectively
2209      */
2210
2211     if (scale>0) {
2212       for (i=0; i<digits-scale; i++) {
2213         (*seq)[sindex] = tmpbuf[i]; /* digits to the left of the decimal point */       
2214         sindex++;
2215       }
2216       
2217       (*seq)[sindex] = '.'; /* decimal point */ 
2218       sindex++;
2219       
2220       for (i=digits-scale; i<digits; i++) {
2221         (*seq)[sindex] = tmpbuf[i]; /* remaining digits to the right of the decimal point */    
2222         sindex++;
2223       }
2224
2225       (*seq)[sindex] = '\0'; /* string terminator */    
2226
2227     } else {
2228
2229       /* negative scale, dump digits and  pad out with 0's */
2230
2231       for (i=0; i<digits-scale; i++) {
2232         if (i<digits) {
2233           (*seq)[sindex] = tmpbuf[i]; /* save digits */ 
2234         } else {
2235           (*seq)[sindex] = '0'; /* all digits used up, so pad with 0's */       
2236         }
2237         sindex++;
2238       }
2239
2240       (*seq)[sindex] = '\0'; /* string terminator */    
2241       
2242     }
2243
2244     /*
2245      * We're done with tmpbuf, so we can call the cleanup handler to free
2246      * it, and then pop the cleanup handler.
2247      */
2248     CLEANUP_CALL_AND_POP;
2249     
2250 #if DEBUG
2251     printf("giop:get_CDR_fixed(): value = %s \n", *seq);
2252 #endif
2253
2254     return; 
2255
2256 }
2257
2258
2259
2260 /*
2261  * Floating Point Data Type float IEEE 754-1985 
2262  * 
2263  * Copy an 4 octet sequence from the tvbuff 
2264  * which represents a float value, and convert
2265  * it to a float value, taking into account byte order.
2266  * offset is first incremented so that it falls on a proper alignment
2267  * boundary for float values.
2268  * offset is then incremented by 4, to indicate the 4 octets which
2269  * have been processed.
2270  */
2271
2272 gfloat get_CDR_float(tvbuff_t *tvb, int *offset, gboolean stream_is_big_endian, int boundary) {
2273   
2274   guint8 sign;
2275   guint8 e1,e2,f1,f2,f3;
2276   gfloat val;
2277   guint8 exp;
2278   guint32 fract;
2279   gdouble d_fract;              
2280   
2281   /* float values must be aligned on a 4 byte boundary */
2282
2283   while( ( (*offset + boundary) % 4) != 0)
2284     ++(*offset);
2285
2286   if(stream_is_big_endian) {    
2287     e1  = get_CDR_octet(tvb,offset);
2288     sign = e1 >> 7;                     /* sign value */
2289     e1 &= 0x7f;         /* bottom 7 bits */
2290     f1  = get_CDR_octet(tvb,offset);
2291     e2 = f1 >> 7;
2292     f1 &= 0x7f;         /* bottom 7 bits */
2293     f2  = get_CDR_octet(tvb,offset);
2294     f3  = get_CDR_octet(tvb,offset);
2295
2296   } else {
2297
2298     f3  = get_CDR_octet(tvb,offset);
2299     f2  = get_CDR_octet(tvb,offset);
2300     f1  = get_CDR_octet(tvb,offset);
2301     e2 = f1 >> 7;
2302     f1 &= 0x7f;         /* bottom 7 bits */
2303     e1  = get_CDR_octet(tvb,offset);
2304     sign = e1 >> 7;                     /* sign value */
2305     e1 &= 0x7f;         /* bottom 7 bits */
2306
2307   }
2308
2309
2310   exp = (e1 << 1) + e2;
2311   fract = f3 + (f2 << 8) + (f1 << 16);
2312
2313   d_fract = fract / (pow(2,23)); /* 23 bits represent a fraction */
2314
2315   val = pow(-1,sign) * pow(2,(exp - 127)) * (1 + d_fract);
2316
2317   return val;           /* FIX rounding ?? */
2318
2319 }
2320
2321
2322 /*
2323  * Decode an Interface type, and display it on the tree.
2324  */
2325
2326 void get_CDR_interface(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int *offset, 
2327                        gboolean stream_is_big_endian, int boundary) {
2328
2329
2330   decode_IOR(tvb, pinfo, tree, offset, boundary, stream_is_big_endian);
2331   
2332   return;
2333 }
2334
2335
2336 /* Copy a 4 octet sequence from the tvbuff 
2337  * which represents a signed long value, and convert
2338  * it to an signed long vaule, taking into account byte order.
2339  * offset is first incremented so that it falls on a proper alignment
2340  * boundary for long values.
2341  * offset is then incremented by 4, to indicate the 4 octets which
2342  * have been processed.
2343  */
2344
2345 gint32 get_CDR_long(tvbuff_t *tvb, int *offset, gboolean stream_is_big_endian, int boundary) {
2346
2347   gint32 val;
2348
2349   /* unsigned long values must be aligned on a 4 byte boundary */
2350   while( ( (*offset + boundary) % 4) != 0)
2351           ++(*offset);
2352
2353   val = (stream_is_big_endian) ? tvb_get_ntohl (tvb, *offset) :
2354                                  tvb_get_letohl (tvb, *offset);
2355
2356   *offset += 4; 
2357   return val; 
2358 }
2359
2360 /*
2361  * Decode an Object type, and display it on the tree.
2362  */
2363
2364 void get_CDR_object(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int *offset, 
2365                     gboolean stream_is_big_endian, int boundary) {
2366   
2367   decode_IOR(tvb, pinfo, tree, offset, boundary, stream_is_big_endian);
2368   
2369   return;
2370 }
2371
2372
2373 /* Copy a 1 octet sequence from the tvbuff 
2374  * which represents a octet, and convert
2375  * it to an octet value.
2376  * offset is then incremented by 1, to indicate the 1 octet which
2377  * has been processed.
2378  */
2379
2380 guint8 get_CDR_octet(tvbuff_t *tvb, int *offset) {
2381   guint8 val;
2382
2383   val = tvb_get_guint8(tvb, *offset); /* easy */
2384   (*offset)++;
2385   return val;
2386 }
2387
2388
2389 /* Copy a sequence of octets from the tvbuff.
2390  * Caller of this function must remember to free the 
2391  * array pointed to by seq.
2392  * This function also increments offset by len. 
2393  */
2394
2395 void get_CDR_octet_seq(tvbuff_t *tvb, gchar **seq, int *offset, int len) {
2396
2397   if (! tvb_bytes_exist(tvb, *offset,len)) {
2398     /*
2399      * Generate an exception, and stop processing.
2400      * We do that now, rather than after allocating the buffer, so we
2401      * don't have to worry about freeing the buffer.
2402      * XXX - would we be better off using a cleanup routine?
2403      */
2404     tvb_get_guint8(tvb, *offset + len);
2405   }
2406
2407   /*
2408    * XXX - should we just allocate "len" bytes, and have "get_CDR_string()"
2409    * do what we do now, and null-terminate the string (which also means
2410    * we don't need to zero out the entire allocation, just the last byte)?
2411    */
2412   *seq = g_new0(gchar, len + 1);
2413   tvb_memcpy( tvb, *seq, *offset, len);
2414   *offset += len;
2415 }
2416
2417
2418 /* Copy a 2 octet sequence from the tvbuff 
2419  * which represents a signed short value, and convert
2420  * it to a signed short value, taking into account byte order.
2421  * offset is first incremented so that it falls on a proper alignment
2422  * boundary for short values.
2423  * offset is then incremented by 2, to indicate the 2 octets which
2424  * have been processed.
2425  */
2426
2427 gint16 get_CDR_short(tvbuff_t *tvb, int *offset, gboolean stream_is_big_endian, int boundary) {
2428
2429   gint16 val;
2430
2431   /* short values must be aligned on a 2 byte boundary */
2432   while( ( (*offset + boundary) % 2) != 0)
2433           ++(*offset);
2434
2435   val = (stream_is_big_endian) ? tvb_get_ntohs (tvb, *offset) :
2436                                  tvb_get_letohs (tvb, *offset);
2437
2438   *offset += 2; 
2439   return val; 
2440 }
2441
2442
2443
2444 /* Copy an octet sequence from the tvbuff 
2445  * which represents a string, and convert
2446  * it to an string value, taking into account byte order.
2447  * offset is first incremented so that it falls on a proper alignment
2448  * boundary for string values. (begins with an unsigned long LI)
2449  *
2450  * String sequence is copied to a  buffer "seq". This must
2451  * be freed by the calling program.
2452  * offset is then incremented, to indicate the  octets which
2453  * have been processed.
2454  *
2455  * returns number of octets in the sequence
2456  *
2457  * Note: This function only supports single byte encoding at the
2458  *       moment until I get a handle on multibyte encoding etc.
2459  *
2460  */
2461
2462
2463 guint32 get_CDR_string(tvbuff_t *tvb, gchar **seq, int *offset, gboolean stream_is_big_endian, 
2464                        int boundary ) {
2465   
2466   guint32 slength;
2467
2468   slength = get_CDR_ulong(tvb,offset,stream_is_big_endian,boundary); /* get length first */
2469
2470 #if 0
2471   (*offset)++;                  /* must step past \0 delimiter */
2472 #endif
2473   
2474   if (slength > 0) {
2475     get_CDR_octet_seq(tvb, seq, offset, slength);
2476   } else {
2477     *seq = g_strdup("");        /* zero-length string */
2478   }
2479
2480   return slength;               /* return length */
2481
2482 }
2483
2484 /* Process a sequence of octets that represent the 
2485  * Pseudo Object Type "TypeCode". Typecodes are used for example,
2486  * by "Any values". 
2487  * This function also increments offset to the correct position.
2488  *
2489  * It will parse the TypeCode and output data to the "tree" provided
2490  * by the user
2491  *
2492  * It returns a guint32 representing a TCKind value. 
2493  */
2494
2495 guint32 get_CDR_typeCode(tvbuff_t *tvb, proto_tree *tree, gint *offset, 
2496                          gboolean stream_is_big_endian, int boundary,
2497                          MessageHeader * header ) {
2498   guint32 val;
2499
2500   gint16  s_octet2; /* signed int16 */
2501   guint16 u_octet2; /* unsigned int16 */
2502   guint32 u_octet4; /* unsigned int32 */
2503
2504   val = get_CDR_ulong(tvb,offset,stream_is_big_endian,boundary); /* get TCKind enum */
2505   if (tree) {
2506     proto_tree_add_uint(tree,hf_giop_TCKind,tvb,
2507                         *offset-sizeof(val),4,val);
2508   }
2509
2510   /* Grab the data according to Typecode Table - Corba Chapter 15 */
2511
2512   switch (val) {
2513   case tk_null: /* empty parameter list */
2514     break;
2515   case tk_void: /* empty parameter list */
2516     break;
2517   case tk_short: /* empty parameter list */
2518     break;
2519   case tk_long: /* empty parameter list */
2520     break;
2521   case tk_ushort: /* empty parameter list */
2522     break;
2523   case tk_ulong: /* empty parameter list */
2524     break;
2525   case tk_float: /* empty parameter list */
2526     break;
2527   case tk_double: /* empty parameter list */
2528     break;
2529   case tk_boolean: /* empty parameter list */
2530     break;
2531   case tk_char: /* empty parameter list */
2532     break;
2533   case tk_octet: /* empty parameter list */
2534     break;
2535   case tk_any: /* empty parameter list */
2536     break;
2537   case tk_TypeCode: /* empty parameter list */
2538     break;
2539   case tk_Principal: /* empty parameter list */
2540     break;
2541   case tk_objref: /* complex parameter list */
2542     dissect_tk_objref_params(tvb, tree, offset, stream_is_big_endian, boundary, header );
2543     break;
2544   case tk_struct: /* complex parameter list */
2545     dissect_tk_struct_params(tvb, tree, offset, stream_is_big_endian, boundary, header );
2546     break;
2547   case tk_union: /* complex parameter list */
2548     dissect_tk_union_params(tvb, tree, offset, stream_is_big_endian, boundary, header );
2549     break;
2550   case tk_enum: /* complex parameter list */
2551     dissect_tk_enum_params(tvb, tree, offset, stream_is_big_endian, boundary, header );
2552     break;
2553
2554   case tk_string: /* simple parameter list */
2555     u_octet4 = get_CDR_ulong(tvb,offset,stream_is_big_endian,boundary); /* get maximum length */
2556     if (tree) {
2557       proto_tree_add_uint(tree,hf_giop_typecode_max_length,tvb,
2558                           *offset-sizeof(u_octet4),4,u_octet4);
2559     }
2560     break;
2561
2562   case tk_sequence: /* complex parameter list */
2563     dissect_tk_sequence_params(tvb, tree, offset, stream_is_big_endian, boundary, header );
2564     break;
2565   case tk_array: /* complex parameter list */
2566     dissect_tk_array_params(tvb, tree, offset, stream_is_big_endian, boundary, header );
2567     break;
2568   case tk_alias: /* complex parameter list */
2569     dissect_tk_alias_params(tvb, tree, offset, stream_is_big_endian, boundary, header );
2570     break;
2571   case tk_except: /* complex parameter list */
2572     dissect_tk_except_params(tvb, tree, offset, stream_is_big_endian, boundary, header );
2573     break;
2574   case tk_longlong: /* empty parameter list */
2575     break;
2576   case tk_ulonglong: /* empty parameter list */
2577     break;
2578   case tk_longdouble: /* empty parameter list */
2579     break;
2580   case tk_wchar: /* empty parameter list */
2581     break;
2582   case tk_wstring: /* simple parameter list */
2583     u_octet4 = get_CDR_ulong(tvb,offset,stream_is_big_endian,boundary); /* get maximum length */
2584     if (tree) {
2585       proto_tree_add_uint(tree,hf_giop_typecode_max_length,tvb,
2586                           *offset-sizeof(u_octet4),4,u_octet4);
2587     }
2588     break;
2589
2590   case tk_fixed: /* simple parameter list */
2591     u_octet2 = get_CDR_ushort(tvb,offset,stream_is_big_endian,boundary); /* get digits */
2592     if (tree) {
2593       proto_tree_add_uint(tree,hf_giop_typecode_digits,tvb,
2594                           *offset-sizeof(u_octet2),2,u_octet2);
2595     }
2596
2597     s_octet2 = get_CDR_short(tvb,offset,stream_is_big_endian,boundary); /* get scale */
2598     if (tree) {
2599       proto_tree_add_int(tree,hf_giop_typecode_scale,tvb,
2600                           *offset-sizeof(s_octet2),2,s_octet2);
2601     }
2602     break;
2603
2604   case tk_value: /* complex parameter list */
2605     dissect_tk_value_params(tvb, tree, offset, stream_is_big_endian, boundary, header );
2606     break;
2607   case tk_value_box: /* complex parameter list */
2608     dissect_tk_value_box_params(tvb, tree, offset, stream_is_big_endian, boundary, header );
2609     break;
2610   case tk_native: /* complex parameter list */
2611     dissect_tk_native_params(tvb, tree, offset, stream_is_big_endian, boundary, header );
2612     break;
2613   case tk_abstract_interface: /* complex parameter list */
2614     dissect_tk_abstract_interface_params(tvb, tree, offset, stream_is_big_endian, boundary, header );
2615     break;
2616   default:
2617     g_warning("giop: Unknown TCKind %u \n", val);
2618     break;
2619   } /* val */
2620
2621   return val;
2622 }
2623
2624
2625
2626 /* Copy a 4 octet sequence from the tvbuff 
2627  * which represents an unsigned long value, and convert
2628  * it to an unsigned long vaule, taking into account byte order.
2629  * offset is first incremented so that it falls on a proper alignment
2630  * boundary for unsigned long values.
2631  * offset is then incremented by 4, to indicate the 4 octets which
2632  * have been processed.
2633  */
2634
2635 guint32 get_CDR_ulong(tvbuff_t *tvb, int *offset, gboolean stream_is_big_endian, int boundary) {
2636
2637   guint32 val;
2638
2639   /* unsigned long values must be aligned on a 4 byte boundary */
2640   while( ( (*offset + boundary) % 4) != 0)
2641           ++(*offset);
2642
2643   val = (stream_is_big_endian) ? tvb_get_ntohl (tvb, *offset) :
2644                                  tvb_get_letohl (tvb, *offset);
2645
2646   *offset += 4; 
2647   return val; 
2648 }
2649
2650
2651 /* Copy a 2 octet sequence from the tvbuff 
2652  * which represents an unsigned short value, and convert
2653  * it to an unsigned short value, taking into account byte order.
2654  * offset is first incremented so that it falls on a proper alignment
2655  * boundary for unsigned short values.
2656  * offset is then incremented by 2, to indicate the 2 octets which
2657  * have been processed.
2658  */
2659
2660 guint16 get_CDR_ushort(tvbuff_t *tvb, int *offset, gboolean stream_is_big_endian, int boundary) {
2661
2662   guint16 val;
2663
2664   /* unsigned short values must be aligned on a 2 byte boundary */
2665   while( ( (*offset + boundary) % 2) != 0)
2666           ++(*offset);
2667
2668   val = (stream_is_big_endian) ? tvb_get_ntohs (tvb, *offset) :
2669                                  tvb_get_letohs (tvb, *offset);
2670
2671   *offset += 2; 
2672   return val; 
2673 }
2674
2675
2676
2677 /* Copy a wchar from the tvbuff.
2678  * Caller of this function must remember to free the 
2679  * array pointed to by seq.
2680  * This function also increments offset according to
2681  * the wchar size.
2682  *
2683  * For GIOP 1.1 read 2 octets and return size -2. The
2684  * negation means there is no size element in the packet
2685  * and therefore no size to add to the tree.
2686  *
2687  * For GIOP 1.2 read size of wchar and the size
2688  * octets. size is returned as a gint8.
2689  *
2690  * For both GIOP versions the wchar is returned
2691  * as a printable string.
2692  *
2693  */
2694
2695 /* NOTE: This is very primitive in that it just reads
2696  * the wchar as a series of octets and returns them
2697  * to the user. No translation is attempted based on
2698  * byte orientation, nor on code set. I.e it only 
2699  * really reads past the wchar and sets the offset
2700  * correctly.
2701  */
2702
2703 /* The "decoding" is done according to CORBA chapter 15.
2704  * Wchar is not supported for GIOP 1.0.
2705  */
2706
2707 gint8 get_CDR_wchar(tvbuff_t *tvb, gchar **seq, int *offset, MessageHeader * header) {
2708   
2709   gint8 slength;
2710   gchar *raw_wstring;
2711
2712   /* CORBA chapter 15:
2713    *   - prior to GIOP 1.2 wchar limited to two octet fixed length.
2714    *   - GIOP 1.2 wchar is encoded as an unsigned binary octet
2715    *     followed by the elements of the octet sequence representing
2716    *     the encoded value of the wchar.
2717    */
2718
2719   *seq = NULL; /* set in case GIOP 1.2 length is 0 */
2720   slength = 2; /* set for GIOP 1.1 length in octets */
2721
2722   if (header->GIOP_version.minor > 1) /* if GIOP 1.2 get length of wchar */
2723     slength = get_CDR_octet(tvb,offset);
2724
2725   if (slength > 0) {
2726     /* ??? assume alignment is ok for GIOP 1.1 ??? */
2727     get_CDR_octet_seq(tvb, &raw_wstring, offset, slength);
2728
2729     /* now turn octets (wchar) into something that can be printed by the user */
2730     *seq = make_printable_string(raw_wstring, slength);
2731
2732     g_free(raw_wstring);
2733   }
2734
2735   /* if GIOP 1.1 negate length to indicate not an item to add to tree */
2736   if (header->GIOP_version.minor < 2)
2737     slength = -slength;
2738
2739   return slength;               /* return length */
2740
2741 }
2742
2743
2744 /* Copy a wstring from the tvbuff.
2745  * Caller of this function must remember to free the 
2746  * array pointed to by seq.
2747  * This function also increments offset, according to
2748  * wstring length. length is returned as guint32
2749  */
2750
2751 /* NOTE: This is very primitive in that it just reads
2752  * the wstring as a series of octets and returns them
2753  * to the user. No translation is attempted based on
2754  * byte orientation, nor on code set. I.e it only 
2755  * really reads past the wstring and sets the offset
2756  * correctly.
2757  */
2758
2759 /* The "decoding" is done according to CORBA chapter 15.
2760  * Wstring is not supported for GIOP 1.0.
2761  */
2762
2763
2764 guint32 get_CDR_wstring(tvbuff_t *tvb, gchar **seq, int *offset, gboolean stream_is_big_endian, 
2765                        int boundary, MessageHeader * header) {
2766   
2767   guint32 slength;
2768   gchar *raw_wstring;
2769
2770   /* CORBA chapter 15:
2771    *   - prior to GIOP 1.2 wstring limited to two octet fixed length.
2772    *     length and string are NUL terminated (length???).
2773    *   - GIOP 1.2 length is total number of octets. wstring is NOT NUL
2774    *     terminated.
2775    */
2776
2777   *seq = NULL; /* set in case GIOP 1.2 length is 0 */
2778
2779   /* get length, same for all GIOP versions,
2780    * although for 1.2 CORBA doesnt say, so assume. 
2781    */
2782   slength = get_CDR_ulong(tvb,offset,stream_is_big_endian,boundary);
2783
2784 #ifdef DEBUG
2785   if (slength>200) {
2786         fprintf(stderr, "giop:get_CDR_wstring, length %u > 200, truncating to 5 \n", slength);
2787         slength = 5;            /* better than core dumping during debug */
2788   }
2789 #endif
2790   
2791   if (header->GIOP_version.minor < 2) {
2792 #if 0
2793     (*offset)++;  /* must step past \0 delimiter */
2794 #endif
2795     /* assume length is number of characters and not octets, spec not clear */
2796     slength = slength * 2; /* length in octets is 2 * wstring length */
2797   }
2798
2799   if (slength > 0) {
2800     get_CDR_octet_seq(tvb, &raw_wstring, offset, slength);
2801
2802     /* now turn octets (wstring) into something that can be printed by the user */
2803     *seq = make_printable_string(raw_wstring, slength);
2804
2805     g_free(raw_wstring);
2806   }
2807
2808   return slength;               /* return length */
2809
2810 }
2811
2812
2813
2814 /**
2815  *  Dissects a TargetAddress which is defined in (CORBA 2.4, section 15.4.2)
2816  *  GIOP 1.2
2817  *  typedef short AddressingDisposition;
2818  *  const short KeyAddr = 0;
2819  *  const short ProfileAddr = 1;
2820  *  const short ReferenceAddr = 2;
2821  *  struct IORAddressingInfo {
2822  *    unsigned long selected_profile_index;
2823  *    IOP::IOR ior;
2824  *  };
2825  *
2826  *  union TargetAddress switch (AddressingDisposition) {
2827  *      case KeyAddr: sequence <octet> object_key;
2828  *      case ProfileAddr: IOP::TaggedProfile profile;
2829  *      case ReferenceAddr: IORAddressingInfo ior;
2830  *  };
2831  */
2832
2833 static void
2834 dissect_target_address(tvbuff_t * tvb, packet_info *pinfo, int *offset, proto_tree * tree, 
2835                        MessageHeader * header, gboolean stream_is_big_endian)
2836 {
2837    guint16 discriminant;
2838    gchar *object_key;
2839    gchar *p_object_key;
2840    guint32 len = 0;
2841    guint32 u_octet4;
2842
2843    discriminant = get_CDR_ushort(tvb, offset, stream_is_big_endian,GIOP_HEADER_SIZE);
2844    if(tree)
2845    {
2846      proto_tree_add_text (tree, tvb, *offset -2, 2,
2847                  "TargetAddress Discriminant: %u", discriminant);
2848    }
2849   
2850    switch (discriminant)
2851    {
2852            case 0:  /* KeyAddr */
2853                    len = get_CDR_ulong(tvb, offset, stream_is_big_endian,GIOP_HEADER_SIZE);
2854                    if(tree)
2855                    {
2856                       proto_tree_add_text (tree, tvb, *offset -4, 4,
2857                                            "KeyAddr (object key length): %u", len);
2858                    }
2859
2860                    if (len > 0) {
2861
2862                      get_CDR_octet_seq(tvb, &object_key, offset, len);
2863                      p_object_key = make_printable_string( object_key, len );
2864                    
2865                      if(tree)
2866                        {
2867                          proto_tree_add_text (tree, tvb, *offset -len, len,
2868                                                "KeyAddr (object key): %s", p_object_key);
2869                        }
2870                      g_free( p_object_key );
2871                      g_free( object_key );
2872                    }
2873                    break;
2874            case 1: /* ProfileAddr */
2875                    decode_TaggedProfile(tvb, pinfo, tree, offset, GIOP_HEADER_SIZE,
2876                                         stream_is_big_endian, NULL);
2877                    break;
2878            case 2: /* ReferenceAddr */
2879                    u_octet4 = get_CDR_ulong(tvb, offset, stream_is_big_endian,GIOP_HEADER_SIZE);
2880
2881                    if(tree)
2882                    {
2883                       proto_tree_add_text (tree, tvb, *offset -len -4, 4,
2884                                            "ReferenceAddr (selected_profile_index): %u", u_octet4);
2885                    }
2886
2887                    decode_IOR(tvb, pinfo, tree, offset, GIOP_HEADER_SIZE, stream_is_big_endian);
2888                    break;
2889            default:
2890                    break;
2891    }
2892 }
2893
2894 static void
2895 dissect_reply_body (tvbuff_t *tvb, u_int offset, packet_info *pinfo,
2896                     proto_tree *tree, gboolean stream_is_big_endian,
2897                     guint32 reply_status, MessageHeader *header, proto_tree *clnp_tree) {
2898
2899   u_int sequence_length;
2900   gboolean exres = FALSE;               /* result of trying explicit dissectors */
2901   gchar * repoid = NULL;        /* Repositor ID looked up from  objkey */
2902   
2903   /*
2904    * comp_req_list stuff
2905    */
2906
2907   comp_req_list_entry_t * entry = NULL; /* data element in our list */
2908   
2909   guint32 mfn;
2910
2911   switch (reply_status)
2912     {
2913     case SYSTEM_EXCEPTION:
2914
2915       decode_SystemExceptionReplyBody (tvb, tree, &offset, stream_is_big_endian, GIOP_HEADER_SIZE);
2916       break;
2917
2918     case USER_EXCEPTION:
2919
2920       sequence_length = get_CDR_ulong(tvb, &offset, stream_is_big_endian,GIOP_HEADER_SIZE);
2921
2922       if (tree)
2923       {
2924           proto_tree_add_text(tree, tvb, offset-4, 4,
2925                            "Exception length: %u", sequence_length);
2926       }
2927       if (sequence_length != 0)
2928         {
2929           if (tree)
2930           {
2931               proto_tree_add_text(tree, tvb, offset, sequence_length,
2932                            "Exception id: %s",
2933                            tvb_format_text(tvb, offset, sequence_length));
2934           }
2935 #if 1
2936
2937           header->exception_id = g_new0(gchar,sequence_length ); /* allocate buffer */
2938
2939           /* read exception id from buffer and store in*/
2940
2941           tvb_get_nstringz0(tvb,offset,sequence_length, header->exception_id );
2942           
2943
2944 #endif          
2945           
2946
2947           offset += sequence_length;
2948         }
2949
2950
2951
2952       /*
2953        * Now just fall through to the NO_EXCEPTION part
2954        * as this is common .
2955        */
2956       
2957
2958
2959     case NO_EXCEPTION:
2960
2961
2962       /* lookup MFN in hash directly */
2963  
2964       mfn = get_mfn_from_fn(pinfo->fd->num); 
2965       
2966       if (mfn == pinfo->fd->num)
2967         return;                 /* no matching frame number, what am I */
2968
2969       /* get entry for this MFN */
2970       entry = find_fn_in_list(mfn); /* get data entry in complete_request_list */
2971
2972       if (!entry)
2973         return;                 /* no matching entry */
2974         
2975
2976       /*
2977        * If this packet is a REPLY to a RESOLVE(request) 
2978        * then decode IOR.
2979        * TODO - make this lookup faster -- FS
2980        */
2981       
2982       if (!strcmp(giop_op_resolve,entry->operation)) {
2983         decode_IOR(tvb, pinfo, tree, &offset, GIOP_HEADER_SIZE,stream_is_big_endian);
2984         return;         /* done */
2985       }
2986       
2987       /* TODO -- Put stuff here for other "interesting operations" */
2988
2989       /*
2990        *
2991        * Call sub dissector.
2992        * First try an find a explicit sub_dissector, then if that
2993        * fails, try the heuristic method.
2994        */
2995
2996
2997       if(entry->repoid) {    
2998         exres = try_explicit_giop_dissector(tvb,pinfo,clnp_tree, &offset, header, entry->operation, entry->repoid );
2999       }
3000
3001       /* Only call heuristic if no explicit dixxector was found */
3002
3003       if(! exres) {
3004         try_heuristic_giop_dissector(tvb,pinfo,clnp_tree,&offset,header,entry->operation);
3005       } 
3006
3007
3008       break;
3009       
3010     case LOCATION_FORWARD:
3011       g_warning("giop: We don't yet dissect LOCATION_FORWARD\n");
3012
3013       break;
3014
3015     case LOCATION_FORWARD_PERM:
3016       g_warning("giop: We don't yet dissect LOCATION_FORWARD_PERM\n");
3017
3018       break;
3019
3020     case NEEDS_ADDRESSING_MODE:
3021       g_warning("giop: We don't yet dissect NEEDS_ADDRESSING_MODE\n");
3022
3023       break;
3024
3025     default:
3026       
3027       g_warning("giop: Unknown reply status %i request_id = %u\n",reply_status, header->req_id);
3028       
3029       break;
3030       
3031     } /* switch */
3032   
3033   g_free(repoid);               /* free resource */
3034   
3035   return;                       /* done */
3036   
3037 }
3038
3039
3040
3041
3042
3043 /* The format of the Reply Header for GIOP 1.0 and 1.1
3044  * is documented in Section 15.4.3.1 of the CORBA 2.4 standard.
3045
3046     struct ReplyHeader_1_0 {
3047           IOP::ServiceContextList service_context;
3048           unsigned long request_id;
3049           ReplyStatusType_1_0 reply_status;
3050     };
3051  */
3052
3053 static void dissect_giop_reply (tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree,
3054                                 proto_tree * clnp_tree, MessageHeader * header,
3055                                 gboolean stream_is_big_endian) {
3056
3057   guint32 offset = 0;
3058   guint32 request_id;
3059   guint32 reply_status;
3060   proto_tree *reply_tree = NULL;
3061   proto_item *tf;
3062   guint32 mfn;                  /* matching frame number */
3063
3064   if (tree) {
3065     tf = proto_tree_add_text (tree, tvb, offset,
3066                               tvb_length (tvb),
3067                               "General Inter-ORB Protocol Reply");
3068     if (reply_tree == NULL)
3069       {
3070         reply_tree = proto_item_add_subtree (tf, ett_giop_reply);
3071         
3072       }
3073   }
3074   
3075   /*
3076    * Decode IOP::ServiceContextList
3077    */
3078   
3079   decode_ServiceContextList(tvb, pinfo, reply_tree, &offset,stream_is_big_endian, GIOP_HEADER_SIZE);
3080
3081   request_id = get_CDR_ulong(tvb, &offset, stream_is_big_endian,GIOP_HEADER_SIZE);
3082
3083   if (check_col(pinfo->fd, COL_INFO)) {
3084     col_append_fstr(pinfo->fd, COL_INFO, " %u", request_id);
3085   }
3086
3087   if (tree) {
3088     proto_tree_add_text (reply_tree, tvb, offset-4, 4,
3089                          "Request id: %u", request_id);
3090   }
3091
3092   reply_status = get_CDR_ulong(tvb, &offset, stream_is_big_endian,GIOP_HEADER_SIZE);
3093
3094   if (check_col(pinfo->fd, COL_INFO)) {
3095     col_append_fstr(pinfo->fd, COL_INFO, ": %s",
3096                     val_to_str(reply_status, reply_status_types, "Unknown (%u)"));
3097
3098   }
3099
3100   if (tree) {
3101     proto_tree_add_text (reply_tree, tvb, offset-4, 4,
3102                          "Reply status: %s",
3103                          val_to_str(reply_status, reply_status_types, "Unknown (%u)"));
3104     
3105   }
3106
3107   /*
3108    * Save FN and MFN in complete_reply_hash, only if user is NOT clicking
3109    */
3110
3111   if (! pinfo->fd->flags.visited) {
3112     mfn = get_mfn_from_fn_and_reqid(pinfo->fd->num,request_id); /* find MFN for this FN */
3113     if (mfn != pinfo->fd->num) { /* if mfn is not fn, good */
3114       insert_in_complete_reply_hash(pinfo->fd->num, mfn);
3115     }
3116   }
3117
3118   header->req_id = request_id;          /* save for sub dissector */
3119   header->rep_status = reply_status;   /* save for sub dissector */
3120
3121   dissect_reply_body(tvb, offset, pinfo, reply_tree, stream_is_big_endian,
3122     reply_status, header,tree);
3123
3124
3125 }
3126
3127 /** The format of the GIOP 1.2 Reply header is very similar to the 1.0
3128  *  and 1.1 header, only the fields have been rearranged.  From Section
3129  *  15.4.3.1 of the CORBA 2.4 specification:
3130  *
3131  *   struct ReplyHeader_1_2 {
3132  *         unsigned long request_id;
3133  *         ReplyStatusType_1_2 reply_status;
3134  *         IOP:ServiceContextList service_context; 
3135  *    };
3136  */
3137
3138 static void dissect_giop_reply_1_2 (tvbuff_t * tvb, packet_info * pinfo,
3139                                     proto_tree * tree, proto_tree * clnp_tree,
3140                                     MessageHeader * header,
3141                                     gboolean stream_is_big_endian) {
3142
3143   u_int offset = 0;
3144   guint32 request_id;
3145   guint32 reply_status;
3146   proto_tree *reply_tree = NULL;
3147   proto_item *tf;
3148   guint32 mfn;                  /* matching frame number */
3149   
3150   if (tree) {
3151     tf = proto_tree_add_text (tree, tvb, offset,
3152                               tvb_length (tvb),
3153                               "General Inter-ORB Protocol Reply");
3154     reply_tree = proto_item_add_subtree (tf, ett_giop_reply);
3155   }
3156   
3157   request_id = get_CDR_ulong(tvb, &offset, stream_is_big_endian,GIOP_HEADER_SIZE);
3158   
3159   if (check_col(pinfo->fd, COL_INFO)) {
3160     col_append_fstr(pinfo->fd, COL_INFO, " %u", request_id);
3161   }
3162
3163   if (tree) {
3164     proto_tree_add_text (reply_tree, tvb, offset-4, 4,
3165                          "Request id: %u", request_id);
3166   }
3167
3168   reply_status = get_CDR_ulong(tvb, &offset, stream_is_big_endian,GIOP_HEADER_SIZE);
3169   
3170   if (check_col(pinfo->fd, COL_INFO)) {
3171     col_append_fstr(pinfo->fd, COL_INFO, ": %s",
3172                     val_to_str(reply_status, reply_status_types, "Unknown (%u)"));
3173
3174   }
3175
3176   if (tree) {
3177     proto_tree_add_text (reply_tree, tvb, offset-4, 4,
3178                          "Reply status: %s",
3179                          val_to_str(reply_status, reply_status_types, "Unknown (%u)"));
3180
3181   }
3182
3183   /*
3184    * Decode IOP::ServiceContextList
3185    */
3186
3187   decode_ServiceContextList(tvb, pinfo, reply_tree, &offset,stream_is_big_endian, GIOP_HEADER_SIZE);
3188
3189   /*
3190    * GIOP 1.2 Reply body must fall on an 8 octet alignment.
3191    */
3192
3193   set_new_alignment(&offset, GIOP_HEADER_SIZE, 8);
3194
3195   /*
3196    * Save FN and MFN in complete_reply_hash, only if user is NOT clicking
3197    */
3198   
3199   if (! pinfo->fd->flags.visited) {
3200     mfn = get_mfn_from_fn_and_reqid(pinfo->fd->num,request_id); /* find MFN for this FN */
3201     if (mfn != pinfo->fd->num) { /* if mfn is not fn, good */
3202       insert_in_complete_reply_hash(pinfo->fd->num, mfn);
3203     }
3204   }
3205
3206   /*
3207    * Add header to argument list so sub dissector can get header info.
3208    */
3209
3210   header->req_id = request_id;          /* save for sub dissector */
3211   header->rep_status = reply_status;   /* save for sub dissector */
3212
3213   dissect_reply_body(tvb, offset, pinfo, reply_tree, stream_is_big_endian,
3214                      reply_status,header,tree);
3215
3216 }
3217
3218
3219
3220 static void dissect_giop_cancel_request (tvbuff_t * tvb, packet_info * pinfo,
3221                         proto_tree * tree, proto_tree * clnp_tree,
3222                         MessageHeader * header, gboolean stream_is_big_endian) {
3223
3224   u_int offset = 0;
3225   guint32 request_id;
3226   proto_tree *cancel_request_tree = NULL;
3227   proto_item *tf;
3228
3229   if (tree) {
3230     tf = proto_tree_add_text (tree, tvb, offset,
3231                               tvb_length (tvb),
3232                               "General Inter-ORB Protocol CancelRequest");
3233     cancel_request_tree = proto_item_add_subtree (tf, ett_giop_cancel_request);
3234   }
3235
3236   request_id = get_CDR_ulong(tvb, &offset, stream_is_big_endian,GIOP_HEADER_SIZE);
3237   
3238   if (check_col(pinfo->fd, COL_INFO)) {
3239     col_append_fstr(pinfo->fd, COL_INFO, " %u", request_id);
3240   }
3241
3242   if (tree) {
3243     proto_tree_add_text (cancel_request_tree, tvb, offset-4, 4,
3244                          "Request id: %u", request_id);
3245   }
3246
3247   
3248 }
3249
3250 /**  The formats for GIOP 1.0 and 1.1 Request messages are defined
3251  *   in section 15.4.2.1 of the CORBA 2.4 specification.
3252  *
3253  *   struct RequestHeader{
3254  *          IOP::ServiceContextList   service_context;
3255  *          unsigned long             request_id;
3256  *          boolean                   response_expected;
3257  *          octet                     reserved[3];  // Only in GIOP 1.1
3258  *          sequence<octet>           object_key;
3259  *          string                    operation;
3260  *          CORBA::OctetSeq           requesting_principal;
3261  *   }
3262  */
3263 static void
3264 dissect_giop_request_1_1 (tvbuff_t * tvb, packet_info * pinfo,
3265                         proto_tree * tree, proto_tree * clnp_tree,
3266                         MessageHeader * header, gboolean stream_is_big_endian)
3267 {
3268   guint32 offset = 0;
3269   guint32 request_id;
3270   guint32 len = 0;
3271
3272   guint32 objkey_len = 0;       /* object key length */
3273   gchar *objkey = NULL;         /* object key sequence */
3274   gchar *print_objkey;          /* printable object key sequence */
3275   gboolean exres = FALSE;       /* result of trying explicit dissectors */
3276
3277   gchar *operation;
3278   gchar *requesting_principal;
3279   gchar *print_requesting_principal;
3280   guint8 response_expected;
3281   gchar *reserved;
3282   proto_tree *request_tree = NULL;
3283   proto_item *tf;
3284
3285   gchar *repoid = NULL;         /* from object key lookup in objkey hash */
3286
3287
3288   if (tree)
3289     {
3290       tf = proto_tree_add_text (tree, tvb, offset,
3291                                 tvb_length (tvb),
3292                                 "General Inter-ORB Protocol Request");
3293       if (request_tree == NULL)
3294         {
3295           request_tree = proto_item_add_subtree (tf, ett_giop_request);
3296
3297         }
3298     }
3299
3300
3301
3302
3303   /*
3304    * Decode IOP::ServiceContextList
3305    */
3306   
3307   decode_ServiceContextList(tvb, pinfo, request_tree, &offset,stream_is_big_endian, GIOP_HEADER_SIZE);
3308
3309
3310   request_id = get_CDR_ulong(tvb, &offset, stream_is_big_endian,GIOP_HEADER_SIZE);
3311   if (check_col(pinfo->fd, COL_INFO))
3312     {
3313       col_append_fstr(pinfo->fd, COL_INFO, " %u", request_id);
3314     }
3315   if (tree)
3316     {
3317       proto_tree_add_text (request_tree, tvb, offset-4, 4,
3318                            "Request id: %u", request_id);
3319     }
3320
3321   response_expected = tvb_get_guint8( tvb, offset );
3322   offset += 1;
3323   if (check_col(pinfo->fd, COL_INFO))
3324     {
3325       col_append_fstr(pinfo->fd, COL_INFO, " (%s)",
3326                 response_expected ? "two-way" : "one-way");
3327     }
3328   if (tree)
3329     {
3330       proto_tree_add_text (request_tree, tvb, offset-1, 1,
3331                            "Response expected: %u", response_expected);
3332     }
3333
3334   if( header->GIOP_version.minor > 0)
3335   {
3336      get_CDR_octet_seq( tvb, &reserved, &offset, 3);
3337      if (tree)
3338        {
3339          proto_tree_add_text (request_tree, tvb, offset-3, 3,
3340                            "Reserved: %x %x %x", reserved[0], reserved[1], reserved[2]);
3341        }
3342      g_free(reserved);
3343   }
3344
3345
3346
3347   /* Length of object_key sequence */
3348   objkey_len = get_CDR_ulong(tvb, &offset, stream_is_big_endian,GIOP_HEADER_SIZE);
3349
3350
3351   if(tree)
3352   {
3353          proto_tree_add_text (request_tree, tvb, offset-4, 4,
3354          /**/                 "Object Key length: %u", objkey_len);
3355   } 
3356
3357   if (objkey_len > 0)
3358   {
3359        get_CDR_octet_seq(tvb, &objkey, &offset, objkey_len);
3360
3361        print_objkey = make_printable_string(objkey, objkey_len);
3362
3363        if(tree)
3364        {
3365          proto_tree_add_text (request_tree, tvb, offset - objkey_len, objkey_len,
3366          /**/                 "Object Key: %s", print_objkey);
3367
3368        }
3369
3370        g_free( print_objkey );  
3371   } 
3372
3373   /*
3374    * Register a cleanup function in case on of our tvbuff accesses
3375    * throws an exception. We need to clean up objkey.
3376    */
3377   CLEANUP_PUSH(g_free, objkey);
3378
3379   /* length of operation string and string */ 
3380   len = get_CDR_string(tvb, &operation, &offset, stream_is_big_endian,GIOP_HEADER_SIZE);
3381   if(tree)
3382   {
3383          proto_tree_add_text (request_tree, tvb, offset - 4 - len, 4,
3384          /**/                 "Operation length: %u", len);
3385   } 
3386
3387   if( len > 0)
3388   {
3389        if (check_col(pinfo->fd, COL_INFO))
3390        {
3391          col_append_fstr(pinfo->fd, COL_INFO, ": %s", operation);
3392        }
3393        if(tree)
3394        {
3395          proto_tree_add_text (request_tree, tvb, offset - len, len,
3396          /**/                 "Operation: %s", operation);
3397
3398        }
3399   }
3400
3401   /*
3402    * Register a cleanup function in case on of our tvbuff accesses
3403    * throws an exception. We need to clean up operation.
3404    */
3405   CLEANUP_PUSH(g_free, operation);
3406
3407   /* length of requesting_principal string */ 
3408   len = get_CDR_ulong(tvb, &offset, stream_is_big_endian,GIOP_HEADER_SIZE);
3409   if(tree)
3410   {
3411          proto_tree_add_text (request_tree, tvb, offset-4, 4,
3412          /**/                 "Requesting Principal Length: %u", len);
3413   } 
3414
3415   if( len > 0)
3416   {
3417        get_CDR_octet_seq(tvb, &requesting_principal, &offset, len);
3418
3419        print_requesting_principal = make_printable_string(requesting_principal, len);
3420
3421        if(tree)
3422        {
3423          proto_tree_add_text (request_tree, tvb, offset - len, len, 
3424          /**/                 "Requesting Principal: %s", print_requesting_principal);
3425
3426        }
3427
3428        g_free( print_requesting_principal );
3429        g_free( requesting_principal );
3430   }
3431
3432
3433   /*
3434    * Save FN,reqid,and operation for later. Add sub_handle later.
3435    * But only if user is NOT clicking.
3436    */
3437
3438   if (! pinfo->fd->flags.visited)
3439     giop_complete_request_list = insert_in_comp_req_list(giop_complete_request_list,pinfo->fd->num,
3440                                                          request_id,operation,NULL);
3441
3442   
3443   /*
3444    * Call subdissector here before freeing "operation" and "key"
3445    * pass request_id also. 
3446    * First try an find an explicit sub_dissector, then if that
3447    * fails, try the heuristic method.
3448    *
3449    */
3450
3451
3452   header->req_id = request_id;          /* save for sub dissector */
3453   repoid = get_repoid_from_objkey(giop_objkey_hash,objkey,objkey_len);
3454
3455
3456   if(repoid) {    
3457     exres = try_explicit_giop_dissector(tvb,pinfo,tree,&offset,header,operation,repoid);
3458   }
3459
3460   /* Only call heuristic if no explicit dissector was found */
3461
3462   if (! exres) {
3463     try_heuristic_giop_dissector(tvb,pinfo,tree,&offset,header,operation);
3464   }
3465   
3466
3467   /*
3468    * We're done with operation, so we can call the cleanup handler to free
3469    * it, and then pop the cleanup handler.
3470    */
3471   CLEANUP_CALL_AND_POP;
3472
3473   /*
3474    * We're done with objkey, so we can call the cleanup handler to free
3475    * it, and then pop the cleanup handler.
3476    */
3477   CLEANUP_CALL_AND_POP;
3478
3479 }
3480
3481 /**  The format of a GIOP 1.2 RequestHeader message is 
3482  *   (CORBA 2.4, sec. 15.4.2):
3483  *
3484  *   struct RequestHeader_1_2 {
3485  *       unsigned long request_id;
3486  *       octet response_flags;
3487  *       octet reserved[3];
3488  *       TargetAddress target;
3489  *       string operation;
3490  *       IOP::ServiceContextList service_context;
3491  *       // requesting_principal not in GIOP 1.2
3492  *   };
3493  */
3494 static void
3495 dissect_giop_request_1_2 (tvbuff_t * tvb, packet_info * pinfo,
3496                         proto_tree * tree, proto_tree * clnp_tree,
3497                         MessageHeader * header, gboolean stream_is_big_endian)
3498 {
3499   guint32 offset = 0;
3500   guint32 request_id;
3501   guint32 len = 0;
3502   guint8 response_flags;
3503   gchar *reserved;
3504   gchar *operation = NULL;
3505   proto_tree *request_tree = NULL;
3506   proto_item *tf;
3507   gboolean exres = FALSE;               /* result of trying explicit dissectors */
3508
3509   gchar *repoid = NULL;
3510
3511
3512   if (tree)
3513     {
3514       tf = proto_tree_add_text (tree, tvb, offset,
3515                                 tvb_length (tvb),
3516                                 "General Inter-ORB Protocol Request");
3517       request_tree = proto_item_add_subtree (tf, ett_giop_reply);
3518     }
3519
3520   request_id = get_CDR_ulong(tvb, &offset, stream_is_big_endian,GIOP_HEADER_SIZE);
3521   if (check_col(pinfo->fd, COL_INFO))
3522     {
3523       col_append_fstr(pinfo->fd, COL_INFO, " %u", request_id);
3524     }
3525   if (request_tree)
3526     {
3527       proto_tree_add_text (request_tree, tvb, offset-4, 4,
3528                            "Request id: %u", request_id);
3529     }
3530
3531   response_flags = tvb_get_guint8( tvb, offset );
3532   offset += 1;
3533   if (request_tree)
3534     {
3535       proto_tree_add_text (request_tree, tvb, offset-1, 1,
3536                            "Response flags: %s (%u)",
3537                                 match_strval(response_flags, sync_scope),  
3538                                 response_flags);
3539     }
3540
3541   get_CDR_octet_seq( tvb, &reserved, &offset, 3);
3542   if (request_tree)
3543    {
3544      proto_tree_add_text (request_tree, tvb, offset-3, 3,
3545            "Reserved: %x %x %x", reserved[0], reserved[1], reserved[2]);
3546    }
3547   g_free(reserved);
3548
3549   dissect_target_address(tvb, pinfo, &offset, request_tree, header, stream_is_big_endian);
3550
3551   /* length of operation string */ 
3552   len = get_CDR_string(tvb, &operation, &offset, stream_is_big_endian,GIOP_HEADER_SIZE);
3553   if(tree)
3554   {
3555          proto_tree_add_text (request_tree, tvb, offset - len - 4, 4,
3556          /**/                 "Operation length: %u", len);
3557   } 
3558
3559   if( len > 0)
3560   {
3561        if (check_col(pinfo->fd, COL_INFO))
3562        {
3563          col_append_fstr(pinfo->fd, COL_INFO, ": %s", operation);
3564        }
3565        if(request_tree)
3566        {
3567          proto_tree_add_text (request_tree, tvb, offset - len, len,
3568          /**/                 "Operation: %s", operation);
3569
3570        }
3571
3572   }
3573
3574   /*
3575    * Register a cleanup function in case on of our tvbuff accesses
3576    * throws an exception. We need to clean up operation.
3577    */
3578   CLEANUP_PUSH(g_free, operation);
3579
3580   /*
3581    * Decode IOP::ServiceContextList
3582    */
3583
3584   decode_ServiceContextList(tvb, pinfo, request_tree, &offset,  stream_is_big_endian, GIOP_HEADER_SIZE);
3585
3586   /*
3587    * GIOP 1.2 Request body must fall on an 8 octet alignment, taking into
3588    * account we are in a new tvbuff, GIOP_HEADER_SIZE octets from the
3589    * GIOP octet stream start.
3590    */
3591
3592   set_new_alignment(&offset, GIOP_HEADER_SIZE, 8);
3593
3594   /*
3595    * Save FN,reqid,and operation for later. Add sub_handle later.
3596    * But only if user is NOT clicking.
3597    */
3598   
3599   if (! pinfo->fd->flags.visited)
3600     giop_complete_request_list = insert_in_comp_req_list(giop_complete_request_list,pinfo->fd->num,
3601                                                          request_id,operation,NULL);
3602
3603   /*
3604    *
3605    * Call sub dissector.
3606    * First try an find a explicit sub_dissector, then if that
3607    * fails, try the heuristic method.
3608    */
3609   
3610
3611   if(repoid) {    
3612     exres = try_explicit_giop_dissector(tvb,pinfo,tree,&offset,header,operation,repoid);
3613   }
3614
3615   /* Only call heuristic if no explicit dissector was found */
3616
3617   if (! exres) {
3618     try_heuristic_giop_dissector(tvb,pinfo,tree,&offset,header,operation);
3619   }
3620   
3621
3622   /*
3623    * We're done with operation, so we can call the cleanup handler to free
3624    * it, and then pop the cleanup handler.
3625    */
3626   CLEANUP_CALL_AND_POP;
3627 }
3628
3629 static void
3630 dissect_giop_locate_request( tvbuff_t * tvb, packet_info * pinfo,
3631                         proto_tree * tree, MessageHeader * header,
3632                         gboolean stream_is_big_endian)
3633 {
3634   guint32 offset = 0;
3635   guint32 request_id;
3636   guint32 len = 0;
3637   gchar *object_key;
3638   gchar *p_object_key;
3639   proto_tree *locate_request_tree = NULL;
3640   proto_item *tf;
3641
3642   if (tree)
3643     {
3644       tf = proto_tree_add_text (tree, tvb, offset,
3645                                 tvb_length (tvb),
3646                                 "General Inter-ORB Locate Request");
3647       if (locate_request_tree == NULL)
3648         {
3649           locate_request_tree = proto_item_add_subtree (tf, ett_giop_locate_request);
3650
3651         }
3652     }
3653
3654   request_id = get_CDR_ulong(tvb, &offset, stream_is_big_endian,GIOP_HEADER_SIZE);
3655   if (check_col(pinfo->fd, COL_INFO))
3656     {
3657       col_append_fstr(pinfo->fd, COL_INFO, " %u", request_id);
3658     }
3659   if (locate_request_tree)
3660     {
3661       proto_tree_add_text (locate_request_tree, tvb, offset-4, 4,
3662                            "Request id: %u", request_id);
3663     }
3664
3665   if(header->GIOP_version.minor < 2)
3666   {
3667         len = get_CDR_ulong(tvb, &offset, stream_is_big_endian,GIOP_HEADER_SIZE);
3668         if (locate_request_tree)
3669           {
3670             proto_tree_add_text (locate_request_tree, tvb, offset-4, 4,
3671                                  "Object Key length: %u", len);
3672           }
3673
3674         if (len > 0) {
3675           get_CDR_octet_seq(tvb, &object_key, &offset, len);
3676
3677           p_object_key = make_printable_string(object_key, len);
3678   
3679           if(locate_request_tree)
3680             {
3681
3682               proto_tree_add_text (locate_request_tree, tvb, offset-len, len,
3683                                    "Object Key: %s", p_object_key);
3684             }
3685
3686           g_free(p_object_key);
3687           g_free(object_key);
3688         }
3689   }
3690   else     /* GIOP 1.2 and higher */
3691   {
3692       dissect_target_address(tvb, pinfo, &offset, locate_request_tree, header,
3693                              stream_is_big_endian);
3694
3695   }
3696 }
3697
3698 static void
3699 dissect_giop_locate_reply( tvbuff_t * tvb, packet_info * pinfo,
3700                         proto_tree * tree, MessageHeader * header,
3701                         gboolean stream_is_big_endian)
3702 {
3703   guint32 offset = 0;
3704   guint32 request_id;
3705   guint32 locate_status;
3706   guint16 addr_disp;
3707
3708   proto_tree *locate_reply_tree = NULL;
3709   proto_item *tf;
3710
3711   if (tree)
3712     {
3713       tf = proto_tree_add_text (tree, tvb, offset,
3714                                 tvb_length (tvb),
3715                                 "General Inter-ORB Locate Reply");
3716       if (locate_reply_tree == NULL)
3717         {
3718           locate_reply_tree = proto_item_add_subtree (tf, ett_giop_locate_reply);
3719
3720         }
3721     }
3722
3723   request_id = get_CDR_ulong(tvb, &offset, stream_is_big_endian,GIOP_HEADER_SIZE);
3724   if (check_col(pinfo->fd, COL_INFO))
3725     {
3726       col_append_fstr(pinfo->fd, COL_INFO, " %u", request_id);
3727     }
3728   if (locate_reply_tree)
3729     {
3730       proto_tree_add_text (locate_reply_tree, tvb, offset-4, 4,
3731                            "Request id: %u", request_id);
3732     }
3733
3734   locate_status = get_CDR_ulong(tvb, &offset, stream_is_big_endian,GIOP_HEADER_SIZE);
3735   if (locate_reply_tree)
3736     {
3737       proto_tree_add_text (locate_reply_tree, tvb, offset-4, 4,
3738                            "Locate status: %s", 
3739                            match_strval(locate_status, giop_locate_status_types)
3740                            );
3741     }
3742
3743   /* Decode the LocateReply body.
3744    *
3745    * For GIOP 1.0 and 1.1 body immediately follows header.
3746    * For GIOP 1.2 it is aligned on 8 octet boundary so need to
3747    * spin up.
3748    */
3749
3750   if (header->GIOP_version.minor > 1) {
3751     while( ( (offset + GIOP_HEADER_SIZE) % 8) != 0)
3752       ++(offset);
3753   }
3754
3755   switch(locate_status) {
3756   case OBJECT_FORWARD: /* fall through to OBJECT_FORWARD_PERM */
3757   case OBJECT_FORWARD_PERM:
3758     decode_IOR(tvb, pinfo, locate_reply_tree, &offset, GIOP_HEADER_SIZE, stream_is_big_endian);
3759     break;
3760   case LOC_SYSTEM_EXCEPTION:
3761     decode_SystemExceptionReplyBody (tvb, tree, &offset, stream_is_big_endian, GIOP_HEADER_SIZE);
3762     break;
3763   case LOC_NEEDS_ADDRESSING_MODE:
3764     addr_disp = get_CDR_ushort(tvb, &offset, stream_is_big_endian,GIOP_HEADER_SIZE);
3765     if(locate_reply_tree) {
3766       proto_tree_add_text (tree, tvb, offset -2, 2,
3767                            "AddressingDisposition: %u", addr_disp);
3768     }
3769     break;
3770   default: /* others have no reply body */
3771     break;
3772   }
3773
3774 }
3775
3776 static void
3777 dissect_giop_fragment( tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree,
3778                         MessageHeader * header, gboolean stream_is_big_endian)
3779 {
3780   guint32 offset = 0;
3781   guint32 request_id;
3782   proto_tree *fragment_tree = NULL;
3783   proto_item *tf;
3784
3785   if (tree)
3786     {
3787       tf = proto_tree_add_text (tree, tvb, offset,
3788                                 tvb_length (tvb),
3789                                 "General Inter-ORB Fragment");
3790       if (fragment_tree == NULL)
3791         {
3792           fragment_tree = proto_item_add_subtree (tf, ett_giop_fragment);
3793
3794         }
3795     }
3796
3797   request_id = get_CDR_ulong(tvb, &offset, stream_is_big_endian,GIOP_HEADER_SIZE);
3798   if (check_col(pinfo->fd, COL_INFO))
3799     {
3800       col_append_fstr(pinfo->fd, COL_INFO, " %u", request_id);
3801     }
3802   if (fragment_tree )
3803     {
3804       proto_tree_add_text (fragment_tree, tvb, offset-4, 4,
3805                            "Request id: %u", request_id);
3806     }
3807                                    
3808 }
3809
3810
3811 /* Main entry point */
3812
3813 gboolean dissect_giop (tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree) {
3814   u_int offset = 0;
3815   MessageHeader header;
3816   tvbuff_t *giop_header_tvb;
3817   tvbuff_t *payload_tvb;
3818
3819   proto_tree *clnp_tree = NULL;
3820   proto_item *ti;
3821   u_int message_size;
3822   u_int minor_version;
3823   gboolean stream_is_big_endian;
3824
3825
3826   /* DEBUG */
3827   
3828 #if DEBUG
3829   giop_dump_collection(cd_module_hash);
3830   giop_dump_collection(cd_objkey_hash);
3831   giop_dump_collection(cd_heuristic_users);
3832   giop_dump_collection(cd_complete_reply_hash);
3833   giop_dump_collection(cd_complete_request_list);
3834 #endif
3835
3836   header.exception_id = NULL;
3837
3838   /* check magic number and version */
3839
3840
3841   /*define END_OF_GIOP_MESSAGE (offset - first_offset - GIOP_HEADER_SIZE) */
3842
3843   if (tvb_length_remaining(tvb, 0) < GIOP_HEADER_SIZE)
3844     {
3845       /* Not enough data captured to hold the GIOP header; don't try
3846          to interpret it as GIOP. */
3847       return FALSE;
3848     }
3849
3850   giop_header_tvb = tvb_new_subset (tvb, 0, GIOP_HEADER_SIZE, -1);
3851   payload_tvb = tvb_new_subset (tvb, GIOP_HEADER_SIZE, -1, -1);
3852   
3853   /*
3854    * because I have added extra elements in MessageHeader struct
3855    * for sub dissectors. -- FS
3856    */
3857
3858   tvb_memcpy (giop_header_tvb, (guint8 *)&header, 0, GIOP_HEADER_SIZE );
3859
3860   if (memcmp (header.magic, GIOP_MAGIC, sizeof (header.magic)) != 0)
3861     {
3862       /* Not a GIOP message. */
3863
3864       return FALSE;
3865     }
3866
3867   if (check_col (pinfo->fd, COL_PROTOCOL))
3868     {
3869       col_set_str (pinfo->fd, COL_PROTOCOL, "GIOP");
3870     }
3871
3872   if (header.GIOP_version.major != GIOP_MAJOR ||
3873       ((minor_version = header.GIOP_version.minor) > GIOP_MINOR))
3874     {
3875       /* Bad version number; should we note that and dissect the rest
3876          as data, or should we return FALSE on the theory that it
3877          might have been some other packet that happened to begin with
3878          "GIOP"?  We shouldn't do *both*, so we return TRUE, for now.
3879          If we should return FALSE, we should do so *without* setting
3880          the "Info" column, *without* setting the "Protocol" column,
3881          and *without* adding anything to the protocol tree. */
3882
3883       if (check_col (pinfo->fd, COL_INFO))
3884         {
3885           col_add_fstr (pinfo->fd, COL_INFO, "Version %u.%u",
3886                         header.GIOP_version.major, header.GIOP_version.minor);
3887         }
3888       if (tree)
3889         {
3890           ti = proto_tree_add_item (tree, proto_giop, tvb, 0,
3891                                     tvb_length (tvb), FALSE);
3892           clnp_tree = proto_item_add_subtree (ti, ett_giop);
3893           proto_tree_add_text (clnp_tree, giop_header_tvb, 0,
3894                                tvb_length (giop_header_tvb),
3895                                "Version %u.%u not supported",
3896                                header.GIOP_version.major,
3897                                header.GIOP_version.minor);
3898         }
3899       dissect_data (payload_tvb, 0, pinfo, tree);
3900       return TRUE;
3901     }
3902
3903   if (check_col (pinfo->fd, COL_INFO)) 
3904   { 
3905       col_add_fstr (pinfo->fd, COL_INFO, "GIOP %u.%u %s",
3906                     header.GIOP_version.major, header.GIOP_version.minor,
3907                     val_to_str(header.message_type, giop_message_types,
3908                                "Unknown message type (0x%02x)"));
3909   }
3910
3911   stream_is_big_endian = is_big_endian (&header);
3912
3913   if (stream_is_big_endian)
3914     message_size = pntohl (&header.message_size);
3915   else
3916     message_size = pletohl (&header.message_size);
3917
3918   if (tree)
3919     {
3920       ti = proto_tree_add_item (tree, proto_giop, tvb, 0, 12, FALSE);
3921       clnp_tree = proto_item_add_subtree (ti, ett_giop);
3922       proto_tree_add_text (clnp_tree, giop_header_tvb, offset, 4,
3923                            "Magic number: %s", GIOP_MAGIC);
3924       proto_tree_add_text (clnp_tree, giop_header_tvb, 4, 2,
3925                            "Version: %u.%u",
3926                            header.GIOP_version.major,
3927                            header.GIOP_version.minor);
3928       switch (minor_version)
3929         {
3930         case 2:
3931         case 1:
3932           proto_tree_add_text (clnp_tree, giop_header_tvb, 6, 1,
3933                                "Flags: 0x%02x (%s %s)",
3934                                header.flags,
3935                                (stream_is_big_endian) ? "big-endian" : "little-endian",
3936                                (header.flags & 0x02) ? " fragment" : "");
3937           break;
3938         case 0:
3939           proto_tree_add_text (clnp_tree, giop_header_tvb, 6, 1,
3940                                "Byte ordering: %s-endian",
3941                                (stream_is_big_endian) ? "big" : "little");
3942           break;
3943         default:
3944           break;
3945         }                       /* minor_version */
3946
3947       proto_tree_add_uint_format (clnp_tree,
3948                                   hf_giop_message_type,
3949                                   giop_header_tvb, 7, 1,
3950                                   header.message_type,
3951                                   "Message type: %s", match_strval(header.message_type, giop_message_types));
3952
3953       proto_tree_add_uint (clnp_tree,
3954                            hf_giop_message_size,
3955                            giop_header_tvb, 8, 4, message_size);
3956
3957     }                           /* tree */
3958
3959 #if 0
3960   if (check_col (pinfo->fd, COL_INFO)) 
3961   { 
3962       col_add_fstr (pinfo->fd, COL_INFO, "GIOP %u.%u %s",
3963                     header.GIOP_version.major, header.GIOP_version.minor,
3964                     match_strval(header.message_type, giop_message_types));
3965   }
3966 #endif
3967
3968   switch (header.message_type)
3969     {
3970
3971     case Request:
3972       if(header.GIOP_version.minor < 2)
3973       {
3974            dissect_giop_request_1_1 (payload_tvb, pinfo, tree, clnp_tree,
3975                                      &header, stream_is_big_endian);
3976       }
3977       else
3978       {    
3979            dissect_giop_request_1_2 (payload_tvb, pinfo, tree, clnp_tree,
3980                                      &header, stream_is_big_endian);
3981       }
3982       
3983       break;
3984
3985
3986     case Reply:
3987       if(header.GIOP_version.minor < 2)
3988         {
3989            dissect_giop_reply (payload_tvb, pinfo, tree, clnp_tree, &header,
3990                                stream_is_big_endian);
3991         }
3992       else
3993         {
3994            dissect_giop_reply_1_2 (payload_tvb, pinfo, tree, clnp_tree,
3995                                    &header, stream_is_big_endian);
3996         }
3997       break;
3998     case CancelRequest:
3999         dissect_giop_cancel_request(payload_tvb, pinfo, tree, clnp_tree,
4000                                     &header, stream_is_big_endian);
4001         break;
4002     case LocateRequest:
4003         dissect_giop_locate_request(payload_tvb, pinfo, tree, &header,
4004                                     stream_is_big_endian);
4005         break;
4006     case LocateReply:
4007         dissect_giop_locate_reply(payload_tvb, pinfo, tree, &header,
4008                                   stream_is_big_endian);
4009         break;
4010     case Fragment:
4011         dissect_giop_fragment(payload_tvb, pinfo, tree, &header,
4012                               stream_is_big_endian);
4013         break;  
4014     default:
4015       break;
4016
4017     }                           /* switch message_type */
4018
4019
4020   /*
4021    * XXX - we should catch exceptions here, so that we can free
4022    * this if an exception is thrown.
4023    * We'd then have to forward the exception.
4024    */
4025   if (header.exception_id != NULL)
4026     g_free(header.exception_id);
4027
4028   return TRUE;
4029 }
4030
4031 void
4032 proto_register_giop (void)
4033 {
4034   static hf_register_info hf[] = {
4035     { &hf_giop_message_type,
4036      { "Message type", "giop.type",
4037        FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }
4038     },
4039     
4040     { &hf_giop_message_size,
4041       { "Message size", "giop.len",
4042         FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }
4043     },
4044
4045     { &hf_giop_repoid,
4046      { "Repository ID", "giop.repoid",
4047        FT_STRING, BASE_DEC, NULL, 0x0, "", HFILL }
4048     },
4049
4050     { &hf_giop_string_length,
4051      { "String Length", "giop.strlen",
4052        FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }
4053     },
4054
4055     { &hf_giop_sequence_length,
4056      { "Sequence Length", "giop.seqlen",
4057        FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }
4058     },
4059
4060     { &hf_giop_profile_id,
4061      { "Profile ID", "giop.profid",
4062        FT_UINT32, BASE_DEC, VALS(profile_id_vals), 0x0, "", HFILL }
4063     },
4064
4065
4066     { &hf_giop_type_id,
4067      { "IOR::type_id", "giop.typeid",
4068        FT_STRING, BASE_DEC, NULL, 0x0, "", HFILL }
4069     },
4070
4071     { &hf_giop_iiop_v_maj,
4072      { "IIOP Major Version", "giop.iiop_vmaj",
4073        FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }
4074     }
4075     ,
4076     { &hf_giop_iiop_v_min,
4077      { "IIOP Minor Version", "giop.iiop_vmin",
4078        FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }
4079     },
4080
4081     { &hf_giop_endianess,
4082      { "Endianess", "giop.endianess",
4083        FT_UINT8, BASE_DEC, VALS(giop_endianess_vals), 0x0, "", HFILL }
4084     },
4085
4086     { &hf_giop_IIOP_tag,
4087      { "IIOP Component TAG", "giop.iioptag",
4088        FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }
4089     },
4090
4091     { &hf_giop_IOR_tag,
4092      { "IOR Profile TAG", "giop.iortag",
4093        FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }
4094     },
4095
4096     { &hf_giop_TCKind,
4097      { "TypeCode enum", "giop.TCKind",
4098        FT_UINT32, BASE_DEC, VALS(tckind_vals), 0x0, "", HFILL }
4099     },
4100
4101     { &hf_giop_typecode_count,
4102      { "TypeCode count", "giop.tccount",
4103        FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }
4104     },
4105
4106     { &hf_giop_typecode_default_used,
4107      { "default_used", "giop.tcdefault_used",
4108        FT_INT32, BASE_DEC, NULL, 0x0, "", HFILL }
4109     },
4110
4111     { &hf_giop_typecode_digits,
4112      { "Digits", "giop.tcdigits",
4113        FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }
4114     },
4115
4116
4117     { &hf_giop_typecode_length,
4118      { "Length", "giop.tclength",
4119        FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }
4120     },
4121
4122     { &hf_giop_typecode_max_length,
4123      { "Maximum length", "giop.tcmaxlen",
4124        FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }
4125     },
4126
4127     { &hf_giop_typecode_member_name,
4128      { "TypeCode member name", "giop.tcmemname",
4129        FT_STRING, BASE_DEC, NULL, 0x0, "", HFILL }
4130     },
4131
4132     { &hf_giop_typecode_name,
4133      { "TypeCode name", "giop.tcname",
4134        FT_STRING, BASE_DEC, NULL, 0x0, "", HFILL }
4135     },
4136
4137     { &hf_giop_typecode_scale,
4138      { "Scale", "giop.tcscale",
4139        FT_INT16, BASE_DEC, NULL, 0x0, "", HFILL }
4140     },
4141
4142     { &hf_giop_typecode_ValueModifier,
4143      { "ValueModifier", "giop.tcValueModifier",
4144        FT_INT16, BASE_DEC, NULL, 0x0, "", HFILL }
4145     },
4146
4147     { &hf_giop_typecode_Visibility,
4148      { "Visibility", "giop.tcVisibility",
4149        FT_INT16, BASE_DEC, NULL, 0x0, "", HFILL }
4150     },
4151
4152
4153
4154     { &hf_giop_type_boolean,
4155       { "TypeCode boolean data", "giop.tcboolean",
4156         FT_BOOLEAN, BASE_DEC,  NULL, 0x0, "", HFILL }
4157     },
4158
4159     { &hf_giop_type_char,
4160       { "TypeCode char data", "giop.tcchar",
4161         FT_UINT8, BASE_DEC,  NULL, 0x0, "", HFILL }
4162     },
4163
4164     { &hf_giop_type_double,
4165       { "TypeCode double data", "giop.tcdouble",
4166         FT_DOUBLE, BASE_DEC,  NULL, 0x0, "", HFILL }
4167     },
4168
4169     { &hf_giop_type_enum,
4170      { "TypeCode enum data", "giop.tcenumdata",
4171        FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }
4172     },
4173
4174     /*
4175      * float as double ?? -- FIX
4176      */
4177
4178     { &hf_giop_type_float,
4179       { "TypeCode float data", "giop.tcfloat",
4180         FT_DOUBLE, BASE_DEC,  NULL, 0x0, "", HFILL }
4181     },
4182
4183     { &hf_giop_type_long,
4184      { "TypeCode long data", "giop.tclongdata",
4185        FT_INT32, BASE_DEC, NULL, 0x0, "", HFILL }
4186     },
4187
4188     { &hf_giop_type_octet,
4189       { "TypeCode octet data", "giop.tcoctet",
4190         FT_UINT8, BASE_DEC,  NULL, 0x0, "", HFILL }
4191     },
4192
4193     { &hf_giop_type_short,
4194      { "TypeCode short data", "giop.tcshortdata",
4195        FT_INT16, BASE_DEC, NULL, 0x0, "", HFILL }
4196     },
4197
4198     { &hf_giop_type_string,
4199       { "TypeCode string data", "giop.tcstring",
4200         FT_STRING, BASE_DEC,  NULL, 0x0, "", HFILL }
4201     },
4202
4203     { &hf_giop_type_ulong,
4204      { "TypeCode ulong data", "giop.tculongdata",
4205        FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }
4206     },
4207
4208     { &hf_giop_type_ushort,
4209      { "TypeCode ushort data", "giop.tcushortdata",
4210        FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }
4211     },
4212
4213     /*
4214      * IIOP Module - Chapter 15.10.2
4215      */
4216
4217     { &hf_giop_iiop_host,
4218      { "IIOP::Profile_host", "giop.iiop.host",
4219        FT_STRING, BASE_DEC, NULL, 0x0, "", HFILL }
4220     }
4221     ,
4222
4223     { &hf_giop_iiop_port,
4224      { "IIOP::Profile_port", "giop.iiop.port",
4225        FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }
4226     }
4227     ,
4228
4229     /*
4230      * IIOP ServiceContext
4231      */
4232
4233     { &hf_giop_iop_vscid,
4234      { "VSCID", "giop.iiop.vscid",
4235        FT_UINT32, BASE_HEX, NULL, 0xfffff000, "", HFILL }
4236     }
4237     ,
4238
4239     { &hf_giop_iop_scid,
4240      { "SCID", "giop.iiop.scid",
4241        FT_UINT32, BASE_HEX, NULL, 0x00000fff, "", HFILL }
4242     }
4243     ,
4244
4245
4246   };
4247
4248   static gint *ett[] = {
4249     &ett_giop,
4250     &ett_giop_reply,
4251     &ett_giop_request,
4252     &ett_giop_cancel_request,
4253     &ett_giop_locate_request,
4254     &ett_giop_locate_reply,
4255     &ett_giop_fragment,
4256     &ett_giop_scl,
4257     &ett_giop_ior
4258
4259   };
4260   proto_giop = proto_register_protocol("General Inter-ORB Protocol", "GIOP",
4261                                        "giop");
4262   proto_register_field_array (proto_giop, hf, array_length (hf));
4263   proto_register_subtree_array (ett, array_length (ett));
4264
4265
4266   /* register init routine */
4267
4268   register_init_routine( &giop_init); /* any init stuff */
4269
4270   /*
4271    * Init the giop user module hash tables here, as giop users
4272    * will populate it via register_giop_user_module BEFORE my
4273    * own giop_init() is called.
4274    */
4275
4276   giop_module_hash = g_hash_table_new(giop_hash_module_hash, giop_hash_module_equal);
4277   
4278   giop_module_keys = g_mem_chunk_new("giop_module_keys",
4279                                      sizeof(struct giop_module_key),
4280                                      giop_module_init_count * sizeof(struct giop_module_key), 
4281                                      G_ALLOC_AND_FREE);
4282   
4283   giop_module_vals = g_mem_chunk_new("giop_module_vals", 
4284                   &n