1/* -*- Mode: C; tab-width: 4 -*-
2 *
3 * Copyright (c) 2009 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
18
19
20#pragma warning(disable:4995)
21
22
23
24#include "stdafx.h"
25
26#include <strsafe.h>
27
28#include "DNSSDService.h"
29
30#include "DNSSDEventManager.h"
31
32#include "DNSSDRecord.h"
33
34#include "TXTRecord.h"
35
36#include "StringServices.h"
37
38#include <DebugServices.h>
39
40
41
42
43
44#define WM_SOCKET (WM_APP + 100)
45
46
47
48
49
50// CDNSSDService
51
52
53
54BOOL						CDNSSDService::m_registeredWindowClass	= FALSE;
55
56HWND						CDNSSDService::m_hiddenWindow			= NULL;
57
58CDNSSDService::SocketMap	CDNSSDService::m_socketMap;
59
60
61
62
63
64HRESULT CDNSSDService::FinalConstruct()
65
66{
67
68	DNSServiceErrorType	err	= 0;
69
70	HRESULT				hr	= S_OK;
71
72
73
74	m_isPrimary = TRUE;
75
76	err = DNSServiceCreateConnection( &m_primary );
77
78	require_action( !err, exit, hr = E_FAIL );
79
80
81
82	if ( !m_hiddenWindow )
83
84	{
85
86		TCHAR windowClassName[ 256 ];
87
88
89
90		StringCchPrintf( windowClassName, sizeof( windowClassName ) / sizeof( TCHAR ), TEXT( "Bonjour Hidden Window %d" ), GetProcessId( NULL ) );
91
92
93
94		if ( !m_registeredWindowClass )
95
96		{
97
98			WNDCLASS	wc;
99
100			ATOM		atom;
101
102
103
104			wc.style			= 0;
105
106			wc.lpfnWndProc		= WndProc;
107
108			wc.cbClsExtra		= 0;
109
110			wc.cbWndExtra		= 0;
111
112			wc.hInstance		= NULL;
113
114			wc.hIcon			= NULL;
115
116			wc.hCursor			= NULL;
117
118			wc.hbrBackground	= NULL;
119
120			wc.lpszMenuName		= NULL;
121
122			wc.lpszClassName	= windowClassName;
123
124
125
126			atom = RegisterClass(&wc);
127
128			require_action( atom != NULL, exit, hr = E_FAIL );
129
130
131
132			m_registeredWindowClass = TRUE;
133
134		}
135
136
137
138		m_hiddenWindow = CreateWindow( windowClassName, windowClassName, WS_OVERLAPPED, 0, 0, 0, 0, NULL, NULL, GetModuleHandle( NULL ), NULL );
139
140		require_action( m_hiddenWindow != NULL, exit, hr = E_FAIL );
141
142	}
143
144
145
146	err = WSAAsyncSelect( DNSServiceRefSockFD( m_primary ), m_hiddenWindow, WM_SOCKET, FD_READ );
147
148	require_action( !err, exit, hr = E_FAIL );
149
150
151
152	m_socketMap[ DNSServiceRefSockFD( m_primary ) ] = this;
153
154
155
156exit:
157
158
159
160	return hr;
161
162}
163
164
165
166
167
168void CDNSSDService::FinalRelease()
169
170{
171
172	dlog( kDebugLevelTrace, "FinalRelease()\n" );
173
174	Stop();
175
176}
177
178
179
180
181
182STDMETHODIMP CDNSSDService::EnumerateDomains(DNSSDFlags flags, ULONG ifIndex, IDNSSDEventManager *eventManager, IDNSSDService **service)
183
184{
185
186	CComObject<CDNSSDService>	*	object	= NULL;
187
188	DNSServiceRef					subord	= NULL;
189
190	DNSServiceErrorType				err		= 0;
191
192	HRESULT							hr		= 0;
193
194
195
196	check( m_primary );
197
198
199
200	// Initialize
201
202	*service = NULL;
203
204
205
206	try
207
208	{
209
210		object = new CComObject<CDNSSDService>();
211
212	}
213
214	catch ( ... )
215
216	{
217
218		object = NULL;
219
220	}
221
222
223
224	require_action( object != NULL, exit, err = kDNSServiceErr_NoMemory );
225
226	object->AddRef();
227
228
229
230	subord = m_primary;
231
232	err = DNSServiceEnumerateDomains( &subord, flags | kDNSServiceFlagsShareConnection, ifIndex, ( DNSServiceDomainEnumReply ) &DomainEnumReply, object );
233
234	require_noerr( err, exit );
235
236
237
238	object->SetPrimaryRef( m_primary );
239
240	object->SetSubordRef( subord );
241
242	object->SetEventManager( eventManager );
243
244
245
246	*service = object;
247
248
249
250exit:
251
252
253
254	if ( err && object )
255
256	{
257
258		object->Release();
259
260	}
261
262
263
264	return err;
265
266}
267
268
269
270
271
272STDMETHODIMP CDNSSDService::Browse(DNSSDFlags flags, ULONG ifIndex, BSTR regtype, BSTR domain, IDNSSDEventManager* eventManager, IDNSSDService** service )
273
274{
275
276	CComObject<CDNSSDService>	*	object		= NULL;
277
278	std::string						regtypeUTF8;
279
280	std::string						domainUTF8;
281
282	DNSServiceRef					subord		= NULL;
283
284	DNSServiceErrorType				err			= 0;
285
286	HRESULT							hr			= 0;
287
288	BOOL							ok;
289
290
291
292	check( m_primary );
293
294
295
296	// Initialize
297
298	*service = NULL;
299
300
301
302	// Convert BSTR params to utf8
303
304	ok = BSTRToUTF8( regtype, regtypeUTF8 );
305
306	require_action( ok, exit, err = kDNSServiceErr_BadParam );
307
308	ok = BSTRToUTF8( domain, domainUTF8 );
309
310	require_action( ok, exit, err = kDNSServiceErr_BadParam );
311
312
313
314	try
315
316	{
317
318		object = new CComObject<CDNSSDService>();
319
320	}
321
322	catch ( ... )
323
324	{
325
326		object = NULL;
327
328	}
329
330
331
332	require_action( object != NULL, exit, err = kDNSServiceErr_NoMemory );
333
334	object->AddRef();
335
336
337
338	subord = m_primary;
339
340	err = DNSServiceBrowse( &subord, flags | kDNSServiceFlagsShareConnection, ifIndex, regtypeUTF8.c_str(), ( domainUTF8.size() > 0 ) ? domainUTF8.c_str() : NULL, ( DNSServiceBrowseReply ) &BrowseReply, object );
341
342	require_noerr( err, exit );
343
344
345
346	object->SetPrimaryRef( m_primary );
347
348	object->SetSubordRef( subord );
349
350	object->SetEventManager( eventManager );
351
352
353
354	*service = object;
355
356
357
358exit:
359
360
361
362	if ( err && object )
363
364	{
365
366		object->Release();
367
368	}
369
370
371
372	return err;
373
374}
375
376
377
378
379
380STDMETHODIMP CDNSSDService::Resolve(DNSSDFlags flags, ULONG ifIndex, BSTR serviceName, BSTR regType, BSTR domain, IDNSSDEventManager* eventManager, IDNSSDService** service)
381
382{
383
384	CComObject<CDNSSDService>	*	object			= NULL;
385
386	std::string						serviceNameUTF8;
387
388	std::string						regTypeUTF8;
389
390	std::string						domainUTF8;
391
392	DNSServiceRef					subord			= NULL;
393
394	DNSServiceErrorType				err				= 0;
395
396	HRESULT							hr				= 0;
397
398	BOOL							ok;
399
400
401
402	check( m_primary );
403
404
405
406	// Initialize
407
408	*service = NULL;
409
410
411
412	// Convert BSTR params to utf8
413
414	ok = BSTRToUTF8( serviceName, serviceNameUTF8 );
415
416	require_action( ok, exit, err = kDNSServiceErr_BadParam );
417
418	ok = BSTRToUTF8( regType, regTypeUTF8 );
419
420	require_action( ok, exit, err = kDNSServiceErr_BadParam );
421
422	ok = BSTRToUTF8( domain, domainUTF8 );
423
424	require_action( ok, exit, err = kDNSServiceErr_BadParam );
425
426
427
428	try
429
430	{
431
432		object = new CComObject<CDNSSDService>();
433
434	}
435
436	catch ( ... )
437
438	{
439
440		object = NULL;
441
442	}
443
444
445
446	require_action( object != NULL, exit, err = kDNSServiceErr_NoMemory );
447
448	object->AddRef();
449
450
451
452	subord = m_primary;
453
454	err = DNSServiceResolve( &subord, flags | kDNSServiceFlagsShareConnection, ifIndex, serviceNameUTF8.c_str(), regTypeUTF8.c_str(), domainUTF8.c_str(), ( DNSServiceResolveReply ) &ResolveReply, object );
455
456	require_noerr( err, exit );
457
458
459
460	object->SetPrimaryRef( m_primary );
461
462	object->SetSubordRef( subord );
463
464	object->SetEventManager( eventManager );
465
466
467
468	*service = object;
469
470
471
472exit:
473
474
475
476	if ( err && object )
477
478	{
479
480		object->Release();
481
482	}
483
484
485
486	return err;
487
488}
489
490
491
492
493
494STDMETHODIMP CDNSSDService::Register(DNSSDFlags flags, ULONG ifIndex, BSTR serviceName, BSTR regType, BSTR domain, BSTR host, USHORT port, ITXTRecord *record, IDNSSDEventManager *eventManager, IDNSSDService **service)
495
496{
497
498	CComObject<CDNSSDService>	*	object			= NULL;
499
500	std::string						serviceNameUTF8;
501
502	std::string						regTypeUTF8;
503
504	std::string						domainUTF8;
505
506	std::string						hostUTF8;
507
508	const void					*	txtRecord		= NULL;
509
510	uint16_t						txtLen			= 0;
511
512	DNSServiceRef					subord			= NULL;
513
514	DNSServiceErrorType				err				= 0;
515
516	HRESULT							hr				= 0;
517
518	BOOL							ok;
519
520
521
522	check( m_primary );
523
524
525
526	// Initialize
527
528	*service = NULL;
529
530
531
532	// Convert BSTR params to utf8
533
534	ok = BSTRToUTF8( serviceName, serviceNameUTF8 );
535
536	require_action( ok, exit, err = kDNSServiceErr_BadParam );
537
538	ok = BSTRToUTF8( regType, regTypeUTF8 );
539
540	require_action( ok, exit, err = kDNSServiceErr_BadParam );
541
542	ok = BSTRToUTF8( domain, domainUTF8 );
543
544	require_action( ok, exit, err = kDNSServiceErr_BadParam );
545
546	ok = BSTRToUTF8( host, hostUTF8 );
547
548	require_action( ok, exit, err = kDNSServiceErr_BadParam );
549
550
551
552	try
553
554	{
555
556		object = new CComObject<CDNSSDService>();
557
558	}
559
560	catch ( ... )
561
562	{
563
564		object = NULL;
565
566	}
567
568
569
570	require_action( object != NULL, exit, err = kDNSServiceErr_NoMemory );
571
572	object->AddRef();
573
574
575
576	if ( record )
577
578	{
579
580		CComObject< CTXTRecord > * realTXTRecord;
581
582
583
584		realTXTRecord = ( CComObject< CTXTRecord >* ) record;
585
586
587
588		txtRecord	= realTXTRecord->GetBytes();
589
590		txtLen		= realTXTRecord->GetLen();
591
592	}
593
594
595
596	subord = m_primary;
597
598	err = DNSServiceRegister( &subord, flags | kDNSServiceFlagsShareConnection, ifIndex, serviceNameUTF8.c_str(), regTypeUTF8.c_str(), ( domainUTF8.size() > 0 ) ? domainUTF8.c_str() : NULL, hostUTF8.c_str(), htons( port ), txtLen, txtRecord, ( DNSServiceRegisterReply ) &RegisterReply, object );
599
600	require_noerr( err, exit );
601
602
603
604	object->SetPrimaryRef( m_primary );
605
606	object->SetSubordRef( subord );
607
608	object->SetEventManager( eventManager );
609
610
611
612	*service = object;
613
614
615
616exit:
617
618
619
620	if ( err && object )
621
622	{
623
624		object->Release();
625
626	}
627
628
629
630	return err;
631
632}
633
634
635
636
637
638STDMETHODIMP CDNSSDService::QueryRecord(DNSSDFlags flags, ULONG ifIndex, BSTR fullname, DNSSDRRType rrtype, DNSSDRRClass rrclass, IDNSSDEventManager *eventManager, IDNSSDService **service)
639
640{
641
642	CComObject<CDNSSDService>	*	object			= NULL;
643
644	DNSServiceRef					subord			= NULL;
645
646	std::string						fullNameUTF8;
647
648	DNSServiceErrorType				err				= 0;
649
650	HRESULT							hr				= 0;
651
652	BOOL							ok;
653
654
655
656	check( m_primary );
657
658
659
660	// Initialize
661
662	*service = NULL;
663
664
665
666	// Convert BSTR params to utf8
667
668	ok = BSTRToUTF8( fullname, fullNameUTF8 );
669
670	require_action( ok, exit, err = kDNSServiceErr_BadParam );
671
672
673
674	try
675
676	{
677
678		object = new CComObject<CDNSSDService>();
679
680	}
681
682	catch ( ... )
683
684	{
685
686		object = NULL;
687
688	}
689
690
691
692	require_action( object != NULL, exit, err = kDNSServiceErr_NoMemory );
693
694	object->AddRef();
695
696
697
698	subord = m_primary;
699
700	err = DNSServiceQueryRecord( &subord, flags | kDNSServiceFlagsShareConnection, ifIndex, fullNameUTF8.c_str(), ( uint16_t ) rrtype, ( uint16_t ) rrclass, ( DNSServiceQueryRecordReply ) &QueryRecordReply, object );
701
702	require_noerr( err, exit );
703
704
705
706	object->SetPrimaryRef( m_primary );
707
708	object->SetSubordRef( subord );
709
710	object->SetEventManager( eventManager );
711
712
713
714	*service = object;
715
716
717
718exit:
719
720
721
722	if ( err && object )
723
724	{
725
726		object->Release();
727
728	}
729
730
731
732	return err;
733
734}
735
736
737
738
739
740STDMETHODIMP CDNSSDService::RegisterRecord(DNSSDFlags flags, ULONG ifIndex, BSTR fullName, DNSSDRRType rrtype, DNSSDRRClass rrclass, VARIANT rdata, ULONG ttl, IDNSSDEventManager* eventManager, IDNSSDRecord** record)
741
742{
743
744	CComObject<CDNSSDRecord>	*	object			= NULL;
745
746	DNSRecordRef					rref			= NULL;
747
748	std::string						fullNameUTF8;
749
750	std::vector< BYTE >				byteArray;
751
752	const void					*	byteArrayPtr	= NULL;
753
754	DNSServiceErrorType				err				= 0;
755
756	HRESULT							hr				= 0;
757
758	BOOL							ok;
759
760
761
762	check( m_primary );
763
764
765
766	// Initialize
767
768	*object = NULL;
769
770
771
772	// Convert BSTR params to utf8
773
774	ok = BSTRToUTF8( fullName, fullNameUTF8 );
775
776	require_action( ok, exit, err = kDNSServiceErr_BadParam );
777
778
779
780	// Convert the VARIANT
781
782	ok = VariantToByteArray( &rdata, byteArray );
783
784	require_action( ok, exit, err = kDNSServiceErr_Unknown );
785
786
787
788	try
789
790	{
791
792		object = new CComObject<CDNSSDRecord>();
793
794	}
795
796	catch ( ... )
797
798	{
799
800		object = NULL;
801
802	}
803
804
805
806	require_action( object != NULL, exit, err = kDNSServiceErr_NoMemory );
807
808	object->AddRef();
809
810
811
812	err = DNSServiceRegisterRecord( m_primary, &rref, flags, ifIndex, fullNameUTF8.c_str(), rrtype, rrclass, ( uint16_t ) byteArray.size(), byteArray.size() > 0 ? &byteArray[ 0 ] : NULL, ttl, &RegisterRecordReply, object );
813
814	require_noerr( err, exit );
815
816
817
818	object->SetServiceObject( this );
819
820	object->SetRecordRef( rref );
821
822	this->SetEventManager( eventManager );
823
824
825
826	*record = object;
827
828
829
830exit:
831
832
833
834	if ( err && object )
835
836	{
837
838		object->Release();
839
840	}
841
842
843
844	return err;
845
846}
847
848
849
850
851
852STDMETHODIMP CDNSSDService::AddRecord(DNSSDFlags flags, DNSSDRRType rrtype, VARIANT rdata, ULONG ttl, IDNSSDRecord ** record)
853
854{
855
856	CComObject<CDNSSDRecord>	*	object			= NULL;
857
858	DNSRecordRef					rref			= NULL;
859
860	std::vector< BYTE >				byteArray;
861
862	const void					*	byteArrayPtr	= NULL;
863
864	DNSServiceErrorType				err				= 0;
865
866	HRESULT							hr				= 0;
867
868	BOOL							ok;
869
870
871
872	check( m_primary );
873
874
875
876	// Initialize
877
878	*object = NULL;
879
880
881
882	// Convert the VARIANT
883
884	ok = VariantToByteArray( &rdata, byteArray );
885
886	require_action( ok, exit, err = kDNSServiceErr_Unknown );
887
888
889
890	try
891
892	{
893
894		object = new CComObject<CDNSSDRecord>();
895
896	}
897
898	catch ( ... )
899
900	{
901
902		object = NULL;
903
904	}
905
906
907
908	require_action( object != NULL, exit, err = kDNSServiceErr_NoMemory );
909
910	object->AddRef();
911
912
913
914	err = DNSServiceAddRecord( m_primary, &rref, flags, rrtype, ( uint16_t ) byteArray.size(), byteArray.size() > 0 ? &byteArray[ 0 ] : NULL, ttl );
915
916	require_noerr( err, exit );
917
918
919
920	object->SetServiceObject( this );
921
922	object->SetRecordRef( rref );
923
924
925
926	*record = object;
927
928
929
930exit:
931
932
933
934	if ( err && object )
935
936	{
937
938		object->Release();
939
940	}
941
942
943
944	return err;
945
946}
947
948
949
950STDMETHODIMP CDNSSDService::ReconfirmRecord(DNSSDFlags flags, ULONG ifIndex, BSTR fullName, DNSSDRRType rrtype, DNSSDRRClass rrclass, VARIANT rdata)
951
952{
953
954	std::string						fullNameUTF8;
955
956	std::vector< BYTE >				byteArray;
957
958	const void					*	byteArrayPtr	= NULL;
959
960	DNSServiceErrorType				err				= 0;
961
962	HRESULT							hr				= 0;
963
964	BOOL							ok;
965
966
967
968	// Convert BSTR params to utf8
969
970	ok = BSTRToUTF8( fullName, fullNameUTF8 );
971
972	require_action( ok, exit, err = kDNSServiceErr_BadParam );
973
974
975
976	// Convert the VARIANT
977
978	ok = VariantToByteArray( &rdata, byteArray );
979
980	require_action( ok, exit, err = kDNSServiceErr_Unknown );
981
982
983
984	err = DNSServiceReconfirmRecord( flags, ifIndex, fullNameUTF8.c_str(), rrtype, rrclass, ( uint16_t ) byteArray.size(), byteArray.size() > 0 ? &byteArray[ 0 ] : NULL );
985
986	require_noerr( err, exit );
987
988
989
990exit:
991
992
993
994	return err;
995
996}
997
998
999
1000
1001
1002STDMETHODIMP CDNSSDService::GetProperty(BSTR prop, VARIANT * value )
1003
1004{
1005
1006	std::string			propUTF8;
1007
1008	std::vector< BYTE >	byteArray;
1009
1010	SAFEARRAY		*	psa			= NULL;
1011
1012	BYTE			*	pData		= NULL;
1013
1014	uint32_t			elems		= 0;
1015
1016	DNSServiceErrorType	err			= 0;
1017
1018	BOOL				ok = TRUE;
1019
1020
1021
1022	// Convert BSTR params to utf8
1023
1024	ok = BSTRToUTF8( prop, propUTF8 );
1025
1026	require_action( ok, exit, err = kDNSServiceErr_BadParam );
1027
1028
1029
1030	// Setup the byte array
1031
1032	require_action( V_VT( value ) == ( VT_ARRAY|VT_UI1 ), exit, err = kDNSServiceErr_Unknown );
1033
1034	psa = V_ARRAY( value );
1035
1036	require_action( psa, exit, err = kDNSServiceErr_Unknown );
1037
1038	require_action( SafeArrayGetDim( psa ) == 1, exit, err = kDNSServiceErr_Unknown );
1039
1040	byteArray.reserve( psa->rgsabound[0].cElements );
1041
1042	byteArray.assign( byteArray.capacity(), 0 );
1043
1044	elems = ( uint32_t ) byteArray.capacity();
1045
1046
1047
1048	// Call the function and package the return value in the Variant
1049
1050	err = DNSServiceGetProperty( propUTF8.c_str(), &byteArray[ 0 ], &elems );
1051
1052	require_noerr( err, exit );
1053
1054	ok = ByteArrayToVariant( &byteArray[ 0 ], elems, value );
1055
1056	require_action( ok, exit, err = kDNSSDError_Unknown );
1057
1058
1059
1060exit:
1061
1062
1063
1064	if ( psa )
1065
1066	{
1067
1068		SafeArrayUnaccessData( psa );
1069
1070		psa = NULL;
1071
1072	}
1073
1074
1075
1076	return err;
1077
1078}
1079
1080
1081
1082STDMETHODIMP CDNSSDService::GetAddrInfo(DNSSDFlags flags, ULONG ifIndex, DNSSDAddressFamily addressFamily, BSTR hostName, IDNSSDEventManager *eventManager, IDNSSDService **service)
1083
1084{
1085
1086	CComObject<CDNSSDService>	*	object			= NULL;
1087
1088	DNSServiceRef					subord			= NULL;
1089
1090	std::string						hostNameUTF8;
1091
1092	DNSServiceErrorType				err				= 0;
1093
1094	HRESULT							hr				= 0;
1095
1096	BOOL							ok;
1097
1098
1099
1100	check( m_primary );
1101
1102
1103
1104	// Initialize
1105
1106	*service = NULL;
1107
1108
1109
1110	// Convert BSTR params to utf8
1111
1112	ok = BSTRToUTF8( hostName, hostNameUTF8 );
1113
1114	require_action( ok, exit, err = kDNSServiceErr_BadParam );
1115
1116
1117
1118	try
1119
1120	{
1121
1122		object = new CComObject<CDNSSDService>();
1123
1124	}
1125
1126	catch ( ... )
1127
1128	{
1129
1130		object = NULL;
1131
1132	}
1133
1134
1135
1136	require_action( object != NULL, exit, err = kDNSServiceErr_NoMemory );
1137
1138	object->AddRef();
1139
1140
1141
1142	subord = m_primary;
1143
1144	err = DNSServiceGetAddrInfo( &subord, flags | kDNSServiceFlagsShareConnection, ifIndex, addressFamily, hostNameUTF8.c_str(), ( DNSServiceGetAddrInfoReply ) &GetAddrInfoReply, object );
1145
1146	require_noerr( err, exit );
1147
1148
1149
1150	object->SetPrimaryRef( m_primary );
1151
1152	object->SetSubordRef( subord );
1153
1154	object->SetEventManager( eventManager );
1155
1156
1157
1158	*service = object;
1159
1160
1161
1162exit:
1163
1164
1165
1166	if ( err && object )
1167
1168	{
1169
1170		object->Release();
1171
1172	}
1173
1174
1175
1176	return err;
1177
1178}
1179
1180
1181
1182
1183
1184STDMETHODIMP CDNSSDService::NATPortMappingCreate(DNSSDFlags flags, ULONG ifIndex, DNSSDAddressFamily addressFamily, DNSSDProtocol protocol, USHORT internalPort, USHORT externalPort, ULONG ttl, IDNSSDEventManager *eventManager, IDNSSDService **service)
1185
1186{
1187
1188	CComObject<CDNSSDService>	*	object			= NULL;
1189
1190	DNSServiceRef					subord			= NULL;
1191
1192	DNSServiceProtocol				prot			= 0;
1193
1194	DNSServiceErrorType				err				= 0;
1195
1196	HRESULT							hr				= 0;
1197
1198
1199
1200	check( m_primary );
1201
1202
1203
1204	// Initialize
1205
1206	*service = NULL;
1207
1208
1209
1210	try
1211
1212	{
1213
1214		object = new CComObject<CDNSSDService>();
1215
1216	}
1217
1218	catch ( ... )
1219
1220	{
1221
1222		object = NULL;
1223
1224	}
1225
1226
1227
1228	require_action( object != NULL, exit, err = kDNSServiceErr_NoMemory );
1229
1230	object->AddRef();
1231
1232
1233
1234	prot = ( addressFamily | protocol );
1235
1236
1237
1238	subord = m_primary;
1239
1240	err = DNSServiceNATPortMappingCreate( &subord, flags | kDNSServiceFlagsShareConnection, ifIndex, prot, htons( internalPort ), htons( externalPort ), ttl, ( DNSServiceNATPortMappingReply ) &NATPortMappingReply, object );
1241
1242	require_noerr( err, exit );
1243
1244
1245
1246	object->SetPrimaryRef( m_primary );
1247
1248	object->SetSubordRef( subord );
1249
1250	object->SetEventManager( eventManager );
1251
1252
1253
1254	*service = object;
1255
1256
1257
1258exit:
1259
1260
1261
1262	if ( err && object )
1263
1264	{
1265
1266		object->Release();
1267
1268	}
1269
1270
1271
1272	return err;
1273
1274}
1275
1276
1277
1278
1279
1280STDMETHODIMP CDNSSDService::Stop(void)
1281
1282{
1283
1284	if ( !m_stopped )
1285
1286	{
1287
1288		m_stopped = TRUE;
1289
1290
1291
1292		dlog( kDebugLevelTrace, "Stop()\n" );
1293
1294
1295
1296		if ( m_isPrimary && m_primary )
1297
1298		{
1299
1300			SocketMap::iterator it;
1301
1302
1303
1304			if ( m_hiddenWindow )
1305
1306			{
1307
1308				WSAAsyncSelect( DNSServiceRefSockFD( m_primary ), m_hiddenWindow, 0, 0 );
1309
1310			}
1311
1312
1313
1314			it = m_socketMap.find( DNSServiceRefSockFD( m_primary ) );
1315
1316
1317
1318			if ( it != m_socketMap.end() )
1319
1320			{
1321
1322				m_socketMap.erase( it );
1323
1324			}
1325
1326
1327
1328			DNSServiceRefDeallocate( m_primary );
1329
1330			m_primary = NULL;
1331
1332		}
1333
1334		else if ( m_subord )
1335
1336		{
1337
1338			DNSServiceRefDeallocate( m_subord );
1339
1340			m_subord = NULL;
1341
1342		}
1343
1344
1345
1346		if ( m_eventManager != NULL )
1347
1348		{
1349
1350			m_eventManager->Release();
1351
1352			m_eventManager = NULL;
1353
1354		}
1355
1356	}
1357
1358
1359
1360	return S_OK;
1361
1362}
1363
1364
1365
1366
1367
1368void DNSSD_API
1369CDNSSDService::DomainEnumReply
1370    (
1371    DNSServiceRef                       sdRef,
1372    DNSServiceFlags                     flags,
1373    uint32_t                            ifIndex,
1374    DNSServiceErrorType                 errorCode,
1375    const char                          *replyDomainUTF8,
1376    void                                *context
1377    )
1378
1379{
1380
1381	CComObject<CDNSSDService>	* service		= NULL;
1382
1383	CDNSSDEventManager			* eventManager	= NULL;
1384
1385	int err = 0;
1386
1387
1388
1389	service = ( CComObject< CDNSSDService>* ) context;
1390
1391	require_action( service, exit, err = kDNSServiceErr_Unknown );
1392
1393
1394
1395	if ( service->ShouldHandleReply( errorCode, eventManager ) )
1396
1397	{
1398
1399		CComBSTR replyDomain;
1400
1401		BOOL ok;
1402
1403
1404
1405		ok = UTF8ToBSTR( replyDomainUTF8, replyDomain );
1406
1407		require_action( ok, exit, err = kDNSServiceErr_Unknown );
1408
1409
1410
1411		if ( flags & kDNSServiceFlagsAdd )
1412
1413		{
1414
1415			eventManager->Fire_DomainFound( service, ( DNSSDFlags ) flags, ifIndex, replyDomain );
1416
1417		}
1418
1419		else
1420
1421		{
1422
1423			eventManager->Fire_DomainLost( service, ( DNSSDFlags ) flags, ifIndex, replyDomain );
1424
1425		}
1426
1427	}
1428
1429
1430
1431exit:
1432
1433
1434
1435	return;
1436
1437}
1438
1439
1440
1441
1442
1443void DNSSD_API
1444CDNSSDService::BrowseReply
1445		(
1446		DNSServiceRef                       sdRef,
1447		DNSServiceFlags                     flags,
1448		uint32_t                            ifIndex,
1449		DNSServiceErrorType                 errorCode,
1450		const char                          *serviceNameUTF8,
1451		const char                          *regTypeUTF8,
1452		const char                          *replyDomainUTF8,
1453		void                                *context
1454		)
1455
1456{
1457
1458	CComObject<CDNSSDService>	* service		= NULL;
1459
1460	CDNSSDEventManager			* eventManager	= NULL;
1461
1462	int err = 0;
1463
1464
1465
1466	service = ( CComObject< CDNSSDService>* ) context;
1467
1468	require_action( service, exit, err = kDNSServiceErr_Unknown );
1469
1470
1471
1472	if ( service->ShouldHandleReply( errorCode, eventManager ) )
1473
1474	{
1475
1476		CComBSTR	serviceName;
1477
1478		CComBSTR	regType;
1479
1480		CComBSTR	replyDomain;
1481
1482
1483
1484		UTF8ToBSTR( serviceNameUTF8, serviceName );
1485
1486		UTF8ToBSTR( regTypeUTF8, regType );
1487
1488		UTF8ToBSTR( replyDomainUTF8, replyDomain );
1489
1490
1491
1492		if ( flags & kDNSServiceFlagsAdd )
1493
1494		{
1495
1496			eventManager->Fire_ServiceFound( service, ( DNSSDFlags ) flags, ifIndex, serviceName, regType, replyDomain );
1497
1498		}
1499
1500		else
1501
1502		{
1503
1504			eventManager->Fire_ServiceLost( service, ( DNSSDFlags ) flags, ifIndex, serviceName, regType, replyDomain );
1505
1506		}
1507
1508	}
1509
1510
1511
1512exit:
1513
1514
1515
1516	return;
1517
1518}
1519
1520
1521
1522
1523
1524void DNSSD_API
1525
1526CDNSSDService::ResolveReply
1527
1528		(
1529		DNSServiceRef                       sdRef,
1530		DNSServiceFlags                     flags,
1531		uint32_t                            ifIndex,
1532		DNSServiceErrorType                 errorCode,
1533		const char                          *fullNameUTF8,
1534		const char                          *hostNameUTF8,
1535		uint16_t                            port,
1536		uint16_t                            txtLen,
1537		const unsigned char                 *txtRecord,
1538		void                                *context
1539
1540		)
1541
1542{
1543
1544	CComObject<CDNSSDService>	* service		= NULL;
1545
1546	CDNSSDEventManager			* eventManager	= NULL;
1547
1548	int err = 0;
1549
1550
1551
1552	service = ( CComObject< CDNSSDService>* ) context;
1553
1554	require_action( service, exit, err = kDNSServiceErr_Unknown );
1555
1556
1557
1558	if ( service->ShouldHandleReply( errorCode, eventManager ) )
1559
1560	{
1561
1562		CComBSTR					fullName;
1563
1564		CComBSTR					hostName;
1565
1566		CComBSTR					regType;
1567
1568		CComBSTR					replyDomain;
1569
1570		CComObject< CTXTRecord >*	record;
1571
1572		BOOL						ok;
1573
1574
1575
1576		ok = UTF8ToBSTR( fullNameUTF8, fullName );
1577
1578		require_action( ok, exit, err = kDNSServiceErr_Unknown );
1579
1580		ok = UTF8ToBSTR( hostNameUTF8, hostName );
1581
1582		require_action( ok, exit, err = kDNSServiceErr_Unknown );
1583
1584
1585
1586		try
1587
1588		{
1589
1590			record = new CComObject<CTXTRecord>();
1591
1592		}
1593
1594		catch ( ... )
1595
1596		{
1597
1598			record = NULL;
1599
1600		}
1601
1602
1603
1604		require_action( record, exit, err = kDNSServiceErr_NoMemory );
1605
1606		record->AddRef();
1607
1608
1609
1610		if ( txtLen > 0 )
1611
1612		{
1613
1614			record->SetBytes( txtRecord, txtLen );
1615
1616		}
1617
1618
1619
1620		eventManager->Fire_ServiceResolved( service, ( DNSSDFlags ) flags, ifIndex, fullName, hostName, ntohs( port ), record );
1621
1622	}
1623
1624
1625
1626exit:
1627
1628
1629
1630	return;
1631
1632}
1633
1634
1635
1636
1637
1638void DNSSD_API
1639CDNSSDService::RegisterReply
1640		(
1641		DNSServiceRef                       sdRef,
1642		DNSServiceFlags                     flags,
1643		DNSServiceErrorType                 errorCode,
1644		const char                          *serviceNameUTF8,
1645		const char                          *regTypeUTF8,
1646		const char                          *domainUTF8,
1647		void                                *context
1648		)
1649
1650{
1651
1652	CComObject<CDNSSDService>	* service		= NULL;
1653
1654	CDNSSDEventManager			* eventManager	= NULL;
1655
1656	int err = 0;
1657
1658
1659
1660	service = ( CComObject< CDNSSDService>* ) context;
1661
1662	require_action( service, exit, err = kDNSServiceErr_Unknown );
1663
1664
1665
1666	if ( service->ShouldHandleReply( errorCode, eventManager ) )
1667
1668	{
1669
1670		CComBSTR					serviceName;
1671
1672		CComBSTR					regType;
1673
1674		CComBSTR					domain;
1675
1676		BOOL						ok;
1677
1678
1679
1680		ok = UTF8ToBSTR( serviceNameUTF8, serviceName );
1681
1682		require_action( ok, exit, err = kDNSServiceErr_Unknown );
1683
1684		ok = UTF8ToBSTR( regTypeUTF8, regType );
1685
1686		require_action( ok, exit, err = kDNSServiceErr_Unknown );
1687
1688		ok = UTF8ToBSTR( domainUTF8, domain );
1689
1690		require_action( ok, exit, err = kDNSServiceErr_Unknown );
1691
1692
1693
1694		eventManager->Fire_ServiceRegistered( service, ( DNSSDFlags ) flags, serviceName, regType, domain );
1695
1696	}
1697
1698
1699
1700exit:
1701
1702
1703
1704	return;
1705
1706}
1707
1708
1709
1710
1711
1712void DNSSD_API
1713CDNSSDService::QueryRecordReply
1714		(
1715		DNSServiceRef                       sdRef,
1716		DNSServiceFlags                     flags,
1717		uint32_t                            ifIndex,
1718		DNSServiceErrorType                 errorCode,
1719		const char                          *fullNameUTF8,
1720		uint16_t                            rrtype,
1721		uint16_t                            rrclass,
1722		uint16_t                            rdlen,
1723		const void                          *rdata,
1724		uint32_t                            ttl,
1725		void                                *context
1726		)
1727
1728{
1729
1730	CComObject<CDNSSDService>	* service		= NULL;
1731
1732	CDNSSDEventManager			* eventManager	= NULL;
1733
1734	int err = 0;
1735
1736
1737
1738	service = ( CComObject< CDNSSDService>* ) context;
1739
1740	require_action( service, exit, err = kDNSServiceErr_Unknown );
1741
1742
1743
1744	if ( service->ShouldHandleReply( errorCode, eventManager ) )
1745
1746	{
1747
1748		CComBSTR	fullName;
1749
1750		VARIANT		var;
1751
1752		BOOL		ok;
1753
1754
1755
1756		ok = UTF8ToBSTR( fullNameUTF8, fullName );
1757
1758		require_action( ok, exit, err = kDNSServiceErr_Unknown );
1759
1760		ok = ByteArrayToVariant( rdata, rdlen, &var );
1761
1762		require_action( ok, exit, err = kDNSServiceErr_Unknown );
1763
1764
1765
1766		eventManager->Fire_QueryRecordAnswered( service, ( DNSSDFlags ) flags, ifIndex, fullName, ( DNSSDRRType ) rrtype, ( DNSSDRRClass ) rrclass, var, ttl );
1767
1768	}
1769
1770
1771
1772exit:
1773
1774
1775
1776	return;
1777
1778}
1779
1780
1781
1782
1783
1784void DNSSD_API
1785CDNSSDService::GetAddrInfoReply
1786		(
1787		DNSServiceRef                    sdRef,
1788		DNSServiceFlags                  flags,
1789		uint32_t                         ifIndex,
1790		DNSServiceErrorType              errorCode,
1791		const char                       *hostNameUTF8,
1792		const struct sockaddr            *rawAddress,
1793		uint32_t                         ttl,
1794		void                             *context
1795		)
1796
1797{
1798
1799	CComObject<CDNSSDService>	* service		= NULL;
1800
1801	CDNSSDEventManager			* eventManager	= NULL;
1802
1803	int err = 0;
1804
1805
1806
1807	service = ( CComObject< CDNSSDService>* ) context;
1808
1809	require_action( service, exit, err = kDNSServiceErr_Unknown );
1810
1811
1812
1813	if ( service->ShouldHandleReply( errorCode, eventManager ) )
1814
1815	{
1816
1817		CComBSTR			hostName;
1818
1819		DWORD				sockaddrLen;
1820
1821		DNSSDAddressFamily	addressFamily;
1822
1823		char				addressUTF8[INET6_ADDRSTRLEN];
1824
1825		DWORD				addressLen = sizeof( addressUTF8 );
1826
1827		CComBSTR			address;
1828
1829		BOOL				ok;
1830
1831
1832
1833		ok = UTF8ToBSTR( hostNameUTF8, hostName );
1834
1835		require_action( ok, exit, err = kDNSServiceErr_Unknown );
1836
1837
1838
1839		switch ( rawAddress->sa_family )
1840
1841		{
1842
1843			case AF_INET:
1844
1845			{
1846
1847				addressFamily	= kDNSSDAddressFamily_IPv4;
1848
1849				sockaddrLen		= sizeof( sockaddr_in );
1850
1851			}
1852
1853			break;
1854
1855
1856
1857			case AF_INET6:
1858
1859			{
1860
1861				addressFamily	= kDNSSDAddressFamily_IPv6;
1862
1863				sockaddrLen		= sizeof( sockaddr_in6 );
1864
1865			}
1866
1867			break;
1868
1869		}
1870
1871
1872
1873		err = WSAAddressToStringA( ( LPSOCKADDR ) rawAddress, sockaddrLen, NULL, addressUTF8, &addressLen );
1874
1875		require_noerr( err, exit );
1876
1877		ok = UTF8ToBSTR( addressUTF8, address );
1878
1879		require_action( ok, exit, err = kDNSServiceErr_Unknown );
1880
1881
1882
1883		eventManager->Fire_AddressFound( service, ( DNSSDFlags ) flags, ifIndex, hostName, addressFamily, address, ttl );
1884
1885	}
1886
1887
1888
1889exit:
1890
1891
1892
1893	return;
1894
1895}
1896
1897
1898
1899
1900
1901void DNSSD_API
1902CDNSSDService::NATPortMappingReply
1903    (
1904    DNSServiceRef                    sdRef,
1905    DNSServiceFlags                  flags,
1906    uint32_t                         ifIndex,
1907    DNSServiceErrorType              errorCode,
1908    uint32_t                         externalAddress,   /* four byte IPv4 address in network byte order */
1909    DNSServiceProtocol               protocol,
1910    uint16_t                         internalPort,
1911    uint16_t                         externalPort,      /* may be different than the requested port     */
1912    uint32_t                         ttl,               /* may be different than the requested ttl      */
1913    void                             *context
1914    )
1915
1916{
1917
1918	CComObject<CDNSSDService>	* service		= NULL;
1919
1920	CDNSSDEventManager			* eventManager	= NULL;
1921
1922	int err = 0;
1923
1924
1925
1926	service = ( CComObject< CDNSSDService>* ) context;
1927
1928	require_action( service, exit, err = kDNSServiceErr_Unknown );
1929
1930
1931
1932	if ( service->ShouldHandleReply( errorCode, eventManager ) )
1933
1934	{
1935
1936		eventManager->Fire_MappingCreated( service, ( DNSSDFlags ) flags, ifIndex, externalAddress, ( DNSSDAddressFamily ) ( protocol & 0x8 ), ( DNSSDProtocol ) ( protocol & 0x80 ), ntohs( internalPort ), ntohs( externalPort ), ttl  );
1937
1938	}
1939
1940
1941
1942exit:
1943
1944
1945
1946	return;
1947
1948}
1949
1950
1951
1952
1953
1954void DNSSD_API
1955CDNSSDService::RegisterRecordReply
1956		(
1957		DNSServiceRef		sdRef,
1958		DNSRecordRef		RecordRef,
1959		DNSServiceFlags		flags,
1960		DNSServiceErrorType	errorCode,
1961		void				*context
1962		)
1963
1964{
1965
1966	CComObject<CDNSSDRecord>	* record		= NULL;
1967
1968	CDNSSDService				* service		= NULL;
1969
1970	CDNSSDEventManager			* eventManager	= NULL;
1971
1972	int err = 0;
1973
1974
1975
1976	record = ( CComObject< CDNSSDRecord >* ) context;
1977
1978	require_action( record, exit, err = kDNSServiceErr_Unknown );
1979
1980	service = record->GetServiceObject();
1981
1982	require_action( service, exit, err = kDNSServiceErr_Unknown );
1983
1984
1985
1986	if ( service->ShouldHandleReply( errorCode, eventManager ) )
1987
1988	{
1989
1990		eventManager->Fire_RecordRegistered( record, ( DNSSDFlags ) flags );
1991
1992	}
1993
1994
1995
1996exit:
1997
1998
1999
2000	return;
2001
2002}
2003
2004
2005
2006
2007
2008BOOL
2009
2010CDNSSDService::ShouldHandleReply( DNSServiceErrorType errorCode, CDNSSDEventManager *& eventManager )
2011
2012{
2013
2014	BOOL ok = FALSE;
2015
2016
2017
2018	if ( !this->Stopped() )
2019
2020	{
2021
2022		eventManager = this->GetEventManager();
2023
2024		require_action( eventManager, exit, ok = FALSE );
2025
2026
2027
2028		if ( !errorCode )
2029
2030		{
2031
2032			ok = TRUE;
2033
2034		}
2035
2036		else
2037
2038		{
2039
2040			eventManager->Fire_OperationFailed( this, ( DNSSDError ) errorCode );
2041
2042		}
2043
2044	}
2045
2046
2047
2048exit:
2049
2050
2051
2052	return ok;
2053
2054}
2055
2056
2057
2058
2059
2060LRESULT CALLBACK
2061
2062CDNSSDService::WndProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam )
2063
2064{
2065
2066	if ( msg == WM_SOCKET )
2067
2068	{
2069
2070		SocketMap::iterator it;
2071
2072
2073
2074		it = m_socketMap.find( ( SOCKET ) wParam );
2075
2076		check( it != m_socketMap.end() );
2077
2078
2079
2080		if ( it != m_socketMap.end() )
2081
2082		{
2083
2084			DNSServiceProcessResult( it->second->m_primary );
2085
2086		}
2087
2088	}
2089
2090
2091
2092	return DefWindowProc(hWnd, msg, wParam, lParam);;
2093
2094}
2095
2096