1 //
2 // Copyright (c) ZeroC, Inc. All rights reserved.
3 //
4 
5 #include <IceUtil/Mutex.h>
6 #include <IceUtil/MutexPtrLock.h>
7 #include <Ice/StringUtil.h>
8 #include <Ice/TraceUtil.h>
9 #include <Ice/Instance.h>
10 #include <Ice/Object.h>
11 #include <Ice/Proxy.h>
12 #include <Ice/TraceLevels.h>
13 #include <Ice/Logger.h>
14 #include <Ice/OutputStream.h>
15 #include <Ice/InputStream.h>
16 #include <Ice/Protocol.h>
17 #include <Ice/ReplyStatus.h>
18 #include <set>
19 
20 using namespace std;
21 using namespace Ice;
22 using namespace IceInternal;
23 
24 static void
printIdentityFacetOperation(ostream & s,InputStream & stream)25 printIdentityFacetOperation(ostream& s, InputStream& stream)
26 {
27     ToStringMode toStringMode = ICE_ENUM(ToStringMode, Unicode);
28     if(stream.instance())
29     {
30         toStringMode = stream.instance()->toStringMode();
31     }
32 
33     Identity identity;
34     stream.read(identity);
35     s << "\nidentity = " << Ice::identityToString(identity, toStringMode);
36 
37     vector<string> facet;
38     stream.read(facet);
39     s << "\nfacet = ";
40     if(!facet.empty())
41     {
42         s << escapeString(facet[0], "", toStringMode);
43     }
44 
45     string operation;
46     stream.read(operation, false);
47     s << "\noperation = " << operation;
48 }
49 
50 static string
getMessageTypeAsString(Byte type)51 getMessageTypeAsString(Byte type)
52 {
53     switch(type)
54     {
55         case requestMsg:
56             return "request";
57         case requestBatchMsg:
58             return "batch request";
59         case replyMsg:
60             return "reply";
61         case closeConnectionMsg:
62             return "close connection";
63         case validateConnectionMsg:
64             return "validate connection";
65         default:
66             return "unknown";
67     }
68 }
69 
70 static void
printRequestHeader(ostream & s,InputStream & stream)71 printRequestHeader(ostream& s, InputStream& stream)
72 {
73     printIdentityFacetOperation(s, stream);
74 
75     Byte mode;
76     stream.read(mode);
77     s << "\nmode = " << static_cast<int>(mode) << ' ';
78     switch(static_cast<OperationMode>(mode))
79     {
80         case ICE_ENUM(OperationMode, Normal):
81         {
82             s << "(normal)";
83             break;
84         }
85 
86         case ICE_ENUM(OperationMode, Nonmutating):
87         {
88             s << "(nonmutating)";
89             break;
90         }
91 
92         case ICE_ENUM(OperationMode, Idempotent):
93         {
94             s << "(idempotent)";
95             break;
96         }
97 
98         default:
99         {
100             s << "(unknown)";
101             break;
102         }
103     }
104 
105     Int sz = stream.readSize();
106     s << "\ncontext = ";
107     while(sz--)
108     {
109         pair<string, string> pair;
110         stream.read(pair.first);
111         stream.read(pair.second);
112         s << pair.first << '/' << pair.second;
113         if(sz)
114         {
115             s << ", ";
116         }
117     }
118 
119     Ice::EncodingVersion v = stream.skipEncapsulation();
120     if(v > Ice::Encoding_1_0)
121     {
122         s << "\nencoding = " << v;
123     }
124 }
125 
126 static Byte
printHeader(ostream & s,InputStream & stream)127 printHeader(ostream& s, InputStream& stream)
128 {
129     Byte magicNumber;
130     stream.read(magicNumber);   // Don't bother printing the magic number
131     stream.read(magicNumber);
132     stream.read(magicNumber);
133     stream.read(magicNumber);
134 
135     Byte pMajor;
136     Byte pMinor;
137     stream.read(pMajor);
138     stream.read(pMinor);
139 //    s << "\nprotocol version = " << static_cast<unsigned>(pMajor)
140 //      << "." << static_cast<unsigned>(pMinor);
141 
142     Byte eMajor;
143     Byte eMinor;
144     stream.read(eMajor);
145     stream.read(eMinor);
146 //    s << "\nencoding version = " << static_cast<unsigned>(eMajor)
147 //      << "." << static_cast<unsigned>(eMinor);
148 
149     Byte type;
150     stream.read(type);
151     s << "\nmessage type = "  << static_cast<int>(type) << " (" << getMessageTypeAsString(type) << ')';
152 
153     Byte compress;
154     stream.read(compress);
155     s << "\ncompression status = "  << static_cast<int>(compress) << ' ';
156 
157     switch(compress)
158     {
159         case 0:
160         {
161             s << "(not compressed; do not compress response, if any)";
162             break;
163         }
164 
165         case 1:
166         {
167             s << "(not compressed; compress response, if any)";
168             break;
169         }
170 
171         case 2:
172         {
173             s << "(compressed; compress response, if any)";
174             break;
175         }
176 
177         default:
178         {
179             s << "(unknown)";
180             break;
181         }
182     }
183 
184     Int size;
185     stream.read(size);
186     s << "\nmessage size = " << size;
187 
188     return type;
189 }
190 
191 static void
printRequest(ostream & s,InputStream & stream)192 printRequest(ostream& s, InputStream& stream)
193 {
194     Int requestId;
195     stream.read(requestId);
196     s << "\nrequest id = " << requestId;
197     if(requestId == 0)
198     {
199         s << " (oneway)";
200     }
201 
202     printRequestHeader(s, stream);
203 }
204 
205 static void
printBatchRequest(ostream & s,InputStream & stream)206 printBatchRequest(ostream& s, InputStream& stream)
207 {
208     int batchRequestNum;
209     stream.read(batchRequestNum);
210     s << "\nnumber of requests = " << batchRequestNum;
211 
212     for(int i = 0; i < batchRequestNum; ++i)
213     {
214         s << "\nrequest #" << i << ':';
215         printRequestHeader(s, stream);
216     }
217 }
218 
219 static void
printReply(ostream & s,InputStream & stream)220 printReply(ostream& s, InputStream& stream)
221 {
222     Int requestId;
223     stream.read(requestId);
224     s << "\nrequest id = " << requestId;
225 
226     Byte replyStatus;
227     stream.read(replyStatus);
228     s << "\nreply status = " << static_cast<int>(replyStatus) << ' ';
229     switch(replyStatus)
230     {
231     case replyOK:
232     {
233         s << "(ok)";
234         break;
235     }
236 
237     case replyUserException:
238     {
239         s << "(user exception)";
240         break;
241     }
242 
243     case replyObjectNotExist:
244     case replyFacetNotExist:
245     case replyOperationNotExist:
246     {
247         switch(replyStatus)
248         {
249         case replyObjectNotExist:
250         {
251             s << "(object not exist)";
252             break;
253         }
254 
255         case replyFacetNotExist:
256         {
257             s << "(facet not exist)";
258             break;
259         }
260 
261         case replyOperationNotExist:
262         {
263             s << "(operation not exist)";
264             break;
265         }
266 
267         default:
268         {
269             assert(false);
270             break;
271         }
272         }
273 
274         printIdentityFacetOperation(s, stream);
275         break;
276     }
277 
278     case replyUnknownException:
279     case replyUnknownLocalException:
280     case replyUnknownUserException:
281     {
282         switch(replyStatus)
283         {
284         case replyUnknownException:
285         {
286             s << "(unknown exception)";
287             break;
288         }
289 
290         case replyUnknownLocalException:
291         {
292             s << "(unknown local exception)";
293             break;
294         }
295 
296         case replyUnknownUserException:
297         {
298             s << "(unknown user exception)";
299             break;
300         }
301 
302         default:
303         {
304             assert(false);
305             break;
306         }
307         }
308 
309         string unknown;
310         stream.read(unknown, false);
311         s << "\nunknown = " << unknown;
312         break;
313     }
314 
315     default:
316     {
317         s << "(unknown)";
318         break;
319     }
320     }
321 
322     if(replyStatus == replyOK || replyStatus == replyUserException)
323     {
324         Ice::EncodingVersion v = stream.skipEncapsulation();
325         if(v > Ice::Encoding_1_0)
326         {
327             s << "\nencoding = " << v;
328         }
329     }
330 }
331 
332 static Byte
printMessage(ostream & s,InputStream & stream)333 printMessage(ostream& s, InputStream& stream)
334 {
335     Byte type = printHeader(s, stream);
336 
337     switch(type)
338     {
339     case closeConnectionMsg:
340     case validateConnectionMsg:
341     {
342         // We're done.
343         break;
344     }
345 
346     case requestMsg:
347     {
348         printRequest(s, stream);
349         break;
350     }
351 
352     case requestBatchMsg:
353     {
354         printBatchRequest(s, stream);
355         break;
356     }
357 
358     case replyMsg:
359     {
360         printReply(s, stream);
361         break;
362     }
363 
364     default:
365     {
366         break;
367     }
368     }
369 
370     return type;
371 }
372 
373 namespace
374 {
375 
376 IceUtil::Mutex* slicingMutex = 0;
377 
378 class Init
379 {
380 public:
381 
Init()382     Init()
383     {
384         slicingMutex = new IceUtil::Mutex;
385     }
386 
~Init()387     ~Init()
388     {
389         delete slicingMutex;
390         slicingMutex = 0;
391     }
392 };
393 
394 Init init;
395 
396 }
397 
398 void
traceSlicing(const char * kind,const string & typeId,const char * slicingCat,const LoggerPtr & logger)399 IceInternal::traceSlicing(const char* kind, const string& typeId, const char* slicingCat, const LoggerPtr& logger)
400 {
401     IceUtilInternal::MutexPtrLock<IceUtil::Mutex> lock(slicingMutex);
402     static set<string> slicingIds;
403     if(slicingIds.insert(typeId).second)
404     {
405         string s("unknown ");
406         s += kind;
407         s += " type `" + typeId + "'";
408         logger->trace(slicingCat, s);
409     }
410 }
411 
412 void
traceSend(const OutputStream & str,const LoggerPtr & logger,const TraceLevelsPtr & tl)413 IceInternal::traceSend(const OutputStream& str, const LoggerPtr& logger, const TraceLevelsPtr& tl)
414 {
415     if(tl->protocol >= 1)
416     {
417         OutputStream& stream = const_cast<OutputStream&>(str);
418         InputStream is(stream.instance(), stream.getEncoding(), stream);
419         is.i = is.b.begin();
420 
421         ostringstream s;
422         Byte type = printMessage(s, is);
423 
424         logger->trace(tl->protocolCat, "sending " + getMessageTypeAsString(type) + " " + s.str());
425     }
426 }
427 
428 void
traceRecv(const InputStream & str,const LoggerPtr & logger,const TraceLevelsPtr & tl)429 IceInternal::traceRecv(const InputStream& str, const LoggerPtr& logger, const TraceLevelsPtr& tl)
430 {
431     if(tl->protocol >= 1)
432     {
433         InputStream& stream = const_cast<InputStream&>(str);
434         InputStream::Container::iterator p = stream.i;
435         stream.i = stream.b.begin();
436 
437         ostringstream s;
438         Byte type = printMessage(s, stream);
439 
440         logger->trace(tl->protocolCat, "received " + getMessageTypeAsString(type) + " " + s.str());
441         stream.i = p;
442     }
443 }
444 
445 void
trace(const char * heading,const OutputStream & str,const LoggerPtr & logger,const TraceLevelsPtr & tl)446 IceInternal::trace(const char* heading, const OutputStream& str, const LoggerPtr& logger, const TraceLevelsPtr& tl)
447 {
448     if(tl->protocol >= 1)
449     {
450         OutputStream& stream = const_cast<OutputStream&>(str);
451         InputStream is(stream.instance(), stream.getEncoding(), stream);
452         is.i = is.b.begin();
453 
454         ostringstream s;
455         s << heading;
456         printMessage(s, is);
457 
458         logger->trace(tl->protocolCat, s.str());
459     }
460 }
461 
462 void
trace(const char * heading,const InputStream & str,const LoggerPtr & logger,const TraceLevelsPtr & tl)463 IceInternal::trace(const char* heading, const InputStream& str, const LoggerPtr& logger, const TraceLevelsPtr& tl)
464 {
465     if(tl->protocol >= 1)
466     {
467         InputStream& stream = const_cast<InputStream&>(str);
468         InputStream::Container::iterator p = stream.i;
469         stream.i = stream.b.begin();
470 
471         ostringstream s;
472         s << heading;
473         printMessage(s, stream);
474 
475         logger->trace(tl->protocolCat, s.str());
476         stream.i = p;
477     }
478 }
479