]> git.saurik.com Git - apple/mdnsresponder.git/blob - Clients/ExplorerPlugin/ExplorerBarWindow.cpp
mDNSResponder-107.4.tar.gz
[apple/mdnsresponder.git] / Clients / ExplorerPlugin / ExplorerBarWindow.cpp
1 /*
2 * Copyright (c) 2003-2004 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22
23 Change History (most recent first):
24
25 $Log: ExplorerBarWindow.cpp,v $
26 Revision 1.18 2005/02/26 01:24:05 shersche
27 Remove display lines in tree control
28
29 Revision 1.17 2005/02/25 19:57:30 shersche
30 <rdar://problem/4023323> Remove FTP browsing from plugin
31
32 Revision 1.16 2005/02/08 23:31:06 shersche
33 Move "About ..." item underneath WebSites, change icons for discovered sites and "About ..." item
34
35 Revision 1.15 2005/01/27 22:38:27 shersche
36 add About item to tree list
37
38 Revision 1.14 2005/01/25 17:55:39 shersche
39 <rdar://problem/3911084> Get bitmaps from non-localizable resource module
40 Bug #: 3911084
41
42 Revision 1.13 2005/01/06 21:13:09 shersche
43 <rdar://problem/3796779> Handle kDNSServiceErr_Firewall return codes
44 Bug #: 3796779
45
46 Revision 1.12 2004/10/26 00:56:03 cheshire
47 Use "#if 0" instead of commenting out code
48
49 Revision 1.11 2004/10/18 23:49:17 shersche
50 <rdar://problem/3841564> Remove trailing dot from hostname, because some flavors of Windows have difficulty parsing hostnames with a trailing dot.
51 Bug #: 3841564
52
53 Revision 1.10 2004/09/02 02:18:58 cheshire
54 Minor textual cleanup to improve readability
55
56 Revision 1.9 2004/09/02 02:11:56 cheshire
57 <rdar://problem/3783611> Fix incorrect testing of MoreComing flag
58
59 Revision 1.8 2004/07/26 05:47:31 shersche
60 use TXTRecord APIs, fix bug in locating service to be removed
61
62 Revision 1.7 2004/07/22 16:08:20 shersche
63 clean up debug print statements, re-enable code inadvertently commented out
64
65 Revision 1.6 2004/07/22 05:27:20 shersche
66 <rdar://problem/3735827> Check to make sure error isn't WSAEWOULDBLOCK when canceling browse
67 Bug #: 3735827
68
69 Revision 1.5 2004/07/20 06:49:18 shersche
70 clean up socket handling code
71
72 Revision 1.4 2004/07/13 21:24:21 rpantos
73 Fix for <rdar://problem/3701120>.
74
75 Revision 1.3 2004/06/27 14:59:59 shersche
76 reference count service info to handle multi-homed hosts
77
78 Revision 1.2 2004/06/23 16:09:34 shersche
79 Add the resolve DNSServiceRef to list of extant refs. This fixes the "doesn't resolve when double clicking" problem
80
81 Submitted by: Scott Herscher
82
83 Revision 1.1 2004/06/18 04:34:59 rpantos
84 Move to Clients from mDNSWindows
85
86 Revision 1.5 2004/04/15 01:00:05 bradley
87 Removed support for automatically querying for A/AAAA records when resolving names. Platforms
88 without .local name resolving support will need to manually query for A/AAAA records as needed.
89
90 Revision 1.4 2004/04/09 21:03:15 bradley
91 Changed port numbers to use network byte order for consistency with other platforms.
92
93 Revision 1.3 2004/04/08 09:43:43 bradley
94 Changed callback calling conventions to __stdcall so they can be used with C# delegates.
95
96 Revision 1.2 2004/02/21 04:36:19 bradley
97 Enable dot local name lookups now that the NSP is being installed.
98
99 Revision 1.1 2004/01/30 03:01:56 bradley
100 Explorer Plugin to browse for DNS-SD advertised Web and FTP servers from within Internet Explorer.
101
102 */
103
104 #include "StdAfx.h"
105
106 #include "CommonServices.h"
107 #include "DebugServices.h"
108 #include "WinServices.h"
109 #include "dns_sd.h"
110
111 #include "ExplorerBar.h"
112 #include "LoginDialog.h"
113 #include "Resource.h"
114
115 #include "ExplorerBarWindow.h"
116 #include "ExplorerPlugin.h"
117
118 // MFC Debugging
119
120 #ifdef _DEBUG
121 #define new DEBUG_NEW
122 #undef THIS_FILE
123 static char THIS_FILE[] = __FILE__;
124 #endif
125
126 #if 0
127 #pragma mark == Constants ==
128 #endif
129
130 //===========================================================================================================================
131 // Constants
132 //===========================================================================================================================
133
134 // Control IDs
135
136 #define IDC_EXPLORER_TREE 1234
137
138 // Private Messages
139
140 #define WM_PRIVATE_SERVICE_EVENT ( WM_USER + 0x100 )
141
142 // TXT records
143
144 #define kTXTRecordKeyPath "path"
145
146
147 #if 0
148 #pragma mark == Prototypes ==
149 #endif
150
151 //===========================================================================================================================
152 // Prototypes
153 //===========================================================================================================================
154
155 DEBUG_LOCAL int FindServiceArrayIndex( const ServiceInfoArray &inArray, const ServiceInfo &inService, int &outIndex );
156
157 #if 0
158 #pragma mark == Message Map ==
159 #endif
160
161 //===========================================================================================================================
162 // Message Map
163 //===========================================================================================================================
164
165 BEGIN_MESSAGE_MAP( ExplorerBarWindow, CWnd )
166 ON_WM_CREATE()
167 ON_WM_DESTROY()
168 ON_WM_SIZE()
169 ON_NOTIFY( NM_DBLCLK, IDC_EXPLORER_TREE, OnDoubleClick )
170 ON_MESSAGE( WM_PRIVATE_SERVICE_EVENT, OnServiceEvent )
171 END_MESSAGE_MAP()
172
173 #if 0
174 #pragma mark -
175 #endif
176
177 //===========================================================================================================================
178 // ExplorerBarWindow
179 //===========================================================================================================================
180
181 ExplorerBarWindow::ExplorerBarWindow( void )
182 {
183 mOwner = NULL;
184 mResolveServiceRef = NULL;
185 }
186
187 //===========================================================================================================================
188 // ~ExplorerBarWindow
189 //===========================================================================================================================
190
191 ExplorerBarWindow::~ExplorerBarWindow( void )
192 {
193 //
194 }
195
196 #if 0
197 #pragma mark -
198 #endif
199
200 //===========================================================================================================================
201 // OnCreate
202 //===========================================================================================================================
203
204 int ExplorerBarWindow::OnCreate( LPCREATESTRUCT inCreateStruct )
205 {
206 AFX_MANAGE_STATE( AfxGetStaticModuleState() );
207
208 OSStatus err;
209 CRect rect;
210 CBitmap bitmap;
211 CString s;
212
213 err = CWnd::OnCreate( inCreateStruct );
214 require_noerr( err, exit );
215
216 GetClientRect( rect );
217 mTree.Create( WS_TABSTOP | WS_VISIBLE | WS_CHILD | TVS_HASBUTTONS | TVS_LINESATROOT | TVS_NOHSCROLL , rect, this,
218 IDC_EXPLORER_TREE );
219
220 ServiceHandlerEntry * e;
221
222 // Web Site Handler
223
224 e = new ServiceHandlerEntry;
225 check( e );
226 e->type = "_http._tcp";
227 e->urlScheme = "http://";
228 e->ref = NULL;
229 e->obj = this;
230 e->needsLogin = false;
231 mServiceHandlers.Add( e );
232
233 s.LoadString( IDS_ABOUT );
234 m_about = mTree.InsertItem( s, 1, 1 );
235
236 err = DNSServiceBrowse( &e->ref, 0, 0, e->type, NULL, BrowseCallBack, e );
237 require_noerr( err, exit );
238
239 err = WSAAsyncSelect((SOCKET) DNSServiceRefSockFD(e->ref), m_hWnd, WM_PRIVATE_SERVICE_EVENT, FD_READ|FD_CLOSE);
240 require_noerr( err, exit );
241
242 m_serviceRefs.push_back(e->ref);
243
244 m_imageList.Create( 16, 16, ILC_COLORDDB, 2, 0);
245 bitmap.Attach( ::LoadBitmap( GetNonLocalizedResources(), MAKEINTRESOURCE( IDB_GLOBE ) ) );
246 m_imageList.Add( &bitmap, (CBitmap*) NULL );
247 bitmap.Detach();
248 bitmap.Attach( ::LoadBitmap( GetNonLocalizedResources(), MAKEINTRESOURCE( IDB_LOGO ) ) );
249 m_imageList.Add( &bitmap, (CBitmap*) NULL );
250
251 mTree.SetImageList(&m_imageList, TVSIL_NORMAL);
252
253 exit:
254
255 // Cannot talk to the mDNSResponder service. Show the error message and exit (with kNoErr so they can see it).
256 if ( err )
257 {
258 if ( err == kDNSServiceErr_Firewall )
259 {
260 s.LoadString( IDS_FIREWALL );
261 }
262 else
263 {
264 s.LoadString( IDS_MDNSRESPONDER_NOT_AVAILABLE );
265 }
266
267 mTree.DeleteAllItems();
268 mTree.InsertItem( s, 0, 0, TVI_ROOT, TVI_LAST );
269
270 err = kNoErr;
271 }
272
273 return( err );
274 }
275
276 //===========================================================================================================================
277 // OnDestroy
278 //===========================================================================================================================
279
280 void ExplorerBarWindow::OnDestroy( void )
281 {
282 // Stop any resolves that may still be pending (shouldn't be any).
283
284 StopResolve();
285
286 // Clean up the extant browses
287 while (m_serviceRefs.size() > 0)
288 {
289 //
290 // take the head of the list
291 //
292 DNSServiceRef ref = m_serviceRefs.front();
293
294 //
295 // Stop will remove it from the list
296 //
297 Stop( ref );
298 }
299
300 // Clean up the service handlers.
301
302 int i;
303 int n;
304
305 n = (int) mServiceHandlers.GetSize();
306 for( i = 0; i < n; ++i )
307 {
308 delete mServiceHandlers[ i ];
309 }
310
311 CWnd::OnDestroy();
312 }
313
314 //===========================================================================================================================
315 // OnSize
316 //===========================================================================================================================
317
318 void ExplorerBarWindow::OnSize( UINT inType, int inX, int inY )
319 {
320 CWnd::OnSize( inType, inX, inY );
321 mTree.MoveWindow( 0, 0, inX, inY );
322 }
323
324 //===========================================================================================================================
325 // OnDoubleClick
326 //===========================================================================================================================
327
328 void ExplorerBarWindow::OnDoubleClick( NMHDR *inNMHDR, LRESULT *outResult )
329 {
330 HTREEITEM item;
331 ServiceInfo * service;
332 OSStatus err;
333
334 DEBUG_UNUSED( inNMHDR );
335
336 item = mTree.GetSelectedItem();
337 require( item, exit );
338
339 // Tell Internet Explorer to go to the URL if it's about item
340
341 if ( item == m_about )
342 {
343 CString url;
344
345 check( mOwner );
346
347 url.LoadString( IDS_ABOUT_URL );
348 mOwner->GoToURL( url );
349 }
350 else
351 {
352 service = reinterpret_cast < ServiceInfo * > ( mTree.GetItemData( item ) );
353 require_quiet( service, exit );
354
355 err = StartResolve( service );
356 require_noerr( err, exit );
357 }
358
359 exit:
360 *outResult = 0;
361 }
362
363
364 //===========================================================================================================================
365 // OnServiceEvent
366 //===========================================================================================================================
367
368 LONG
369 ExplorerBarWindow::OnServiceEvent(WPARAM inWParam, LPARAM inLParam)
370 {
371 if (WSAGETSELECTERROR(inLParam) && !(HIWORD(inLParam)))
372 {
373 dlog( kDebugLevelError, "OnServiceEvent: window error\n" );
374 }
375 else
376 {
377 SOCKET sock = (SOCKET) inWParam;
378
379 // iterate thru list
380 ServiceRefList::iterator it;
381
382 for (it = m_serviceRefs.begin(); it != m_serviceRefs.end(); it++)
383 {
384 DNSServiceRef ref = *it;
385
386 check(ref != NULL);
387
388 if ((SOCKET) DNSServiceRefSockFD(ref) == sock)
389 {
390 DNSServiceErrorType err;
391
392 err = DNSServiceProcessResult(ref);
393
394 if (err != 0)
395 {
396 CString s;
397
398 s.LoadString( IDS_MDNSRESPONDER_NOT_AVAILABLE );
399 mTree.DeleteAllItems();
400 mTree.InsertItem( s, 0, 0, TVI_ROOT, TVI_LAST );
401
402 Stop(ref);
403 }
404
405 break;
406 }
407 }
408 }
409
410 return ( 0 );
411 }
412
413 #if 0
414 #pragma mark -
415 #endif
416
417 //===========================================================================================================================
418 // BrowseCallBack
419 //===========================================================================================================================
420
421 void DNSSD_API
422 ExplorerBarWindow::BrowseCallBack(
423 DNSServiceRef inRef,
424 DNSServiceFlags inFlags,
425 uint32_t inInterfaceIndex,
426 DNSServiceErrorType inErrorCode,
427 const char * inName,
428 const char * inType,
429 const char * inDomain,
430 void * inContext )
431 {
432 ServiceHandlerEntry * obj;
433 ServiceInfo * service;
434 OSStatus err;
435
436 DEBUG_UNUSED( inRef );
437
438 obj = NULL;
439 service = NULL;
440
441 require_noerr( inErrorCode, exit );
442 obj = reinterpret_cast < ServiceHandlerEntry * > ( inContext );
443 check( obj );
444 check( obj->obj );
445
446 //
447 // set the UI to hold off on updates
448 //
449 obj->obj->mTree.SetRedraw(FALSE);
450
451 try
452 {
453 service = new ServiceInfo;
454 require_action( service, exit, err = kNoMemoryErr );
455
456 err = UTF8StringToStringObject( inName, service->displayName );
457 check_noerr( err );
458
459 service->name = strdup( inName );
460 require_action( service->name, exit, err = kNoMemoryErr );
461
462 service->type = strdup( inType );
463 require_action( service->type, exit, err = kNoMemoryErr );
464
465 service->domain = strdup( inDomain );
466 require_action( service->domain, exit, err = kNoMemoryErr );
467
468 service->ifi = inInterfaceIndex;
469 service->handler = obj;
470
471 service->refs = 1;
472
473 if (inFlags & kDNSServiceFlagsAdd) obj->obj->OnServiceAdd (service);
474 else obj->obj->OnServiceRemove(service);
475
476 service = NULL;
477 }
478 catch( ... )
479 {
480 dlog( kDebugLevelError, "BrowseCallBack: exception thrown\n" );
481 }
482
483 exit:
484 //
485 // If no more coming, then update UI
486 //
487 if (obj && obj->obj && ((inFlags & kDNSServiceFlagsMoreComing) == 0))
488 {
489 obj->obj->mTree.SetRedraw(TRUE);
490 obj->obj->mTree.Invalidate();
491 }
492
493 if( service )
494 {
495 delete service;
496 }
497 }
498
499 //===========================================================================================================================
500 // OnServiceAdd
501 //===========================================================================================================================
502
503 LONG ExplorerBarWindow::OnServiceAdd( ServiceInfo * service )
504 {
505 ServiceHandlerEntry * handler;
506 int cmp;
507 int index;
508
509
510 check( service );
511 handler = service->handler;
512 check( handler );
513
514 cmp = FindServiceArrayIndex( handler->array, *service, index );
515 if( cmp == 0 )
516 {
517 // Found a match so update the item. The index is index + 1 so subtract 1.
518
519 index -= 1;
520 check( index < handler->array.GetSize() );
521
522 handler->array[ index ]->refs++;
523
524 delete service;
525 }
526 else
527 {
528 HTREEITEM afterItem;
529
530 // Insert the new item in sorted order.
531
532 afterItem = ( index > 0 ) ? handler->array[ index - 1 ]->item : m_about;
533 handler->array.InsertAt( index, service );
534 service->item = mTree.InsertItem( service->displayName, 0, 0, NULL, afterItem );
535 mTree.SetItemData( service->item, (DWORD_PTR) service );
536 }
537 return( 0 );
538 }
539
540 //===========================================================================================================================
541 // OnServiceRemove
542 //===========================================================================================================================
543
544 LONG ExplorerBarWindow::OnServiceRemove( ServiceInfo * service )
545 {
546 ServiceHandlerEntry * handler;
547 int cmp;
548 int index;
549
550
551 check( service );
552 handler = service->handler;
553 check( handler );
554
555 // Search to see if we know about this service instance. If so, remove it from the list.
556
557 cmp = FindServiceArrayIndex( handler->array, *service, index );
558 check( cmp == 0 );
559
560 if( cmp == 0 )
561 {
562 // Possibly found a match remove the item. The index
563 // is index + 1 so subtract 1.
564 index -= 1;
565 check( index < handler->array.GetSize() );
566
567 if ( --handler->array[ index ]->refs == 0 )
568 {
569 mTree.DeleteItem( handler->array[ index ]->item );
570 delete handler->array[ index ];
571 handler->array.RemoveAt( index );
572 }
573 }
574
575 delete service;
576 return( 0 );
577 }
578
579 #if 0
580 #pragma mark -
581 #endif
582
583 //===========================================================================================================================
584 // StartResolve
585 //===========================================================================================================================
586
587 OSStatus ExplorerBarWindow::StartResolve( ServiceInfo *inService )
588 {
589 OSStatus err;
590
591 check( inService );
592
593 // Stop any current resolve that may be in progress.
594
595 StopResolve();
596
597 // Resolve the service.
598 err = DNSServiceResolve( &mResolveServiceRef, 0, 0,
599 inService->name, inService->type, inService->domain, (DNSServiceResolveReply) ResolveCallBack, inService->handler );
600 require_noerr( err, exit );
601
602 err = WSAAsyncSelect((SOCKET) DNSServiceRefSockFD(mResolveServiceRef), m_hWnd, WM_PRIVATE_SERVICE_EVENT, FD_READ|FD_CLOSE);
603 require_noerr( err, exit );
604
605 m_serviceRefs.push_back(mResolveServiceRef);
606
607 exit:
608 return( err );
609 }
610
611 //===========================================================================================================================
612 // StopResolve
613 //===========================================================================================================================
614
615 void ExplorerBarWindow::StopResolve( void )
616 {
617 if( mResolveServiceRef )
618 {
619 Stop( mResolveServiceRef );
620 mResolveServiceRef = NULL;
621 }
622 }
623
624 //===========================================================================================================================
625 // ResolveCallBack
626 //===========================================================================================================================
627
628 void DNSSD_API
629 ExplorerBarWindow::ResolveCallBack(
630 DNSServiceRef inRef,
631 DNSServiceFlags inFlags,
632 uint32_t inInterfaceIndex,
633 DNSServiceErrorType inErrorCode,
634 const char * inFullName,
635 const char * inHostName,
636 uint16_t inPort,
637 uint16_t inTXTSize,
638 const char * inTXT,
639 void * inContext )
640 {
641 ExplorerBarWindow * obj;
642 ServiceHandlerEntry * handler;
643 OSStatus err;
644
645 DEBUG_UNUSED( inRef );
646 DEBUG_UNUSED( inFlags );
647 DEBUG_UNUSED( inErrorCode );
648 DEBUG_UNUSED( inFullName );
649
650 require_noerr( inErrorCode, exit );
651 handler = (ServiceHandlerEntry *) inContext;
652 check( handler );
653 obj = handler->obj;
654 check( obj );
655
656 try
657 {
658 ResolveInfo * resolve;
659 int idx;
660
661 dlog( kDebugLevelNotice, "resolved %s on ifi %d to %s\n", inFullName, inInterfaceIndex, inHostName );
662
663 // Stop resolving after the first good result.
664
665 obj->StopResolve();
666
667 // Post a message to the main thread so it can handle it since MFC is not thread safe.
668
669 resolve = new ResolveInfo;
670 require_action( resolve, exit, err = kNoMemoryErr );
671
672 UTF8StringToStringObject( inHostName, resolve->host );
673
674 // rdar://problem/3841564
675 //
676 // strip trailing dot from hostname because some flavors of Windows
677 // have trouble parsing it.
678
679 idx = resolve->host.ReverseFind('.');
680
681 if ((idx > 1) && ((resolve->host.GetLength() - 1) == idx))
682 {
683 resolve->host.Delete(idx, 1);
684 }
685
686 resolve->port = ntohs( inPort );
687 resolve->ifi = inInterfaceIndex;
688 resolve->handler = handler;
689
690 err = resolve->txt.SetData( inTXT, inTXTSize );
691 check_noerr( err );
692
693 obj->OnResolve(resolve);
694 }
695 catch( ... )
696 {
697 dlog( kDebugLevelError, "ResolveCallBack: exception thrown\n" );
698 }
699
700 exit:
701 return;
702 }
703
704 //===========================================================================================================================
705 // OnResolve
706 //===========================================================================================================================
707
708 LONG ExplorerBarWindow::OnResolve( ResolveInfo * resolve )
709 {
710 CString url;
711 uint8_t * path;
712 uint8_t pathSize;
713 char * pathPrefix;
714 CString username;
715 CString password;
716
717
718 check( resolve );
719
720 // Get login info if needed.
721
722 if( resolve->handler->needsLogin )
723 {
724 LoginDialog dialog;
725
726 if( !dialog.GetLogin( username, password ) )
727 {
728 goto exit;
729 }
730 }
731
732 // If the HTTP TXT record is a "path=" entry, use it as the resource path. Otherwise, use "/".
733
734 pathPrefix = "";
735 if( strcmp( resolve->handler->type, "_http._tcp" ) == 0 )
736 {
737 uint8_t * txtData;
738 uint16_t txtLen;
739
740 resolve->txt.GetData( &txtData, &txtLen );
741
742 path = (uint8_t*) TXTRecordGetValuePtr(txtLen, txtData, kTXTRecordKeyPath, &pathSize);
743
744 if (path == NULL)
745 {
746 path = (uint8_t*) "";
747 pathSize = 1;
748 }
749 }
750 else
751 {
752 path = (uint8_t *) "";
753 pathSize = 1;
754 }
755
756 // Build the URL in the following format:
757 //
758 // <urlScheme>[<username>[:<password>]@]<name/ip>[<path>]
759
760 url.AppendFormat( TEXT( "%S" ), resolve->handler->urlScheme ); // URL Scheme
761 if( username.GetLength() > 0 )
762 {
763 url.AppendFormat( TEXT( "%s" ), username ); // Username
764 if( password.GetLength() > 0 )
765 {
766 url.AppendFormat( TEXT( ":%s" ), password ); // Password
767 }
768 url.AppendFormat( TEXT( "@" ) );
769 }
770
771 url += resolve->host; // Host
772 url.AppendFormat( TEXT( ":%d" ), resolve->port ); // :Port
773 url.AppendFormat( TEXT( "%S" ), pathPrefix ); // Path Prefix ("/" or empty).
774 url.AppendFormat( TEXT( "%.*S" ), (int) pathSize, (char *) path ); // Path (possibly empty).
775
776 // Tell Internet Explorer to go to the URL.
777
778 check( mOwner );
779 mOwner->GoToURL( url );
780
781 exit:
782 delete resolve;
783 return( 0 );
784 }
785
786 //===========================================================================================================================
787 // Stop
788 //===========================================================================================================================
789 void ExplorerBarWindow::Stop( DNSServiceRef ref )
790 {
791 m_serviceRefs.remove( ref );
792
793 WSAAsyncSelect(DNSServiceRefSockFD( ref ), m_hWnd, WM_PRIVATE_SERVICE_EVENT, 0);
794
795 DNSServiceRefDeallocate( ref );
796 }
797
798
799 #if 0
800 #pragma mark -
801 #endif
802
803 //===========================================================================================================================
804 // FindServiceArrayIndex
805 //===========================================================================================================================
806
807 DEBUG_LOCAL int FindServiceArrayIndex( const ServiceInfoArray &inArray, const ServiceInfo &inService, int &outIndex )
808 {
809 int result;
810 int lo;
811 int hi;
812 int mid;
813
814 result = -1;
815 mid = 0;
816 lo = 0;
817 hi = (int)( inArray.GetSize() - 1 );
818 while( lo <= hi )
819 {
820 mid = ( lo + hi ) / 2;
821 result = inService.displayName.CompareNoCase( inArray[ mid ]->displayName );
822 #if 0
823 if( result == 0 )
824 {
825 result = ( (int) inService.ifi ) - ( (int) inArray[ mid ]->ifi );
826 }
827 #endif
828 if( result == 0 )
829 {
830 break;
831 }
832 else if( result < 0 )
833 {
834 hi = mid - 1;
835 }
836 else
837 {
838 lo = mid + 1;
839 }
840 }
841 if( result == 0 )
842 {
843 mid += 1; // Bump index so new item is inserted after matching item.
844 }
845 else if( result > 0 )
846 {
847 mid += 1;
848 }
849 outIndex = mid;
850 return( result );
851 }