Include files from the "epan" directory and subdirectories thereof with
[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.54 2002/01/21 07:36:34 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 <epan/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 static dissector_handle_t data_handle;
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   const char *saved_proto;
1744
1745   len = g_slist_length(giop_sub_list); /* find length */
1746
1747   if (len == 0)
1748     return FALSE;
1749
1750   saved_proto = pinfo->current_proto;
1751   for (i=0; i<len; i++) {
1752     subh = (giop_sub_handle_t *) g_slist_nth_data(giop_sub_list,i); /* grab dissector handle */
1753
1754     if (proto_is_protocol_enabled(subh->sub_proto)) {
1755       pinfo->current_proto =
1756         proto_get_protocol_short_name(subh->sub_proto);
1757       res = (subh->sub_fn)(tvb,pinfo,tree,offset,header,operation,NULL); /* callit TODO - replace NULL */
1758       if (res) {
1759         pinfo->current_proto = saved_proto;
1760         return TRUE;            /* found one, lets return */
1761       }  
1762     } /* protocol_is_enabled */
1763   } /* loop */
1764
1765   if (check_col (pinfo->cinfo, COL_PROTOCOL))
1766       col_set_str (pinfo->cinfo, COL_PROTOCOL, "GIOP");
1767
1768   pinfo->current_proto = saved_proto;
1769   return res;                   /* result */
1770
1771 }
1772
1773
1774 /*
1775  * Find the matching repoid in the module hash and call
1776  * the dissector function if offset exists.
1777  * 
1778  *
1779  * Repoid is eg IDL:tux.antarctic/Penguin/Teeth:1.0 but subdissectors 
1780  * will register possibly "tux.antarctic/Penguin" and "tux.antarctic/Penguin/Teeth". 
1781  *
1782  *
1783  *
1784  */
1785
1786 static gboolean try_explicit_giop_dissector(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int *offset,
1787                                             MessageHeader *header, gchar *operation, gchar *repoid ) {
1788
1789   giop_sub_handle_t *subdiss = NULL; /* handle */
1790   gboolean res = FALSE;
1791   gchar *modname = NULL;
1792   struct giop_module_key module_key;
1793   struct giop_module_val *module_val = NULL;
1794   const char *saved_proto;
1795
1796
1797   /*
1798    * Get top level module/interface from complete repoid 
1799    */
1800
1801   modname = get_modname_from_repoid(repoid); 
1802   if (modname == NULL) {
1803     return res;                 /* unknown module name */
1804   }
1805
1806
1807   /* Search for Module or interface name */
1808
1809   module_key.module = modname; /*  module name */
1810   module_val = (struct giop_module_val *)g_hash_table_lookup(giop_module_hash, &module_key);
1811
1812   if (module_val == NULL) {
1813     return res;                 /* module not registered */
1814   }
1815   
1816   subdiss = (giop_sub_handle_t *) module_val->subh; /* grab dissector handle */
1817
1818   if (subdiss) {
1819     /* Add giop_sub_handle_t and repoid into complete_request_list, so REPLY can */
1820     /* look it up directly, later ie: FN -> MFN -> giop_sub_handle_t and repoid */
1821     /* but only if user not clicking */
1822
1823     if (!pinfo->fd->flags.visited)
1824       add_sub_handle_repoid_to_comp_req_list(pinfo->fd->num,subdiss,repoid);
1825
1826
1827     /* Call subdissector if current offset exists , and dissector is enabled in GUI "edit protocols" */
1828
1829     if (tvb_offset_exists(tvb, *offset)) {   
1830 #if DEBUG  
1831       printf("giop:try_explicit_dissector calling sub = %s with module = (%s) \n", subdiss->sub_name  , modname);
1832 #endif
1833
1834       if (proto_is_protocol_enabled(subdiss->sub_proto)) {
1835
1836         saved_proto = pinfo->current_proto;
1837         pinfo->current_proto =
1838           proto_get_protocol_short_name(subdiss->sub_proto);
1839         res = (subdiss->sub_fn)(tvb,pinfo,tree,offset,header,operation, modname); /* callit, TODO replace NULL with idlname */
1840         pinfo->current_proto = saved_proto;
1841
1842       } /* protocol_is_enabled */
1843     } /* offset exists */
1844   } /* subdiss */
1845   
1846   return res;                   /* return result */
1847 }
1848
1849
1850
1851 /* Take in an array of char and create a new string.
1852  * Replace non-printable characters with periods.
1853  *
1854  * The array may contain \0's so dont use strdup
1855  * The string is \0 terminated, and thus longer than
1856  * the initial sequence. 
1857  * Caller must free the new string.
1858  */
1859
1860 static gchar * make_printable_string (gchar *in, guint32 len) {
1861   guint32 i = 0;
1862   gchar *print_string = NULL;
1863
1864   print_string = (gchar * )g_malloc0(len + 1); /* make some space and zero it */
1865   memcpy(print_string, in, len);        /* and make a copy of input data */
1866   
1867   for(i=0; i < len; i++) {
1868     if( !isprint( (unsigned char)print_string[i] ) ) 
1869       print_string[i] = '.';
1870   }
1871
1872   return print_string;          /* return ptr */
1873 }
1874
1875 /* Determine the byte order from the GIOP MessageHeader */
1876
1877 gboolean is_big_endian (MessageHeader * header) {
1878   gboolean big_endian = FALSE;
1879
1880   switch (header->GIOP_version.minor) {
1881   case 2:
1882   case 1:
1883     if (header->flags & 0x01)
1884       big_endian = FALSE;
1885     else
1886       big_endian = TRUE;
1887     break;
1888   case 0:
1889     if (header->flags)
1890       big_endian = FALSE;
1891     else
1892       big_endian = TRUE;
1893     break;
1894   default:
1895     break;
1896   }
1897   return big_endian;
1898 }
1899
1900
1901
1902 /* 
1903  * Calculate new offset, based on the current offset, and user supplied 
1904  * "offset delta" value, and the alignment requirement.
1905  *
1906  *
1907  *
1908  * eg: Used for GIOP 1.2 where Request and Reply bodies are 
1909  *     aligned on 8 byte boundaries.
1910  */
1911
1912 static void set_new_alignment(int *offset, int delta, int  alignment) {
1913
1914   while( ( (*offset + delta) % alignment) != 0)
1915           ++(*offset);
1916
1917
1918 }
1919
1920
1921
1922 /*
1923  * ------------------------------------------------------------------------------------------+ 
1924  *                                 Public get_CDR_xxx functions.
1925  * ------------------------------------------------------------------------------------------+
1926  */
1927
1928
1929
1930 /*
1931  * Gets data of type any. This is encoded as a TypeCode
1932  * followed by the encoded value.
1933  */
1934
1935 void get_CDR_any(tvbuff_t *tvb, proto_tree *tree, gint *offset, 
1936                  gboolean stream_is_big_endian, int boundary,
1937                  MessageHeader * header ) {
1938   
1939   guint32  TCKind;    /* TypeCode */
1940
1941   /* get TypeCode of any */
1942   TCKind = get_CDR_typeCode(tvb, tree, offset, stream_is_big_endian, boundary, header );
1943
1944   /* dissect data of type TCKind */
1945   dissect_data_for_typecode(tvb, tree, offset, stream_is_big_endian, boundary, header, TCKind );
1946 }
1947
1948
1949 /* Copy a 1 octet sequence from the tvbuff 
1950  * which represents a boolean value, and convert
1951  * it to a boolean value.
1952  * Offset is then incremented by 1, to indicate the 1 octet which
1953  * has been processed.
1954  */
1955
1956 gboolean get_CDR_boolean(tvbuff_t *tvb, int *offset) {
1957   guint8 val;
1958
1959   val = tvb_get_guint8(tvb, *offset); /* easy */
1960   (*offset)++;
1961   return val;
1962 }
1963
1964 /* Copy a 1 octet sequence from the tvbuff 
1965  * which represents a char, and convert
1966  * it to an char value.
1967  * offset is then incremented by 1, to indicate the 1 octet which
1968  * has been processed.
1969  */
1970
1971 guint8 get_CDR_char(tvbuff_t *tvb, int *offset) {
1972   guint8 val;
1973
1974   val = tvb_get_guint8(tvb, *offset); /* easy */
1975   (*offset)++;
1976   return val;
1977 }
1978
1979
1980
1981 /* 
1982  * Floating Point Data Type double IEEE 754-1985 
1983  *
1984  * Copy an 8 octet sequence from the tvbuff 
1985  * which represents a double value, and convert
1986  * it to a double value, taking into account byte order.
1987  * offset is first incremented so that it falls on a proper alignment
1988  * boundary for double values.
1989  * offset is then incremented by 8, to indicate the 8 octets which
1990  * have been processed.
1991  */
1992
1993 gdouble get_CDR_double(tvbuff_t *tvb, int *offset, gboolean stream_is_big_endian, int boundary) {
1994
1995   guint8 sign;
1996   guint8 e1,e2,f1,f2,f3,f4,f5,f6,f7;
1997   gdouble val;
1998   guint16 exp;
1999   guint32 fract0, fract1;
2000   gdouble d_fract;              
2001   
2002
2003   /* double values must be aligned on a 8 byte boundary */
2004
2005   while( ( (*offset + boundary) % 8) != 0)
2006           ++(*offset);
2007
2008
2009   if(stream_is_big_endian) {    
2010     e1  = get_CDR_octet(tvb,offset);
2011     sign = e1 >> 7;                     /* sign value */
2012     e1 &= 0x7f;         /* bottom 7 bits */
2013     f1  = get_CDR_octet(tvb,offset);
2014     e2 = f1 >> 4;
2015     f1 &= 0x0f;         /* bottom 4 bits */
2016     f2  = get_CDR_octet(tvb,offset);
2017     f3  = get_CDR_octet(tvb,offset);
2018     f4  = get_CDR_octet(tvb,offset);
2019     f5  = get_CDR_octet(tvb,offset);
2020     f6  = get_CDR_octet(tvb,offset);
2021     f7  = get_CDR_octet(tvb,offset);
2022
2023   } else {
2024
2025     f7  = get_CDR_octet(tvb,offset);
2026     f6  = get_CDR_octet(tvb,offset);
2027     f5  = get_CDR_octet(tvb,offset);
2028     f4  = get_CDR_octet(tvb,offset);
2029     f3  = get_CDR_octet(tvb,offset);
2030     f2  = get_CDR_octet(tvb,offset);
2031     f1  = get_CDR_octet(tvb,offset);
2032     e2 = f1 >> 4;
2033     f1 &= 0x0f;         /* bottom 4 bits */
2034     e1  = get_CDR_octet(tvb,offset);
2035     sign = e1 >> 7;                     /* sign value */
2036     e1 &= 0x7f;         /* bottom 7 bits */
2037
2038   }
2039
2040   exp = (e1 << 4) + e2;
2041
2042   /* Now lets do some 52 bit math with 32 bit constraint */
2043
2044   fract0 = f7 + (f6 << 8) + (f5 << 16) + (f4 << 24); /* lower 32 bits of fractional part */
2045   fract1 = f3 + (f2 << 8) + (f1 << 16);              /* top 20 bits of fractional part   */
2046
2047   d_fract = (fract1 / (pow(2,20))) + (fract0 / (pow(2,52))); /* 52 bits represent a fraction */
2048
2049   val = pow(-1,sign) * pow(2,(exp - 1023)) * (1 + d_fract);
2050
2051   return val;           /* FIX rounding ?? */
2052
2053 }
2054
2055
2056 /* Copy a 4 octet sequence from the tvbuff 
2057  * which represents an enum value, and convert
2058  * it to an enum value, taking into account byte order.
2059  * offset is first incremented so that it falls on a proper alignment
2060  * boundary for an enum (4)
2061  * offset is then incremented by 4, to indicate the 4 octets which
2062  * have been processed.
2063  *
2064  * Enum values are encoded as unsigned long.
2065  */
2066
2067
2068 guint32 get_CDR_enum(tvbuff_t *tvb, int *offset, gboolean stream_is_big_endian, int boundary) {
2069
2070   return get_CDR_ulong(tvb, offset, stream_is_big_endian, boundary );
2071
2072 }
2073
2074
2075 /*
2076  * Copy an octet sequence from the tvbuff
2077  * which represents a Fixed point decimal type, and create a string representing
2078  * a Fixed point decimal type. There are no alignment restrictions.
2079  * Size and scale of fixed decimal type is determined by IDL.
2080  * 
2081  * digits - IDL specified number of "digits" for this fixed type
2082  * scale  - IDL specified "scale" for this fixed type
2083  *
2084  *
2085  * eg: typedef fixed <5,2> fixed_t;
2086  *     could represent numbers like 123.45, 789.12, 
2087  *
2088  *
2089  * As the fixed type could be any size, I will not try to fit it into our
2090  * simple types like gdouble or glong etc. I will just create a string buffer holding
2091  * a  representation (after scale is applied), and with a decimal point or zero padding
2092  * inserted at the right place if necessary. The string is null terminated
2093  *
2094  * so string may look like 
2095  *
2096  *
2097  *  "+1.234" or "-3456.78" or "1234567309475760377365465897891" or "-2789000000" etc
2098  *
2099  * According to spec, digits <= 31
2100  * and scale is positive (except for constants eg: 1000 has digit=1 and implied scale = -3)
2101  * or <4,0> ?
2102  *
2103  * User must remember to free the buffer
2104  *
2105  */
2106
2107
2108 void get_CDR_fixed(tvbuff_t *tvb, gchar **seq, gint *offset, guint32 digits, gint32 scale) {
2109
2110   guint8 sign;                  /* 0x0c is positive, 0x0d is negative */
2111   guint32 i ;                   /* loop */
2112   guint32 slen;                 /* number of bytes to hold digits + extra 0's if scale <0 */
2113                                 /* this does not include sign, decimal point and \0 */
2114   guint32 sindex = 0;           /* string index */
2115   gchar *tmpbuf;                /* temp buff, holds string without scaling */
2116   guint8 tval;                  /* temp val storage */
2117
2118   /*
2119    * how many bytes to hold digits and scale (if scale <0) 
2120    *
2121    * eg: fixed <5,2> = 5 digits
2122    *     fixed <5,-2> = 7 digits (5 + 2 added 0's)
2123    */
2124
2125 #if DEBUG
2126     printf("giop:get_CDR_fixed() called , digits = %u, scale = %u \n", digits, scale);
2127 #endif
2128
2129   if (scale <0) {
2130     slen = digits - scale;      /* allow for digits + padding 0's for negative scal */
2131   } else {
2132     slen = digits;              /*  digits */
2133   }
2134
2135 #if DEBUG
2136     printf("giop:get_CDR_fixed(): slen =  %.2x \n", slen);
2137 #endif
2138   
2139   tmpbuf = g_new0(gchar, slen); /* allocate temp buffer */ 
2140
2141   /*
2142    * Register a cleanup function in case on of our tvbuff accesses
2143    * throws an exception. We need to clean up tmpbuf.
2144    */
2145   CLEANUP_PUSH(g_free, tmpbuf);
2146
2147   /* If even , grab 1st dig */
2148
2149   if (!(digits & 0x01)) {
2150     tval = get_CDR_octet(tvb,offset);
2151 #if DEBUG
2152     printf("giop:get_CDR_fixed():even: octet = %.2x \n", tval);
2153 #endif
2154     tmpbuf[sindex] = (tval & 0x0f) + 0x30; /* convert top nibble to ascii */
2155     sindex++;
2156   }
2157
2158   /*
2159    * Loop, but stop BEFORE we hit last digit and sign 
2160    * if digits = 1 or 2, then this part is skipped 
2161    */
2162
2163   if (digits>2) {
2164     for(i=0; i< ((digits-1)/2 ); i++) {
2165       tval = get_CDR_octet(tvb,offset);
2166 #if DEBUG
2167       printf("giop:get_CDR_fixed():odd: octet = %.2x \n", tval);
2168 #endif
2169       
2170       tmpbuf[sindex] = ((tval & 0xf0) >> 4) + 0x30; /* convert top nibble to ascii */
2171       sindex++;
2172       tmpbuf[sindex] = (tval & 0x0f)  + 0x30; /* convert bot nibble to ascii */
2173       sindex++;
2174       
2175     }
2176   } /* digits > 3 */
2177
2178 #if DEBUG
2179     printf("giop:get_CDR_fixed(): before last digit \n");
2180 #endif
2181   
2182
2183   /* Last digit and sign if digits >1, or 1st dig and sign if digits = 1 */
2184
2185     tval = get_CDR_octet(tvb,offset);
2186 #if DEBUG
2187     printf("giop:get_CDR_fixed(): octet = %.2x \n", tval);
2188 #endif
2189     tmpbuf[sindex] = (( tval & 0xf0)>> 4) + 0x30; /* convert top nibble to ascii */
2190     sindex++;
2191
2192     sign = tval & 0x0f; /* get sign */
2193
2194     /* So now, we have all digits in an array, and the sign byte 
2195      * so lets generate a printable string, taking into account the scale
2196      * and sign values.
2197      */
2198  
2199     sindex = 0;                         /* reset */
2200     *seq = g_new0(gchar, slen + 3);     /* allocate temp buffer , including space for sign, decimal point and 
2201                                          * \0 -- TODO check slen is reasonable first */
2202 #if DEBUG
2203     printf("giop:get_CDR_fixed(): sign =  %.2x \n", sign);
2204 #endif                                  
2205     
2206     switch(sign) {
2207     case 0x0c:
2208       (*seq)[sindex] = '+';     /* put sign in first string position */
2209       break;                    
2210     case 0x0d:
2211       (*seq)[sindex] = '-';
2212       break;
2213     default:
2214       g_warning("giop: Unknown sign value in fixed type %u \n", sign);
2215       (*seq)[sindex] = '*';     /* flag as sign unkown */
2216       break;
2217     }
2218
2219     sindex++;
2220
2221     /* Add decimal point or padding 0's, depending if scale is positive or
2222      * negative, respectively
2223      */
2224
2225     if (scale>0) {
2226       for (i=0; i<digits-scale; i++) {
2227         (*seq)[sindex] = tmpbuf[i]; /* digits to the left of the decimal point */       
2228         sindex++;
2229       }
2230       
2231       (*seq)[sindex] = '.'; /* decimal point */ 
2232       sindex++;
2233       
2234       for (i=digits-scale; i<digits; i++) {
2235         (*seq)[sindex] = tmpbuf[i]; /* remaining digits to the right of the decimal point */    
2236         sindex++;
2237       }
2238
2239       (*seq)[sindex] = '\0'; /* string terminator */    
2240
2241     } else {
2242
2243       /* negative scale, dump digits and  pad out with 0's */
2244
2245       for (i=0; i<digits-scale; i++) {
2246         if (i<digits) {
2247           (*seq)[sindex] = tmpbuf[i]; /* save digits */ 
2248         } else {
2249           (*seq)[sindex] = '0'; /* all digits used up, so pad with 0's */       
2250         }
2251         sindex++;
2252       }
2253
2254       (*seq)[sindex] = '\0'; /* string terminator */    
2255       
2256     }
2257
2258     /*
2259      * We're done with tmpbuf, so we can call the cleanup handler to free
2260      * it, and then pop the cleanup handler.
2261      */
2262     CLEANUP_CALL_AND_POP;
2263     
2264 #if DEBUG
2265     printf("giop:get_CDR_fixed(): value = %s \n", *seq);
2266 #endif
2267
2268     return; 
2269
2270 }
2271
2272
2273
2274 /*
2275  * Floating Point Data Type float IEEE 754-1985 
2276  * 
2277  * Copy an 4 octet sequence from the tvbuff 
2278  * which represents a float value, and convert
2279  * it to a float value, taking into account byte order.
2280  * offset is first incremented so that it falls on a proper alignment
2281  * boundary for float values.
2282  * offset is then incremented by 4, to indicate the 4 octets which
2283  * have been processed.
2284  */
2285
2286 gfloat get_CDR_float(tvbuff_t *tvb, int *offset, gboolean stream_is_big_endian, int boundary) {
2287   
2288   guint8 sign;
2289   guint8 e1,e2,f1,f2,f3;
2290   gfloat val;
2291   guint8 exp;
2292   guint32 fract;
2293   gdouble d_fract;              
2294   
2295   /* float values must be aligned on a 4 byte boundary */
2296
2297   while( ( (*offset + boundary) % 4) != 0)
2298     ++(*offset);
2299
2300   if(stream_is_big_endian) {    
2301     e1  = get_CDR_octet(tvb,offset);
2302     sign = e1 >> 7;                     /* sign value */
2303     e1 &= 0x7f;         /* bottom 7 bits */
2304     f1  = get_CDR_octet(tvb,offset);
2305     e2 = f1 >> 7;
2306     f1 &= 0x7f;         /* bottom 7 bits */
2307     f2  = get_CDR_octet(tvb,offset);
2308     f3  = get_CDR_octet(tvb,offset);
2309
2310   } else {
2311
2312     f3  = get_CDR_octet(tvb,offset);
2313     f2  = get_CDR_octet(tvb,offset);
2314     f1  = get_CDR_octet(tvb,offset);
2315     e2 = f1 >> 7;
2316     f1 &= 0x7f;         /* bottom 7 bits */
2317     e1  = get_CDR_octet(tvb,offset);
2318     sign = e1 >> 7;                     /* sign value */
2319     e1 &= 0x7f;         /* bottom 7 bits */
2320
2321   }
2322
2323
2324   exp = (e1 << 1) + e2;
2325   fract = f3 + (f2 << 8) + (f1 << 16);
2326
2327   d_fract = fract / (pow(2,23)); /* 23 bits represent a fraction */
2328
2329   val = pow(-1,sign) * pow(2,(exp - 127)) * (1 + d_fract);
2330
2331   return val;           /* FIX rounding ?? */
2332
2333 }
2334
2335
2336 /*
2337  * Decode an Interface type, and display it on the tree.
2338  */
2339
2340 void get_CDR_interface(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int *offset, 
2341                        gboolean stream_is_big_endian, int boundary) {
2342
2343
2344   decode_IOR(tvb, pinfo, tree, offset, boundary, stream_is_big_endian);
2345   
2346   return;
2347 }
2348
2349
2350 /* Copy a 4 octet sequence from the tvbuff 
2351  * which represents a signed long value, and convert
2352  * it to an signed long vaule, taking into account byte order.
2353  * offset is first incremented so that it falls on a proper alignment
2354  * boundary for long values.
2355  * offset is then incremented by 4, to indicate the 4 octets which
2356  * have been processed.
2357  */
2358
2359 gint32 get_CDR_long(tvbuff_t *tvb, int *offset, gboolean stream_is_big_endian, int boundary) {
2360
2361   gint32 val;
2362
2363   /* unsigned long values must be aligned on a 4 byte boundary */
2364   while( ( (*offset + boundary) % 4) != 0)
2365           ++(*offset);
2366
2367   val = (stream_is_big_endian) ? tvb_get_ntohl (tvb, *offset) :
2368                                  tvb_get_letohl (tvb, *offset);
2369
2370   *offset += 4; 
2371   return val; 
2372 }
2373
2374 /*
2375  * Decode an Object type, and display it on the tree.
2376  */
2377
2378 void get_CDR_object(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int *offset, 
2379                     gboolean stream_is_big_endian, int boundary) {
2380   
2381   decode_IOR(tvb, pinfo, tree, offset, boundary, stream_is_big_endian);
2382   
2383   return;
2384 }
2385
2386
2387 /* Copy a 1 octet sequence from the tvbuff 
2388  * which represents a octet, and convert
2389  * it to an octet value.
2390  * offset is then incremented by 1, to indicate the 1 octet which
2391  * has been processed.
2392  */
2393
2394 guint8 get_CDR_octet(tvbuff_t *tvb, int *offset) {
2395   guint8 val;
2396
2397   val = tvb_get_guint8(tvb, *offset); /* easy */
2398   (*offset)++;
2399   return val;
2400 }
2401
2402
2403 /* Copy a sequence of octets from the tvbuff.
2404  * Caller of this function must remember to free the 
2405  * array pointed to by seq.
2406  * This function also increments offset by len. 
2407  */
2408
2409 void get_CDR_octet_seq(tvbuff_t *tvb, gchar **seq, int *offset, int len) {
2410
2411   if (! tvb_bytes_exist(tvb, *offset,len)) {
2412     /*
2413      * Generate an exception, and stop processing.
2414      * We do that now, rather than after allocating the buffer, so we
2415      * don't have to worry about freeing the buffer.
2416      * XXX - would we be better off using a cleanup routine?
2417      */
2418     tvb_get_guint8(tvb, *offset + len);
2419   }
2420
2421   /*
2422    * XXX - should we just allocate "len" bytes, and have "get_CDR_string()"
2423    * do what we do now, and null-terminate the string (which also means
2424    * we don't need to zero out the entire allocation, just the last byte)?
2425    */
2426   *seq = g_new0(gchar, len + 1);
2427   tvb_memcpy( tvb, *seq, *offset, len);
2428   *offset += len;
2429 }
2430
2431
2432 /* Copy a 2 octet sequence from the tvbuff 
2433  * which represents a signed short value, and convert
2434  * it to a signed short value, taking into account byte order.
2435  * offset is first incremented so that it falls on a proper alignment
2436  * boundary for short values.
2437  * offset is then incremented by 2, to indicate the 2 octets which
2438  * have been processed.
2439  */
2440
2441 gint16 get_CDR_short(tvbuff_t *tvb, int *offset, gboolean stream_is_big_endian, int boundary) {
2442
2443   gint16 val;
2444
2445   /* short values must be aligned on a 2 byte boundary */
2446   while( ( (*offset + boundary) % 2) != 0)
2447           ++(*offset);
2448
2449   val = (stream_is_big_endian) ? tvb_get_ntohs (tvb, *offset) :
2450                                  tvb_get_letohs (tvb, *offset);
2451
2452   *offset += 2; 
2453   return val; 
2454 }
2455
2456
2457
2458 /* Copy an octet sequence from the tvbuff 
2459  * which represents a string, and convert
2460  * it to an string value, taking into account byte order.
2461  * offset is first incremented so that it falls on a proper alignment
2462  * boundary for string values. (begins with an unsigned long LI)
2463  *
2464  * String sequence is copied to a  buffer "seq". This must
2465  * be freed by the calling program.
2466  * offset is then incremented, to indicate the  octets which
2467  * have been processed.
2468  *
2469  * returns number of octets in the sequence
2470  *
2471  * Note: This function only supports single byte encoding at the
2472  *       moment until I get a handle on multibyte encoding etc.
2473  *
2474  */
2475
2476
2477 guint32 get_CDR_string(tvbuff_t *tvb, gchar **seq, int *offset, gboolean stream_is_big_endian, 
2478                        int boundary ) {
2479   
2480   guint32 slength;
2481
2482   slength = get_CDR_ulong(tvb,offset,stream_is_big_endian,boundary); /* get length first */
2483
2484 #if 0
2485   (*offset)++;                  /* must step past \0 delimiter */
2486 #endif
2487   
2488   if (slength > 0) {
2489     get_CDR_octet_seq(tvb, seq, offset, slength);
2490   } else {
2491     *seq = g_strdup("");        /* zero-length string */
2492   }
2493
2494   return slength;               /* return length */
2495
2496 }
2497
2498 /* Process a sequence of octets that represent the 
2499  * Pseudo Object Type "TypeCode". Typecodes are used for example,
2500  * by "Any values". 
2501  * This function also increments offset to the correct position.
2502  *
2503  * It will parse the TypeCode and output data to the "tree" provided
2504  * by the user
2505  *
2506  * It returns a guint32 representing a TCKind value. 
2507  */
2508
2509 guint32 get_CDR_typeCode(tvbuff_t *tvb, proto_tree *tree, gint *offset, 
2510                          gboolean stream_is_big_endian, int boundary,
2511                          MessageHeader * header ) {
2512   guint32 val;
2513
2514   gint16  s_octet2; /* signed int16 */
2515   guint16 u_octet2; /* unsigned int16 */
2516   guint32 u_octet4; /* unsigned int32 */
2517
2518   val = get_CDR_ulong(tvb,offset,stream_is_big_endian,boundary); /* get TCKind enum */
2519   if (tree) {
2520     proto_tree_add_uint(tree,hf_giop_TCKind,tvb,
2521                         *offset-sizeof(val),4,val);
2522   }
2523
2524   /* Grab the data according to Typecode Table - Corba Chapter 15 */
2525
2526   switch (val) {
2527   case tk_null: /* empty parameter list */
2528     break;
2529   case tk_void: /* empty parameter list */
2530     break;
2531   case tk_short: /* empty parameter list */
2532     break;
2533   case tk_long: /* empty parameter list */
2534     break;
2535   case tk_ushort: /* empty parameter list */
2536     break;
2537   case tk_ulong: /* empty parameter list */
2538     break;
2539   case tk_float: /* empty parameter list */
2540     break;
2541   case tk_double: /* empty parameter list */
2542     break;
2543   case tk_boolean: /* empty parameter list */
2544     break;
2545   case tk_char: /* empty parameter list */
2546     break;
2547   case tk_octet: /* empty parameter list */
2548     break;
2549   case tk_any: /* empty parameter list */
2550     break;
2551   case tk_TypeCode: /* empty parameter list */
2552     break;
2553   case tk_Principal: /* empty parameter list */
2554     break;
2555   case tk_objref: /* complex parameter list */
2556     dissect_tk_objref_params(tvb, tree, offset, stream_is_big_endian, boundary, header );
2557     break;
2558   case tk_struct: /* complex parameter list */
2559     dissect_tk_struct_params(tvb, tree, offset, stream_is_big_endian, boundary, header );
2560     break;
2561   case tk_union: /* complex parameter list */
2562     dissect_tk_union_params(tvb, tree, offset, stream_is_big_endian, boundary, header );
2563     break;
2564   case tk_enum: /* complex parameter list */
2565     dissect_tk_enum_params(tvb, tree, offset, stream_is_big_endian, boundary, header );
2566     break;
2567
2568   case tk_string: /* simple parameter list */
2569     u_octet4 = get_CDR_ulong(tvb,offset,stream_is_big_endian,boundary); /* get maximum length */
2570     if (tree) {
2571       proto_tree_add_uint(tree,hf_giop_typecode_max_length,tvb,
2572                           *offset-sizeof(u_octet4),4,u_octet4);
2573     }
2574     break;
2575
2576   case tk_sequence: /* complex parameter list */
2577     dissect_tk_sequence_params(tvb, tree, offset, stream_is_big_endian, boundary, header );
2578     break;
2579   case tk_array: /* complex parameter list */
2580     dissect_tk_array_params(tvb, tree, offset, stream_is_big_endian, boundary, header );
2581     break;
2582   case tk_alias: /* complex parameter list */
2583     dissect_tk_alias_params(tvb, tree, offset, stream_is_big_endian, boundary, header );
2584     break;
2585   case tk_except: /* complex parameter list */
2586     dissect_tk_except_params(tvb, tree, offset, stream_is_big_endian, boundary, header );
2587     break;
2588   case tk_longlong: /* empty parameter list */
2589     break;
2590   case tk_ulonglong: /* empty parameter list */
2591     break;
2592   case tk_longdouble: /* empty parameter list */
2593     break;
2594   case tk_wchar: /* empty parameter list */
2595     break;
2596   case tk_wstring: /* simple parameter list */
2597     u_octet4 = get_CDR_ulong(tvb,offset,stream_is_big_endian,boundary); /* get maximum length */
2598     if (tree) {
2599       proto_tree_add_uint(tree,hf_giop_typecode_max_length,tvb,
2600                           *offset-sizeof(u_octet4),4,u_octet4);
2601     }
2602     break;
2603
2604   case tk_fixed: /* simple parameter list */
2605     u_octet2 = get_CDR_ushort(tvb,offset,stream_is_big_endian,boundary); /* get digits */
2606     if (tree) {
2607       proto_tree_add_uint(tree,hf_giop_typecode_digits,tvb,
2608                           *offset-sizeof(u_octet2),2,u_octet2);
2609     }
2610
2611     s_octet2 = get_CDR_short(tvb,offset,stream_is_big_endian,boundary); /* get scale */
2612     if (tree) {
2613       proto_tree_add_int(tree,hf_giop_typecode_scale,tvb,
2614                           *offset-sizeof(s_octet2),2,s_octet2);
2615     }
2616     break;
2617
2618   case tk_value: /* complex parameter list */
2619     dissect_tk_value_params(tvb, tree, offset, stream_is_big_endian, boundary, header );
2620     break;
2621   case tk_value_box: /* complex parameter list */
2622     dissect_tk_value_box_params(tvb, tree, offset, stream_is_big_endian, boundary, header );
2623     break;
2624   case tk_native: /* complex parameter list */
2625     dissect_tk_native_params(tvb, tree, offset, stream_is_big_endian, boundary, header );
2626     break;
2627   case tk_abstract_interface: /* complex parameter list */
2628     dissect_tk_abstract_interface_params(tvb, tree, offset, stream_is_big_endian, boundary, header );
2629     break;
2630   default:
2631     g_warning("giop: Unknown TCKind %u \n", val);
2632     break;
2633   } /* val */
2634
2635   return val;
2636 }
2637
2638
2639
2640 /* Copy a 4 octet sequence from the tvbuff 
2641  * which represents an unsigned long value, and convert
2642  * it to an unsigned long vaule, taking into account byte order.
2643  * offset is first incremented so that it falls on a proper alignment
2644  * boundary for unsigned long values.
2645  * offset is then incremented by 4, to indicate the 4 octets which
2646  * have been processed.
2647  */
2648
2649 guint32 get_CDR_ulong(tvbuff_t *tvb, int *offset, gboolean stream_is_big_endian, int boundary) {
2650
2651   guint32 val;
2652
2653   /* unsigned long values must be aligned on a 4 byte boundary */
2654   while( ( (*offset + boundary) % 4) != 0)
2655           ++(*offset);
2656
2657   val = (stream_is_big_endian) ? tvb_get_ntohl (tvb, *offset) :
2658                                  tvb_get_letohl (tvb, *offset);
2659
2660   *offset += 4; 
2661   return val; 
2662 }
2663
2664
2665 /* Copy a 2 octet sequence from the tvbuff 
2666  * which represents an unsigned short value, and convert
2667  * it to an unsigned short value, taking into account byte order.
2668  * offset is first incremented so that it falls on a proper alignment
2669  * boundary for unsigned short values.
2670  * offset is then incremented by 2, to indicate the 2 octets which
2671  * have been processed.
2672  */
2673
2674 guint16 get_CDR_ushort(tvbuff_t *tvb, int *offset, gboolean stream_is_big_endian, int boundary) {
2675
2676   guint16 val;
2677
2678   /* unsigned short values must be aligned on a 2 byte boundary */
2679   while( ( (*offset + boundary) % 2) != 0)
2680           ++(*offset);
2681
2682   val = (stream_is_big_endian) ? tvb_get_ntohs (tvb, *offset) :
2683                                  tvb_get_letohs (tvb, *offset);
2684
2685   *offset += 2; 
2686   return val; 
2687 }
2688
2689
2690
2691 /* Copy a wchar from the tvbuff.
2692  * Caller of this function must remember to free the 
2693  * array pointed to by seq.
2694  * This function also increments offset according to
2695  * the wchar size.
2696  *
2697  * For GIOP 1.1 read 2 octets and return size -2. The
2698  * negation means there is no size element in the packet
2699  * and therefore no size to add to the tree.
2700  *
2701  * For GIOP 1.2 read size of wchar and the size
2702  * octets. size is returned as a gint8.
2703  *
2704  * For both GIOP versions the wchar is returned
2705  * as a printable string.
2706  *
2707  */
2708
2709 /* NOTE: This is very primitive in that it just reads
2710  * the wchar as a series of octets and returns them
2711  * to the user. No translation is attempted based on
2712  * byte orientation, nor on code set. I.e it only 
2713  * really reads past the wchar and sets the offset
2714  * correctly.
2715  */
2716
2717 /* The "decoding" is done according to CORBA chapter 15.
2718  * Wchar is not supported for GIOP 1.0.
2719  */
2720
2721 gint8 get_CDR_wchar(tvbuff_t *tvb, gchar **seq, int *offset, MessageHeader * header) {
2722   
2723   gint8 slength;
2724   gchar *raw_wstring;
2725
2726   /* CORBA chapter 15:
2727    *   - prior to GIOP 1.2 wchar limited to two octet fixed length.
2728    *   - GIOP 1.2 wchar is encoded as an unsigned binary octet
2729    *     followed by the elements of the octet sequence representing
2730    *     the encoded value of the wchar.
2731    */
2732
2733   *seq = NULL; /* set in case GIOP 1.2 length is 0 */
2734   slength = 2; /* set for GIOP 1.1 length in octets */
2735
2736   if (header->GIOP_version.minor > 1) /* if GIOP 1.2 get length of wchar */
2737     slength = get_CDR_octet(tvb,offset);
2738
2739   if (slength > 0) {
2740     /* ??? assume alignment is ok for GIOP 1.1 ??? */
2741     get_CDR_octet_seq(tvb, &raw_wstring, offset, slength);
2742
2743     /* now turn octets (wchar) into something that can be printed by the user */
2744     *seq = make_printable_string(raw_wstring, slength);
2745
2746     g_free(raw_wstring);
2747   }
2748
2749   /* if GIOP 1.1 negate length to indicate not an item to add to tree */
2750   if (header->GIOP_version.minor < 2)
2751     slength = -slength;
2752
2753   return slength;               /* return length */
2754
2755 }
2756
2757
2758 /* Copy a wstring from the tvbuff.
2759  * Caller of this function must remember to free the 
2760  * array pointed to by seq.
2761  * This function also increments offset, according to
2762  * wstring length. length is returned as guint32
2763  */
2764
2765 /* NOTE: This is very primitive in that it just reads
2766  * the wstring as a series of octets and returns them
2767  * to the user. No translation is attempted based on
2768  * byte orientation, nor on code set. I.e it only 
2769  * really reads past the wstring and sets the offset
2770  * correctly.
2771  */
2772
2773 /* The "decoding" is done according to CORBA chapter 15.
2774  * Wstring is not supported for GIOP 1.0.
2775  */
2776
2777
2778 guint32 get_CDR_wstring(tvbuff_t *tvb, gchar **seq, int *offset, gboolean stream_is_big_endian, 
2779                        int boundary, MessageHeader * header) {
2780   
2781   guint32 slength;
2782   gchar *raw_wstring;
2783
2784   /* CORBA chapter 15:
2785    *   - prior to GIOP 1.2 wstring limited to two octet fixed length.
2786    *     length and string are NUL terminated (length???).
2787    *   - GIOP 1.2 length is total number of octets. wstring is NOT NUL
2788    *     terminated.
2789    */
2790
2791   *seq = NULL; /* set in case GIOP 1.2 length is 0 */
2792
2793   /* get length, same for all GIOP versions,
2794    * although for 1.2 CORBA doesnt say, so assume. 
2795    */
2796   slength = get_CDR_ulong(tvb,offset,stream_is_big_endian,boundary);
2797
2798 #ifdef DEBUG
2799   if (slength>200) {
2800         fprintf(stderr, "giop:get_CDR_wstring, length %u > 200, truncating to 5 \n", slength);
2801         slength = 5;            /* better than core dumping during debug */
2802   }
2803 #endif
2804   
2805   if (header->GIOP_version.minor < 2) {
2806 #if 0
2807     (*offset)++;  /* must step past \0 delimiter */
2808 #endif
2809     /* assume length is number of characters and not octets, spec not clear */
2810     slength = slength * 2; /* length in octets is 2 * wstring length */
2811   }
2812
2813   if (slength > 0) {
2814     get_CDR_octet_seq(tvb, &raw_wstring, offset, slength);
2815
2816     /* now turn octets (wstring) into something that can be printed by the user */
2817     *seq = make_printable_string(raw_wstring, slength);
2818
2819     g_free(raw_wstring);
2820   }
2821
2822   return slength;               /* return length */
2823
2824 }
2825
2826
2827
2828 /**
2829  *  Dissects a TargetAddress which is defined in (CORBA 2.4, section 15.4.2)
2830  *  GIOP 1.2
2831  *  typedef short AddressingDisposition;
2832  *  const short KeyAddr = 0;
2833  *  const short ProfileAddr = 1;
2834  *  const short ReferenceAddr = 2;
2835  *  struct IORAddressingInfo {
2836  *    unsigned long selected_profile_index;
2837  *    IOP::IOR ior;
2838  *  };
2839  *
2840  *  union TargetAddress switch (AddressingDisposition) {
2841  *      case KeyAddr: sequence <octet> object_key;
2842  *      case ProfileAddr: IOP::TaggedProfile profile;
2843  *      case ReferenceAddr: IORAddressingInfo ior;
2844  *  };
2845  */
2846
2847 static void
2848 dissect_target_address(tvbuff_t * tvb, packet_info *pinfo, int *offset, proto_tree * tree, 
2849                        MessageHeader * header, gboolean stream_is_big_endian)
2850 {
2851    guint16 discriminant;
2852    gchar *object_key;
2853    gchar *p_object_key;
2854    guint32 len = 0;
2855    guint32 u_octet4;
2856
2857    discriminant = get_CDR_ushort(tvb, offset, stream_is_big_endian,GIOP_HEADER_SIZE);
2858    if(tree)
2859    {
2860      proto_tree_add_text (tree, tvb, *offset -2, 2,
2861                  "TargetAddress Discriminant: %u", discriminant);
2862    }
2863   
2864    switch (discriminant)
2865    {
2866            case 0:  /* KeyAddr */
2867                    len = get_CDR_ulong(tvb, offset, stream_is_big_endian,GIOP_HEADER_SIZE);
2868                    if(tree)
2869                    {
2870                       proto_tree_add_text (tree, tvb, *offset -4, 4,
2871                                            "KeyAddr (object key length): %u", len);
2872                    }
2873
2874                    if (len > 0) {
2875
2876                      get_CDR_octet_seq(tvb, &object_key, offset, len);
2877                      p_object_key = make_printable_string( object_key, len );
2878                    
2879                      if(tree)
2880                        {
2881                          proto_tree_add_text (tree, tvb, *offset -len, len,
2882                                                "KeyAddr (object key): %s", p_object_key);
2883                        }
2884                      g_free( p_object_key );
2885                      g_free( object_key );
2886                    }
2887                    break;
2888            case 1: /* ProfileAddr */
2889                    decode_TaggedProfile(tvb, pinfo, tree, offset, GIOP_HEADER_SIZE,
2890                                         stream_is_big_endian, NULL);
2891                    break;
2892            case 2: /* ReferenceAddr */
2893                    u_octet4 = get_CDR_ulong(tvb, offset, stream_is_big_endian,GIOP_HEADER_SIZE);
2894
2895                    if(tree)
2896                    {
2897                       proto_tree_add_text (tree, tvb, *offset -len -4, 4,
2898                                            "ReferenceAddr (selected_profile_index): %u", u_octet4);
2899                    }
2900
2901                    decode_IOR(tvb, pinfo, tree, offset, GIOP_HEADER_SIZE, stream_is_big_endian);
2902                    break;
2903            default:
2904                    break;
2905    }
2906 }
2907
2908 static void
2909 dissect_reply_body (tvbuff_t *tvb, u_int offset, packet_info *pinfo,
2910                     proto_tree *tree, gboolean stream_is_big_endian,
2911                     guint32 reply_status, MessageHeader *header, proto_tree *clnp_tree) {
2912
2913   u_int sequence_length;
2914   gboolean exres = FALSE;               /* result of trying explicit dissectors */
2915   gchar * repoid = NULL;        /* Repositor ID looked up from  objkey */
2916   
2917   /*
2918    * comp_req_list stuff
2919    */
2920
2921   comp_req_list_entry_t * entry = NULL; /* data element in our list */
2922   
2923   guint32 mfn;
2924
2925   switch (reply_status)
2926     {
2927     case SYSTEM_EXCEPTION:
2928
2929       decode_SystemExceptionReplyBody (tvb, tree, &offset, stream_is_big_endian, GIOP_HEADER_SIZE);
2930       break;
2931
2932     case USER_EXCEPTION:
2933
2934       sequence_length = get_CDR_ulong(tvb, &offset, stream_is_big_endian,GIOP_HEADER_SIZE);
2935
2936       if (tree)
2937       {
2938           proto_tree_add_text(tree, tvb, offset-4, 4,
2939                            "Exception length: %u", sequence_length);
2940       }
2941       if (sequence_length != 0)
2942         {
2943           if (tree)
2944           {
2945               proto_tree_add_text(tree, tvb, offset, sequence_length,
2946                            "Exception id: %s",
2947                            tvb_format_text(tvb, offset, sequence_length));
2948           }
2949 #if 1
2950
2951           header->exception_id = g_new0(gchar,sequence_length ); /* allocate buffer */
2952
2953           /* read exception id from buffer and store in*/
2954
2955           tvb_get_nstringz0(tvb,offset,sequence_length, header->exception_id );
2956           
2957
2958 #endif          
2959           
2960
2961           offset += sequence_length;
2962         }
2963
2964
2965
2966       /*
2967        * Now just fall through to the NO_EXCEPTION part
2968        * as this is common .
2969        */
2970       
2971
2972
2973     case NO_EXCEPTION:
2974
2975
2976       /* lookup MFN in hash directly */
2977  
2978       mfn = get_mfn_from_fn(pinfo->fd->num); 
2979       
2980       if (mfn == pinfo->fd->num)
2981         return;                 /* no matching frame number, what am I */
2982
2983       /* get entry for this MFN */
2984       entry = find_fn_in_list(mfn); /* get data entry in complete_request_list */
2985
2986       if (!entry)
2987         return;                 /* no matching entry */
2988         
2989
2990       /*
2991        * If this packet is a REPLY to a RESOLVE(request) 
2992        * then decode IOR.
2993        * TODO - make this lookup faster -- FS
2994        */
2995       
2996       if (!strcmp(giop_op_resolve,entry->operation)) {
2997         decode_IOR(tvb, pinfo, tree, &offset, GIOP_HEADER_SIZE,stream_is_big_endian);
2998         return;         /* done */
2999       }
3000       
3001       /* TODO -- Put stuff here for other "interesting operations" */
3002
3003       /*
3004        *
3005        * Call sub dissector.
3006        * First try an find a explicit sub_dissector, then if that
3007        * fails, try the heuristic method.
3008        */
3009
3010
3011       if(entry->repoid) {    
3012         exres = try_explicit_giop_dissector(tvb,pinfo,clnp_tree, &offset, header, entry->operation, entry->repoid );
3013       }
3014
3015       /* Only call heuristic if no explicit dixxector was found */
3016
3017       if(! exres) {
3018         try_heuristic_giop_dissector(tvb,pinfo,clnp_tree,&offset,header,entry->operation);
3019       } 
3020
3021
3022       break;
3023       
3024     case LOCATION_FORWARD:
3025       decode_IOR(tvb, pinfo, tree, &offset, GIOP_HEADER_SIZE, stream_is_big_endian);
3026
3027       break;
3028
3029     case LOCATION_FORWARD_PERM:
3030       decode_IOR(tvb, pinfo, tree, &offset, GIOP_HEADER_SIZE, stream_is_big_endian);
3031
3032       break;
3033
3034     case NEEDS_ADDRESSING_MODE: {
3035       guint16 addr_disp;
3036       addr_disp = get_CDR_ushort(tvb, &offset, stream_is_big_endian, GIOP_HEADER_SIZE);
3037       if(tree) {
3038         proto_tree_add_text (tree, tvb, offset -2, 2,
3039                              "AddressingDisposition: %u", addr_disp);
3040       }
3041
3042       break;
3043     }
3044
3045     default:
3046       
3047       g_warning("giop: Unknown reply status %i request_id = %u\n",reply_status, header->req_id);
3048       
3049       break;
3050       
3051     } /* switch */
3052   
3053   g_free(repoid);               /* free resource */
3054   
3055   return;                       /* done */
3056   
3057 }
3058
3059
3060
3061
3062
3063 /* The format of the Reply Header for GIOP 1.0 and 1.1
3064  * is documented in Section 15.4.3.1 of the CORBA 2.4 standard.
3065
3066     struct ReplyHeader_1_0 {
3067           IOP::ServiceContextList service_context;
3068           unsigned long request_id;
3069           ReplyStatusType_1_0 reply_status;
3070     };
3071  */
3072
3073 static void dissect_giop_reply (tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree,
3074                                 proto_tree * clnp_tree, MessageHeader * header,
3075                                 gboolean stream_is_big_endian) {
3076
3077   guint32 offset = 0;
3078   guint32 request_id;
3079   guint32 reply_status;
3080   proto_tree *reply_tree = NULL;
3081   proto_item *tf;
3082   guint32 mfn;                  /* matching frame number */
3083
3084   if (tree) {
3085     tf = proto_tree_add_text (tree, tvb, offset,
3086                               tvb_length (tvb),
3087                               "General Inter-ORB Protocol Reply");
3088     if (reply_tree == NULL)
3089       {
3090         reply_tree = proto_item_add_subtree (tf, ett_giop_reply);
3091         
3092       }
3093   }
3094   
3095   /*
3096    * Decode IOP::ServiceContextList
3097    */
3098   
3099   decode_ServiceContextList(tvb, pinfo, reply_tree, &offset,stream_is_big_endian, GIOP_HEADER_SIZE);
3100
3101   request_id = get_CDR_ulong(tvb, &offset, stream_is_big_endian,GIOP_HEADER_SIZE);
3102
3103   if (check_col(pinfo->cinfo, COL_INFO)) {
3104     col_append_fstr(pinfo->cinfo, COL_INFO, " %u", request_id);
3105   }
3106
3107   if (tree) {
3108     proto_tree_add_text (reply_tree, tvb, offset-4, 4,
3109                          "Request id: %u", request_id);
3110   }
3111
3112   reply_status = get_CDR_ulong(tvb, &offset, stream_is_big_endian,GIOP_HEADER_SIZE);
3113
3114   if (check_col(pinfo->cinfo, COL_INFO)) {
3115     col_append_fstr(pinfo->cinfo, COL_INFO, ": %s",
3116                     val_to_str(reply_status, reply_status_types, "Unknown (%u)"));
3117
3118   }
3119
3120   if (tree) {
3121     proto_tree_add_text (reply_tree, tvb, offset-4, 4,
3122                          "Reply status: %s",
3123                          val_to_str(reply_status, reply_status_types, "Unknown (%u)"));
3124     
3125   }
3126
3127   /*
3128    * Save FN and MFN in complete_reply_hash, only if user is NOT clicking
3129    */
3130
3131   if (! pinfo->fd->flags.visited) {
3132     mfn = get_mfn_from_fn_and_reqid(pinfo->fd->num,request_id); /* find MFN for this FN */
3133     if (mfn != pinfo->fd->num) { /* if mfn is not fn, good */
3134       insert_in_complete_reply_hash(pinfo->fd->num, mfn);
3135     }
3136   }
3137
3138   header->req_id = request_id;          /* save for sub dissector */
3139   header->rep_status = reply_status;   /* save for sub dissector */
3140
3141   dissect_reply_body(tvb, offset, pinfo, reply_tree, stream_is_big_endian,
3142     reply_status, header,tree);
3143
3144
3145 }
3146
3147 /** The format of the GIOP 1.2 Reply header is very similar to the 1.0
3148  *  and 1.1 header, only the fields have been rearranged.  From Section
3149  *  15.4.3.1 of the CORBA 2.4 specification:
3150  *
3151  *   struct ReplyHeader_1_2 {
3152  *         unsigned long request_id;
3153  *         ReplyStatusType_1_2 reply_status;
3154  *         IOP:ServiceContextList service_context; 
3155  *    };
3156  */
3157
3158 static void dissect_giop_reply_1_2 (tvbuff_t * tvb, packet_info * pinfo,
3159                                     proto_tree * tree, proto_tree * clnp_tree,
3160                                     MessageHeader * header,
3161                                     gboolean stream_is_big_endian) {
3162
3163   u_int offset = 0;
3164   guint32 request_id;
3165   guint32 reply_status;
3166   proto_tree *reply_tree = NULL;
3167   proto_item *tf;
3168   guint32 mfn;                  /* matching frame number */
3169   
3170   if (tree) {
3171     tf = proto_tree_add_text (tree, tvb, offset,
3172                               tvb_length (tvb),
3173                               "General Inter-ORB Protocol Reply");
3174     reply_tree = proto_item_add_subtree (tf, ett_giop_reply);
3175   }
3176   
3177   request_id = get_CDR_ulong(tvb, &offset, stream_is_big_endian,GIOP_HEADER_SIZE);
3178   
3179   if (check_col(pinfo->cinfo, COL_INFO)) {
3180     col_append_fstr(pinfo->cinfo, COL_INFO, " %u", request_id);
3181   }
3182
3183   if (tree) {
3184     proto_tree_add_text (reply_tree, tvb, offset-4, 4,
3185                          "Request id: %u", request_id);
3186   }
3187
3188   reply_status = get_CDR_ulong(tvb, &offset, stream_is_big_endian,GIOP_HEADER_SIZE);
3189   
3190   if (check_col(pinfo->cinfo, COL_INFO)) {
3191     col_append_fstr(pinfo->cinfo, COL_INFO, ": %s",
3192                     val_to_str(reply_status, reply_status_types, "Unknown (%u)"));
3193
3194   }
3195
3196   if (tree) {
3197     proto_tree_add_text (reply_tree, tvb, offset-4, 4,
3198                          "Reply status: %s",
3199                          val_to_str(reply_status, reply_status_types, "Unknown (%u)"));
3200
3201   }
3202
3203   /*
3204    * Decode IOP::ServiceContextList
3205    */
3206
3207   decode_ServiceContextList(tvb, pinfo, reply_tree, &offset,stream_is_big_endian, GIOP_HEADER_SIZE);
3208
3209   /*
3210    * GIOP 1.2 Reply body must fall on an 8 octet alignment.
3211    */
3212
3213   set_new_alignment(&offset, GIOP_HEADER_SIZE, 8);
3214
3215   /*
3216    * Save FN and MFN in complete_reply_hash, only if user is NOT clicking
3217    */
3218   
3219   if (! pinfo->fd->flags.visited) {
3220     mfn = get_mfn_from_fn_and_reqid(pinfo->fd->num,request_id); /* find MFN for this FN */
3221     if (mfn != pinfo->fd->num) { /* if mfn is not fn, good */
3222       insert_in_complete_reply_hash(pinfo->fd->num, mfn);
3223     }
3224   }
3225
3226   /*
3227    * Add header to argument list so sub dissector can get header info.
3228    */
3229
3230   header->req_id = request_id;          /* save for sub dissector */
3231   header->rep_status = reply_status;   /* save for sub dissector */
3232
3233   dissect_reply_body(tvb, offset, pinfo, reply_tree, stream_is_big_endian,
3234                      reply_status,header,tree);
3235
3236 }
3237
3238
3239
3240 static void dissect_giop_cancel_request (tvbuff_t * tvb, packet_info * pinfo,
3241                         proto_tree * tree, proto_tree * clnp_tree,
3242                         MessageHeader * header, gboolean stream_is_big_endian) {
3243
3244   u_int offset = 0;
3245   guint32 request_id;
3246   proto_tree *cancel_request_tree = NULL;
3247   proto_item *tf;
3248
3249   if (tree) {
3250     tf = proto_tree_add_text (tree, tvb, offset,
3251                               tvb_length (tvb),
3252                               "General Inter-ORB Protocol CancelRequest");
3253     cancel_request_tree = proto_item_add_subtree (tf, ett_giop_cancel_request);
3254   }
3255
3256   request_id = get_CDR_ulong(tvb, &offset, stream_is_big_endian,GIOP_HEADER_SIZE);
3257   
3258   if (check_col(pinfo->cinfo, COL_INFO)) {
3259     col_append_fstr(pinfo->cinfo, COL_INFO, " %u", request_id);
3260   }
3261
3262   if (tree) {
3263     proto_tree_add_text (cancel_request_tree, tvb, offset-4, 4,
3264                          "Request id: %u", request_id);
3265   }
3266
3267   
3268 }
3269
3270 /**  The formats for GIOP 1.0 and 1.1 Request messages are defined
3271  *   in section 15.4.2.1 of the CORBA 2.4 specification.
3272  *
3273  *   struct RequestHeader{
3274  *          IOP::ServiceContextList   service_context;
3275  *          unsigned long             request_id;
3276  *          boolean                   response_expected;
3277  *          octet                     reserved[3];  // Only in GIOP 1.1
3278  *          sequence<octet>           object_key;
3279  *          string                    operation;
3280  *          CORBA::OctetSeq           requesting_principal;
3281  *   }
3282  */
3283 static void
3284 dissect_giop_request_1_1 (tvbuff_t * tvb, packet_info * pinfo,
3285                         proto_tree * tree, proto_tree * clnp_tree,
3286                         MessageHeader * header, gboolean stream_is_big_endian)
3287 {
3288   guint32 offset = 0;
3289   guint32 request_id;
3290   guint32 len = 0;
3291
3292   guint32 objkey_len = 0;       /* object key length */
3293   gchar *objkey = NULL;         /* object key sequence */
3294   gchar *print_objkey;          /* printable object key sequence */
3295   gboolean exres = FALSE;       /* result of trying explicit dissectors */
3296
3297   gchar *operation;
3298   gchar *requesting_principal;
3299   gchar *print_requesting_principal;
3300   guint8 response_expected;
3301   gchar *reserved;
3302   proto_tree *request_tree = NULL;
3303   proto_item *tf;
3304
3305   gchar *repoid = NULL;         /* from object key lookup in objkey hash */
3306
3307
3308   if (tree)
3309     {
3310       tf = proto_tree_add_text (tree, tvb, offset,
3311                                 tvb_length (tvb),
3312                                 "General Inter-ORB Protocol Request");
3313       if (request_tree == NULL)
3314         {
3315           request_tree = proto_item_add_subtree (tf, ett_giop_request);
3316
3317         }
3318     }
3319
3320
3321
3322
3323   /*
3324    * Decode IOP::ServiceContextList
3325    */
3326   
3327   decode_ServiceContextList(tvb, pinfo, request_tree, &offset,stream_is_big_endian, GIOP_HEADER_SIZE);
3328
3329
3330   request_id = get_CDR_ulong(tvb, &offset, stream_is_big_endian,GIOP_HEADER_SIZE);
3331   if (check_col(pinfo->cinfo, COL_INFO))
3332     {
3333       col_append_fstr(pinfo->cinfo, COL_INFO, " %u", request_id);
3334     }
3335   if (tree)
3336     {
3337       proto_tree_add_text (request_tree, tvb, offset-4, 4,
3338                            "Request id: %u", request_id);
3339     }
3340
3341   response_expected = tvb_get_guint8( tvb, offset );
3342   offset += 1;
3343   if (check_col(pinfo->cinfo, COL_INFO))
3344     {
3345       col_append_fstr(pinfo->cinfo, COL_INFO, " (%s)",
3346                 response_expected ? "two-way" : "one-way");
3347     }
3348   if (tree)
3349     {
3350       proto_tree_add_text (request_tree, tvb, offset-1, 1,
3351                            "Response expected: %u", response_expected);
3352     }
3353
3354   if( header->GIOP_version.minor > 0)
3355   {
3356      get_CDR_octet_seq( tvb, &reserved, &offset, 3);
3357      if (tree)
3358        {
3359          proto_tree_add_text (request_tree, tvb, offset-3, 3,
3360                            "Reserved: %x %x %x", reserved[0], reserved[1], reserved[2]);
3361        }
3362      g_free(reserved);
3363   }
3364
3365
3366
3367   /* Length of object_key sequence */
3368   objkey_len = get_CDR_ulong(tvb, &offset, stream_is_big_endian,GIOP_HEADER_SIZE);
3369
3370
3371   if(tree)
3372   {
3373          proto_tree_add_text (request_tree, tvb, offset-4, 4,
3374          /**/                 "Object Key length: %u", objkey_len);
3375   } 
3376
3377   if (objkey_len > 0)
3378   {
3379        get_CDR_octet_seq(tvb, &objkey, &offset, objkey_len);
3380
3381        print_objkey = make_printable_string(objkey, objkey_len);
3382
3383        if(tree)
3384        {
3385          proto_tree_add_text (request_tree, tvb, offset - objkey_len, objkey_len,
3386          /**/                 "Object Key: %s", print_objkey);
3387
3388        }
3389
3390        g_free( print_objkey );  
3391   } 
3392
3393   /*
3394    * Register a cleanup function in case on of our tvbuff accesses
3395    * throws an exception. We need to clean up objkey.
3396    */
3397   CLEANUP_PUSH(g_free, objkey);
3398
3399   /* length of operation string and string */ 
3400   len = get_CDR_string(tvb, &operation, &offset, stream_is_big_endian,GIOP_HEADER_SIZE);
3401   if(tree)
3402   {
3403          proto_tree_add_text (request_tree, tvb, offset - 4 - len, 4,
3404          /**/                 "Operation length: %u", len);
3405   } 
3406
3407   if( len > 0)
3408   {
3409        if (check_col(pinfo->cinfo, COL_INFO))
3410        {
3411          col_append_fstr(pinfo->cinfo, COL_INFO, ": %s", operation);
3412        }
3413        if(tree)
3414        {
3415          proto_tree_add_text (request_tree, tvb, offset - len, len,
3416          /**/                 "Operation: %s", operation);
3417
3418        }
3419   }
3420
3421   /*
3422    * Register a cleanup function in case on of our tvbuff accesses
3423    * throws an exception. We need to clean up operation.
3424    */
3425   CLEANUP_PUSH(g_free, operation);
3426
3427   /* length of requesting_principal string */ 
3428   len = get_CDR_ulong(tvb, &offset, stream_is_big_endian,GIOP_HEADER_SIZE);
3429   if(tree)
3430   {
3431          proto_tree_add_text (request_tree, tvb, offset-4, 4,
3432          /**/                 "Requesting Principal Length: %u", len);
3433   } 
3434
3435   if( len > 0)
3436   {
3437        get_CDR_octet_seq(tvb, &requesting_principal, &offset, len);
3438
3439        print_requesting_principal = make_printable_string(requesting_principal, len);
3440
3441        if(tree)
3442        {
3443          proto_tree_add_text (request_tree, tvb, offset - len, len, 
3444          /**/                 "Requesting Principal: %s", print_requesting_principal);
3445
3446        }
3447
3448        g_free( print_requesting_principal );
3449        g_free( requesting_principal );
3450   }
3451
3452
3453   /*
3454    * Save FN,reqid,and operation for later. Add sub_handle later.
3455    * But only if user is NOT clicking.
3456    */
3457
3458   if (! pinfo->fd->flags.visited)
3459     giop_complete_request_list = insert_in_comp_req_list(giop_complete_request_list,pinfo->fd->num,
3460                                                          request_id,operation,NULL);
3461
3462   
3463   /*
3464    * Call subdissector here before freeing "operation" and "key"
3465    * pass request_id also. 
3466    * First try an find an explicit sub_dissector, then if that
3467    * fails, try the heuristic method.
3468    *
3469    */
3470
3471
3472   header->req_id = request_id;          /* save for sub dissector */
3473   repoid = get_repoid_from_objkey(giop_objkey_hash,objkey,objkey_len);
3474
3475
3476   if(repoid) {    
3477     exres = try_explicit_giop_dissector(tvb,pinfo,tree,&offset,header,operation,repoid);
3478   }
3479
3480   /* Only call heuristic if no explicit dissector was found */
3481
3482   if (! exres) {
3483     try_heuristic_giop_dissector(tvb,pinfo,tree,&offset,header,operation);
3484   }
3485   
3486
3487   /*
3488    * We're done with operation, so we can call the cleanup handler to free
3489    * it, and then pop the cleanup handler.
3490    */
3491   CLEANUP_CALL_AND_POP;
3492
3493   /*
3494    * We're done with objkey, so we can call the cleanup handler to free
3495    * it, and then pop the cleanup handler.
3496    */
3497   CLEANUP_CALL_AND_POP;
3498
3499 }
3500
3501 /**  The format of a GIOP 1.2 RequestHeader message is 
3502  *   (CORBA 2.4, sec. 15.4.2):
3503  *
3504  *   struct RequestHeader_1_2 {
3505  *       unsigned long request_id;
3506  *       octet response_flags;
3507  *       octet reserved[3];
3508  *       TargetAddress target;
3509  *       string operation;
3510  *       IOP::ServiceContextList service_context;
3511  *       // requesting_principal not in GIOP 1.2
3512  *   };
3513  */
3514 static void
3515 dissect_giop_request_1_2 (tvbuff_t * tvb, packet_info * pinfo,
3516                         proto_tree * tree, proto_tree * clnp_tree,
3517                         MessageHeader * header, gboolean stream_is_big_endian)
3518 {
3519   guint32 offset = 0;
3520   guint32 request_id;
3521   guint32 len = 0;
3522   guint8 response_flags;
3523   gchar *reserved;
3524   gchar *operation = NULL;
3525   proto_tree *request_tree = NULL;
3526   proto_item *tf;
3527   gboolean exres = FALSE;               /* result of trying explicit dissectors */
3528
3529   gchar *repoid = NULL;
3530
3531
3532   if (tree)
3533     {
3534       tf = proto_tree_add_text (tree, tvb, offset,
3535                                 tvb_length (tvb),
3536                                 "General Inter-ORB Protocol Request");
3537       request_tree = proto_item_add_subtree (tf, ett_giop_reply);
3538     }
3539
3540   request_id = get_CDR_ulong(tvb, &offset, stream_is_big_endian,GIOP_HEADER_SIZE);
3541   if (check_col(pinfo->cinfo, COL_INFO))
3542     {
3543       col_append_fstr(pinfo->cinfo, COL_INFO, " %u", request_id);
3544     }
3545   if (request_tree)
3546     {
3547       proto_tree_add_text (request_tree, tvb, offset-4, 4,
3548                            "Request id: %u", request_id);
3549     }
3550
3551   response_flags = tvb_get_guint8( tvb, offset );
3552   offset += 1;
3553   if (request_tree)
3554     {
3555       proto_tree_add_text (request_tree, tvb, offset-1, 1,
3556                            "Response flags: %s (%u)",
3557                                 match_strval(response_flags, sync_scope),  
3558                                 response_flags);
3559     }
3560
3561   get_CDR_octet_seq( tvb, &reserved, &offset, 3);
3562   if (request_tree)
3563    {
3564      proto_tree_add_text (request_tree, tvb, offset-3, 3,
3565            "Reserved: %x %x %x", reserved[0], reserved[1], reserved[2]);
3566    }
3567   g_free(reserved);
3568
3569   dissect_target_address(tvb, pinfo, &offset, request_tree, header, stream_is_big_endian);
3570
3571   /* length of operation string */ 
3572   len = get_CDR_string(tvb, &operation, &offset, stream_is_big_endian,GIOP_HEADER_SIZE);
3573   if(tree)
3574   {
3575          proto_tree_add_text (request_tree, tvb, offset - len - 4, 4,
3576          /**/                 "Operation length: %u", len);
3577   } 
3578
3579   if( len > 0)
3580   {
3581        if (check_col(pinfo->cinfo, COL_INFO))
3582        {
3583          col_append_fstr(pinfo->cinfo, COL_INFO, ": %s", operation);
3584        }
3585        if(request_tree)
3586        {
3587          proto_tree_add_text (request_tree, tvb, offset - len, len,
3588          /**/                 "Operation: %s", operation);
3589
3590        }
3591
3592   }
3593
3594   /*
3595    * Register a cleanup function in case on of our tvbuff accesses
3596    * throws an exception. We need to clean up operation.
3597    */
3598   CLEANUP_PUSH(g_free, operation);
3599
3600   /*
3601    * Decode IOP::ServiceContextList
3602    */
3603
3604   decode_ServiceContextList(tvb, pinfo, request_tree, &offset,  stream_is_big_endian, GIOP_HEADER_SIZE);
3605
3606   /*
3607    * GIOP 1.2 Request body must fall on an 8 octet alignment, taking into
3608    * account we are in a new tvbuff, GIOP_HEADER_SIZE octets from the
3609    * GIOP octet stream start.
3610    */
3611
3612   set_new_alignment(&offset, GIOP_HEADER_SIZE, 8);
3613
3614   /*
3615    * Save FN,reqid,and operation for later. Add sub_handle later.
3616    * But only if user is NOT clicking.
3617    */
3618   
3619   if (! pinfo->fd->flags.visited)
3620     giop_complete_request_list = insert_in_comp_req_list(giop_complete_request_list,pinfo->fd->num,
3621                                                          request_id,operation,NULL);
3622
3623   /*
3624    *
3625    * Call sub dissector.
3626    * First try an find a explicit sub_dissector, then if that
3627    * fails, try the heuristic method.
3628    */
3629   
3630
3631   if(repoid) {    
3632     exres = try_explicit_giop_dissector(tvb,pinfo,tree,&offset,header,operation,repoid);
3633   }
3634
3635   /* Only call heuristic if no explicit dissector was found */
3636
3637   if (! exres) {
3638     try_heuristic_giop_dissector(tvb,pinfo,tree,&offset,header,operation);
3639   }
3640   
3641
3642   /*
3643    * We're done with operation, so we can call the cleanup handler to free
3644    * it, and then pop the cleanup handler.
3645    */
3646   CLEANUP_CALL_AND_POP;
3647 }
3648
3649 static void
3650 dissect_giop_locate_request( tvbuff_t * tvb, packet_info * pinfo,
3651                         proto_tree * tree, MessageHeader * header,
3652                         gboolean stream_is_big_endian)
3653 {
3654   guint32 offset = 0;
3655   guint32 request_id;
3656   guint32 len = 0;
3657   gchar *object_key;
3658   gchar *p_object_key;