1/* -*- Mode: C; tab-width: 4 -*-
2 *
3 * Copyright (c) 2005 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#include	"stdafx.h"
19
20#include	<assert.h>
21#include	<stdio.h>
22
23#include	"dns_sd.h"
24
25// Constants
26
27#define BONJOUR_EVENT		( WM_USER + 0x100 )	// Message sent to the Window when a Bonjour event occurs.
28
29// Prototypes
30
31static LRESULT CALLBACK WndProc( HWND inWindow, UINT inMsg, WPARAM inWParam, LPARAM inLParam );
32
33static void DNSSD_API
34	BrowserCallBack(
35		DNSServiceRef		inServiceRef,
36		DNSServiceFlags		inFlags,
37		uint32_t			inIFI,
38		DNSServiceErrorType	inError,
39		const char *		inName,
40		const char *		inType,
41		const char *		inDomain,
42		void *				inContext );
43
44// Globals
45
46DNSServiceRef		gServiceRef = NULL;
47
48// Main entry point for application.
49
50int _tmain( int argc, _TCHAR *argv[] )
51{
52	HINSTANCE				instance;
53	WNDCLASSEX				wcex;
54	HWND					wind;
55	MSG						msg;
56	DNSServiceErrorType		err;
57
58	(void) argc; // Unused
59	(void) argv; // Unused
60
61	// Create the window. This window won't actually be shown, but it demonstrates how to use Bonjour
62	// with Windows GUI applications by having Bonjour events processed as messages to a Window.
63
64	instance = GetModuleHandle( NULL );
65	assert( instance );
66
67	wcex.cbSize			= sizeof( wcex );
68	wcex.style			= 0;
69	wcex.lpfnWndProc	= (WNDPROC) WndProc;
70	wcex.cbClsExtra		= 0;
71	wcex.cbWndExtra		= 0;
72	wcex.hInstance		= instance;
73	wcex.hIcon			= NULL;
74	wcex.hCursor		= NULL;
75	wcex.hbrBackground	= NULL;
76	wcex.lpszMenuName	= NULL;
77	wcex.lpszClassName	= TEXT( "BonjourExample" );
78	wcex.hIconSm		= NULL;
79	RegisterClassEx( &wcex );
80
81	wind = CreateWindow( wcex.lpszClassName, wcex.lpszClassName, 0, CW_USEDEFAULT, 0, CW_USEDEFAULT,
82		0, NULL, NULL, instance, NULL );
83	assert( wind );
84
85	// Start browsing for services and associate the Bonjour browser with our window using the
86	// WSAAsyncSelect mechanism. Whenever something related to the Bonjour browser occurs, our
87	// private Windows message will be sent to our window so we can give Bonjour a chance to
88	// process it. This allows Bonjour to avoid using a secondary thread (and all the issues
89	// with synchronization that would introduce), but still process everything asynchronously.
90	// This also simplifies app code because Bonjour will only run when we explicitly call it.
91
92	err = DNSServiceBrowse(
93		&gServiceRef, 					// Receives reference to Bonjour browser object.
94		0,								// No flags.
95		kDNSServiceInterfaceIndexAny,	// Browse on all network interfaces.
96		"_http._tcp",					// Browse for HTTP service types.
97		NULL,							// Browse on the default domain (e.g. local.).
98		BrowserCallBack, 				// Callback function when Bonjour events occur.
99		NULL );							// No callback context needed.
100	assert( err == kDNSServiceErr_NoError );
101
102	err = WSAAsyncSelect( (SOCKET) DNSServiceRefSockFD( gServiceRef ), wind, BONJOUR_EVENT, FD_READ | FD_CLOSE );
103	assert( err == kDNSServiceErr_NoError );
104
105	fprintf( stderr, "Browsing for _http._tcp\n" );
106
107	// Main event loop for the application. All Bonjour events are dispatched while in this loop.
108
109	while( GetMessage( &msg, NULL, 0, 0 ) )
110	{
111		TranslateMessage( &msg );
112		DispatchMessage( &msg );
113	}
114
115	// Clean up Bonjour. This is not strictly necessary since the normal process cleanup will
116	// close Bonjour socket(s) and release memory, but it's here to demonstrate how to do it.
117
118	if( gServiceRef )
119	{
120		WSAAsyncSelect( (SOCKET) DNSServiceRefSockFD( gServiceRef ), wind, BONJOUR_EVENT, 0 );
121		DNSServiceRefDeallocate( gServiceRef );
122	}
123	return( 0 );
124}
125
126// Callback for the Window. Bonjour events are delivered here.
127
128static LRESULT CALLBACK WndProc( HWND inWindow, UINT inMsg, WPARAM inWParam, LPARAM inLParam )
129{
130	LRESULT					result;
131	DNSServiceErrorType		err;
132
133	switch( inMsg )
134	{
135		case BONJOUR_EVENT:
136
137			// Process the Bonjour event. All Bonjour callbacks occur from within this function.
138			// If an error occurs while trying to process the result, it most likely means that
139			// something serious has gone wrong with Bonjour, such as it being terminated. This
140			// does not normally occur, but code should be prepared to handle it. If the error
141			// is ignored, the window will receive a constant stream of BONJOUR_EVENT messages so
142			// if an error occurs, we disassociate the DNSServiceRef from the window, deallocate
143			// it, and invalidate the reference so we don't try to deallocate it again on quit.
144			// Since this is a simple example app, if this error occurs, we quit the app too.
145
146			err = DNSServiceProcessResult( gServiceRef );
147			if( err != kDNSServiceErr_NoError )
148			{
149				fprintf( stderr, "### ERROR! serious Bonjour error: %d\n", err );
150
151				WSAAsyncSelect( (SOCKET) DNSServiceRefSockFD( gServiceRef ), inWindow, BONJOUR_EVENT, 0 );
152				DNSServiceRefDeallocate( gServiceRef );
153				gServiceRef = NULL;
154
155				PostQuitMessage( 0 );
156			}
157			result = 0;
158			break;
159
160		default:
161			result = DefWindowProc( inWindow, inMsg, inWParam, inLParam );
162			break;
163	}
164	return( result );
165}
166
167// Callback for Bonjour browser events. Called when services are added or removed.
168
169static void DNSSD_API
170	BrowserCallBack(
171		DNSServiceRef		inServiceRef,
172		DNSServiceFlags		inFlags,
173		uint32_t			inIFI,
174		DNSServiceErrorType	inError,
175		const char *		inName,
176		const char *		inType,
177		const char *		inDomain,
178		void *				inContext )
179{
180	(void) inServiceRef;	// Unused
181	(void) inContext;		// Unused
182
183	if( inError == kDNSServiceErr_NoError )
184	{
185		const char *		action;
186		const char *		more;
187
188		if( inFlags & kDNSServiceFlagsAdd )			action	= "ADD";
189		else										action	= "RMV";
190		if( inFlags & kDNSServiceFlagsMoreComing )	more	= " (MORE)";
191		else										more	= "";
192
193		fprintf( stderr, "%s %30s.%s%s on interface %d%s\n", action, inName, inType, inDomain, (int) inIFI, more );
194	}
195	else
196	{
197		fprintf( stderr, "Bonjour browser error occurred: %d\n", inError );
198	}
199}
200