Imported Upstream version 878.70.2
[platform/upstream/mdnsresponder.git] / mDNSMacOSX / BonjourTop / source / BonjourTop.cpp
1 //
2 //  BonjourTop.cpp
3 //  TestTB
4 //
5 //  Created by Terrin Eager on 9/26/12.
6 //
7 //
8
9 #include <stdio.h>
10 #include <errno.h>
11 #include <string.h>
12 #include <sys/socket.h>
13 #include <sys/types.h>
14 #include <netinet/in.h>
15 #include <unistd.h>
16 #include <stdlib.h>
17 #include <arpa/inet.h>
18 #include <ncurses.h>
19
20 #include "BonjourTop.h"
21 #include "DNSFrame.h"
22 #include "CaptureFile.h"
23 #include "bjsocket.h"
24 #include "bjstring.h"
25
26 #include <sys/sysctl.h>
27 #include <mach/mach.h>
28
29 #define SERVICE_IPV4    0
30 #define SERVICE_IPV6    1
31 #define APP_IPV4        2
32 #define APP_IPV6        3
33
34 #define TRACE_PLATFORM_UNKNOWN              0
35 #define TRACE_PLATFORM_OSX                  1
36 #define TRACE_PLATFORM_iOS                  2
37 #define TRACE_PLATFORM_APPLE_TV             3
38 #define TRACE_PLATFORM_NON_APPLE_PLATFORM   4
39 #define DISCOVERYD_TRACE_PLATFORM_OSX                   (1 | 0x80)
40 #define DISCOVERYD_TRACE_PLATFORM_iOS                   (2 | 0x80)
41 #define DISCOVERYD_TRACE_PLATFORM_APPLE_TV              (3 | 0x80)
42 #define DISCOVERYD_TRACE_PLATFORM_NON_APPLE_PLATFORM    (4 | 0x80)
43
44 int CDeviceNode::nCreateCount = 0;
45 static integer_t Usage(void);
46
47 char CVSFileNameExample[] ="BonjourTop";
48 char DeviceNameExample[] ="BonjourTopDevice.csv";
49
50 char Service2App[][50] = {
51     // Service_Name,             Application_Name,    Browse_OS_Type, Register_OS_Type
52     "_device-info._tcp.local.",     "Device-Info",  "?" , "?",
53     "_rfb._tcp.local.",             "Finder",       "X" , "?",
54     "_afpovertcp._tcp.local.",      "Finder",       "?" , "X",
55     "_adisk._tcp.local.",           "Finder",       "?" , "X",
56     "_odisk._tcp.local.",           "Finder",       "?" , "X",
57     "_smb._tcp.local.",             "Finder",       "X" , "X",
58     "_smb2._tcp.local.",            "Finder",       "X" , "X",
59     "_workstation._tcp.local.",     "Finder",       "X" , "X",
60     "_kerberos.",                   "Finder",       "X" , "X",
61     "_nfs._tcp.local.",             "Finder",       "X" , "X",
62     "_ftp._tcp.local.",             "Finder",       "X" , "X",
63
64     "_appletv._tcp.local.",         "AppleTV",      "?" , "t",
65     "_appletv-v2._tcp.local.",      "AppleTV",      "?" , "?",
66     "_appletv-pair._tcp.local.",    "AppleTV",      "?" , "?",
67
68     "A",                            "LinkLocal",    "?" , "?",
69     "AAAA",                         "LinkLocal",    "?" , "?",
70     "*.ip6.arpa.",                  "LinkLocal",     "?" , "?",
71     "*.arpa.",                      "LinkLocal",    "?" , "?",
72
73     "_airplay._tcp.local.",         "AirPlay",      "?" , "t",
74     "_airplayTXT",                  "AirPlay","?" , "t",
75     "_raop._tcp.local.",            "AirPlay","?" , "?",
76
77     "_ubd._tcp.local.",             "Ubiquity",     "?" , "?",
78     "_ubiquity._tcp.local.",        "Ubiquity",     "?" , "?",
79     "_ubiquityV1._tcp.local.",        "Ubiquity",     "?" , "?",
80     "_ubiquityV2._tcp.local.",        "Ubiquity",     "?" , "?",
81
82     " _ipps._tcp.local.",           "Printing",     "?" , "?",
83     "_ipp._tcp.local.",             "Printing",     "?" , "?",
84     "_ipps._tcp.local.",            "Printing",     "?" , "?",
85     "_ipp-tls._tcp.local.",         "Printing",     "?" , "?",
86     "_printer._tcp.local.",         "Printing",     "?" , "?",
87     "_scanner._tcp.local.",         "Printing",     "?" , "?",
88     "_pdl-datastream._tcp.local.",  "Printing",     "?" , "?",
89     "_fax-ipp._tcp.local.",         "Printing",     "?" , "?",
90
91     "_apple-mobdev._tcp.local.",    "iTunes-WiFiSync","?" , "i",
92     "_daap._tcp.local.",            "iTunes",       "?" , "?",
93
94     "_sftp-ssh._tcp.local.",        "Terminal",     "?" , "X",
95     "_ssh._tcp.local.",             "Terminal",     "?" , "X",
96
97     "_sleep-proxy._udp.local.",     "Sleep Proxy",  "?" , "?",
98     "_keepalive._dns-sd._udp.local.","Sleep Proxy", "X" , "?",
99     "_services._dns-sd._udp.local.", "Services",    "?" , "?",
100     "ANY *.ip6.arpa.",              "Sleep Proxy",  "?" , "?",
101     "ANY *.arpa.",                  "Sleep Proxy",  "?" , "?",
102
103     "AirPort_presence._tcp.local.", "AirPort",      "?" , "?",
104     "_airport._tcp.local.",         "AirPort",      "?" , "?",
105     "_presence._tcp.local.",        "iChat",        "X" , "X",
106     "_home-sharing._tcp.local.",    "HomeSharing",  "?" , "X",
107
108     "_ptp._tcp.local.",             "iPhoto",       "?" , "X",
109     "_ica-networking2._tcp.local.", "iPhoto",       "X" , "X",
110     "_mobileiphoto._udp.local.",    "iPhoto",       "?" , "?",
111     "_mobileiphoto2._udp.local.",   "iPhoto",       "?" , "?",
112     "_dpap._tcp.local.",            "iPhoto",       "?" , "X",
113     "_airdrop._tcp.local.",         "AirDrop",      "?" , "?",
114     "_http._tcp.local.",            "Safari",       "X" , "X",
115     "_net-assistant._udp.local.","Apple Remote Desktop","X" , "X",
116     "_servermgr._tcp.local.",       "OSX Server",   "X" , "X",
117     ""
118 };
119
120 char DeviceInfo2DeviceOS[][50] = {
121     // deviceModel,   deviceType
122     "MacBookAir",       "X",
123     "MacBookPro",       "X",
124     "Macmini",          "X",
125     "iMac",             "X",
126     "MacPro",           "X",
127     "MacBook",          "X",
128     "AAPLJ15",          "X",
129     "AAPLJ41",          "X",
130     "AAPLJ43",          "X",
131     "AAPLJ45",          "X",
132     "AAPLJ90",          "X",
133     "AAPLJ17",          "X",
134     "PowerMac",         "X",
135
136
137     "J33AP",            "t",
138     "J33iAP",           "t",
139     "J71AP",            "i",
140     "J72AP",            "i",
141     "J75AP",            "i",
142     "J85DEV",           "i",
143     "K66AP",            "t",
144     "N41AP",            "i",
145     "N42AP",            "i",
146     "N48AP",            "i",
147     "N51AP",            "i",
148     "N53AP",            "i",
149     "N78AP",            "i",
150     "P101AP",           "i",
151     "P102AP",           "i",
152     "P103AP",           "i",
153     "P105AP",           "i",
154     "P106AP",           "i",
155     "P107AP",           "i",
156     "AirPort",          "b",
157     "TimeCapsule",          "b",
158     ""
159 };
160
161 char Name2DeviceOS[][50] = {
162     // Name contains,   osType
163     "iPhone",           "i",
164     "phone",            "i",
165     "Phone",            "i",
166     "iPod",             "i",
167     "iPad",             "i",
168     "ipad",             "i",
169     "Apple-TV",         "t",
170     "AppleTV",          "t",
171     "MacBook",          "X",
172     "macbook",          "X",
173     "iMac",             "X",
174     "macmini",          "X",
175     ""
176 };
177
178 BJ_UINT64 Hash(const char* pStr);
179 BJ_UINT64 Hash2(char* pStr);
180
181
182 CSocketStats::CSocketStats()
183 {
184     Init();
185
186 }
187 void CSocketStats::Init()
188 {
189     m_nFrameCount = 0;
190
191     m_nQuestionOnlyFrames = 0;
192     m_nAnswerOnlyFrames = 0;
193     m_nQandAFrames = 0;
194
195     m_SampleDay = 0;
196 }
197
198 void CSocketStats::Clear()
199 {
200     Init();
201 }
202
203 CBonjourTop::CBonjourTop()
204 {
205
206     m_bCursers = true;
207     m_pTcpDumpFileName = NULL;
208     m_pExportFileName = CVSFileNameExample;
209     m_DeviceFileName = DeviceNameExample;
210
211     m_nFrameCount = 0;
212     m_nTotalBytes = 0;
213
214     m_StartTime = m_EndTime = time(NULL);
215
216     m_SnapshotSeconds = 0;
217
218     m_MinAnswerCountForTruncatedFrames = 0;
219     m_AvgAnswerCountForTruncatedFrames = 0;
220     m_MaxAnswerCountForTruncatedFrames = 0;
221
222     window_size_changed = false;
223     m_bImportExportDeviceMap = false;
224
225     // loadup application mapping
226     for(int i=0; Service2App[i][0] != 0;)
227     {
228         BJString a(Service2App[i++]);
229
230         m_Service2AppMap.FindwithAddRecord(&a)->value = Service2App[i++];
231         m_Service2osBrowseMap.FindwithAddRecord(&a)->value = Service2App[i++];
232         m_Service2osRegisterMap.FindwithAddRecord(&a)->value = Service2App[i++];
233
234     }
235
236
237     m_CurrentDisplay = CBonjourTop::BJ_DISPLAY_APP;
238   //  m_CurrentDisplay = CBonjourTop::BJ_DISPLAY_SERVICE;
239
240     Usage();
241
242 }
243
244 static int CbClearDataDevice(const void* pNode, const void*)
245 {
246     CDeviceNode* pDeviceRecord = (CDeviceNode*)pNode;
247
248     pDeviceRecord->ClearData();
249     return 0;
250 }
251
252 void CBonjourTop::Reset()
253 {
254     m_nFrameCount = 0;
255     m_nTotalBytes = 0;
256
257     m_MinAnswerCountForTruncatedFrames = 0;
258     m_AvgAnswerCountForTruncatedFrames = 0;
259     m_MaxAnswerCountForTruncatedFrames = 0;
260
261     m_StartTime = m_EndTime = time(NULL);
262
263     m_ServicePtrCache.ClearAll();
264     m_ApplPtrCache.ClearAll();
265
266     m_ServicePtrCacheIPv6.ClearAll();
267     m_ApplPtrCacheIPv6.ClearAll();
268
269     // Clear all data in the map
270     m_AppBreakdownIPv4OSX.clear();
271     m_AppBreakdownIPv4iOS.clear();
272     m_AppBreakdownIPv6OSX.clear();
273     m_AppBreakdownIPv6iOS.clear();
274
275     m_ServiceBreakdownIPv4OSX.clear();
276     m_ServiceBreakdownIPv4iOS.clear();
277     m_ServiceBreakdownIPv6OSX.clear();
278     m_ServiceBreakdownIPv6iOS.clear();
279
280     // Clear Socket Status
281     for (int i = 0; i < NUM_SOCKET_STATUS; i++)
282     {
283         m_SocketStatus[i].Clear();
284     }
285
286     for (int i = 0; i < HOURS_IN_DAY; i++)
287     {
288         for (int j = 0; j < MINUTES_IN_HOUR; j++)
289         {
290             m_MinSnapshot[i][j].Clear();
291         }
292     }
293
294     CDeviceNode* pDeviceNode = m_DeviceMap.GetRoot();
295     if (pDeviceNode)
296     {
297         pDeviceNode->CallBack(&CbClearDataDevice,NULL);
298     }
299
300 }
301
302 void CBonjourTop::SetIPAddr(const char* pStr)
303 {
304     m_IPv4Addr.Set(pStr);
305
306 }
307
308 void CBonjourTop::UpdateRecord(CStringTree&  Cache,CDNSRecord* pDNSRecord,BJString& RecordName,BJString& ServiceName,BJ_UINT32 nBytes,bool bGoodbye)
309 {
310     BJ_UINT64 nHashValue = 0;
311     char deviceOS = '?';
312
313     nHashValue = Hash(RecordName.GetBuffer());
314     CStringNode* pRecord = Cache.Find(&nHashValue);
315     if (pRecord == NULL)
316     {
317         pRecord = (CStringNode*) Cache.FindwithAddRecord(&nHashValue);
318         strcpy(pRecord->m_Value, RecordName.GetBuffer());
319     }
320
321     if (pRecord == NULL)
322         return;
323     CDeviceNode dummyDevice;
324     CDeviceNode *device = &dummyDevice;
325     CIPDeviceNode *pipNode = m_IPtoNameMap.Find(&m_Frame.m_SourceIPAddress);
326
327     device = (pipNode)? pipNode->pDeviceNode : &dummyDevice;
328     pRecord->m_nBytes += 10 + nBytes;
329     deviceOS = device->GetDeviceOS();
330     device->frameTotal.Increment(m_nFrameCount);
331
332     if (pRecord->m_nLastFrameIndex != m_nFrameCount)
333     {
334         pRecord->m_nLastFrameIndex = m_nFrameCount;
335
336         pRecord->m_nFrames++;
337         if (deviceOS == 't' || deviceOS == 'i')
338         {
339             pRecord->m_nFramesiOS++;
340         }
341         else if (deviceOS == 'X')
342         {
343             pRecord->m_nFramesOSX++;
344         }
345     }
346
347     // Update Total Device Count
348     if (pRecord->m_DeviceTotalTree.Find(&m_Frame.m_SourceIPAddress) == NULL)
349     {
350         pRecord->m_nDeviceTotalCount++;
351         pRecord->m_DeviceTotalTree.FindwithAddRecord(&m_Frame.m_SourceIPAddress);
352     }
353
354     if (m_Frame.IsQueryFrame())
355     {
356         GetOSTypeFromQuery(pDNSRecord, ServiceName);
357         device->questionFrame.Increment(m_nFrameCount);
358         if (pRecord->m_nLastQueryFrameIndex != m_nFrameCount)
359         {
360             pRecord->m_nLastQueryFrameIndex = m_nFrameCount;
361
362             pRecord->m_nQuestionFrames++;
363
364             if (deviceOS == 't' || deviceOS == 'i')
365             {
366                 pRecord->m_nQuestionFramesiOS++;
367             }
368             else if (deviceOS == 'X')
369             {
370                 pRecord->m_nQuestionFramesOSX++;
371             }
372
373             if (pRecord->m_DeviceAskingTree.Find(&m_Frame.m_SourceIPAddress) == NULL)
374             {
375                 pRecord->m_nDeviceAskingCount++;
376                 pRecord->m_DeviceAskingTree.FindwithAddRecord(&m_Frame.m_SourceIPAddress);
377             }
378         }
379     }
380     else
381     {
382         GetOSTypeFromRegistration(pDNSRecord,ServiceName);
383
384         device->answerFrame.Increment(m_nFrameCount);
385         if (pRecord->m_nLastRespondsFrameIndex != m_nFrameCount)
386         {
387             pRecord->m_nLastRespondsFrameIndex = m_nFrameCount;
388
389             pRecord->m_nAnswerFrames++;
390             if (deviceOS == 't' || deviceOS == 'i')
391             {
392                 pRecord->m_nAnswerFramesiOS++;
393             }
394             else if (deviceOS == 'X')
395             {
396                 pRecord->m_nAnswerFramesOSX++;
397             }
398
399             if (bGoodbye)
400             {
401                 pRecord->m_nGoodbyeFrames++;
402             }
403
404             if (pRecord->m_DeviceAnsweringTree.Find(&m_Frame.m_SourceIPAddress) == NULL)
405             {
406                 pRecord->m_nDeviceAnsweringCount++;
407                 pRecord->m_DeviceAnsweringTree.FindwithAddRecord(&m_Frame.m_SourceIPAddress);
408             }
409         }
410     }
411
412     if (m_Frame.IsWakeFrame())
413     {
414         if (pRecord->m_nLastWakeFrameIndex != m_nFrameCount)
415         {
416             pRecord->m_nLastWakeFrameIndex = m_nFrameCount;
417             if (pRecord->m_lastQUFrameTime +1000000ll < m_Frame.GetTime() || pRecord->m_lastQUFrameTime == 0) // last qu frame has been over 1 sec
418             {
419                 pRecord->m_nWakeFrames++;
420                 pRecord->m_lastQUFrameTime = m_Frame.GetTime();
421                 device->QUFrame.Increment(m_nFrameCount);
422             }
423             pRecord->m_lastQUFrameTime = m_Frame.GetTime();
424         }
425     }
426
427
428 }
429
430 void CBonjourTop::UpdateShortRecordHelper(BJ_UINT32 cacheType, BJ_UINT32 tracePlatform, BJ_UINT32 traceVersion, char deviceOS, CDNSRecord* pDNSRecord,BJString& RecordName,BJString& ServiceName,BJ_UINT32 nBytes,bool bGoodbye)
431 {
432     bool isOSX = false;
433     BJString versionNumber = "mDNSResponder-";
434     const int version_max_length = 11; // largest number is 0xffffffff = 4294967295
435     char versionChar[version_max_length];
436
437     CStringShortTree *cache;
438     map<BJString, CStringShortTree*>* myMap;
439
440     if ((tracePlatform | 0x80) == tracePlatform)
441     {
442         versionNumber = "Discoveryd-";
443     }
444
445     snprintf(versionChar, sizeof(versionChar), "%u", 0); // Set versionChar to "0" by default
446     if (tracePlatform == TRACE_PLATFORM_UNKNOWN) // Pre iOS 7 or Pre OSX 10.9
447     {
448         if (deviceOS == 'i' || deviceOS == 't') // Pre iOS 7
449         {
450             isOSX = false;
451         }
452         else if (deviceOS == 'X') // Pre OSX 10.9
453         {
454             isOSX = true;
455         }
456     }
457     else if ((tracePlatform == TRACE_PLATFORM_OSX) || (tracePlatform == DISCOVERYD_TRACE_PLATFORM_OSX)) // >= OSX 10.9
458     {
459         isOSX = true;
460         snprintf(versionChar, sizeof(versionChar), "%u", traceVersion);
461     }
462     else if ((tracePlatform == TRACE_PLATFORM_iOS) || (tracePlatform == DISCOVERYD_TRACE_PLATFORM_iOS)) // >= iOS 7.x
463     {
464         isOSX = false;
465         snprintf(versionChar, sizeof(versionChar), "%u", traceVersion);
466     }
467     else if ((tracePlatform == TRACE_PLATFORM_APPLE_TV) || (tracePlatform == DISCOVERYD_TRACE_PLATFORM_APPLE_TV))
468     {
469         snprintf(versionChar, sizeof(versionChar), "%u", traceVersion);
470     }
471
472     versionNumber += (const char*)versionChar;
473
474     switch (cacheType) {
475         case SERVICE_IPV4:
476             if (isOSX)
477             {
478                 myMap = &m_ServiceBreakdownIPv4OSX;
479             }
480             else
481             {
482                 myMap = &m_ServiceBreakdownIPv4iOS;
483             }
484             break;
485         case SERVICE_IPV6:
486             if (isOSX)
487             {
488                 myMap = &m_ServiceBreakdownIPv6OSX;
489             }
490             else
491             {
492                 myMap = &m_ServiceBreakdownIPv6iOS;
493             }
494             break;
495         case APP_IPV4:
496             if (isOSX)
497             {
498                 myMap = &m_AppBreakdownIPv4OSX;
499             }
500             else
501             {
502                 myMap = &m_AppBreakdownIPv4iOS;
503             }
504             break;
505         case APP_IPV6:
506             if (isOSX)
507             {
508                 myMap = &m_AppBreakdownIPv6OSX;
509             }
510             else
511             {
512                 myMap = &m_AppBreakdownIPv6iOS;
513             }
514             break;
515
516         default:
517             return;
518             break;
519     }
520
521     if (myMap->find(versionNumber) == myMap->end()) // Version number not found. Create new record
522     {
523         myMap->insert(std::pair<BJString, CStringShortTree*>(versionNumber, new CStringShortTree()));
524     }
525     cache = (*myMap)[versionNumber];
526     UpdateShortRecord(cache, pDNSRecord, RecordName, ServiceName, nBytes, bGoodbye);
527 }
528
529 void CBonjourTop::UpdateShortRecord(CStringShortTree*  Cache,CDNSRecord* pDNSRecord,BJString& RecordName,BJString& ServiceName,BJ_UINT32 nBytes,bool bGoodbye)
530 {
531     if (Cache == NULL)
532     {
533         return;
534     }
535
536     BJ_UINT64 nHashValue = 0;
537     char deviceOS = '?';
538
539     nHashValue = Hash(RecordName.GetBuffer());
540     CStringShortNode* pRecord = Cache->Find(&nHashValue);
541     if (pRecord == NULL)
542     {
543         pRecord = (CStringShortNode*) Cache->FindwithAddRecord(&nHashValue);
544         strcpy(pRecord->m_Value, RecordName.GetBuffer());
545     }
546
547     if (pRecord == NULL)
548     {
549         return;
550     }
551
552     CDeviceNode dummyDevice;
553     CDeviceNode *device = &dummyDevice;
554     CIPDeviceNode *pipNode = m_IPtoNameMap.Find(&m_Frame.m_SourceIPAddress);
555
556     device = (pipNode)? pipNode->pDeviceNode : &dummyDevice;
557     pRecord->m_nBytes += 10 + nBytes;
558     deviceOS = device->GetDeviceOS();
559     device->frameTotal.Increment(m_nFrameCount);
560
561     if (pRecord->m_nLastFrameIndex != m_nFrameCount)
562     {
563         pRecord->m_nLastFrameIndex = m_nFrameCount;
564         pRecord->m_nFrames++;
565     }
566
567     // Update Total Device Count
568     if (pRecord->m_DeviceTotalTree.Find(&m_Frame.m_SourceIPAddress) == NULL)
569     {
570         pRecord->m_nDeviceTotalCount++;
571         pRecord->m_DeviceTotalTree.FindwithAddRecord(&m_Frame.m_SourceIPAddress);
572     }
573
574     if (m_Frame.IsQueryFrame())
575     {
576         GetOSTypeFromQuery(pDNSRecord, ServiceName);
577         device->questionFrame.Increment(m_nFrameCount);
578         if (pRecord->m_nLastQueryFrameIndex != m_nFrameCount)
579         {
580             pRecord->m_nLastQueryFrameIndex = m_nFrameCount;
581
582             pRecord->m_nQuestionFrames++;
583
584             if (pRecord->m_DeviceAskingTree.Find(&m_Frame.m_SourceIPAddress) == NULL)
585             {
586                 pRecord->m_nDeviceAskingCount++;
587                 pRecord->m_DeviceAskingTree.FindwithAddRecord(&m_Frame.m_SourceIPAddress);
588             }
589
590         }
591     }
592     else
593     {
594         GetOSTypeFromRegistration(pDNSRecord,ServiceName);
595
596         device->answerFrame.Increment(m_nFrameCount);
597         if (pRecord->m_nLastRespondsFrameIndex != m_nFrameCount)
598         {
599             pRecord->m_nLastRespondsFrameIndex = m_nFrameCount;
600
601             pRecord->m_nAnswerFrames++;
602
603             if (bGoodbye)
604             {
605                 pRecord->m_nGoodbyeFrames++;
606             }
607
608             if (pRecord->m_DeviceAnsweringTree.Find(&m_Frame.m_SourceIPAddress) == NULL)
609             {
610                 pRecord->m_nDeviceAnsweringCount++;
611                 pRecord->m_DeviceAnsweringTree.FindwithAddRecord(&m_Frame.m_SourceIPAddress);
612             }
613         }
614     }
615
616     if (m_Frame.IsWakeFrame())
617     {
618         if (pRecord->m_nLastWakeFrameIndex != m_nFrameCount)
619         {
620             pRecord->m_nLastWakeFrameIndex = m_nFrameCount;
621             if (pRecord->m_lastQUFrameTime +1000000ll < m_Frame.GetTime() || pRecord->m_lastQUFrameTime == 0) // last qu frame has been over 1 sec
622             {
623                 pRecord->m_nWakeFrames++;
624                 pRecord->m_lastQUFrameTime = m_Frame.GetTime();
625                 device->QUFrame.Increment(m_nFrameCount);
626             }
627             pRecord->m_lastQUFrameTime = m_Frame.GetTime();
628         }
629     }
630
631
632 }
633
634 void CBonjourTop::GetOSTypeFromQuery(CDNSRecord *pDNSRecord,BJString& ServiceName)
635 {
636     if (pDNSRecord->m_RecType == DNS_TYPE_PTR)
637     {
638         StringMapNode* pStringNode = m_Service2osBrowseMap.Find(&ServiceName);
639         if (pStringNode && *pStringNode->value.GetBuffer() != '?')
640         {
641             CIPDeviceNode *ipNode = m_IPtoNameMap.FindwithAddRecord(&m_Frame.m_SourceIPAddress);
642             if (ipNode->pDeviceNode)
643             {
644                 StringMapNode* pStringNode_temp = m_Service2osBrowseMap.Find(&ServiceName);
645                 ipNode->pDeviceNode->SetDeviceOS(*pStringNode_temp->value.GetBuffer(),ServiceName.GetBuffer());
646             }
647         }
648     }
649 }
650
651 void CBonjourTop::GetOSTypeFromRegistration(CDNSRecord *pDNSRecord,BJString& ServiceName)
652 {
653     CDeviceNode* deviceNode = NULL;
654     BJString sDeviceName;
655
656     if (pDNSRecord->m_RecType == DNS_TYPE_PTR)
657     {
658         BJString sInstanceName;
659         pDNSRecord->GetRdata(sInstanceName,0,99);
660         CDNSRecord* pSRVRecord = m_Frame.FindAdditionRecord(sInstanceName, DNS_TYPE_SRV);
661         if (pSRVRecord)
662         {
663             pSRVRecord->GetRdata(sDeviceName,0,1);
664         }
665         else
666         {
667             sDeviceName = sInstanceName;
668         }
669         deviceNode = m_DeviceMap.Find(&sDeviceName);
670     }
671
672     // Name guess
673      if (Name2OSType(sDeviceName,deviceNode))
674          return;
675
676     StringMapNode* pStringNode = m_Service2osRegisterMap.Find(&ServiceName);
677
678     if (pStringNode == NULL || *pStringNode->value.GetBuffer() == '?')
679         return;
680
681
682
683     if (sDeviceName.GetLength() > 0)
684     {
685         // update global device table with os type
686         if (deviceNode)
687         {
688             deviceNode->SetDeviceOS(*pStringNode->value.GetBuffer(),ServiceName.GetBuffer());
689         }
690     }
691 }
692 bool CBonjourTop::Name2OSType(BJString name,CDeviceNode* device)
693 {
694     if (device == NULL)
695         return false;
696     // try to set device type from common names
697     for (int i=0; Name2DeviceOS[i][0] != 0; i +=2)
698     {
699         if (name.Contains(Name2DeviceOS[i]))
700         {
701             device->SetDeviceOS(Name2DeviceOS[i+1][0], "Name Mapping");
702             return true;
703         }
704     }
705     return false;
706 }
707 void CBonjourTop::ProcessFrame(BJ_UINT8* pBuffer,BJ_INT32 nLength,BJ_UINT64 nFrameTime)
708 {
709
710     m_Frame.ParseDNSFrame(pBuffer, nLength, nFrameTime);
711
712     if (m_Collection.IsValid())
713     {
714         // setup static collectby
715         CollectByPacketCount::nFrameIndex = m_nFrameCount;
716         CollectBySameSubnetDiffSubnet::bSameSubnet = m_Frame.m_SourceIPAddress.IsIPv6()? true: m_IPv4Addr.IsSameSubNet(&m_Frame.m_SourceIPAddress);
717         m_Collection.ProcessFrame(&m_Frame);
718         return;
719     }
720
721     if (m_Frame.IsTruncatedFrame())
722     {
723         if (m_Frame.GetAnswerCount() > 0)
724         {
725             if (m_AvgAnswerCountForTruncatedFrames)
726             {
727                 m_AvgAnswerCountForTruncatedFrames += m_Frame.GetAnswerCount();
728                 m_AvgAnswerCountForTruncatedFrames /=2;
729             }
730             else
731                 m_AvgAnswerCountForTruncatedFrames += m_Frame.GetAnswerCount();
732
733             if (m_MinAnswerCountForTruncatedFrames > m_Frame.GetAnswerCount() || m_MinAnswerCountForTruncatedFrames == 0)
734                 m_MinAnswerCountForTruncatedFrames = m_Frame.GetAnswerCount();
735             if (m_MaxAnswerCountForTruncatedFrames < m_Frame.GetAnswerCount())
736                 m_MaxAnswerCountForTruncatedFrames = m_Frame.GetAnswerCount();
737
738         }
739     }
740
741     // find min snapshot bucket
742     time_t now = time(NULL);
743     struct tm* timeStruct = localtime(&now);
744     if (m_MinSnapshot[timeStruct->tm_hour][timeStruct->tm_min].m_SampleDay != timeStruct->tm_mday)
745     {
746         //Reset Snapshot 24 hour wrap around
747         m_MinSnapshot[timeStruct->tm_hour][timeStruct->tm_min].Init();
748         m_MinSnapshot[timeStruct->tm_hour][timeStruct->tm_min].m_SampleDay = timeStruct->tm_mday;
749
750     }
751     m_MinSnapshot[timeStruct->tm_hour][timeStruct->tm_min].m_nFrameCount++;
752
753     if (m_Frame.GetQuestionCount() == 0 && m_Frame.GetAnswerCount() > 0)
754         m_SocketStatus[0].m_nAnswerOnlyFrames++;
755     else if (m_Frame.GetQuestionCount() > 0 && m_Frame.GetAnswerCount() == 0)
756         m_SocketStatus[0].m_nQuestionOnlyFrames++;
757     else
758         m_SocketStatus[0].m_nQandAFrames++;
759
760     BJString InstanceName;
761     BJString RecordName;
762     BJString ApplRecordName;
763
764     /// first get the name to address
765     for (int dnsItemsIndex =m_Frame.GetQuestionCount(); dnsItemsIndex < m_Frame.GetMaxRecords();dnsItemsIndex++)
766     {
767         CDNSRecord* pDNSRecord = m_Frame.GetDnsRecord(dnsItemsIndex);
768         if (pDNSRecord == NULL)
769             continue;
770
771         if (pDNSRecord->m_RecType == DNS_TYPE_A)
772         {
773             BJString sName;
774             pDNSRecord->GetDnsRecordName(sName, 0, 1);
775             BJIPAddr ip;
776             ip.Setv4Raw(pDNSRecord->GetStartofRdata());
777
778             CDeviceNode* device = m_DeviceMap.FindwithAddRecord(&sName);
779             device->ipAddressv4 = ip;
780
781             // create ip to name mapping
782             CIPDeviceNode* pipNode = m_IPtoNameMap.FindwithAddRecord(&ip);
783
784             if (pipNode->pDeviceNode && pipNode->pDeviceNode->bIPName &&  pipNode->pDeviceNode->m_Key != device->m_Key)
785             {
786                 pipNode->pDeviceNode->bDuplicate = true;
787                 device->MergeData(pipNode->pDeviceNode);
788                 pipNode->pDeviceNode->ClearData();
789                 // remap IPv6
790                 if (!pipNode->pDeviceNode->ipAddressv6.IsEmpty())
791                 {
792                     CIPDeviceNode* ipv6Node = m_IPtoNameMap.Find(&pipNode->pDeviceNode->ipAddressv6);
793                     if (ipv6Node)
794                         ipv6Node->pDeviceNode = device;
795                 }
796             }
797
798             pipNode->pDeviceNode = device;
799             Name2OSType(sName,device);
800         }
801
802         if (pDNSRecord->m_RecType == DNS_TYPE_AAAA)
803         {
804             BJString sName;
805             pDNSRecord->GetDnsRecordName(sName, 0, 1);
806             BJIPAddr ip;
807             ip.Setv6Raw(pDNSRecord->GetStartofRdata());
808
809             if (ip.IsIPv6LinkLocal())
810             {
811                 CDeviceNode* device = m_DeviceMap.FindwithAddRecord(&sName);
812                 device->ipAddressv6 = ip;
813
814                 // create ip to name mapping
815                 CIPDeviceNode* pipNode = m_IPtoNameMap.FindwithAddRecord(&ip);
816
817                 if (pipNode->pDeviceNode && pipNode->pDeviceNode->bIPName && pipNode->pDeviceNode->m_Key != device->m_Key)
818                 {
819                     pipNode->pDeviceNode->bDuplicate = true;
820                     device->MergeData(pipNode->pDeviceNode);
821                     pipNode->pDeviceNode->ClearData();
822                     // remap IPv4
823                     if (!pipNode->pDeviceNode->ipAddressv4.IsEmpty())
824                     {
825                         CIPDeviceNode* ipv4Node = m_IPtoNameMap.Find(&pipNode->pDeviceNode->ipAddressv4);
826                         if (ipv4Node)
827                             ipv4Node->pDeviceNode = device;
828                     }
829                 }
830
831                 pipNode->pDeviceNode = device;
832                 Name2OSType(sName,device);
833             }
834         }
835         if (pDNSRecord->m_RecType == DNS_TYPE_SRV)
836         {   // Save SVR to Target
837             BJString sName;
838             pDNSRecord->GetDnsRecordName(sName, 0, 1);
839             StringMapNode *node = SVRtoDeviceName.FindwithAddRecord(&sName);
840             pDNSRecord->GetRdata(node->value, 0, 1);
841         }
842     }
843
844     CIPDeviceNode* pipNode = m_IPtoNameMap.FindwithAddRecord(&m_Frame.m_SourceIPAddress);
845     CDeviceNode* device = pipNode->pDeviceNode;
846     if (device == NULL)
847     {
848         // find the device by mac address
849         CMACAddrDeviceNode *macDevice = m_MACtoDevice.FindwithAddRecord(&m_Frame.m_SourceMACAddress);
850         device = macDevice->device;
851         if (device == NULL)
852         {
853             // auto create a device record
854             BJString name = m_Frame.m_SourceIPAddress.GetString();
855             device = m_DeviceMap.FindwithAddRecord(&name);
856             device->bIPName = true;
857             macDevice->device = device;
858         }
859
860         if (m_Frame.m_SourceIPAddress.IsIPv4())
861             device->ipAddressv4 = m_Frame.m_SourceIPAddress;
862         else
863             device->ipAddressv6 = m_Frame.m_SourceIPAddress;
864         if (device->macAddress.IsEmpty())
865             device->macAddress = m_Frame.m_SourceMACAddress;
866
867         pipNode->pDeviceNode = device;
868     }
869     device->bHasFrames = true;
870     // update mac address
871     if (m_Frame.IsQueryFrame() ||  device->GetDeviceOS() == 'i' ) // iOS don't use BSP so we can use SourceIP
872     {
873         if (m_Frame.m_SourceIPAddress.IsIPv4())
874             device->ipAddressv4 = m_Frame.m_SourceIPAddress;
875         if (m_Frame.m_SourceIPAddress.IsIPv6())
876             device->ipAddressv6 =m_Frame.m_SourceIPAddress;
877         device->macAddress = m_Frame.m_SourceMACAddress;
878     }
879
880     BJ_UINT8 traceplatform = TRACE_PLATFORM_UNKNOWN;
881     BJ_UINT32 traceversion = 0;
882     BJMACAddr traceMac;
883     if (device /*&& device->GetDeviceOS() == '?' */&& m_Frame.GetTracingInfo(traceplatform, traceversion, traceMac))
884     {
885    //     printf("Tracing Data found platform=%d traceversion=%d\n",traceplatform,traceversion);
886         char platformMap[]= "?Xitw";
887         device->SetDeviceOS((traceplatform < 5) ? platformMap[traceplatform] : '?', "EDNS0 Trace");
888         if ((traceplatform == TRACE_PLATFORM_OSX) || (traceplatform == DISCOVERYD_TRACE_PLATFORM_OSX))
889         {
890              device->bOSXWithEDNSField = true;
891         }
892         else if ((traceplatform == TRACE_PLATFORM_iOS) || (traceplatform == DISCOVERYD_TRACE_PLATFORM_iOS))
893         {
894             device->biOSWithEDNSField = true;
895         }
896     }
897
898     for (int dnsItemsIndex =0; dnsItemsIndex < m_Frame.GetQuestionCount()+m_Frame.GetAnswerCount();dnsItemsIndex++)
899     {
900         RecordName = "";
901         ApplRecordName = "";
902         InstanceName = "";
903         //    printf("Name = %s\n", GetDnsRecordName(&Frame,dnsItemsIndex,tempBuffer,sizeof(tempBuffer),0));
904
905         CDNSRecord* pDNSRecord = m_Frame.GetDnsRecord(dnsItemsIndex);
906         if (pDNSRecord == NULL)
907             continue;
908
909         pDNSRecord->GetDnsRecordName(RecordName,0,99);
910         InstanceName = RecordName;
911
912         if (RecordName.Contains("_kerberos."))
913         {
914             RecordName = "_kerberos.";
915         }
916         else
917             pDNSRecord->GetDnsRecordName(RecordName, (pDNSRecord->m_RecType == DNS_TYPE_PTR)?0:1,99);
918
919         if (pDNSRecord->m_RecType == DNS_TYPE_PTR)
920         {
921             if (RecordName.Contains(".ip6.arpa."))
922                 RecordName = "*.ip6.arpa.";
923             else if (RecordName.Contains(".arpa."))
924                 RecordName = "*.arpa.";
925         }
926         if (pDNSRecord->m_RecType == DNS_TYPE_A)
927             RecordName = "A";
928         if (pDNSRecord->m_RecType == DNS_TYPE_AAAA)
929            RecordName = "AAAA";
930         if (pDNSRecord->m_RecType == 255)
931         {
932             if (RecordName.Contains(".ip6.arpa."))
933                 RecordName = "ANY *.ip6.arpa.";
934             else if (RecordName.Contains(".arpa."))
935                 RecordName = "ANY *.arpa.";
936             else
937                 RecordName = "Any";
938         }
939         if (RecordName.Contains("_sub."))
940         {
941             pDNSRecord->GetDnsRecordName(RecordName,2,99); /// skip first label and _sub. label
942         }
943
944         BJ_UINT32 nBytes =  pDNSRecord->m_nNameLength + pDNSRecord->m_nRdataLen;
945
946         m_nTotalBytes += 10 + nBytes;
947
948         if (m_Frame.m_SourceIPAddress.IsIPv4())
949         {
950             UpdateRecord(m_ServicePtrCache,pDNSRecord,RecordName,RecordName, nBytes, (pDNSRecord->m_nTTL == 0));
951             UpdateShortRecordHelper(SERVICE_IPV4, traceplatform, traceversion, device->GetDeviceOS(), pDNSRecord, RecordName, RecordName, nBytes, (pDNSRecord->m_nTTL == 0));
952         }
953         else
954         {
955             UpdateRecord(m_ServicePtrCacheIPv6,pDNSRecord,RecordName,RecordName, nBytes, (pDNSRecord->m_nTTL == 0));
956             UpdateShortRecordHelper(SERVICE_IPV6, traceplatform, traceversion, device->GetDeviceOS(), pDNSRecord, RecordName, RecordName, nBytes, (pDNSRecord->m_nTTL == 0));
957         }
958
959         // Add application to cache
960         if (RecordName.GetLength() != 0)
961         {
962
963             ApplRecordName = RecordName;
964             StringMapNode* pNode;
965             pNode = m_Service2AppMap.Find(&ApplRecordName);
966             if (pNode && ApplRecordName.GetBuffer() != NULL)
967             {
968                 ApplRecordName = pNode->value.GetBuffer();
969                 if ( ApplRecordName == "Device-Info")
970                 {
971                     // find device record
972                     BJString svrName;
973                     pDNSRecord->GetDnsRecordName(svrName, 0, 1);
974                     StringMapNode *nodeName = SVRtoDeviceName.Find(&svrName);
975
976                     CDeviceNode* pDeviceNode = nodeName ? m_DeviceMap.Find(&nodeName->value) : NULL;
977
978                     if (pDeviceNode)
979                     {
980                         BJString DeviceInfo;
981                         DeviceInfo.Set((char*)pDNSRecord->GetStartofRdata(),MIN(pDNSRecord->m_nRdataLen,50));
982                         char osType = '?';
983
984                         for (int i=0; DeviceInfo2DeviceOS[i][0] != 0; i+=2)
985                         {
986                             if (DeviceInfo.Contains(DeviceInfo2DeviceOS[i]))
987                             {
988                                 osType = *DeviceInfo2DeviceOS[i+1];
989                                 if (pDeviceNode->GetDeviceOS() != *DeviceInfo2DeviceOS[i])
990                                 {
991                                     pDeviceNode->SetDeviceOS(osType,"_device-info._tcp.local.");
992                                     pDeviceNode->SetModel(DeviceInfo2DeviceOS[i]);
993                                 }
994                                 break;
995                             }
996                         }
997
998
999                         if (osType == 'X' ||  (pDeviceNode && pDeviceNode->GetDeviceOS() == 'X'))
1000                             ApplRecordName = "Finder";
1001                         if (osType == 't' ||  (pDeviceNode && pDeviceNode->GetDeviceOS() == 't'))
1002                             ApplRecordName = "AirPlay";
1003
1004                         if (pDeviceNode && pDeviceNode->GetDeviceOS() == '?' && pDNSRecord->m_nRdataLen > 0)
1005                         {
1006                             BJString DeviceInfo_temp;
1007                             DeviceInfo_temp.Set((char*)pDNSRecord->GetStartofRdata(),MIN(pDNSRecord->m_nRdataLen,25));
1008                         }
1009                     }
1010                 }
1011             }
1012             else
1013             {
1014                 ApplRecordName = "Other";
1015             }
1016
1017             if (m_Frame.m_SourceIPAddress.IsIPv4())
1018             {
1019                 UpdateRecord(m_ApplPtrCache,pDNSRecord,ApplRecordName,RecordName, nBytes, (pDNSRecord->m_nTTL == 0));
1020                 UpdateShortRecordHelper(APP_IPV4, traceplatform, traceversion, device->GetDeviceOS(), pDNSRecord, ApplRecordName, RecordName, nBytes, (pDNSRecord->m_nTTL == 0));
1021
1022             }
1023             else
1024             {
1025                 UpdateRecord(m_ApplPtrCacheIPv6,pDNSRecord,ApplRecordName,RecordName, nBytes, (pDNSRecord->m_nTTL == 0));
1026                 UpdateShortRecordHelper(APP_IPV6, traceplatform, traceversion, device->GetDeviceOS(), pDNSRecord, ApplRecordName, RecordName, nBytes, (pDNSRecord->m_nTTL == 0));
1027             }
1028
1029         }
1030
1031     }
1032 }
1033
1034
1035 class CSortOptions
1036 {
1037
1038 public:
1039     CStringTree m_SortedCache;
1040     int m_nSortCol;
1041
1042 };
1043 static int CbPrintResults(const void* pNode, const void* pParam)
1044 {
1045     CStringNode* pRecord = (CStringNode*)pNode;
1046     CSortOptions* pSortedOption = (CSortOptions*)pParam;
1047
1048     CStringNode* pNewRecord;
1049
1050     BJ_UINT64 SortKey =0;
1051     switch (pSortedOption->m_nSortCol) {
1052         case 0:
1053             SortKey = Hash2(pRecord->m_Value); // cheat the sort to the first 8 char
1054             break;
1055         case 1:
1056             SortKey = pRecord->m_nBytes;
1057             break;
1058         case 2:
1059             SortKey = pRecord->m_nFrames;
1060             break;
1061         case 3:
1062             SortKey = pRecord->m_nQuestionFrames;
1063             break;
1064         case 4:
1065             SortKey = pRecord->m_nAnswerFrames;
1066             break;
1067         default:
1068             break;
1069     }
1070
1071
1072     pNewRecord = pSortedOption->m_SortedCache.AddRecord(&SortKey);
1073
1074     if (pNewRecord)
1075     {
1076         pNewRecord->CopyNode(pRecord);
1077
1078     }
1079
1080     return 0;
1081 }
1082
1083 #if 0 // Not used 
1084 static int CbPrintUnknownDevice(const void* pNode, const void*)
1085 {
1086     CDeviceNode* pDeviceRecord = (CDeviceNode*)pNode;
1087
1088     if (pDeviceRecord->GetDeviceOS() != '?')
1089         return 0;
1090
1091   //  printf("%s %s\n",pDeviceRecord->m_Key.GetBuffer(), pDeviceRecord->macAddress.GetString());
1092     return 0;
1093
1094 }
1095 #endif
1096
1097 static int CbBuildMacMap(const void* pNode, const void* pParam)
1098 {
1099     CDeviceNode* pDeviceNode = (CDeviceNode*)pNode;
1100     CMACAddrTree* pMacMap = (CMACAddrTree*)pParam;
1101
1102
1103     BJMACAddr vendorMac;
1104     vendorMac.CopyVendor(pDeviceNode->macAddress);
1105     if (vendorMac.IsEmpty())
1106         return 0;
1107
1108
1109
1110     if (pDeviceNode->GetDeviceOS() == '?')
1111     {
1112         // try to set device type from MAC address
1113         CMACAddrNode* pMacRecord = pMacMap->Find(&vendorMac);
1114         if (pMacRecord != NULL && pDeviceNode->GetDeviceOS() == '?')
1115         {
1116             pDeviceNode->SetDeviceOS(pMacRecord->deviceOS, "MAC Mapping");
1117 //            printf("update device %s %c\n",vendorMac.GetStringVendor(),pMacRecord->deviceOS);
1118         }
1119
1120         if (pDeviceNode->GetDeviceOS() == '?')
1121             return 0;
1122     }
1123
1124
1125     CMACAddrNode* pMacRecord = pMacMap->Find(&vendorMac);
1126     if (pMacRecord == NULL)
1127     {
1128         pMacRecord = pMacMap->FindwithAddRecord(&vendorMac);
1129         pMacRecord->deviceOS = pDeviceNode->GetDeviceOS();
1130         pMacRecord->model = pDeviceNode->model;
1131         pMacRecord->method = pDeviceNode->settingService;
1132     }
1133     else
1134     {
1135         // Check mapping
1136   ///      if (pMacRecord && pMacRecord->deviceOS != pDeviceNode->GetDeviceOS())
1137    //        printf("Mac Mapping Bad deviceOS %c != %c %s %s %s\n", pMacRecord->deviceOS, pDeviceNode->GetDeviceOS(),pMacRecord->method.GetBuffer(), pDeviceNode->settingService.GetBuffer(),vendorMac.GetStringVendor());
1138     //    if (pMacRecord && !(pMacRecord->model == pDeviceNode->model) && pMacRecord->model.GetLength() > 0 && pDeviceNode->model.GetLength() > 0)
1139     //        printf("Mac Mapping Bad model %s != %s\n", pMacRecord->model.GetBuffer(), pDeviceNode->model.GetBuffer());
1140
1141     }
1142     return 0;
1143
1144 }
1145
1146 CStringNode* CBonjourTop::GetCurrentDisplayRoot(BJString &sTitle)
1147 {
1148     CStringNode* pRecord = NULL;
1149
1150     switch(m_CurrentDisplay)
1151     {
1152         case BJ_DISPLAY_APP:
1153             pRecord = m_ApplPtrCache.GetRoot();
1154             sTitle = "Application (IPv4)";
1155             break;
1156         case BJ_DISPLAY_APPv6:
1157             pRecord = m_ApplPtrCacheIPv6.GetRoot();
1158             sTitle = "Application (IPv6)";
1159             break;
1160         case BJ_DISPLAY_SERVICE:
1161             pRecord = m_ServicePtrCache.GetRoot();
1162             sTitle = "Services (IPv4)";
1163             break;
1164         case BJ_DISPLAY_SERVICEv6:
1165             pRecord = m_ServicePtrCacheIPv6.GetRoot();
1166             sTitle = "Services (IPv6)";
1167             break;
1168         case BJ_DISPLAY_24_MIN:
1169             printf("Error");
1170             break;
1171     }
1172     return pRecord;
1173 }
1174 void CBonjourTop::UpdateOSCounts()
1175 {
1176
1177
1178     CDeviceNode* pDeviceNode = m_DeviceMap.GetRoot();
1179     if (pDeviceNode)
1180     {
1181         pDeviceNode->CallBack(&CbBuildMacMap,&m_MacMap);
1182         //        pDeviceNode->CallBack(&CbPrintUnknownDevice,NULL);
1183     }
1184
1185
1186     // Update Application Caches
1187     CStringNode* pCacheRoot = m_ApplPtrCache.GetRoot();
1188
1189     if (pCacheRoot)
1190     {
1191         pCacheRoot->UpdateOSTypeCounts(&m_DeviceMap,&m_IPtoNameMap);
1192     }
1193     pCacheRoot = m_ApplPtrCacheIPv6.GetRoot();
1194
1195     if (pCacheRoot)
1196     {
1197         pCacheRoot->UpdateOSTypeCounts(&m_DeviceMap,&m_IPtoNameMap);
1198     }
1199
1200     // Update Service caches
1201     pCacheRoot = m_ServicePtrCache.GetRoot();
1202
1203     if (pCacheRoot)
1204     {
1205         pCacheRoot->UpdateOSTypeCounts(&m_DeviceMap,&m_IPtoNameMap);
1206     }
1207     pCacheRoot = m_ServicePtrCacheIPv6.GetRoot();
1208
1209     if (pCacheRoot)
1210     {
1211         pCacheRoot->UpdateOSTypeCounts(&m_DeviceMap,&m_IPtoNameMap);
1212     }
1213
1214
1215 }
1216 void CBonjourTop::PrintResults(int nSortCol, bool bSortAsc)
1217 {
1218
1219     BJString sTitle;
1220     GetCurrentDisplayRoot(sTitle);
1221     device_count devCount;
1222     BJString sTableTitle;
1223
1224     UpdateOSCounts();
1225
1226     /////
1227     BJ_UINT64 nRate = 0;
1228     BJ_UINT64 nElapsedTime = m_EndTime-m_StartTime;
1229     if (nElapsedTime > 0)
1230     {
1231             nRate = (m_nFrameCount *3600) /nElapsedTime;
1232     }
1233     if (m_bCursers)
1234     {
1235         resizeterm(0,0);
1236         clear();
1237
1238         printw("While running the follow keys may be used:\n");
1239         printw("[p = sort by Packets (default)], [b = sort by Bytes], [n = sort by Name]\n");
1240         printw("[a = Display Application Names (default)], [s = Display Services Names], [t = Display 24 hour packet per min]\n");
1241         printw("[o = flip sort order], [e = export to BonjourTop.csv], [q = quit]\n\n");
1242
1243         printw("Total Packets: %llu, Total Bytes: %llu, Elapse Time: %lld sec, Rate: %llu packet/hr\n",m_nFrameCount,m_nTotalBytes,nElapsedTime,nRate);
1244         printw("IPv4 multicast: %llu, IPv6 multicast: %llu, IPv4 Unicast: %lld, IPv6 Unicast: %llu\n",m_SocketStatus[0].m_nFrameCount,m_SocketStatus[1].m_nFrameCount,m_SocketStatus[2].m_nFrameCount,m_SocketStatus[3].m_nFrameCount);
1245         printw("IPv4 Wrong subnet: %llu, IPv6 Wrong subnet: %llu\n",m_SocketStatus[4].m_nFrameCount,m_SocketStatus[5].m_nFrameCount);
1246         printw("QuestionOnly Packets: %llu, AnswerOnly Packets: %llu, Q&A Packets %llu\n",m_SocketStatus[0].m_nQuestionOnlyFrames,m_SocketStatus[0].m_nAnswerOnlyFrames,m_SocketStatus[0].m_nQandAFrames);
1247         printw("AnswerCount for truncated frames(min,avg,max): %llu,%llu,%llu\n\n",m_MinAnswerCountForTruncatedFrames,m_AvgAnswerCountForTruncatedFrames,m_MaxAnswerCountForTruncatedFrames);
1248
1249         bzero(&devCount, sizeof(devCount));
1250         m_DeviceMap.GetDeviceOSTypes(m_DeviceMap.GetRoot(),NULL, devCount);
1251         printw("Total Devices: %llu, iOS Devices: %llu(>= iOS7: %llu), OSX Devices %llu(>= OSX 10.9: %llu)\n",devCount.iOS+devCount.OSX+devCount.unknownOS,devCount.iOS, devCount.iOSWithEDNSField, devCount.OSX,devCount.OSXWithEDNSField);
1252     }
1253     else
1254     {
1255         printf("\nTotal Packets: %llu, Total Bytes: %llu, Elapse Time: %lld sec, Rate: %llu packet/hr\n",m_nFrameCount,m_nTotalBytes,nElapsedTime,nRate);
1256         printf("IPv4 multicast: %llu, IPv6 multicast: %llu, IPv4 Unicast: %lld, IPv6 Unicast: %llu\n",m_SocketStatus[0].m_nFrameCount,m_SocketStatus[1].m_nFrameCount,m_SocketStatus[2].m_nFrameCount,m_SocketStatus[3].m_nFrameCount);
1257         printf("IPv4 Wrong subnet: %llu, IPv6 Wrong subnet: %llu\n",m_SocketStatus[4].m_nFrameCount,m_SocketStatus[5].m_nFrameCount);
1258         printf("QuestionOnly Packets: %llu, AnswerOnly Packets: %llu, Q&A Packets %llu\n",m_SocketStatus[0].m_nQuestionOnlyFrames,m_SocketStatus[0].m_nAnswerOnlyFrames,m_SocketStatus[0].m_nQandAFrames);
1259
1260         bzero(&devCount, sizeof(devCount));
1261         m_DeviceMap.GetDeviceOSTypes(m_DeviceMap.GetRoot(),NULL, devCount);
1262
1263         printf("Total Devices: %llu, iOS Devices: %llu(>= iOS7: %llu), OSX Devices %llu(>= OSX 10.9: %llu), unknown Devices %llu\n",devCount.iOS+devCount.OSX+devCount.unknownOS,devCount.iOS, devCount.iOSWithEDNSField,devCount.OSX,devCount.OSXWithEDNSField,devCount.unknownOS);
1264         printf("AnswerCount for truncated frames(min,avg,max): %llu,%llu,%llu\n\n",m_MinAnswerCountForTruncatedFrames,m_AvgAnswerCountForTruncatedFrames,m_MaxAnswerCountForTruncatedFrames);
1265     }
1266     PrintDetailResults(nSortCol, bSortAsc);
1267     if (m_bCursers)
1268         refresh();
1269 }
1270 void CBonjourTop::PrintDetailResults(int nSortCol, bool bSortAsc)
1271 {
1272     BJString sTitle;
1273     CStringNode* pCacheRoot = GetCurrentDisplayRoot(sTitle);
1274
1275     if (m_bCursers)
1276     {
1277         if(m_CurrentDisplay == CBonjourTop::BJ_DISPLAY_24_MIN)
1278         {
1279             printw("    ");
1280             for(int i=0;i<24;i++)
1281                 printw("   %02d ",i);
1282             printw("\n");
1283         }
1284         else
1285         {
1286             printw("\n%s\n",sTitle.GetBuffer());
1287             printw("     %- 30s %10s %10s%24s%24s%24s%24s%24s\n","","","Total","Question","Answer","Asking","Answering", "Total");
1288             printw("     %- 30s %10s%24s%24s%24s %23s%24s%24s %11s %10s\n","Name","Bytes","Packets(  iOS/  OSX)","Packets(  iOS/  OSX)","Packets(  iOS/  OSX)","Devices(  iOS/  OSX)","Devices(  iOS/  OSX)","Devices(  iOS/  OSX)", "QU Bit","Goodbye");
1289         }
1290     }
1291     else
1292     {
1293         if(m_CurrentDisplay == CBonjourTop::BJ_DISPLAY_24_MIN)
1294         {
1295
1296         }
1297         else
1298         {
1299             printf("\n%s\n",sTitle.GetBuffer());
1300             printf("     %-30s %10s %10s%24s%24s%24s%24s%24s\n","","","Total","Question","Answer","Asking","Answering", "Total");
1301             printf("     %-30s %10s%24s%24s%24s %23s%24s%24s %11s %10s\n","Name","Bytes","Packets(  iOS/  OSX)","Packets(  iOS/  OSX)","Packets(  iOS/  OSX)","Devices(  iOS/  OSX)","Devices(  iOS/  OSX)","Devices(  iOS/  OSX)", "QU Bit","Goodbye");
1302         }
1303     }
1304     if (m_CurrentDisplay == CBonjourTop::BJ_DISPLAY_24_MIN)
1305     {
1306
1307         for(int m=0;m<60;m++)
1308         {
1309             printw(" %02d ",m);
1310             for (int h=0;h<24;h++)
1311                 printw("%5d ",m_MinSnapshot[h][m].m_nFrameCount);
1312             printw("\n");
1313         }
1314     }
1315     else
1316     {
1317     // sort list
1318         CSortOptions SortOptions;
1319         SortOptions.m_nSortCol = nSortCol;
1320
1321         if (pCacheRoot)
1322             pCacheRoot->UpdateOSTypeCounts(&m_DeviceMap,&m_IPtoNameMap);
1323
1324         if (pCacheRoot)
1325             pCacheRoot->CallBack(&CbPrintResults,&SortOptions);
1326
1327         // print list
1328
1329         CStringNode* pRecord = SortOptions.m_SortedCache.GetRoot();
1330         BJ_UINT32 nIndex = 1;
1331
1332         if (pRecord)
1333             pRecord->Print(m_bCursers,bSortAsc, nIndex,0,40);
1334     }
1335
1336
1337 }
1338
1339 void CBonjourTop::LiveCapture()
1340 {
1341     /// Live Capture
1342     const BJ_UINT16 BonjourPort = 5353;
1343     BJSocket Sockv4;
1344     BJSocket Sockv6;
1345     BJSelect SockSelect;
1346
1347     Sockv4.CreateListenerIPv4(interfaceName);
1348     Sockv6.CreateListenerIPv6(interfaceName);
1349
1350     SockSelect.Add(Sockv4);
1351     SockSelect.Add(Sockv6);
1352
1353
1354     m_StartTime = time(NULL);
1355
1356     bool bSortAsc = false;
1357     int nSortCol = 1;
1358
1359     while (1)
1360     {
1361         SockSelect.Add(Sockv4);
1362         SockSelect.Add(Sockv6);
1363
1364         int result = SockSelect.Wait(1);
1365         if (result < 0)
1366         {
1367             // if SockSelect.Wait failed due to an interrupt, then we want to continue processing the packets
1368             if (errno == EINTR)
1369             {
1370                 continue;
1371             }
1372             printf("Error in Select\n");
1373             break;
1374         }
1375
1376         if (SockSelect.IsReady(Sockv4))
1377         {
1378
1379             int recvsize = Sockv4.Read();
1380
1381             if ((recvsize != 0) &&
1382                 (Sockv4.GetSrcAddr()->GetPortNumber() == BonjourPort))
1383             {
1384                 m_nFrameCount++;
1385                 m_SocketStatus[Sockv4.IsMulticastPacket()? 0:2].m_nFrameCount++;
1386
1387                 if (!m_IPv4Addr.IsSameSubNet(Sockv4.GetSrcAddr()))
1388                 {
1389                     m_SocketStatus[4].m_nFrameCount++;
1390                 }
1391                 m_Frame.m_SourceIPAddress = *Sockv4.GetSrcAddr();
1392                 ProcessFrame(Sockv4.GetBuffer(),recvsize,Sockv4.m_CurrentFrame.GetTime());
1393             }
1394         }
1395
1396         if (SockSelect.IsReady(Sockv6))
1397         {
1398             int recvsize = Sockv6.Read();
1399             if ((recvsize != 0) &&
1400                 (Sockv6.GetSrcAddr()->GetPortNumber() == BonjourPort))
1401             {
1402                 m_nFrameCount++;
1403                 m_SocketStatus[Sockv6.IsMulticastPacket()? 1:3].m_nFrameCount++;
1404                 m_Frame.m_SourceIPAddress = *Sockv6.GetSrcAddr();
1405
1406                 ProcessFrame(Sockv6.GetBuffer(),recvsize,Sockv6.m_CurrentFrame.GetTime());
1407             }
1408         }
1409
1410         if (m_bCursers)
1411         {
1412             int ch = getch();
1413             switch (ch)
1414             {
1415                 case 'o':
1416                     bSortAsc = !bSortAsc;
1417                     result = 0; // force an update
1418                     break;
1419                 case 'n':
1420                     nSortCol = 0;
1421                     result = 0; // force an update
1422                     break;
1423                 case 'b':
1424                     nSortCol = 1;
1425                     result = 0; // force an update
1426                     break;
1427                 case 'p':
1428                     if (nSortCol == 2)
1429                         nSortCol = 3;
1430                     else if (nSortCol == 3)
1431                         nSortCol = 4;
1432                     else
1433                         nSortCol = 2;
1434                     result = 0; // force an update
1435                     break;
1436                 case 'a':
1437                 case 'A':
1438                     if (m_CurrentDisplay == CBonjourTop::BJ_DISPLAY_APP)
1439                         m_CurrentDisplay = CBonjourTop::BJ_DISPLAY_APPv6;
1440                     else
1441                         m_CurrentDisplay = CBonjourTop::BJ_DISPLAY_APP;
1442
1443                     result = 0;
1444                     break;
1445                 case 's':
1446                 case 'S':
1447                     if (m_CurrentDisplay == CBonjourTop::BJ_DISPLAY_SERVICE)
1448                         m_CurrentDisplay = CBonjourTop::BJ_DISPLAY_SERVICEv6;
1449                     else
1450                         m_CurrentDisplay = CBonjourTop::BJ_DISPLAY_SERVICE;
1451                     result = 0;
1452                     break;
1453                 case 't':
1454                 case 'T':
1455                    m_CurrentDisplay = CBonjourTop::BJ_DISPLAY_24_MIN;
1456                     result = 0;
1457                     break;
1458                 case 'q':
1459                     return;
1460                 case 'e':
1461                     ExportResults();
1462                     printf("\a");
1463                     break;
1464                 case KEY_RESIZE:
1465                     endwin();
1466                     initscr();
1467                     result = 0; // force an update
1468                     break;
1469                 case KEY_DOWN:
1470                     result = 0; // force an update
1471                     break;
1472             }
1473             if (window_size_changed)
1474             {
1475                 endwin();
1476                 initscr();
1477                 window_size_changed = false;
1478             }
1479         }
1480         if (m_EndTime != time(NULL) || result == 0)
1481         {
1482             m_EndTime = time(NULL);
1483             PrintResults(nSortCol,bSortAsc);
1484             if (m_SnapshotSeconds && (time(NULL) - m_StartTime) > m_SnapshotSeconds)
1485             {
1486                 ExportResults();
1487                 if (m_bImportExportDeviceMap)
1488                 {
1489                     WriteDeviceFile();
1490                     WriteVendorFile();
1491                 }
1492                 Reset();
1493             }
1494         }
1495     }
1496 }
1497
1498
1499
1500 void CBonjourTop::CaptureFile()
1501 {
1502     CCaptureFile CaptureFile;
1503     BJIPAddr* pIPSrcAddr;
1504     BJIPAddr* pIPDestAddr;
1505
1506     CIPAddrMap LocalSubnetIPv6;
1507
1508
1509     CaptureFile.Open(m_pTcpDumpFileName);
1510
1511     m_StartTime = 0;
1512     int nFrameIndex  = 0;
1513
1514     while (CaptureFile.NextFrame())
1515     {
1516         nFrameIndex++;
1517
1518         BJ_UINT8* pBonjourBuffer = (BJ_UINT8*)CaptureFile.m_CurrentFrame.GetBonjourStart();
1519         if (!pBonjourBuffer)
1520             continue;
1521
1522         m_nFrameCount++;
1523         m_nTotalBytes += CaptureFile.GetWiredLength();
1524
1525         pIPSrcAddr = CaptureFile.m_CurrentFrame.GetSrcIPAddr();
1526         pIPDestAddr = CaptureFile.m_CurrentFrame.GetDestIPAddr();
1527         m_Frame.m_SourceIPAddress = *CaptureFile.m_CurrentFrame.GetSrcIPAddr();;
1528         m_Frame.m_SourceMACAddress = *CaptureFile.m_CurrentFrame.GetSrcMACAddr();
1529
1530         if (pIPSrcAddr->IsIPv4())
1531         {
1532             // check fragment flag
1533             BJ_UINT8* pIP = CaptureFile.m_CurrentFrame.GetIPStart();
1534             BJ_UINT16 flags = * ((BJ_UINT16*)(pIP+6));
1535             if (flags)
1536                 continue;
1537
1538             if (!m_IPv4Addr.IsEmptySubnet())
1539             {
1540                 if (m_IPv4Addr.IsSameSubNet(pIPSrcAddr))
1541                 {
1542                     BJ_UINT8* pSourceMac = CaptureFile.m_CurrentFrame.GetEthernetStart()+6;
1543                     BJIPAddr IPv6Addr;
1544                     IPv6Addr.CreateLinkLocalIPv6(pSourceMac);
1545                     LocalSubnetIPv6.FindwithAddRecord(&IPv6Addr);
1546
1547                 }
1548                 else
1549                 {
1550                     m_SocketStatus[4].m_nFrameCount++;
1551
1552                     if (!m_Collection.IsValid())
1553                         continue;
1554                 }
1555             }
1556             m_SocketStatus[(pIPDestAddr->IsBonjourMulticast())?0:2].m_nFrameCount++;
1557         }
1558         if (pIPSrcAddr->IsIPv6())
1559         {
1560             if (!LocalSubnetIPv6.Find(pIPSrcAddr) && !m_IPv4Addr.IsEmptySubnet())
1561             {
1562                 m_SocketStatus[5].m_nFrameCount++;
1563                  if (!m_Collection.IsValid())
1564                      continue;
1565             }
1566             m_SocketStatus[(pIPDestAddr->IsBonjourMulticast())?1:3].m_nFrameCount++;
1567         }
1568
1569         ProcessFrame(pBonjourBuffer,CaptureFile.GetBufferLen((pBonjourBuffer)),CaptureFile.m_CurrentFrame.GetTime());
1570
1571     }
1572     m_EndTime = CaptureFile.GetDeltaTime();
1573
1574     PrintResults(2,false);
1575     if ( m_CurrentDisplay ==  BJ_DISPLAY_APP)
1576         m_CurrentDisplay =  BJ_DISPLAY_APPv6;
1577     else
1578         m_CurrentDisplay =  BJ_DISPLAY_SERVICEv6;
1579
1580     PrintDetailResults(2,false);
1581
1582 }
1583
1584 void CBonjourTop::ExportPtrCache(FILE* hFile, BJString sTitle,CStringNode* pRoot)
1585 {
1586     fprintf(hFile,"%s\n",sTitle.GetBuffer());
1587     fprintf(hFile,"Name,Bytes,Total Packets,Total Packets iOS,Total Packets OSX,Question Packets,Question Packets iOS,Question Packets OSX,Answer Packets,Answer Packets iOS,Answer Packets OSX,Asking Devices, Asking Devices iOS,Asking Devices OSX,Answering Devices,Answering Devices iOS,Answering Devices OSX,Total Devices,Total Devices iOS, Total Devices OSX,QU Bit,Goodbye\n");
1588
1589     if (pRoot)
1590         pRoot->Export(hFile);
1591 }
1592
1593 void CBonjourTop::ExportShortCacheHelper(FILE* hFile, BJString sTitle, CStringShortNode* pRoot)
1594 {
1595     fprintf(hFile,"%s\n",sTitle.GetBuffer());
1596     fprintf(hFile,"Name,Bytes,Total Packets,Question Packets,Answer Packets,Asking Devices,Answering Devices,Total Devices,QU Bit,Goodbye\n");
1597
1598     if (pRoot)
1599     {
1600         pRoot->Export(hFile);
1601     }
1602
1603 }
1604
1605 void CBonjourTop::ExportShortCache(FILE* hFile, BJString sTitle, map<BJString, CStringShortTree*>* myMap)
1606 {
1607     CStringShortTree* cache;
1608     BJString versionNumber;
1609
1610     fprintf(hFile,"%s\n",sTitle.GetBuffer());
1611
1612     for (map<BJString, CStringShortTree*>::iterator it = myMap->begin(); it != myMap->end(); ++it)
1613     {
1614         versionNumber = (*it).first;
1615         cache = (*it).second;
1616
1617         ExportShortCacheHelper(hFile, versionNumber, cache->GetRoot());
1618     }
1619 }
1620
1621 void CBonjourTop::ExportResults()
1622 {
1623
1624     BJString sTempFileName;
1625     device_count devCount;
1626     sTempFileName = m_pExportFileName;
1627
1628     if (m_SnapshotSeconds)
1629     {
1630         BJString sTimeStamp;
1631         sTimeStamp.Format(time(NULL), BJString::BJSS_TIME);
1632         sTempFileName += "_";
1633         sTempFileName += sTimeStamp;
1634     }
1635     sTempFileName += ".csv";
1636
1637     if (m_Collection.IsValid())
1638     {
1639         m_Collection.ExportCollection(sTempFileName);
1640         return;
1641     }
1642
1643     FILE* hFile = fopen(sTempFileName.GetBuffer(),"w");
1644
1645     if (hFile == NULL)
1646     {
1647         printf("file open failed %s\n",m_pExportFileName);
1648         return;
1649     }
1650
1651     fprintf(hFile,"Total Number of Frames, %llu\n",m_nFrameCount);
1652     fprintf(hFile,"Total Number of Bytes, %llu\n",m_nTotalBytes);
1653     fprintf(hFile,"Total Number of Sec, %llu\n",m_EndTime-m_StartTime);
1654
1655     bzero(&devCount, sizeof(devCount));
1656     m_DeviceMap.GetDeviceOSTypes(m_DeviceMap.GetRoot(),NULL, devCount);
1657     fprintf(hFile,"Total Number of Devices, %llu\n\n",devCount.iOS+devCount.OSX+devCount.unknownOS);
1658     fprintf(hFile,"Total Number of iOS Devices, %llu\n",devCount.iOS);
1659     fprintf(hFile,"Total Number of iOS Devices (>= iOS7), %llu\n", devCount.iOSWithEDNSField);
1660     fprintf(hFile,"Total Number of OSX Devices, %llu\n",devCount.OSX);
1661     fprintf(hFile,"Total Number of OSX Devices (>= OSX 10.9), %llu\n",devCount.OSXWithEDNSField);
1662
1663     fprintf(hFile,"IPv4 multicast, %llu\n",m_SocketStatus[0].m_nFrameCount);
1664     fprintf(hFile,"IPv6 multicast, %llu\n",m_SocketStatus[1].m_nFrameCount);
1665     fprintf(hFile,"IPv4 Unicast, %llu\n",m_SocketStatus[2].m_nFrameCount);
1666     fprintf(hFile,"IPv6 Unicast, %llu\n",m_SocketStatus[3].m_nFrameCount);
1667     fprintf(hFile,"IPv4 Wrong subnet, %llu\n",m_SocketStatus[4].m_nFrameCount);
1668     fprintf(hFile,"IPv6 Wrong subnet, %llu\n\n",m_SocketStatus[5].m_nFrameCount);
1669
1670     fprintf(hFile,"QuestionOnly Packets, %llu\n", m_SocketStatus[0].m_nQuestionOnlyFrames);
1671     fprintf(hFile,"AnswerOnly Packets, %llu\n", m_SocketStatus[0].m_nAnswerOnlyFrames);
1672     fprintf(hFile,"Q&A Packets, %llu\n\n", m_SocketStatus[0].m_nQandAFrames);
1673
1674     fprintf(hFile,"AnswerCount for truncated frames min, %llu\n", m_MinAnswerCountForTruncatedFrames);
1675     fprintf(hFile,"AnswerCount for truncated frames avg, %llu\n", m_AvgAnswerCountForTruncatedFrames);
1676     fprintf(hFile,"AnswerCount for truncated frames max, %llu\n\n", m_MaxAnswerCountForTruncatedFrames);
1677
1678     // Export Cache
1679     UpdateOSCounts();
1680     ExportPtrCache(hFile,"Application IPv4 Cache",m_ApplPtrCache.GetRoot());
1681     ExportShortCache(hFile, "OSX", &m_AppBreakdownIPv4OSX);
1682     ExportShortCache(hFile, "iOS", &m_AppBreakdownIPv4iOS);
1683
1684     ExportPtrCache(hFile,"Application IPv6 Cache",m_ApplPtrCacheIPv6.GetRoot());
1685     ExportShortCache(hFile, "OSX", &m_AppBreakdownIPv6OSX);
1686     ExportShortCache(hFile, "iOS", &m_AppBreakdownIPv6iOS);
1687
1688     ExportPtrCache(hFile,"Service IPv4 Cache",m_ServicePtrCache.GetRoot());
1689     ExportShortCache(hFile, "OSX", &m_ServiceBreakdownIPv4OSX);
1690     ExportShortCache(hFile, "iOS", &m_ServiceBreakdownIPv4iOS);
1691
1692     ExportPtrCache(hFile,"Service IPv6 Cache",m_ServicePtrCacheIPv6.GetRoot());
1693     ExportShortCache(hFile, "OSX", &m_ServiceBreakdownIPv6OSX);
1694     ExportShortCache(hFile, "iOS", &m_ServiceBreakdownIPv6iOS);
1695
1696     /// min snapshot table
1697
1698     fprintf(hFile,"Min Snapshot table\n");
1699
1700     for (int h=0;h<24;h++)
1701     {
1702         for(int m=0;m<60;m++)
1703         {
1704             if (m_MinSnapshot[h][m].m_nFrameCount)
1705             {
1706                 fprintf(hFile,"%02d:%02d,%llu\n",h,m,m_MinSnapshot[h][m].m_nFrameCount);
1707             }
1708         }
1709
1710     }
1711
1712     fclose(hFile);
1713
1714 }
1715
1716 void CBonjourTop::WriteDeviceFile()
1717 {
1718     BJString sTempFileName;
1719     BJString sTimeStamp;
1720
1721     sTempFileName = m_DeviceFileName;
1722     sTimeStamp.Format(time(NULL), BJString::BJSS_TIME);
1723     sTempFileName += "_";
1724     sTempFileName += sTimeStamp;
1725     sTempFileName += ".csv";
1726
1727     FILE* hFile = fopen(sTempFileName.GetBuffer(),"w");
1728
1729     if (hFile == NULL)
1730     {
1731         printf("file open failed %s\n",sTempFileName.GetBuffer());
1732         return;
1733     }
1734
1735     fprintf(hFile,"\"Name\",\"IPv4Address\",\"IPv6Address\",\"MACAddress\",O,\"Model\",\"Method\",\"total frames\",\"question frames\",\"QU frames\",\"answer frames\"\n");
1736
1737     CDeviceNode *pDeviceNode = m_DeviceMap.GetRoot();
1738
1739     if (pDeviceNode)
1740         pDeviceNode->Export(hFile);
1741
1742     fclose(hFile);
1743
1744     printf("devicemap count %llu %d\n",m_DeviceMap.GetCount(),CDeviceNode::nCreateCount);
1745
1746 }
1747
1748 void CBonjourTop::WriteVendorFile()
1749 {
1750     BJString sTempFileName = "BonjourTopVendor";
1751     BJString sTimeStamp;
1752
1753     sTimeStamp.Format(time(NULL), BJString::BJSS_TIME);
1754     sTempFileName += "_";
1755     sTempFileName += sTimeStamp;
1756     sTempFileName += ".csv";
1757
1758     FILE* hFile = fopen(sTempFileName.GetBuffer(),"w");
1759
1760     if (hFile == NULL)
1761     {
1762         printf("file open failed %s\n",sTempFileName.GetBuffer());
1763         return;
1764     }
1765     fprintf(hFile,"\"MACAddress\",O,\"Model\",\"Method\"\n");
1766
1767     CMACAddrNode *node = m_MacMap.GetRoot();
1768
1769     if (node)
1770         node->Export(hFile);
1771
1772     fclose(hFile);
1773 }
1774
1775 void CBonjourTop::WindowSizeChanged()
1776 {
1777     window_size_changed = true;
1778 }
1779
1780 BJ_UINT64 Hash(const char* pStr)
1781 {
1782     // to fix
1783     BJ_UINT64 hash = 0;
1784     int c;
1785
1786     while ((c = *pStr++))
1787         hash += c;
1788
1789     return hash;
1790
1791
1792 }
1793
1794 BJ_UINT64 Hash2(char* pStr)
1795 {
1796     // to fix
1797     BJ_UINT64 hash = 0;
1798     int c;
1799     int i = 0;
1800
1801     while ((c = *pStr++) && i++ < 8)
1802     {
1803         hash = hash << 8;
1804         hash |= c;
1805     }
1806
1807     return hash;
1808
1809
1810 }
1811
1812 static integer_t Usage(void)
1813 {
1814     task_t targetTask = mach_task_self();
1815     struct task_basic_info ti;
1816     mach_msg_type_number_t count = TASK_BASIC_INFO_64_COUNT;
1817
1818     kern_return_t kr = task_info(targetTask, TASK_BASIC_INFO_64,
1819                                  (task_info_t) &ti, &count);
1820     if (kr != KERN_SUCCESS)
1821     {
1822         printf("Kernel returned error during memory usage query");
1823         return 0;
1824     }
1825
1826     // On Mac OS X, the resident_size is in bytes, not pages!
1827     // (This differs from the GNU Mach kernel)
1828    // return ti.resident_size;
1829     return ti.user_time.seconds;
1830 }
1831
1832 ///////////////
1833
1834
1835 /* CStringNode */
1836
1837 void CStringNode::UpdateOSTypeCounts(CDeviceMap* pGlobalDeviceMap,CIPAddrMap *pIp2NameMap)
1838 {
1839     if (m_rbLeft)
1840         ((CStringNode*)m_rbLeft)->UpdateOSTypeCounts(pGlobalDeviceMap,pIp2NameMap);
1841     if (m_rbRight)
1842         ((CStringNode*)m_rbRight)->UpdateOSTypeCounts(pGlobalDeviceMap,pIp2NameMap);
1843
1844     BJ_UINT64  nDeviceUnknown = 0;
1845     m_nDeviceAskingiOSCount = 0;
1846     m_nDeviceAskingOSXCount = 0;
1847     m_nDeviceAnsweringiOSCount = 0;
1848     m_nDeviceAnsweringOSXCount = 0;
1849     m_nDeviceTotaliOSCount = 0;
1850     m_nDeviceTotalOSXCount = 0;
1851     m_DeviceAskingTree.GetDeviceOSTypes(m_DeviceAskingTree.GetRoot(),pIp2NameMap,m_nDeviceAskingiOSCount,m_nDeviceAskingOSXCount,nDeviceUnknown);
1852     if (m_DeviceAskingTree.GetCount() != m_nDeviceAskingiOSCount + m_nDeviceAskingOSXCount+nDeviceUnknown)
1853     {
1854         nDeviceUnknown = 0;
1855     }
1856     nDeviceUnknown = 0;
1857     m_DeviceAnsweringTree.GetDeviceOSTypes(m_DeviceAnsweringTree.GetRoot(),pIp2NameMap,m_nDeviceAnsweringiOSCount,m_nDeviceAnsweringOSXCount,nDeviceUnknown);
1858     if (m_DeviceAnsweringTree.GetCount() != m_nDeviceAnsweringiOSCount + m_nDeviceAnsweringOSXCount+nDeviceUnknown)
1859     {
1860         nDeviceUnknown = 0;
1861     }
1862     nDeviceUnknown = 0;
1863     m_DeviceTotalTree.GetDeviceOSTypes(m_DeviceTotalTree.GetRoot(), pIp2NameMap, m_nDeviceTotaliOSCount, m_nDeviceTotalOSXCount, nDeviceUnknown);
1864     if (m_DeviceTotalTree.GetCount() != m_nDeviceTotaliOSCount + m_nDeviceTotalOSXCount + nDeviceUnknown)
1865     {
1866         nDeviceUnknown = 0;
1867     }
1868 }
1869
1870 void CStringNode::Print(bool bCursers,bool bDescendingSort,BJ_UINT32 &nIndex, BJ_UINT32 nStartIndex,BJ_UINT32 nEndIndex)
1871 {
1872     if (bDescendingSort)
1873     {
1874         if (m_rbLeft)
1875             ((CStringNode*)m_rbLeft)->Print(bCursers,bDescendingSort,nIndex,nStartIndex,nEndIndex);
1876
1877         if (nIndex >= nStartIndex && nIndex <= nEndIndex)
1878         {
1879             if (bCursers)
1880             {
1881                 printw("%3d. %-30s %10llu %10llu(%5llu/%5llu) %10llu(%5llu/%5llu) %10llu(%5llu/%5llu) %10llu(%5llu/%5llu) %10llu(%5llu/%5llu) %10llu(%5llu/%5llu)  %10llu %10llu\n",nIndex,(char*)&(m_Value),m_nBytes,m_nFrames, m_nFramesiOS, m_nFramesOSX, m_nQuestionFrames, m_nQuestionFramesiOS, m_nQuestionFramesOSX, m_nAnswerFrames,m_nAnswerFramesiOS, m_nAnswerFramesOSX, m_nDeviceAskingCount,m_nDeviceAskingiOSCount,m_nDeviceAskingOSXCount, m_nDeviceAnsweringCount,m_nDeviceAnsweringiOSCount,m_nDeviceAnsweringOSXCount, m_nDeviceTotalCount, m_nDeviceTotaliOSCount, m_nDeviceTotalOSXCount, m_nWakeFrames,m_nGoodbyeFrames);
1882
1883             }
1884             else
1885             {
1886                 printf("%3d. %-30s %10llu %10llu(%5llu/%5llu) %10llu(%5llu/%5llu) %10llu(%5llu/%5llu) %10llu(%5llu/%5llu) %10llu(%5llu/%5llu) %10llu(%5llu/%5llu)  %10llu %10llu\n",nIndex,(char*)&(m_Value),m_nBytes,m_nFrames, m_nFramesiOS, m_nFramesOSX, m_nQuestionFrames, m_nQuestionFramesiOS, m_nQuestionFramesOSX, m_nAnswerFrames,m_nAnswerFramesiOS, m_nAnswerFramesOSX, m_nDeviceAskingCount,m_nDeviceAskingiOSCount,m_nDeviceAskingOSXCount, m_nDeviceAnsweringCount,m_nDeviceAnsweringiOSCount,m_nDeviceAnsweringOSXCount, m_nDeviceTotalCount, m_nDeviceTotaliOSCount, m_nDeviceTotalOSXCount, m_nWakeFrames,m_nGoodbyeFrames);
1887
1888             }
1889         }
1890         nIndex++;
1891         if (m_rbRight)
1892             ((CStringNode*)m_rbRight)->Print(bCursers,bDescendingSort,nIndex,nStartIndex,nEndIndex);
1893     }
1894     else
1895     {
1896         if (m_rbRight)
1897             ((CStringNode*)m_rbRight)->Print(bCursers,bDescendingSort,nIndex,nStartIndex,nEndIndex);
1898
1899         if (nIndex >= nStartIndex && nIndex <= nEndIndex)
1900         {
1901             if (bCursers)
1902             {
1903                 printw("%3d. %-30s %10llu %10llu(%5llu/%5llu) %10llu(%5llu/%5llu) %10llu(%5llu/%5llu) %10llu(%5llu/%5llu) %10llu(%5llu/%5llu) %10llu(%5llu/%5llu)  %10llu %10llu\n",nIndex,(char*)&(m_Value),m_nBytes,m_nFrames, m_nFramesiOS, m_nFramesOSX, m_nQuestionFrames, m_nQuestionFramesiOS, m_nQuestionFramesOSX, m_nAnswerFrames,m_nAnswerFramesiOS, m_nAnswerFramesOSX, m_nDeviceAskingCount,m_nDeviceAskingiOSCount,m_nDeviceAskingOSXCount, m_nDeviceAnsweringCount,m_nDeviceAnsweringiOSCount,m_nDeviceAnsweringOSXCount, m_nDeviceTotalCount, m_nDeviceTotaliOSCount, m_nDeviceTotalOSXCount, m_nWakeFrames,m_nGoodbyeFrames);
1904             }
1905             else
1906             {
1907                 printf("%3d. %-30s %10llu %10llu(%5llu/%5llu) %10llu(%5llu/%5llu) %10llu(%5llu/%5llu) %10llu(%5llu/%5llu) %10llu(%5llu/%5llu) %10llu(%5llu/%5llu)  %10llu %10llu\n",nIndex,(char*)&(m_Value),m_nBytes,m_nFrames, m_nFramesiOS, m_nFramesOSX, m_nQuestionFrames, m_nQuestionFramesiOS, m_nQuestionFramesOSX, m_nAnswerFrames,m_nAnswerFramesiOS, m_nAnswerFramesOSX, m_nDeviceAskingCount,m_nDeviceAskingiOSCount,m_nDeviceAskingOSXCount, m_nDeviceAnsweringCount,m_nDeviceAnsweringiOSCount,m_nDeviceAnsweringOSXCount, m_nDeviceTotalCount, m_nDeviceTotaliOSCount, m_nDeviceTotalOSXCount, m_nWakeFrames,m_nGoodbyeFrames);
1908             }
1909         }
1910         nIndex++;
1911         if (m_rbLeft)
1912             ((CStringNode*)m_rbLeft)->Print(bCursers,bDescendingSort,nIndex,nStartIndex,nEndIndex);
1913     }
1914
1915 }
1916 void CStringNode::Export(FILE* hFile)
1917 {
1918     fprintf(hFile, "%s,%llu,%llu,%llu,%llu,%llu,%llu,%llu,%llu,%llu,%llu,%llu,%llu,%llu,%llu,%llu,%llu,%llu,%llu,%llu,%llu,%llu\n",
1919             (char*)&(m_Value),m_nBytes,
1920             m_nFrames, m_nFramesiOS, m_nFramesOSX,
1921             m_nQuestionFrames, m_nQuestionFramesiOS, m_nQuestionFramesOSX,
1922             m_nAnswerFrames, m_nAnswerFramesiOS, m_nAnswerFramesOSX,
1923             m_nDeviceAskingCount, m_nDeviceAskingiOSCount,m_nDeviceAskingOSXCount,
1924             m_nDeviceAnsweringCount,m_nDeviceAnsweringiOSCount,m_nDeviceAnsweringOSXCount,
1925             m_nDeviceTotalCount, m_nDeviceTotaliOSCount, m_nDeviceTotalOSXCount,
1926             m_nWakeFrames,m_nGoodbyeFrames);
1927
1928     if (m_rbLeft)
1929         ((CStringNode*)m_rbLeft)->Export(hFile);
1930     if (m_rbRight)
1931         ((CStringNode*)m_rbRight)->Export(hFile);
1932
1933 }
1934
1935 /* CStringShortNode */
1936
1937 void CStringShortNode::Export(FILE *hFile)
1938 {
1939     fprintf(hFile, "%s,%llu,%llu,%llu,%llu,%llu,%llu,%llu,%llu,%llu\n",
1940             (char*)&(m_Value),m_nBytes,
1941             m_nFrames, m_nQuestionFrames, m_nAnswerFrames,
1942             m_nDeviceAskingCount, m_nDeviceAnsweringCount, m_nDeviceTotalCount,
1943             m_nWakeFrames,m_nGoodbyeFrames);
1944
1945
1946     if (m_rbLeft)
1947     {
1948         ((CStringShortNode*)m_rbLeft)->Export(hFile);
1949     }
1950     if (m_rbRight)
1951     {
1952         ((CStringShortNode*)m_rbRight)->Export(hFile);
1953     }
1954 }
1955
1956 /* CDeviceMap */
1957
1958 void CDeviceMap::GetDeviceOSTypes(CDeviceNode *node, CDeviceMap *pGlobalDeviceMap, device_count& dev_cnt)
1959 {
1960     if (node == NULL)
1961         return;
1962
1963     GetDeviceOSTypes(dynamic_cast<CDeviceNode*>(node->m_rbLeft),pGlobalDeviceMap, dev_cnt);
1964     GetDeviceOSTypes(dynamic_cast<CDeviceNode*>(node->m_rbRight),pGlobalDeviceMap, dev_cnt);
1965
1966     if (node->bDuplicate || !node->bHasFrames)
1967         return;
1968
1969     char deviceType = '?';
1970     if (pGlobalDeviceMap)
1971     {
1972         CDeviceNode* globalDevice = pGlobalDeviceMap->Find(&node->m_Key);
1973         if (globalDevice)
1974         {
1975             deviceType = globalDevice->GetDeviceOS();
1976
1977             if (globalDevice->bOSXWithEDNSField && deviceType == 'X')
1978             {
1979                 dev_cnt.OSXWithEDNSField++;
1980             }
1981             else if (globalDevice->biOSWithEDNSField && (deviceType == 't' || deviceType == 'i'))
1982             {
1983                 dev_cnt.iOSWithEDNSField++;
1984             }
1985         }
1986     }
1987     else
1988     {
1989         deviceType = node->GetDeviceOS();
1990         if (node->bOSXWithEDNSField && deviceType == 'X')
1991         {
1992             dev_cnt.OSXWithEDNSField++;
1993         }
1994         else if (node->biOSWithEDNSField && (deviceType == 't' || deviceType == 'i'))
1995         {
1996             dev_cnt.iOSWithEDNSField++;
1997         }
1998     }
1999     switch (deviceType)
2000     {
2001         case 'i':
2002         case 't':
2003             dev_cnt.iOS++;
2004             break;
2005         case 'X':
2006             dev_cnt.OSX++;
2007             break;
2008         default:
2009             dev_cnt.unknownOS++;
2010             break;
2011     }
2012 }
2013
2014 void CIPAddrMap::GetDeviceOSTypes(CIPDeviceNode* node, CIPAddrMap* pGobalMap, BJ_UINT64& iOS,BJ_UINT64& OSX,BJ_UINT64& unknowOS)
2015 {
2016     if (node == NULL)
2017         return;
2018
2019     GetDeviceOSTypes(dynamic_cast<CIPDeviceNode*>(node->m_rbLeft),pGobalMap, iOS, OSX, unknowOS);
2020     GetDeviceOSTypes(dynamic_cast<CIPDeviceNode*>(node->m_rbRight),pGobalMap,iOS, OSX, unknowOS);
2021
2022     char deviceType = '?';
2023     if (pGobalMap)
2024     {
2025         CIPDeviceNode *ipDevice = pGobalMap->Find(&node->m_Key);
2026
2027         if (ipDevice && ipDevice->pDeviceNode )
2028             deviceType = ipDevice->pDeviceNode->GetDeviceOS();
2029
2030     }
2031
2032     switch (deviceType)
2033     {
2034         case 'i':
2035         case 't':
2036             iOS++;
2037             break;
2038         case 'X':
2039             OSX++;
2040             break;
2041         default:
2042             unknowOS++;
2043     }
2044
2045 }
2046
2047
2048 ///////////
2049