1 /*
2  * stats.c
3  */
4 
5 /*
6  *  Copyright (C) 2002 RealVNC Ltd.
7  *  OSXvnc Copyright (C) 2001 Dan McGuirk <mcguirk@incompleteness.net>.
8  *  Original Xvnc code Copyright (C) 1999 AT&T Laboratories Cambridge.
9  *  All Rights Reserved.
10  *
11  *  This is free software; you can redistribute it and/or modify
12  *  it under the terms of the GNU General Public License as published by
13  *  the Free Software Foundation; either version 2 of the License, or
14  *  (at your option) any later version.
15  *
16  *  This software is distributed in the hope that it will be useful,
17  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
18  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  *  GNU General Public License for more details.
20  *
21  *  You should have received a copy of the GNU General Public License
22  *  along with this software; if not, write to the Free Software
23  *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
24  *  USA.
25  */
26 
27 #include <rfb/rfb.h>
28 
29 char *messageNameServer2Client(uint32_t type, char *buf, int len);
30 char *messageNameClient2Server(uint32_t type, char *buf, int len);
31 char *encodingName(uint32_t enc, char *buf, int len);
32 
33 rfbStatList *rfbStatLookupEncoding(rfbClientPtr cl, uint32_t type);
34 rfbStatList *rfbStatLookupMessage(rfbClientPtr cl, uint32_t type);
35 
36 void  rfbStatRecordEncodingSent(rfbClientPtr cl, uint32_t type, int byteCount, int byteIfRaw);
37 void  rfbStatRecordEncodingRcvd(rfbClientPtr cl, uint32_t type, int byteCount, int byteIfRaw);
38 void  rfbStatRecordMessageSent(rfbClientPtr cl, uint32_t type, int byteCount, int byteIfRaw);
39 void  rfbStatRecordMessageRcvd(rfbClientPtr cl, uint32_t type, int byteCount, int byteIfRaw);
40 void rfbResetStats(rfbClientPtr cl);
41 void rfbPrintStats(rfbClientPtr cl);
42 
43 
44 
45 
messageNameServer2Client(uint32_t type,char * buf,int len)46 char *messageNameServer2Client(uint32_t type, char *buf, int len) {
47     if (buf==NULL) return "error";
48     switch (type) {
49     case rfbFramebufferUpdate:        snprintf(buf, len, "FramebufferUpdate"); break;
50     case rfbSetColourMapEntries:      snprintf(buf, len, "SetColourMapEntries"); break;
51     case rfbBell:                     snprintf(buf, len, "Bell"); break;
52     case rfbServerCutText:            snprintf(buf, len, "ServerCutText"); break;
53     case rfbResizeFrameBuffer:        snprintf(buf, len, "ResizeFrameBuffer"); break;
54     case rfbFileTransfer:             snprintf(buf, len, "FileTransfer"); break;
55     case rfbTextChat:                 snprintf(buf, len, "TextChat"); break;
56     case rfbPalmVNCReSizeFrameBuffer: snprintf(buf, len, "PalmVNCReSize"); break;
57     case rfbXvp:                      snprintf(buf, len, "XvpServerMessage"); break;
58     default:
59         snprintf(buf, len, "svr2cli-0x%08X", 0xFF);
60     }
61     return buf;
62 }
63 
messageNameClient2Server(uint32_t type,char * buf,int len)64 char *messageNameClient2Server(uint32_t type, char *buf, int len) {
65     if (buf==NULL) return "error";
66     switch (type) {
67     case rfbSetPixelFormat:           snprintf(buf, len, "SetPixelFormat"); break;
68     case rfbFixColourMapEntries:      snprintf(buf, len, "FixColourMapEntries"); break;
69     case rfbSetEncodings:             snprintf(buf, len, "SetEncodings"); break;
70     case rfbFramebufferUpdateRequest: snprintf(buf, len, "FramebufferUpdate"); break;
71     case rfbKeyEvent:                 snprintf(buf, len, "KeyEvent"); break;
72     case rfbPointerEvent:             snprintf(buf, len, "PointerEvent"); break;
73     case rfbClientCutText:            snprintf(buf, len, "ClientCutText"); break;
74     case rfbFileTransfer:             snprintf(buf, len, "FileTransfer"); break;
75     case rfbSetScale:                 snprintf(buf, len, "SetScale"); break;
76     case rfbSetServerInput:           snprintf(buf, len, "SetServerInput"); break;
77     case rfbSetSW:                    snprintf(buf, len, "SetSingleWindow"); break;
78     case rfbTextChat:                 snprintf(buf, len, "TextChat"); break;
79     case rfbPalmVNCSetScaleFactor:    snprintf(buf, len, "PalmVNCSetScale"); break;
80     case rfbXvp:                      snprintf(buf, len, "XvpClientMessage"); break;
81     default:
82         snprintf(buf, len, "cli2svr-0x%08X", type);
83 
84 
85     }
86     return buf;
87 }
88 
89 /* Encoding name must be <=16 characters to fit nicely on the status output in
90  * an 80 column terminal window
91  */
encodingName(uint32_t type,char * buf,int len)92 char *encodingName(uint32_t type, char *buf, int len) {
93     if (buf==NULL) return "error";
94 
95     switch (type) {
96     case rfbEncodingRaw:                snprintf(buf, len, "raw");         break;
97     case rfbEncodingCopyRect:           snprintf(buf, len, "copyRect");    break;
98     case rfbEncodingRRE:                snprintf(buf, len, "RRE");         break;
99     case rfbEncodingCoRRE:              snprintf(buf, len, "CoRRE");       break;
100     case rfbEncodingHextile:            snprintf(buf, len, "hextile");     break;
101     case rfbEncodingZlib:               snprintf(buf, len, "zlib");        break;
102     case rfbEncodingTight:              snprintf(buf, len, "tight");       break;
103     case rfbEncodingTightPng:           snprintf(buf, len, "tightPng");    break;
104     case rfbEncodingZlibHex:            snprintf(buf, len, "zlibhex");     break;
105     case rfbEncodingUltra:              snprintf(buf, len, "ultra");       break;
106     case rfbEncodingZRLE:               snprintf(buf, len, "ZRLE");        break;
107     case rfbEncodingZYWRLE:             snprintf(buf, len, "ZYWRLE");      break;
108     case rfbEncodingCache:              snprintf(buf, len, "cache");       break;
109     case rfbEncodingCacheEnable:        snprintf(buf, len, "cacheEnable"); break;
110     case rfbEncodingXOR_Zlib:           snprintf(buf, len, "xorZlib");     break;
111     case rfbEncodingXORMonoColor_Zlib:  snprintf(buf, len, "xorMonoZlib");  break;
112     case rfbEncodingXORMultiColor_Zlib: snprintf(buf, len, "xorColorZlib"); break;
113     case rfbEncodingSolidColor:         snprintf(buf, len, "solidColor");  break;
114     case rfbEncodingXOREnable:          snprintf(buf, len, "xorEnable");   break;
115     case rfbEncodingCacheZip:           snprintf(buf, len, "cacheZip");    break;
116     case rfbEncodingSolMonoZip:         snprintf(buf, len, "monoZip");     break;
117     case rfbEncodingUltraZip:           snprintf(buf, len, "ultraZip");    break;
118 
119     case rfbEncodingXCursor:            snprintf(buf, len, "Xcursor");     break;
120     case rfbEncodingRichCursor:         snprintf(buf, len, "RichCursor");  break;
121     case rfbEncodingPointerPos:         snprintf(buf, len, "PointerPos");  break;
122 
123     case rfbEncodingLastRect:           snprintf(buf, len, "LastRect");    break;
124     case rfbEncodingNewFBSize:          snprintf(buf, len, "NewFBSize");   break;
125     case rfbEncodingKeyboardLedState:   snprintf(buf, len, "LedState");    break;
126     case rfbEncodingSupportedMessages:  snprintf(buf, len, "SupportedMessage");  break;
127     case rfbEncodingSupportedEncodings: snprintf(buf, len, "SupportedEncoding"); break;
128     case rfbEncodingServerIdentity:     snprintf(buf, len, "ServerIdentify");    break;
129 
130     /* The following lookups do not report in stats */
131     case rfbEncodingCompressLevel0: snprintf(buf, len, "CompressLevel0");  break;
132     case rfbEncodingCompressLevel1: snprintf(buf, len, "CompressLevel1");  break;
133     case rfbEncodingCompressLevel2: snprintf(buf, len, "CompressLevel2");  break;
134     case rfbEncodingCompressLevel3: snprintf(buf, len, "CompressLevel3");  break;
135     case rfbEncodingCompressLevel4: snprintf(buf, len, "CompressLevel4");  break;
136     case rfbEncodingCompressLevel5: snprintf(buf, len, "CompressLevel5");  break;
137     case rfbEncodingCompressLevel6: snprintf(buf, len, "CompressLevel6");  break;
138     case rfbEncodingCompressLevel7: snprintf(buf, len, "CompressLevel7");  break;
139     case rfbEncodingCompressLevel8: snprintf(buf, len, "CompressLevel8");  break;
140     case rfbEncodingCompressLevel9: snprintf(buf, len, "CompressLevel9");  break;
141 
142     case rfbEncodingQualityLevel0:  snprintf(buf, len, "QualityLevel0");   break;
143     case rfbEncodingQualityLevel1:  snprintf(buf, len, "QualityLevel1");   break;
144     case rfbEncodingQualityLevel2:  snprintf(buf, len, "QualityLevel2");   break;
145     case rfbEncodingQualityLevel3:  snprintf(buf, len, "QualityLevel3");   break;
146     case rfbEncodingQualityLevel4:  snprintf(buf, len, "QualityLevel4");   break;
147     case rfbEncodingQualityLevel5:  snprintf(buf, len, "QualityLevel5");   break;
148     case rfbEncodingQualityLevel6:  snprintf(buf, len, "QualityLevel6");   break;
149     case rfbEncodingQualityLevel7:  snprintf(buf, len, "QualityLevel7");   break;
150     case rfbEncodingQualityLevel8:  snprintf(buf, len, "QualityLevel8");   break;
151     case rfbEncodingQualityLevel9:  snprintf(buf, len, "QualityLevel9");   break;
152 
153 
154     default:
155         snprintf(buf, len, "Enc(0x%08X)", type);
156     }
157 
158     return buf;
159 }
160 
161 
162 
163 
164 
rfbStatLookupEncoding(rfbClientPtr cl,uint32_t type)165 rfbStatList *rfbStatLookupEncoding(rfbClientPtr cl, uint32_t type)
166 {
167     rfbStatList *ptr;
168     if (cl==NULL) return NULL;
169     for (ptr = cl->statEncList; ptr!=NULL; ptr=ptr->Next)
170     {
171         if (ptr->type==type) return ptr;
172     }
173     /* Well, we are here... need to *CREATE* an entry */
174     ptr = (rfbStatList *)malloc(sizeof(rfbStatList));
175     if (ptr!=NULL)
176     {
177         memset((char *)ptr, 0, sizeof(rfbStatList));
178         ptr->type = type;
179         /* add to the top of the list */
180         ptr->Next = cl->statEncList;
181         cl->statEncList = ptr;
182     }
183     return ptr;
184 }
185 
186 
rfbStatLookupMessage(rfbClientPtr cl,uint32_t type)187 rfbStatList *rfbStatLookupMessage(rfbClientPtr cl, uint32_t type)
188 {
189     rfbStatList *ptr;
190     if (cl==NULL) return NULL;
191     for (ptr = cl->statMsgList; ptr!=NULL; ptr=ptr->Next)
192     {
193         if (ptr->type==type) return ptr;
194     }
195     /* Well, we are here... need to *CREATE* an entry */
196     ptr = (rfbStatList *)malloc(sizeof(rfbStatList));
197     if (ptr!=NULL)
198     {
199         memset((char *)ptr, 0, sizeof(rfbStatList));
200         ptr->type = type;
201         /* add to the top of the list */
202         ptr->Next = cl->statMsgList;
203         cl->statMsgList = ptr;
204     }
205     return ptr;
206 }
207 
rfbStatRecordEncodingSentAdd(rfbClientPtr cl,uint32_t type,int byteCount)208 void rfbStatRecordEncodingSentAdd(rfbClientPtr cl, uint32_t type, int byteCount) /* Specifically for tight encoding */
209 {
210     rfbStatList *ptr;
211 
212     ptr = rfbStatLookupEncoding(cl, type);
213     if (ptr!=NULL)
214         ptr->bytesSent      += byteCount;
215 }
216 
217 
rfbStatRecordEncodingSent(rfbClientPtr cl,uint32_t type,int byteCount,int byteIfRaw)218 void  rfbStatRecordEncodingSent(rfbClientPtr cl, uint32_t type, int byteCount, int byteIfRaw)
219 {
220     rfbStatList *ptr;
221 
222     ptr = rfbStatLookupEncoding(cl, type);
223     if (ptr!=NULL)
224     {
225         ptr->sentCount++;
226         ptr->bytesSent      += byteCount;
227         ptr->bytesSentIfRaw += byteIfRaw;
228     }
229 }
230 
rfbStatRecordEncodingRcvd(rfbClientPtr cl,uint32_t type,int byteCount,int byteIfRaw)231 void  rfbStatRecordEncodingRcvd(rfbClientPtr cl, uint32_t type, int byteCount, int byteIfRaw)
232 {
233     rfbStatList *ptr;
234 
235     ptr = rfbStatLookupEncoding(cl, type);
236     if (ptr!=NULL)
237     {
238         ptr->rcvdCount++;
239         ptr->bytesRcvd      += byteCount;
240         ptr->bytesRcvdIfRaw += byteIfRaw;
241     }
242 }
243 
rfbStatRecordMessageSent(rfbClientPtr cl,uint32_t type,int byteCount,int byteIfRaw)244 void  rfbStatRecordMessageSent(rfbClientPtr cl, uint32_t type, int byteCount, int byteIfRaw)
245 {
246     rfbStatList *ptr;
247 
248     ptr = rfbStatLookupMessage(cl, type);
249     if (ptr!=NULL)
250     {
251         ptr->sentCount++;
252         ptr->bytesSent      += byteCount;
253         ptr->bytesSentIfRaw += byteIfRaw;
254     }
255 }
256 
rfbStatRecordMessageRcvd(rfbClientPtr cl,uint32_t type,int byteCount,int byteIfRaw)257 void  rfbStatRecordMessageRcvd(rfbClientPtr cl, uint32_t type, int byteCount, int byteIfRaw)
258 {
259     rfbStatList *ptr;
260 
261     ptr = rfbStatLookupMessage(cl, type);
262     if (ptr!=NULL)
263     {
264         ptr->rcvdCount++;
265         ptr->bytesRcvd      += byteCount;
266         ptr->bytesRcvdIfRaw += byteIfRaw;
267     }
268 }
269 
270 
rfbStatGetSentBytes(rfbClientPtr cl)271 int rfbStatGetSentBytes(rfbClientPtr cl)
272 {
273     rfbStatList *ptr=NULL;
274     int bytes=0;
275     if (cl==NULL) return 0;
276     for (ptr = cl->statMsgList; ptr!=NULL; ptr=ptr->Next)
277         bytes += ptr->bytesSent;
278     for (ptr = cl->statEncList; ptr!=NULL; ptr=ptr->Next)
279         bytes += ptr->bytesSent;
280     return bytes;
281 }
282 
rfbStatGetSentBytesIfRaw(rfbClientPtr cl)283 int rfbStatGetSentBytesIfRaw(rfbClientPtr cl)
284 {
285     rfbStatList *ptr=NULL;
286     int bytes=0;
287     if (cl==NULL) return 0;
288     for (ptr = cl->statMsgList; ptr!=NULL; ptr=ptr->Next)
289         bytes += ptr->bytesSentIfRaw;
290     for (ptr = cl->statEncList; ptr!=NULL; ptr=ptr->Next)
291         bytes += ptr->bytesSentIfRaw;
292     return bytes;
293 }
294 
rfbStatGetRcvdBytes(rfbClientPtr cl)295 int rfbStatGetRcvdBytes(rfbClientPtr cl)
296 {
297     rfbStatList *ptr=NULL;
298     int bytes=0;
299     if (cl==NULL) return 0;
300     for (ptr = cl->statMsgList; ptr!=NULL; ptr=ptr->Next)
301         bytes += ptr->bytesRcvd;
302     for (ptr = cl->statEncList; ptr!=NULL; ptr=ptr->Next)
303         bytes += ptr->bytesRcvd;
304     return bytes;
305 }
306 
rfbStatGetRcvdBytesIfRaw(rfbClientPtr cl)307 int rfbStatGetRcvdBytesIfRaw(rfbClientPtr cl)
308 {
309     rfbStatList *ptr=NULL;
310     int bytes=0;
311     if (cl==NULL) return 0;
312     for (ptr = cl->statMsgList; ptr!=NULL; ptr=ptr->Next)
313         bytes += ptr->bytesRcvdIfRaw;
314     for (ptr = cl->statEncList; ptr!=NULL; ptr=ptr->Next)
315         bytes += ptr->bytesRcvdIfRaw;
316     return bytes;
317 }
318 
rfbStatGetMessageCountSent(rfbClientPtr cl,uint32_t type)319 int rfbStatGetMessageCountSent(rfbClientPtr cl, uint32_t type)
320 {
321   rfbStatList *ptr=NULL;
322     if (cl==NULL) return 0;
323   for (ptr = cl->statMsgList; ptr!=NULL; ptr=ptr->Next)
324       if (ptr->type==type) return ptr->sentCount;
325   return 0;
326 }
rfbStatGetMessageCountRcvd(rfbClientPtr cl,uint32_t type)327 int rfbStatGetMessageCountRcvd(rfbClientPtr cl, uint32_t type)
328 {
329   rfbStatList *ptr=NULL;
330     if (cl==NULL) return 0;
331   for (ptr = cl->statMsgList; ptr!=NULL; ptr=ptr->Next)
332       if (ptr->type==type) return ptr->rcvdCount;
333   return 0;
334 }
335 
rfbStatGetEncodingCountSent(rfbClientPtr cl,uint32_t type)336 int rfbStatGetEncodingCountSent(rfbClientPtr cl, uint32_t type)
337 {
338   rfbStatList *ptr=NULL;
339     if (cl==NULL) return 0;
340   for (ptr = cl->statEncList; ptr!=NULL; ptr=ptr->Next)
341       if (ptr->type==type) return ptr->sentCount;
342   return 0;
343 }
rfbStatGetEncodingCountRcvd(rfbClientPtr cl,uint32_t type)344 int rfbStatGetEncodingCountRcvd(rfbClientPtr cl, uint32_t type)
345 {
346   rfbStatList *ptr=NULL;
347     if (cl==NULL) return 0;
348   for (ptr = cl->statEncList; ptr!=NULL; ptr=ptr->Next)
349       if (ptr->type==type) return ptr->rcvdCount;
350   return 0;
351 }
352 
353 
354 
355 
rfbResetStats(rfbClientPtr cl)356 void rfbResetStats(rfbClientPtr cl)
357 {
358     rfbStatList *ptr;
359     if (cl==NULL) return;
360     while (cl->statEncList!=NULL)
361     {
362         ptr = cl->statEncList;
363         cl->statEncList = ptr->Next;
364         free(ptr);
365     }
366     while (cl->statMsgList!=NULL)
367     {
368         ptr = cl->statMsgList;
369         cl->statMsgList = ptr->Next;
370         free(ptr);
371     }
372 }
373 
374 
rfbPrintStats(rfbClientPtr cl)375 void rfbPrintStats(rfbClientPtr cl)
376 {
377     rfbStatList *ptr=NULL;
378     char encBuf[64];
379     double savings=0.0;
380     int    totalRects=0;
381     double totalBytes=0.0;
382     double totalBytesIfRaw=0.0;
383 
384     char *name=NULL;
385     int bytes=0;
386     int bytesIfRaw=0;
387     int count=0;
388 
389     if (cl==NULL) return;
390 
391     rfbLog("%-21.21s  %-6.6s   %9.9s/%9.9s (%6.6s)\n", "Statistics", "events", "Transmit","RawEquiv","saved");
392     for (ptr = cl->statMsgList; ptr!=NULL; ptr=ptr->Next)
393     {
394         name       = messageNameServer2Client(ptr->type, encBuf, sizeof(encBuf));
395         count      = ptr->sentCount;
396         bytes      = ptr->bytesSent;
397         bytesIfRaw = ptr->bytesSentIfRaw;
398 
399         savings = 0.0;
400         if (bytesIfRaw>0.0)
401             savings = 100.0 - (((double)bytes / (double)bytesIfRaw) * 100.0);
402         if ((bytes>0) || (count>0) || (bytesIfRaw>0))
403             rfbLog(" %-20.20s: %6d | %9d/%9d (%5.1f%%)\n",
404 	        name, count, bytes, bytesIfRaw, savings);
405         totalRects += count;
406         totalBytes += bytes;
407         totalBytesIfRaw += bytesIfRaw;
408     }
409 
410     for (ptr = cl->statEncList; ptr!=NULL; ptr=ptr->Next)
411     {
412         name       = encodingName(ptr->type, encBuf, sizeof(encBuf));
413         count      = ptr->sentCount;
414         bytes      = ptr->bytesSent;
415         bytesIfRaw = ptr->bytesSentIfRaw;
416         savings    = 0.0;
417 
418         if (bytesIfRaw>0.0)
419             savings = 100.0 - (((double)bytes / (double)bytesIfRaw) * 100.0);
420         if ((bytes>0) || (count>0) || (bytesIfRaw>0))
421             rfbLog(" %-20.20s: %6d | %9d/%9d (%5.1f%%)\n",
422 	        name, count, bytes, bytesIfRaw, savings);
423         totalRects += count;
424         totalBytes += bytes;
425         totalBytesIfRaw += bytesIfRaw;
426     }
427     savings=0.0;
428     if (totalBytesIfRaw>0.0)
429         savings = 100.0 - ((totalBytes/totalBytesIfRaw)*100.0);
430     rfbLog(" %-20.20s: %6d | %9.0f/%9.0f (%5.1f%%)\n",
431             "TOTALS", totalRects, totalBytes,totalBytesIfRaw, savings);
432 
433     totalRects=0.0;
434     totalBytes=0.0;
435     totalBytesIfRaw=0.0;
436 
437     rfbLog("%-21.21s  %-6.6s   %9.9s/%9.9s (%6.6s)\n", "Statistics", "events", "Received","RawEquiv","saved");
438     for (ptr = cl->statMsgList; ptr!=NULL; ptr=ptr->Next)
439     {
440         name       = messageNameClient2Server(ptr->type, encBuf, sizeof(encBuf));
441         count      = ptr->rcvdCount;
442         bytes      = ptr->bytesRcvd;
443         bytesIfRaw = ptr->bytesRcvdIfRaw;
444         savings    = 0.0;
445 
446         if (bytesIfRaw>0.0)
447             savings = 100.0 - (((double)bytes / (double)bytesIfRaw) * 100.0);
448         if ((bytes>0) || (count>0) || (bytesIfRaw>0))
449             rfbLog(" %-20.20s: %6d | %9d/%9d (%5.1f%%)\n",
450 	        name, count, bytes, bytesIfRaw, savings);
451         totalRects += count;
452         totalBytes += bytes;
453         totalBytesIfRaw += bytesIfRaw;
454     }
455     for (ptr = cl->statEncList; ptr!=NULL; ptr=ptr->Next)
456     {
457         name       = encodingName(ptr->type, encBuf, sizeof(encBuf));
458         count      = ptr->rcvdCount;
459         bytes      = ptr->bytesRcvd;
460         bytesIfRaw = ptr->bytesRcvdIfRaw;
461         savings    = 0.0;
462 
463         if (bytesIfRaw>0.0)
464             savings = 100.0 - (((double)bytes / (double)bytesIfRaw) * 100.0);
465         if ((bytes>0) || (count>0) || (bytesIfRaw>0))
466             rfbLog(" %-20.20s: %6d | %9d/%9d (%5.1f%%)\n",
467 	        name, count, bytes, bytesIfRaw, savings);
468         totalRects += count;
469         totalBytes += bytes;
470         totalBytesIfRaw += bytesIfRaw;
471     }
472     savings=0.0;
473     if (totalBytesIfRaw>0.0)
474         savings = 100.0 - ((totalBytes/totalBytesIfRaw)*100.0);
475     rfbLog(" %-20.20s: %6d | %9.0f/%9.0f (%5.1f%%)\n",
476             "TOTALS", totalRects, totalBytes,totalBytesIfRaw, savings);
477 
478 }
479 
480