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