mirror of
https://github.com/gnustep/libs-base.git
synced 2025-04-22 16:33:29 +00:00
Attempt to integrate Niels Grewe's avahi code
git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@30952 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
parent
68153c7203
commit
43339cc05e
18 changed files with 12627 additions and 5262 deletions
29
ChangeLog
29
ChangeLog
|
@ -1,3 +1,32 @@
|
|||
2010-03-27 Niels Grewe <niels.grewe@halbordnung.de>
|
||||
|
||||
* configure.ac: Add check for avahi-client.
|
||||
* configure: Regenerate
|
||||
* base.make.in: Add build-variables for Avahi.
|
||||
* Source/GNUmakefile: Add avahi-based NSNetServices to build
|
||||
* Source/GSAvahiRunLoopIntegration.h:
|
||||
* Source/GSAvahiRunLoopIntegration.m:
|
||||
* Source/GSAvahiClient.h:
|
||||
* Source/GSAvahiClient.m:
|
||||
* Source/GSAvahiNetService.m:
|
||||
* Source/GSAvahiNetServiceBrowser.m: Add avahi-based NSNetServices
|
||||
implementation
|
||||
* Source/GSMDNSNetServies.m: Move mDNS-implementation to this file
|
||||
* Source/GSNetServices.h: New private header for NSNetServices
|
||||
* Source/NSNetServices.m: Abstract superclasses
|
||||
* Headers/Foundation/NSNetServices.h: Adopt to new class structure
|
||||
* Headers/Additions/GNUstepBase/GSConfig.h.in: Add zeroconf related
|
||||
variables.
|
||||
* Header/Additions/GNUstepBase/Additions.h:
|
||||
* Headers/Additions/GNUstepBase/NSNetServices+GNUstepBase.h: Add header
|
||||
with extensions for the avahi-based NSNetService class.
|
||||
Implement NSNetService and NSNetServiceBrowser on top of the
|
||||
avahi-client API. Both classes are now abstract superclasses of the
|
||||
concrete implementations based on the mDNSResponder or avahi-client
|
||||
APIs. The API to be used can be configured with the
|
||||
--with-zeroconf-api=API (mdns, avahi, or any) configure-switch. If both
|
||||
APIs are available, the avahi API will be preferred.
|
||||
|
||||
2010-07-12 Richard Frith-Macdonald <rfm@gnu.org>
|
||||
|
||||
* Tools/gdomap.c: Fix logic error in recnt mod. Add some debug.
|
||||
|
|
|
@ -47,6 +47,7 @@
|
|||
#import <GNUstepBase/NSFileHandle+GNUstepBase.h>
|
||||
#import <GNUstepBase/NSLock+GNUstepBase.h>
|
||||
#import <GNUstepBase/NSMutableString+GNUstepBase.h>
|
||||
#import <GNUstepBase/NSNetServices+GNUstepBase.h>
|
||||
#import <GNUstepBase/NSNumber+GNUstepBase.h>
|
||||
#import <GNUstepBase/NSObject+GNUstepBase.h>
|
||||
#import <GNUstepBase/NSProcessInfo+GNUstepBase.h>
|
||||
|
|
|
@ -221,7 +221,8 @@ typedef struct {
|
|||
#define BASE_NATIVE_OBJC_EXCEPTIONS @BASE_NATIVE_OBJC_EXCEPTIONS@
|
||||
#define GS_NONFRAGILE @GS_NONFRAGILE@
|
||||
#define GS_MIXEDABI @GS_MIXEDABI@
|
||||
|
||||
#define GS_USE_AVAHI @HAVE_AVAHI@
|
||||
#define GS_USE_MDNS @HAVE_MDNS@
|
||||
#import <GNUstepBase/preface.h>
|
||||
|
||||
#endif /* included_GSConfig_h */
|
||||
|
|
81
Headers/Additions/GNUstepBase/NSNetServices+GNUstepBase.h
Normal file
81
Headers/Additions/GNUstepBase/NSNetServices+GNUstepBase.h
Normal file
|
@ -0,0 +1,81 @@
|
|||
/* Declarations of GNUstep extensions to NSNetService.
|
||||
Copyright (C) 2010 Free Software Foundation, Inc.
|
||||
|
||||
Written by: Niels Grewe <niels.grewe@halbordnung.de>
|
||||
Date: March 2010
|
||||
|
||||
This file is part of the GNUstep Base Library.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free
|
||||
Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
Boston, MA 02111 USA.
|
||||
*/
|
||||
|
||||
#import <Foundation/NSNetServices.h>
|
||||
#import <GNUstepBase/GSConfig.h>
|
||||
|
||||
/*
|
||||
* Only enable extensions if the Avahi API is used. The mDNS based NSNetService
|
||||
* doesn't support them yet.
|
||||
*/
|
||||
#if GS_USE_AVAHI==1
|
||||
@interface NSNetService (GNUstepBase)
|
||||
/**
|
||||
* Starts monitoring the service represented by the receiver for changes in a
|
||||
* resource record of <code>recordType</code>. The delegate must either
|
||||
* implement a -netService:didUpateFOORecordData: method, where "FOO" is the
|
||||
* record type monitored, or the generic
|
||||
* -netService:didUpdateRecordData:forRecordType: method.
|
||||
*/
|
||||
- (void) startMonitoringForRecordType: (NSString*)recordType;
|
||||
|
||||
/**
|
||||
* Stops monitoring for the specified record type.
|
||||
*/
|
||||
- (void) stopMonitoringForRecordType: (NSString*)recordType;
|
||||
|
||||
/**
|
||||
* Adds the service record for a service set up for publishing. The return value
|
||||
* of this method indicates whether the record was successfully added. The
|
||||
* record will only be published when -publish is called and it is thus
|
||||
* considered an error to call this method on a published service.
|
||||
*/
|
||||
- (BOOL) addServiceRecord;
|
||||
|
||||
/**
|
||||
* Sets <code>data</code> as the value of a resource record of the specified
|
||||
* <code>type</code>. The return value of this method indicates whether the
|
||||
* record was successfully added. The record will only be published when
|
||||
* -publish is called and it is thus considered an error to call this method on
|
||||
* a published service. (But it is possible to add a new record to a published
|
||||
* NSNetService by creating a new NSNetService instance with the same name,
|
||||
* type, domain and port parameters and publish only the new record in that
|
||||
* service.)
|
||||
*/
|
||||
- (BOOL) addRecordData: (NSData*)data
|
||||
forRecordType: (NSString*)type;
|
||||
|
||||
/**
|
||||
* Returns the record data for the specified record type. If there is only one
|
||||
* such record, the return value will be an NSData object, otherwise it will be
|
||||
* an NSArray.
|
||||
*/
|
||||
- (id) recordDataForRecordType: (NSString*)type;
|
||||
|
||||
/**
|
||||
* Returns the full name (including, name, type, and domain) of the service.
|
||||
*/
|
||||
- (NSString*) fullServiceName;
|
||||
@end
|
||||
#endif // GS_USE_AVAHI
|
|
@ -168,6 +168,9 @@
|
|||
/* Define to 1 if you have the <alloca.h> header file. */
|
||||
#undef HAVE_ALLOCA_H
|
||||
|
||||
/* Define to 1 if you have the <avahi-client/client.h> header file. */
|
||||
#undef HAVE_AVAHI_CLIENT_CLIENT_H
|
||||
|
||||
/* Define to 1 if you have the `backtrace' function. */
|
||||
#undef HAVE_BACKTRACE
|
||||
|
||||
|
|
|
@ -120,7 +120,8 @@ GS_EXPORT NSString * const NSNetServicesErrorDomain;
|
|||
* <p>
|
||||
* [NSNetService] lets you publish a network service in a domain using
|
||||
* multicast DNS. Additionally, it lets you resolve a network service that
|
||||
* was discovered by [NSNetServiceBrowser].
|
||||
* was discovered by [NSNetServiceBrowser]. This class is an abstract
|
||||
* superclass for concrete implementations of its functionality.
|
||||
* </p>
|
||||
*/
|
||||
|
||||
|
@ -128,9 +129,9 @@ GS_EXPORT NSString * const NSNetServicesErrorDomain;
|
|||
{
|
||||
#if GS_EXPOSE(NSNetService)
|
||||
@private
|
||||
void * _netService;
|
||||
id _delegate;
|
||||
void * _reserved;
|
||||
void *_netService;
|
||||
id _delegate;
|
||||
void *_reserved;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -151,9 +152,8 @@ GS_EXPORT NSString * const NSNetServicesErrorDomain;
|
|||
forMode: (NSString *) mode;
|
||||
|
||||
#if OS_API_VERSION(100500,GS_API_LATEST)
|
||||
/** Not implemented */
|
||||
- (NSInteger)port;
|
||||
/** Not implemented */
|
||||
|
||||
- (void) publishWithOptions: (NSNetServiceOptions)options;
|
||||
#endif
|
||||
|
||||
|
@ -207,15 +207,19 @@ GS_EXPORT NSString * const NSNetServicesErrorDomain;
|
|||
* <p>
|
||||
* Each [NSNetServiceBrowser] performs one search at a time. So in order
|
||||
* to perform multiple searches simultaneously, create multiple instances.
|
||||
* This class is an abstract superclass for concrete implementations of its
|
||||
* functionality.
|
||||
* </p>
|
||||
*/
|
||||
|
||||
@interface NSNetServiceBrowser : NSObject
|
||||
{
|
||||
#if GS_EXPOSE(NSNetServiceBrowser)
|
||||
@private
|
||||
void * _netServiceBrowser;
|
||||
id _delegate;
|
||||
void * _reserved;
|
||||
void *_netServiceBrowser;
|
||||
id _delegate;
|
||||
void *_reserved;
|
||||
#endif
|
||||
}
|
||||
|
||||
- (id) init;
|
||||
|
@ -450,6 +454,9 @@ GS_EXPORT NSString * const NSNetServicesErrorDomain;
|
|||
|
||||
@end
|
||||
|
||||
#if !NO_GNUSTEP && !defined(GNUSTEP_BASE_INTERNAL)
|
||||
#import <GNUstepBase/NSNetServices+GNUstepBase.h>
|
||||
#endif
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -127,6 +127,7 @@ NSDebug+GNUstepBase.h \
|
|||
NSFileHandle+GNUstepBase.h \
|
||||
NSLock+GNUstepBase.h \
|
||||
NSMutableString+GNUstepBase.h \
|
||||
NSNetServices+GNUstepBase.h \
|
||||
NSNumber+GNUstepBase.h \
|
||||
NSObject+GNUstepBase.h \
|
||||
NSProcessInfo+GNUstepBase.h \
|
||||
|
@ -286,11 +287,19 @@ BASE_MFILES += \
|
|||
GSFileHandle.m \
|
||||
NSMessagePort.m \
|
||||
NSMessagePortNameServer.m
|
||||
|
||||
ifeq ($(GNUSTEP_BASE_HAVE_MDNS), 1)
|
||||
BASE_MFILES += NSNetServices.m
|
||||
endif
|
||||
|
||||
ifeq ($(GNUSTEP_BASE_HAVE_MDNS), 1)
|
||||
BASE_MFILES += NSNetServices.m \
|
||||
GSMDNSNetServices.m
|
||||
endif
|
||||
|
||||
ifeq ($(GNUSTEP_BASE_HAVE_AVAHI), 1)
|
||||
BASE_MFILES += NSNetServices.m \
|
||||
GSAvahiNetService.m \
|
||||
GSAvahiNetServiceBrowser.m \
|
||||
GSAvahiClient.m \
|
||||
GSAvahiRunLoopIntegration.m
|
||||
endif
|
||||
|
||||
ifeq ($(WITH_FFI),libffi)
|
||||
|
|
63
Source/GSAvahiClient.h
Normal file
63
Source/GSAvahiClient.h
Normal file
|
@ -0,0 +1,63 @@
|
|||
/* Interface for avahi-client behaviour used by NSNetServices.
|
||||
Copyright (C) 2010 Free Software Foundation, Inc.
|
||||
|
||||
Written by: Niels Grewe <niels.grewe@halbordnung.de>
|
||||
Date: March 2010
|
||||
|
||||
This file is part of the GNUstep Base Library.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free
|
||||
Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
Boston, MA 02111 USA.
|
||||
*/
|
||||
|
||||
#import "GSAvahiRunLoopIntegration.h"
|
||||
|
||||
@interface GSAvahiClient: NSObject
|
||||
{
|
||||
id _delegate;
|
||||
GSAvahiRunLoopContext *ctx;
|
||||
void *_client;
|
||||
NSRecursiveLock *_lock;
|
||||
}
|
||||
|
||||
|
||||
+ (int)netServicesErrorForAvahiError: (int)errNo;
|
||||
|
||||
|
||||
- (void*)client;
|
||||
|
||||
- (id)initWithRunLoop: (NSRunLoop*)rl
|
||||
forMode: (NSString*)mode;
|
||||
|
||||
- (void)setupClientWithFlags: (int)flags
|
||||
andReportError: (int*)error;
|
||||
|
||||
- (void)setState: (int)theState
|
||||
forClient: (void*)cl;
|
||||
|
||||
- (void)scheduleInRunLoop: (NSRunLoop*)rl
|
||||
forMode: (NSString*)mode;
|
||||
|
||||
- (void)removeFromRunLoop: (NSRunLoop*)rl
|
||||
forMode: (NSString*)mode;
|
||||
|
||||
- (void)handleError: (int)errNo;
|
||||
|
||||
- (void)setDelegate: (id)delegate;
|
||||
|
||||
- (id)delegate;
|
||||
|
||||
- (NSDictionary*)errorDictWithErrorCode: (int) error;
|
||||
@end
|
296
Source/GSAvahiClient.m
Normal file
296
Source/GSAvahiClient.m
Normal file
|
@ -0,0 +1,296 @@
|
|||
/* Classes for avahi-client behaviour used by NSNetServices.
|
||||
Copyright (C) 2010 Free Software Foundation, Inc.
|
||||
|
||||
Written by: Niels Grewe <niels.grewe@halbordnung.de>
|
||||
Date: March 2010
|
||||
|
||||
This file is part of the GNUstep Base Library.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free
|
||||
Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
Boston, MA 02111 USA.
|
||||
*/
|
||||
|
||||
#import "GSAvahiClient.h"
|
||||
#import "Foundation/NSNetServices.h"
|
||||
#import "Foundation/NSDebug.h"
|
||||
#import "Foundation/NSDictionary.h"
|
||||
#import "Foundation/NSValue.h"
|
||||
|
||||
#include <avahi-client/client.h>
|
||||
#include <avahi-common/error.h>
|
||||
|
||||
static void
|
||||
GSAvahiClientState(AvahiClient *client, AvahiClientState state, void *userInfo)
|
||||
{
|
||||
[(GSAvahiClient*)userInfo setState: state
|
||||
forClient: client];
|
||||
}
|
||||
|
||||
@implementation GSAvahiClient
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
*/
|
||||
+ (int)netServicesErrorForAvahiError: (int)errorCode
|
||||
{
|
||||
switch(errorCode)
|
||||
{
|
||||
case AVAHI_ERR_INVALID_HOST_NAME:
|
||||
case AVAHI_ERR_INVALID_DOMAIN_NAME:
|
||||
case AVAHI_ERR_INVALID_TTL:
|
||||
case AVAHI_ERR_IS_PATTERN:
|
||||
case AVAHI_ERR_INVALID_RECORD:
|
||||
case AVAHI_ERR_INVALID_SERVICE_NAME:
|
||||
case AVAHI_ERR_INVALID_SERVICE_TYPE:
|
||||
case AVAHI_ERR_INVALID_PORT:
|
||||
case AVAHI_ERR_INVALID_KEY:
|
||||
case AVAHI_ERR_INVALID_ADDRESS:
|
||||
case AVAHI_ERR_INVALID_SERVICE_SUBTYPE:
|
||||
case AVAHI_ERR_BAD_STATE:
|
||||
case AVAHI_ERR_INVALID_FLAGS:
|
||||
return NSNetServicesBadArgumentError;
|
||||
case AVAHI_ERR_TIMEOUT:
|
||||
return NSNetServicesTimeoutError;
|
||||
case AVAHI_ERR_NO_NETWORK:
|
||||
case AVAHI_ERR_OS:
|
||||
case AVAHI_ERR_INVALID_CONFIG:
|
||||
case AVAHI_ERR_DBUS_ERROR:
|
||||
case AVAHI_ERR_DISCONNECTED:
|
||||
case AVAHI_ERR_NO_DAEMON:
|
||||
case AVAHI_ERR_NO_MEMORY:
|
||||
case AVAHI_ERR_INVALID_INTERFACE:
|
||||
case AVAHI_ERR_INVALID_PROTOCOL:
|
||||
case AVAHI_ERR_TOO_MANY_CLIENTS:
|
||||
case AVAHI_ERR_TOO_MANY_OBJECTS:
|
||||
case AVAHI_ERR_TOO_MANY_ENTRIES:
|
||||
case AVAHI_ERR_ACCESS_DENIED:
|
||||
return NSNetServicesUnknownError;
|
||||
case AVAHI_ERR_NOT_FOUND:
|
||||
return NSNetServicesNotFoundError;
|
||||
case AVAHI_ERR_INVALID_OPERATION:
|
||||
case AVAHI_ERR_INVALID_OBJECT:
|
||||
case AVAHI_ERR_VERSION_MISMATCH:
|
||||
return NSNetServicesInvalidError;
|
||||
case AVAHI_ERR_COLLISION:
|
||||
return NSNetServicesCollisionError;
|
||||
}
|
||||
return NSNetServicesUnknownError;
|
||||
}
|
||||
|
||||
|
||||
- (id) avahiClientInitWithRunLoop: (NSRunLoop*)rl
|
||||
forMode: (NSString*)mode
|
||||
{
|
||||
int avahiError = 0;
|
||||
|
||||
if ( nil == (self = [super init]))
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
_lock = [[NSRecursiveLock alloc] init];
|
||||
ctx = [[GSAvahiRunLoopContext alloc] initWithRunLoop: rl
|
||||
forMode: mode];
|
||||
|
||||
// NOTE: Not setting the AVAHI_CLIENT_NO_FAIL flag mimicks the behaviour of
|
||||
// the DNS-SD compatability code. We will set it subsequently if the avahi
|
||||
// server goes away while we are running.
|
||||
[self setupClientWithFlags: 0
|
||||
andReportError: &avahiError];
|
||||
if (avahiError)
|
||||
{
|
||||
[self handleError: avahiError];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (id) initWithRunLoop: (NSRunLoop*)rl
|
||||
forMode: (NSString*)mode
|
||||
{
|
||||
return [self avahiClientInitWithRunLoop: rl
|
||||
forMode: mode];
|
||||
}
|
||||
|
||||
- (id) avahiClientInit
|
||||
{
|
||||
return [self avahiClientInitWithRunLoop: [NSRunLoop currentRunLoop]
|
||||
forMode: NSDefaultRunLoopMode];
|
||||
}
|
||||
|
||||
- (id) init
|
||||
{
|
||||
return [self avahiClientInit];
|
||||
}
|
||||
|
||||
- (void*) client
|
||||
{
|
||||
return _client;
|
||||
}
|
||||
|
||||
- (void) freeClient
|
||||
{
|
||||
if (_client != NULL)
|
||||
{
|
||||
[_lock lock];
|
||||
if (_client != NULL)
|
||||
{
|
||||
avahi_client_free((AvahiClient*)_client);
|
||||
_client = NULL;
|
||||
}
|
||||
[_lock unlock];
|
||||
}
|
||||
}
|
||||
|
||||
- (void) setupClientWithFlags: (int)flags
|
||||
andReportError: (int*)errNo
|
||||
{
|
||||
if (errNo != NULL)
|
||||
{
|
||||
*errNo = 0;
|
||||
}
|
||||
if (_client == NULL)
|
||||
{
|
||||
[_lock lock];
|
||||
if (_client == NULL)
|
||||
{
|
||||
_client = (void*)avahi_client_new([ctx avahiPoll],
|
||||
(AvahiClientFlags)flags,
|
||||
GSAvahiClientState,
|
||||
(void*)self,
|
||||
errNo);
|
||||
}
|
||||
[_lock unlock];
|
||||
}
|
||||
}
|
||||
|
||||
- (id) delegate
|
||||
{
|
||||
return _delegate;
|
||||
}
|
||||
|
||||
- (void) setState: (int)theState
|
||||
forClient: (void*)cl
|
||||
{
|
||||
if (cl == _client)
|
||||
{
|
||||
NSLog(@"Client entered state: %d",theState);
|
||||
if (theState == AVAHI_CLIENT_FAILURE)
|
||||
{
|
||||
[self handleError: avahi_client_errno((AvahiClient*)cl)];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void) scheduleInRunLoop: (NSRunLoop*)rl
|
||||
forMode: (NSString*)mode
|
||||
{
|
||||
[ctx scheduleInRunLoop: rl forMode: mode];
|
||||
}
|
||||
|
||||
- (void) removeFromRunLoop: (NSRunLoop*)rl
|
||||
forMode: (NSString*)mode
|
||||
{
|
||||
[ctx removeFromRunLoop: rl forMode: mode];
|
||||
}
|
||||
|
||||
- (void) setDelegate: (id)aDelegate
|
||||
{
|
||||
_delegate = aDelegate;
|
||||
}
|
||||
|
||||
|
||||
- (void) avahiClientHandleError: (int)errNo
|
||||
{
|
||||
AvahiClientState state = 0;
|
||||
NSDebugLog(@"Error: %s", avahi_strerror(errNo));
|
||||
// Try to reconnect (in case the server did simply restart.)
|
||||
if (_client != NULL)
|
||||
{
|
||||
state = avahi_client_get_state((AvahiClient*)_client);
|
||||
}
|
||||
else
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (state == AVAHI_CLIENT_FAILURE)
|
||||
{
|
||||
[_lock lock];
|
||||
if (_client != NULL)
|
||||
{
|
||||
state = avahi_client_get_state((AvahiClient*)_client);
|
||||
}
|
||||
else
|
||||
{
|
||||
[_lock unlock];
|
||||
return;
|
||||
}
|
||||
if (state == AVAHI_CLIENT_FAILURE)
|
||||
{
|
||||
/* If the daemon failed, we need to remove timers and watchers
|
||||
* from the runloop, because the dbus internals underlying the
|
||||
* avahi-client api will have changed for the new connection to
|
||||
* the avahi-daemon:
|
||||
*/
|
||||
NSRunLoop *rl = [ctx runLoop];
|
||||
NSString *mode = [[ctx mode] retain];
|
||||
|
||||
[ctx removeFromRunLoop: rl
|
||||
forMode: mode];
|
||||
[self freeClient];
|
||||
[ctx scheduleInRunLoop: rl
|
||||
forMode: mode];
|
||||
[mode release];
|
||||
[self setupClientWithFlags: AVAHI_CLIENT_NO_FAIL
|
||||
andReportError: NULL];
|
||||
}
|
||||
[_lock unlock];
|
||||
}
|
||||
}
|
||||
|
||||
- (void) handleError: (int)errNo
|
||||
{
|
||||
[self avahiClientHandleError: errNo];
|
||||
}
|
||||
|
||||
- (NSDictionary*) errorDictWithErrorCode: (int)errorCode
|
||||
{
|
||||
NSMutableDictionary *dictionary = nil;
|
||||
int error = 0;
|
||||
|
||||
dictionary = [NSMutableDictionary dictionary];
|
||||
error = [[self class] netServicesErrorForAvahiError: errorCode];
|
||||
|
||||
[dictionary setObject: [NSNumber numberWithInt: error]
|
||||
forKey: NSNetServicesErrorCode];
|
||||
[dictionary setObject: self
|
||||
forKey: NSNetServicesErrorDomain];
|
||||
return dictionary; // autorelease'd
|
||||
}
|
||||
|
||||
- (void) avahiClientDealloc
|
||||
{
|
||||
[self freeClient];
|
||||
[ctx release];
|
||||
[_lock release];
|
||||
}
|
||||
|
||||
- (void) dealloc
|
||||
{
|
||||
[self avahiClientDealloc];
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
@end
|
1959
Source/GSAvahiNetService.m
Normal file
1959
Source/GSAvahiNetService.m
Normal file
File diff suppressed because it is too large
Load diff
507
Source/GSAvahiNetServiceBrowser.m
Normal file
507
Source/GSAvahiNetServiceBrowser.m
Normal file
|
@ -0,0 +1,507 @@
|
|||
/* Concrete NSNetServiceBrowser subclass using the avahi API.
|
||||
Copyright (C) 2010 Free Software Foundation, Inc.
|
||||
|
||||
Written by: Niels Grewe <niels.grewe@halbordnung.de>
|
||||
Date: March 2010
|
||||
|
||||
This file is part of the GNUstep Base Library.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free
|
||||
Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
Boston, MA 02111 USA.
|
||||
*/
|
||||
|
||||
#import "GSNetServices.h"
|
||||
#import "GSAvahiClient.h"
|
||||
#import "Foundation/NSNetServices.h"
|
||||
#import "GNUstepBase/NSNetServices+GNUstepBase.h"
|
||||
#import "Foundation/NSArray.h"
|
||||
#import "Foundation/NSDebug.h"
|
||||
#import "Foundation/NSLock.h"
|
||||
#import "Foundation/NSRunLoop.h"
|
||||
#import "Foundation/NSString.h"
|
||||
#import "GNUstepBase/GSObjCRuntime.h"
|
||||
#include <avahi-client/lookup.h>
|
||||
|
||||
#define SERVICE_KEY(name, type, domain, iface, proto) [NSString stringWithFormat: @"%@.%@.%@%d:%d", name, type, domain, iface, proto]
|
||||
|
||||
|
||||
// Private Methods:
|
||||
@interface GSAvahiNetServiceBrowser (GSAvahiNetServiceBrowserPrivate)
|
||||
- (void) stopWithError: (BOOL)yesno;
|
||||
- (BOOL) hasFirstEvent;
|
||||
- (void) setHasFirstEvent: (BOOL)yesno;
|
||||
- (void) setService: (GSAvahiNetService*)service
|
||||
forKey: (NSString*)key;
|
||||
- (void) removeServiceForKey: (NSString*)key;
|
||||
- (GSAvahiNetService*) serviceForKey: (NSString*)key;
|
||||
|
||||
// GSAvahiClient behaviour methods:
|
||||
|
||||
- (id) avahiClientInitWithRunLoop: (NSRunLoop*)loop
|
||||
forMode: (NSString*)mode;
|
||||
|
||||
- (void) avahiClientHandleError: (int)error;
|
||||
|
||||
- (void) avahiClientDealloc;
|
||||
|
||||
- (NSDictionary*) errorDictWithErrorCode: (int)error;
|
||||
|
||||
- (void) handleError: (int)error;
|
||||
|
||||
@end
|
||||
|
||||
NSString*
|
||||
GSNetServiceDotTerminatedNSStringFromString(const char *domain)
|
||||
{
|
||||
if (domain != NULL)
|
||||
{
|
||||
NSString *theDomain = [NSString stringWithUTF8String: domain];
|
||||
//Add a trailing dot if necessary:
|
||||
if ((unichar)'.'
|
||||
!= [theDomain characterAtIndex: ([theDomain length] - 1)])
|
||||
{
|
||||
theDomain = [theDomain stringByAppendingString: @"."];
|
||||
}
|
||||
return theDomain;
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
static void
|
||||
GSAvahiDomainBrowserEvent(AvahiDomainBrowser *db,
|
||||
AvahiIfIndex ifIndex,
|
||||
AvahiProtocol protocol,
|
||||
AvahiBrowserEvent event,
|
||||
const char *domain,
|
||||
AvahiLookupResultFlags flags,
|
||||
void *userInfo)
|
||||
{
|
||||
GSAvahiNetServiceBrowser *browser = nil;
|
||||
NSString *theDomain = nil;
|
||||
|
||||
if (NULL == db)
|
||||
{
|
||||
NSDebugLog(@"NULL pointer to AvahiDomainBrowser.");
|
||||
return;
|
||||
}
|
||||
if (NULL == userInfo)
|
||||
{
|
||||
NSDebugLog(@"NULL pointer to NSNetServiceBrowser.");
|
||||
return;
|
||||
}
|
||||
browser = (GSAvahiNetServiceBrowser*)userInfo;
|
||||
theDomain = GSNetServiceDotTerminatedNSStringFromString(domain);
|
||||
switch (event)
|
||||
{
|
||||
case AVAHI_BROWSER_NEW:
|
||||
if (![browser hasFirstEvent])
|
||||
{
|
||||
[browser netServiceBrowserWillSearch:
|
||||
(NSNetServiceBrowser*)browser];
|
||||
[browser setHasFirstEvent: YES];
|
||||
}
|
||||
[browser netServiceBrowser: (NSNetServiceBrowser*)browser
|
||||
didFindDomain: theDomain
|
||||
moreComing: NO];
|
||||
break;
|
||||
|
||||
case AVAHI_BROWSER_REMOVE:
|
||||
[browser netServiceBrowser: (NSNetServiceBrowser*)browser
|
||||
didRemoveDomain: theDomain
|
||||
moreComing: NO];
|
||||
break;
|
||||
|
||||
case AVAHI_BROWSER_FAILURE:
|
||||
[browser handleError:
|
||||
avahi_client_errno(avahi_domain_browser_get_client(db))];
|
||||
break;
|
||||
|
||||
case AVAHI_BROWSER_CACHE_EXHAUSTED: // Not interesting
|
||||
case AVAHI_BROWSER_ALL_FOR_NOW:
|
||||
// This is useless, it always happens one second after firing the query.
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
GSAvahiServiceBrowserEvent(
|
||||
AvahiServiceBrowser *sb,
|
||||
AvahiIfIndex ifIndex,
|
||||
AvahiProtocol proto,
|
||||
AvahiBrowserEvent event,
|
||||
const char *name,
|
||||
const char *type,
|
||||
const char *domain,
|
||||
AvahiLookupResultFlags flags,
|
||||
void *userInfo)
|
||||
{
|
||||
GSAvahiNetServiceBrowser* browser = (GSAvahiNetServiceBrowser*)userInfo;
|
||||
NSString *theName = NSStringIfNotNull(name);
|
||||
NSString *theType = NSStringIfNotNull(type);
|
||||
NSString *theDomain = GSNetServiceDotTerminatedNSStringFromString(domain);
|
||||
NSString *serviceKey;
|
||||
|
||||
/* Some services might appear on different interface/protocol combinations
|
||||
* and we will get back one event for each of them, so we need a more
|
||||
* specific key to store the service:
|
||||
*/
|
||||
serviceKey = SERVICE_KEY(theName, theType,theDomain, ifIndex, proto);
|
||||
|
||||
if (NULL == sb)
|
||||
{
|
||||
NSDebugLog(@"NULL pointer to AvahiServiceBrowser.");
|
||||
return;
|
||||
}
|
||||
if (NULL == userInfo)
|
||||
{
|
||||
NSDebugLog(@"NULL pointer to NSNetServiceBrowser.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (event != AVAHI_BROWSER_FAILURE)
|
||||
{
|
||||
if (![browser hasFirstEvent])
|
||||
{
|
||||
[browser netServiceBrowserWillSearch: (NSNetServiceBrowser*)browser];
|
||||
[browser setHasFirstEvent: YES];
|
||||
}
|
||||
}
|
||||
|
||||
switch (event)
|
||||
{
|
||||
case AVAHI_BROWSER_NEW:
|
||||
if ((theName && theDomain) && theType)
|
||||
{
|
||||
NSNetService *service = [[[GSAvahiNetService alloc]
|
||||
initWithDomain: theDomain
|
||||
type: theType
|
||||
name: theName
|
||||
avahiIfIndex: ifIndex
|
||||
avahiProtocol: proto] autorelease];
|
||||
[browser setService: (GSAvahiNetService*)service
|
||||
forKey: serviceKey];
|
||||
[browser netServiceBrowser: (NSNetServiceBrowser*)browser
|
||||
didFindService: service
|
||||
moreComing: NO];
|
||||
}
|
||||
break;
|
||||
|
||||
case AVAHI_BROWSER_REMOVE:
|
||||
if ((theName && theDomain) && theType)
|
||||
{
|
||||
NSNetService *service;
|
||||
|
||||
service = (NSNetService*)[browser serviceForKey: serviceKey];
|
||||
[browser netServiceBrowser: (NSNetServiceBrowser*)browser
|
||||
didRemoveService: service
|
||||
moreComing: NO];
|
||||
[browser removeServiceForKey: serviceKey];
|
||||
}
|
||||
break;
|
||||
|
||||
case AVAHI_BROWSER_FAILURE:
|
||||
[browser handleError:
|
||||
avahi_client_errno(avahi_service_browser_get_client(sb))];
|
||||
break;
|
||||
|
||||
case AVAHI_BROWSER_CACHE_EXHAUSTED: // Not interesting
|
||||
case AVAHI_BROWSER_ALL_FOR_NOW:
|
||||
// This is useless, it always happens one second after firing the query.
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@implementation GSAvahiNetServiceBrowser
|
||||
|
||||
+ (void) initialize
|
||||
{
|
||||
if (self == [GSAvahiNetServiceBrowser class])
|
||||
{
|
||||
GSObjCAddClassBehavior(self, [GSAvahiClient class]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
- (id) initWithRunLoop: (NSRunLoop*)rl
|
||||
forMode: (NSString*)mode
|
||||
{
|
||||
if (nil == (self = [self avahiClientInitWithRunLoop: rl
|
||||
forMode: mode]))
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
_services = [[NSMutableDictionary alloc] init];
|
||||
return self;
|
||||
}
|
||||
|
||||
- (id) init
|
||||
{
|
||||
return [self initWithRunLoop: [NSRunLoop currentRunLoop]
|
||||
forMode: NSDefaultRunLoopMode];
|
||||
}
|
||||
|
||||
- (void) setService: (GSAvahiNetService*)service
|
||||
forKey: (NSString*)key
|
||||
{
|
||||
[_services setObject: service
|
||||
forKey: key];
|
||||
}
|
||||
|
||||
- (void) removeServiceForKey: (NSString*)key
|
||||
{
|
||||
[_services removeObjectForKey: key];
|
||||
}
|
||||
|
||||
- (GSAvahiNetService*) serviceForKey: (NSString*)key
|
||||
{
|
||||
return [_services objectForKey: key];
|
||||
}
|
||||
|
||||
- (void) handleError: (int)err
|
||||
{
|
||||
[self netServiceBrowser: self
|
||||
didNotSearch: [self errorDictWithErrorCode: err]];
|
||||
[self stopWithError: YES];
|
||||
[self avahiClientHandleError: err];
|
||||
}
|
||||
|
||||
- (BOOL) canSearch
|
||||
{
|
||||
int err = 0;
|
||||
|
||||
if ([self delegate] == nil)
|
||||
{
|
||||
err = NSNetServicesInvalidError;
|
||||
}
|
||||
else if (_browser != NULL)
|
||||
{
|
||||
err = NSNetServicesActivityInProgress;
|
||||
}
|
||||
|
||||
if (!err)
|
||||
{
|
||||
/* Check whether the avahi-client is in a working state (the caller
|
||||
* might be trying to search again after a failure event).
|
||||
*/
|
||||
switch (avahi_client_get_state((AvahiClient*)_client))
|
||||
{
|
||||
case AVAHI_CLIENT_FAILURE:
|
||||
err = avahi_client_errno((AvahiClient*)_client);
|
||||
break;
|
||||
|
||||
case AVAHI_CLIENT_CONNECTING:
|
||||
case AVAHI_CLIENT_S_REGISTERING:
|
||||
err = NSNetServicesActivityInProgress;
|
||||
break;
|
||||
|
||||
case AVAHI_CLIENT_S_COLLISION:
|
||||
err = NSNetServicesCollisionError;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (err)
|
||||
{
|
||||
[self netServiceBrowser: (NSNetServiceBrowser*)self
|
||||
didNotSearch: [self errorDictWithErrorCode: err]];
|
||||
return NO;
|
||||
}
|
||||
|
||||
{
|
||||
NSRunLoop *rl = [ctx runLoop];
|
||||
NSString *mode = [ctx mode];
|
||||
BOOL schedule = ((rl == nil) || (mode == nil));
|
||||
|
||||
if (schedule)
|
||||
{
|
||||
if (rl == nil)
|
||||
{
|
||||
rl = [NSRunLoop currentRunLoop];
|
||||
}
|
||||
if (mode == nil)
|
||||
{
|
||||
mode = NSDefaultRunLoopMode;
|
||||
}
|
||||
[self scheduleInRunLoop: rl
|
||||
forMode: mode];
|
||||
}
|
||||
}
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (void) searchForDomains: (AvahiDomainBrowserType)domainType
|
||||
{
|
||||
[_lock lock];
|
||||
if ([self canSearch])
|
||||
{
|
||||
_browser = (void*)avahi_domain_browser_new((AvahiClient*)_client,
|
||||
AVAHI_IF_UNSPEC,
|
||||
AVAHI_PROTO_UNSPEC,
|
||||
"local",
|
||||
domainType,
|
||||
0,
|
||||
GSAvahiDomainBrowserEvent,
|
||||
(void*)self);
|
||||
if (NULL == _browser)
|
||||
{
|
||||
[self handleError: avahi_client_errno((AvahiClient*)_client)];
|
||||
}
|
||||
else
|
||||
{
|
||||
_type = GSAvahiDomainBrowser;
|
||||
}
|
||||
/* NOTE: -netServiceBrowserWillSearch: will be called from
|
||||
* GSAvahiDomainBrowserEvent().
|
||||
*/
|
||||
}
|
||||
[_lock unlock];
|
||||
}
|
||||
|
||||
- (void) searchForDefaultRegistrationDomain
|
||||
{
|
||||
[self searchForDomains: AVAHI_DOMAIN_BROWSER_REGISTER_DEFAULT];
|
||||
}
|
||||
|
||||
- (void) searchForDefaultBrowseDomain
|
||||
{
|
||||
[self searchForDomains: AVAHI_DOMAIN_BROWSER_BROWSE_DEFAULT];
|
||||
}
|
||||
|
||||
- (void) searchForAllDomains
|
||||
{
|
||||
/* The dns-sd compatibility layer of avahi assumes the browsable domains
|
||||
* to be a superset of the registration domains, so we take an easy
|
||||
* shortcut here (also, Apple has deprecated it in Mac OS 10.4
|
||||
*/
|
||||
[self searchForBrowsableDomains];
|
||||
}
|
||||
|
||||
- (void) searchForBrowsableDomains
|
||||
{
|
||||
[self searchForDomains: AVAHI_DOMAIN_BROWSER_BROWSE];
|
||||
}
|
||||
|
||||
- (void) searchForRegistrationDomains
|
||||
{
|
||||
[self searchForDomains: AVAHI_DOMAIN_BROWSER_REGISTER];
|
||||
}
|
||||
|
||||
- (void) searchForServicesOfType: (NSString *)serviceType
|
||||
inDomain: (NSString *)domainName
|
||||
{
|
||||
const char* domain;
|
||||
|
||||
if (![domainName isEqualToString: @""])
|
||||
{
|
||||
domain = [domainName UTF8String];
|
||||
}
|
||||
else
|
||||
{
|
||||
domain = NULL;
|
||||
}
|
||||
[_lock lock];
|
||||
if ([self canSearch])
|
||||
{
|
||||
_browser = (void*)avahi_service_browser_new((AvahiClient*)_client,
|
||||
AVAHI_IF_UNSPEC,
|
||||
AVAHI_PROTO_UNSPEC,
|
||||
[serviceType UTF8String],
|
||||
domain,
|
||||
0,
|
||||
GSAvahiServiceBrowserEvent,
|
||||
(void*)self);
|
||||
if (NULL == _browser)
|
||||
{
|
||||
[self handleError: avahi_client_errno((AvahiClient*)_client)];
|
||||
}
|
||||
else
|
||||
{
|
||||
_type = GSAvahiServiceBrowser;
|
||||
}
|
||||
/* NOTE: -netServiceBrowserWillSearch: will be called from
|
||||
* GSAvahiServiceBrowserEvent().
|
||||
*/
|
||||
}
|
||||
[_lock unlock];
|
||||
}
|
||||
|
||||
- (BOOL) hasFirstEvent
|
||||
{
|
||||
return _hasFirstEvent;
|
||||
}
|
||||
|
||||
- (void) setHasFirstEvent: (BOOL)yesno
|
||||
{
|
||||
_hasFirstEvent = yesno;
|
||||
}
|
||||
|
||||
- (void) stopWithError: (BOOL)hadError
|
||||
{
|
||||
[_lock lock];
|
||||
if (_browser != NULL)
|
||||
{
|
||||
/* We can't recover if the type is wrong and we don't want to
|
||||
* leak random memory.
|
||||
*/
|
||||
NSAssert((_type < GSAvahiBrowserMax) && (_type != GSAvahiUnknownBrowser),
|
||||
NSInternalInconsistencyException);
|
||||
[self setHasFirstEvent: NO];
|
||||
switch (_type)
|
||||
{
|
||||
case GSAvahiDomainBrowser:
|
||||
avahi_domain_browser_free((AvahiDomainBrowser*)_browser);
|
||||
break;
|
||||
|
||||
case GSAvahiServiceBrowser:
|
||||
avahi_service_browser_free((AvahiServiceBrowser*)_browser);
|
||||
break;
|
||||
|
||||
case GSAvahiUnknownBrowser:
|
||||
case GSAvahiBrowserMax:
|
||||
break;
|
||||
}
|
||||
_browser = NULL;
|
||||
}
|
||||
_type = GSAvahiUnknownBrowser;
|
||||
[_services removeAllObjects];
|
||||
|
||||
if (!hadError)
|
||||
{
|
||||
[self netServiceBrowserDidStopSearch: self];
|
||||
}
|
||||
[_lock unlock];
|
||||
}
|
||||
|
||||
- (void) stop
|
||||
{
|
||||
[self stopWithError: NO];
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
if (_browser != NULL)
|
||||
{
|
||||
[self stop];
|
||||
}
|
||||
[self setDelegate: nil];
|
||||
[_services release];
|
||||
[self avahiClientDealloc];
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
@end
|
68
Source/GSAvahiRunLoopIntegration.h
Normal file
68
Source/GSAvahiRunLoopIntegration.h
Normal file
|
@ -0,0 +1,68 @@
|
|||
/* Interface for integration of avahi-client into NSRunLoop.
|
||||
Copyright (C) 2010 Free Software Foundation, Inc.
|
||||
|
||||
Written by: Niels Grewe <niels.grewe@halbordnung.de>
|
||||
Date: March 2010
|
||||
|
||||
This file is part of the GNUstep Base Library.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free
|
||||
Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
Boston, MA 02111 USA.
|
||||
*/
|
||||
|
||||
#import "Foundation/NSObject.h"
|
||||
#import "Foundation/NSRunLoop.h"
|
||||
#import "Foundation/NSTimer.h"
|
||||
#import "Foundation/NSString.h"
|
||||
#import "Foundation/NSArray.h"
|
||||
#import "Foundation/NSException.h"
|
||||
#import "Foundation/NSLock.h"
|
||||
#import "GSFastEnumeration.h"
|
||||
#include <avahi-common/watch.h>
|
||||
|
||||
@class GSAvahiWatcher,GSAvahiTimer;
|
||||
|
||||
/**
|
||||
* The GSAvahiRunLoopContext provides hooks for Avahi to hook into NSRunLoop.
|
||||
* This provides relatively hassle-free event handling of all GSAvahiClient
|
||||
* subclasses.
|
||||
*/
|
||||
@interface GSAvahiRunLoopContext: NSObject
|
||||
{
|
||||
NSRunLoop *runLoop;
|
||||
NSString *mode;
|
||||
AvahiPoll *poll;
|
||||
NSMutableArray *children;
|
||||
NSLock *lock;
|
||||
}
|
||||
- (id)initWithRunLoop: (NSRunLoop*)runLoop
|
||||
forMode: (NSString*)runLoopMode;
|
||||
- (NSRunLoop*)runLoop;
|
||||
- (NSString*)mode;
|
||||
- (GSAvahiWatcher*)avahiWatcherWithCallback: (AvahiWatchCallback)callback
|
||||
onEvent: (AvahiWatchEvent)someEvents
|
||||
forFileDescriptor: (NSInteger)fd
|
||||
userData: (void*)userData;
|
||||
- (GSAvahiTimer*)avahiTimerWithCallback: (AvahiTimeoutCallback)callback
|
||||
withTimeval: (const struct timeval*)tv
|
||||
userData: (void*)userData;
|
||||
- (void)removeWatcher: (GSAvahiWatcher*)aw;
|
||||
- (void)removeTimeout: (GSAvahiTimer*)at;
|
||||
- (void)removeFromRunLoop: (NSRunLoop*)rl
|
||||
forMode: (NSString*)mode;
|
||||
- (void)scheduleInRunLoop: (NSRunLoop*)rl
|
||||
forMode: (NSString*)mode;
|
||||
- (const AvahiPoll*)avahiPoll;
|
||||
@end
|
557
Source/GSAvahiRunLoopIntegration.m
Normal file
557
Source/GSAvahiRunLoopIntegration.m
Normal file
|
@ -0,0 +1,557 @@
|
|||
/* Classes for integration of avahi-client into NSRunLoop.
|
||||
Copyright (C) 2010 Free Software Foundation, Inc.
|
||||
|
||||
Written by: Niels Grewe <niels.grewe@halbordnung.de>
|
||||
Date: March 2010
|
||||
|
||||
This file is part of the GNUstep Base Library.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free
|
||||
Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
Boston, MA 02111 USA.
|
||||
*/
|
||||
|
||||
#import "GSAvahiRunLoopIntegration.h"
|
||||
|
||||
#define CTX(x) GSAvahiRunLoopContext *ctx = (GSAvahiRunLoopContext*)x
|
||||
@interface GSAvahiWatcher: NSObject <RunLoopEvents>
|
||||
{
|
||||
//The callback to call for avahi.
|
||||
AvahiWatchCallback callback;
|
||||
BOOL callbackInProgress;
|
||||
AvahiWatchEvent oldEvents;
|
||||
AvahiWatchEvent lastEvent;
|
||||
int fileDesc;
|
||||
GSAvahiRunLoopContext *ctx;
|
||||
void *userData;
|
||||
}
|
||||
@end
|
||||
|
||||
@implementation GSAvahiWatcher
|
||||
- (void)listenForEvents: (AvahiWatchEvent)events
|
||||
saveState: (BOOL)saveState
|
||||
{
|
||||
/* FIXME: NSRunLoop doesn't expose equivalents for POLLERR and POLLHUP but
|
||||
* Avahi doesn't seem to strictly require them (their Qt API doesn't handle
|
||||
* them either). Still, it would be nice to handle AVAHI_WATCH_(ERR|HUP)
|
||||
* here.
|
||||
*/
|
||||
|
||||
// Remove old events:
|
||||
if (!(events & AVAHI_WATCH_IN)
|
||||
&& (oldEvents & AVAHI_WATCH_IN))
|
||||
{
|
||||
[[ctx runLoop] removeEvent: (void*)(intptr_t)fileDesc
|
||||
type: ET_RDESC
|
||||
forMode: [ctx mode]
|
||||
all: NO];
|
||||
}
|
||||
if (!(events & AVAHI_WATCH_OUT)
|
||||
&& (oldEvents & AVAHI_WATCH_OUT))
|
||||
{
|
||||
[[ctx runLoop] removeEvent: (void*)(intptr_t)fileDesc
|
||||
type: ET_WDESC
|
||||
forMode: [ctx mode]
|
||||
all: NO];
|
||||
}
|
||||
|
||||
// Remember event state:
|
||||
if (saveState)
|
||||
{
|
||||
oldEvents = events;
|
||||
}
|
||||
|
||||
// Dispatch new events to the runLoop:
|
||||
if (events & AVAHI_WATCH_IN)
|
||||
{
|
||||
[[ctx runLoop] addEvent: (void*)(intptr_t)fileDesc
|
||||
type: ET_RDESC
|
||||
watcher: self
|
||||
forMode: [ctx mode]];
|
||||
}
|
||||
if (events & AVAHI_WATCH_OUT)
|
||||
{
|
||||
[[ctx runLoop] addEvent: (void*)(intptr_t)fileDesc
|
||||
type: ET_WDESC
|
||||
watcher: self
|
||||
forMode: [ctx mode]];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)listenForEvents: (AvahiWatchEvent)events
|
||||
{
|
||||
[self listenForEvents: events
|
||||
saveState: YES];
|
||||
}
|
||||
|
||||
- (void)unschedule
|
||||
{
|
||||
// Don't save the new event state (i.e. no events) if we are unscheduling
|
||||
// the watcher. We might want to reschedule it with the prior state.
|
||||
[self listenForEvents: (AvahiWatchEvent)0
|
||||
saveState: NO];
|
||||
}
|
||||
|
||||
- (void)reschedule
|
||||
{
|
||||
[self listenForEvents: oldEvents
|
||||
saveState: NO];
|
||||
}
|
||||
|
||||
- (id)initWithCallback: (AvahiWatchCallback)cback
|
||||
andContext: (GSAvahiRunLoopContext*)aCtx
|
||||
onEvent: (AvahiWatchEvent)someEvents
|
||||
forFd: (int)fd
|
||||
userData: (void*)ud
|
||||
{
|
||||
if (nil == (self = [super init]))
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
fileDesc = fd;
|
||||
// The context retains its watchers and timers:
|
||||
ctx = aCtx;
|
||||
callback = cback;
|
||||
userData = ud;
|
||||
[self listenForEvents: someEvents];
|
||||
return self;
|
||||
}
|
||||
|
||||
- (AvahiWatchEvent)getEvents
|
||||
{
|
||||
if (callbackInProgress)
|
||||
{
|
||||
return (AvahiWatchEvent)0;
|
||||
}
|
||||
return lastEvent;
|
||||
}
|
||||
|
||||
- (void)removeFromContext
|
||||
{
|
||||
[self unschedule];
|
||||
[ctx removeWatcher: self];
|
||||
// Don't reference the context anymore, since it won't have any chance of
|
||||
// notifying us if it goes away.
|
||||
ctx = nil;
|
||||
}
|
||||
|
||||
- (void)receivedEvent: (void*)data
|
||||
type: (RunLoopEventType)type
|
||||
extra: (void*)extra
|
||||
forMode: (NSString*)mode
|
||||
{
|
||||
int fd = (int)(intptr_t)data;
|
||||
if(fileDesc != fd)
|
||||
{
|
||||
//Not good
|
||||
return;
|
||||
}
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case ET_RDESC:
|
||||
lastEvent = AVAHI_WATCH_IN;
|
||||
// Remove the corresponding bit from the event mask:
|
||||
oldEvents = (oldEvents ^ AVAHI_WATCH_IN);
|
||||
break;
|
||||
case ET_WDESC:
|
||||
lastEvent = AVAHI_WATCH_OUT;
|
||||
// Remove the corresponding bit from the event mask:
|
||||
oldEvents = (oldEvents ^ AVAHI_WATCH_OUT);
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
/* FIXME: NSRunLoop doesn't expose equivalents for POLLERR and POLLHUP but
|
||||
* Avahi doesn't seem to strictly require them (their Qt API doesn't handle
|
||||
* them either).
|
||||
*/
|
||||
callbackInProgress = YES;
|
||||
callback((AvahiWatch*)self, fd, lastEvent, userData);
|
||||
callbackInProgress = NO;
|
||||
}
|
||||
|
||||
- (void)setContext: (GSAvahiRunLoopContext*)aCtxt
|
||||
{
|
||||
ctx = aCtxt;
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
// Remove all leftover event-handlers from the runLoop:
|
||||
[self listenForEvents: (AvahiWatchEvent)0];
|
||||
[super dealloc];
|
||||
}
|
||||
@end
|
||||
|
||||
|
||||
@interface GSAvahiTimer: NSObject
|
||||
{
|
||||
GSAvahiRunLoopContext *ctx;
|
||||
AvahiTimeoutCallback callback;
|
||||
NSTimer *timer;
|
||||
NSDate *fireDate;
|
||||
void *userData;
|
||||
}
|
||||
@end
|
||||
|
||||
@implementation GSAvahiTimer
|
||||
- (void)didTimeout: (NSTimer*)timer
|
||||
{
|
||||
callback((AvahiTimeout*)self, userData);
|
||||
}
|
||||
|
||||
- (void)setTimerToInterval: (NSTimeInterval)interval
|
||||
{
|
||||
// Invalidate the old timer;
|
||||
if (timer != nil)
|
||||
{
|
||||
[timer invalidate];
|
||||
timer = nil;
|
||||
}
|
||||
|
||||
timer = [[NSTimer timerWithTimeInterval: interval
|
||||
target: self
|
||||
selector: @selector(didTimeout:)
|
||||
userInfo: nil
|
||||
repeats: NO] retain];
|
||||
[[ctx runLoop] addTimer: timer
|
||||
forMode: [ctx mode]];
|
||||
}
|
||||
|
||||
- (void)setTimerToTimeval: (const struct timeval*)tv
|
||||
{
|
||||
// Construct a NSTimeInterval for the timer:
|
||||
NSTimeInterval interval = 0;
|
||||
|
||||
if (NULL != tv)
|
||||
{
|
||||
interval = (NSTimeInterval)tv->tv_sec;
|
||||
interval += (NSTimeInterval)(tv->tv_usec / 1000000.0);
|
||||
}
|
||||
[self setTimerToInterval: interval];
|
||||
}
|
||||
- (id)initWithCallback: (AvahiTimeoutCallback)aCallback
|
||||
andContext: (GSAvahiRunLoopContext*)aCtx
|
||||
forTimeval: (const struct timeval*)tv
|
||||
userData: (void*)ud
|
||||
{
|
||||
if (nil == (self = [super init]))
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
// The context retains its watchers and timeouts:
|
||||
ctx = aCtx;
|
||||
callback = aCallback;
|
||||
userData = ud;
|
||||
[self setTimerToTimeval: tv];
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)unschedule
|
||||
{
|
||||
if ([timer isValid])
|
||||
{
|
||||
[timer invalidate];
|
||||
fireDate = [[timer fireDate] retain];
|
||||
timer = nil;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)removeFromContext
|
||||
{
|
||||
[self unschedule];
|
||||
[ctx removeTimeout: self];
|
||||
ctx = nil;
|
||||
}
|
||||
|
||||
- (void)setContext: (GSAvahiRunLoopContext*)aCtxt
|
||||
{
|
||||
ctx = aCtxt;
|
||||
}
|
||||
|
||||
- (void)reschedule
|
||||
{
|
||||
// Only reschedule if fireDate has been set, otherwise the Avahi layer will
|
||||
// schedule a new timer.
|
||||
if (nil != fireDate)
|
||||
{
|
||||
NSTimeInterval interval = [fireDate timeIntervalSinceNow];
|
||||
[self setTimerToInterval: MAX(0.1,interval)];
|
||||
[fireDate release];
|
||||
fireDate = nil;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
if (nil != timer)
|
||||
{
|
||||
[timer invalidate];
|
||||
}
|
||||
[super dealloc];
|
||||
}
|
||||
@end
|
||||
|
||||
static AvahiWatch*
|
||||
GSAvahiWatchNew(const AvahiPoll *api, int fd, AvahiWatchEvent
|
||||
event, AvahiWatchCallback callback, void *userData)
|
||||
{
|
||||
// NOTE: strangly enough, the userData parameter is not the userdata we
|
||||
// passed to the poll structure (it is somehow related to the dbus
|
||||
// internals).
|
||||
CTX(api->userdata);
|
||||
GSAvahiWatcher *w = [ctx avahiWatcherWithCallback: callback
|
||||
onEvent: event
|
||||
forFileDescriptor: fd
|
||||
userData: userData];
|
||||
// NOTE: avahi defines AvahiWatch as a struct, since we only pass around
|
||||
// pointers to those, we can just cast the pointer to our watcher object to
|
||||
// AvahiWatch*.
|
||||
return (AvahiWatch*)w;
|
||||
}
|
||||
|
||||
static void
|
||||
GSAvahiWatchUpdate(AvahiWatch *watch, AvahiWatchEvent event)
|
||||
{
|
||||
[(GSAvahiWatcher*)watch listenForEvents: event];
|
||||
}
|
||||
|
||||
static AvahiWatchEvent
|
||||
GSAvahiWatchGetEvents(AvahiWatch *watch)
|
||||
{
|
||||
return [(GSAvahiWatcher*)watch getEvents];
|
||||
}
|
||||
|
||||
static void
|
||||
GSAvahiWatchFree(AvahiWatch *watch)
|
||||
{
|
||||
[(GSAvahiWatcher*)watch removeFromContext];
|
||||
}
|
||||
|
||||
static AvahiTimeout*
|
||||
GSAvahiTimeoutNew(const AvahiPoll *api,
|
||||
const struct timeval *tv, AvahiTimeoutCallback callback, void *userData)
|
||||
{
|
||||
// NOTE: strangly enough, the userData parameter is not the userdata we
|
||||
// passed to the poll structure (it is somehow related to the dbus
|
||||
// internals.)
|
||||
CTX(api->userdata);
|
||||
GSAvahiTimer *t = [ctx avahiTimerWithCallback: callback
|
||||
withTimeval: tv
|
||||
userData: userData];
|
||||
// NOTE: Cf. GSAvahiWatchNew().
|
||||
return (AvahiTimeout*)t;
|
||||
}
|
||||
|
||||
static void
|
||||
GSAvahiTimeoutUpdate(AvahiTimeout* timeout,
|
||||
const struct timeval *tv)
|
||||
{
|
||||
[(GSAvahiTimer*)timeout setTimerToTimeval: tv];
|
||||
}
|
||||
|
||||
static void
|
||||
GSAvahiTimeoutFree(AvahiTimeout* timeout)
|
||||
{
|
||||
[(GSAvahiTimer*)timeout removeFromContext];
|
||||
}
|
||||
|
||||
@implementation GSAvahiRunLoopContext
|
||||
- (id)initWithRunLoop: (NSRunLoop*)rl
|
||||
forMode: (NSString*)aMode
|
||||
{
|
||||
if (nil == (self = [super init]))
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
lock = [[NSLock alloc] init];
|
||||
[lock setName: @"GSAvahiRunLoopContextLock"];
|
||||
poll = malloc(sizeof(AvahiPoll));
|
||||
NSAssert(poll, @"Could not allocate avahi polling structure.");
|
||||
poll->userdata = (void*)self; //userInfo
|
||||
poll->watch_new = GSAvahiWatchNew; //create a new GSAvahiWatcher
|
||||
poll->watch_update = GSAvahiWatchUpdate; //update the watcher
|
||||
poll->watch_get_events = GSAvahiWatchGetEvents; //retrieve events
|
||||
poll->watch_free = GSAvahiWatchFree; //remove watcher from context
|
||||
poll->timeout_new = GSAvahiTimeoutNew; //create a new GSAvahiTimer
|
||||
poll->timeout_update = GSAvahiTimeoutUpdate; //update the timer
|
||||
poll->timeout_free = GSAvahiTimeoutFree; //remove the timer from context
|
||||
//Runloops don't need to be retained;
|
||||
runLoop = rl;
|
||||
ASSIGNCOPY(mode,aMode);
|
||||
children = [[NSMutableArray alloc] init];
|
||||
return self;
|
||||
}
|
||||
|
||||
- (NSRunLoop*)runLoop
|
||||
{
|
||||
// NOTE: We don't protect this with the lock because it will only ever be
|
||||
// changed by -removeFromRunLoop:forMode: or -scheduleInRunLoop:forMode:,
|
||||
// which is where we do the locking.
|
||||
return runLoop;
|
||||
}
|
||||
|
||||
- (NSString*)mode
|
||||
{
|
||||
/* NOTE: We don't protect this with the lock because it will only ever be
|
||||
* changed by -removeFromRunLoop:forMode: or -scheduleInRunLoop:forMode:,
|
||||
* which is where we do the locking.
|
||||
*/
|
||||
return mode;
|
||||
}
|
||||
|
||||
- (const AvahiPoll*)avahiPoll
|
||||
{
|
||||
return (const AvahiPoll*)poll;
|
||||
}
|
||||
|
||||
- (GSAvahiTimer*)avahiTimerWithCallback: (AvahiTimeoutCallback)callback
|
||||
withTimeval: (const struct timeval*)tv
|
||||
userData: (void*)ud
|
||||
{
|
||||
GSAvahiTimer *timer = nil;
|
||||
[lock lock];
|
||||
timer = [[[GSAvahiTimer alloc] initWithCallback: callback
|
||||
andContext: self
|
||||
forTimeval: tv
|
||||
userData: ud] autorelease];
|
||||
if (nil != timer)
|
||||
{
|
||||
[children addObject: timer];
|
||||
}
|
||||
[lock unlock];
|
||||
return timer;
|
||||
}
|
||||
|
||||
- (GSAvahiWatcher*)avahiWatcherWithCallback: (AvahiWatchCallback)callback
|
||||
onEvent: (AvahiWatchEvent)someEvents
|
||||
forFileDescriptor: (NSInteger)fd
|
||||
userData: (void*)ud
|
||||
{
|
||||
GSAvahiWatcher *w = nil;
|
||||
[lock lock];
|
||||
w = [[[GSAvahiWatcher alloc] initWithCallback: callback
|
||||
andContext: self
|
||||
onEvent: someEvents
|
||||
forFd: fd
|
||||
userData: ud] autorelease];
|
||||
|
||||
if (nil != w)
|
||||
{
|
||||
[children addObject: w];
|
||||
}
|
||||
[lock unlock];
|
||||
return w;
|
||||
}
|
||||
|
||||
- (void)removeChild: (id)c
|
||||
{
|
||||
if (nil != c)
|
||||
{
|
||||
[lock lock];
|
||||
[children removeObject: c];
|
||||
[lock unlock];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)removeWatcher: (GSAvahiWatcher*)w
|
||||
{
|
||||
[self removeChild: w];
|
||||
}
|
||||
|
||||
- (void)removeTimeout: (GSAvahiTimer*)at
|
||||
{
|
||||
[self removeChild: at];
|
||||
}
|
||||
|
||||
- (void)removeFromRunLoop: (NSRunLoop*)rl
|
||||
forMode: (NSString*)m
|
||||
{
|
||||
if ((rl == runLoop) && [mode isEqualToString: m])
|
||||
{
|
||||
[lock lock];
|
||||
//Test again:
|
||||
if ((rl == runLoop) && [mode isEqualToString: m])
|
||||
{
|
||||
FOR_IN(GSAvahiWatcher*, child, children)
|
||||
{
|
||||
[child unschedule];
|
||||
}
|
||||
END_FOR_IN(children)
|
||||
runLoop = nil;
|
||||
[mode release];
|
||||
mode = nil;
|
||||
}
|
||||
[lock unlock];
|
||||
}
|
||||
else
|
||||
{
|
||||
//FIXME: Raise exception?
|
||||
}
|
||||
}
|
||||
- (void)scheduleInRunLoop: (NSRunLoop*)rl
|
||||
forMode: (NSString*)m
|
||||
{
|
||||
if ((runLoop == nil) && (mode == nil)
|
||||
&& ((rl != nil) && (m != nil)))
|
||||
{
|
||||
[lock lock];
|
||||
//Test again:
|
||||
if ((runLoop == nil) && (mode == nil)
|
||||
&& ((rl != nil) && (m != nil)))
|
||||
{
|
||||
runLoop = rl;
|
||||
ASSIGNCOPY(mode,m);
|
||||
FOR_IN(GSAvahiWatcher*, child, children)
|
||||
{
|
||||
[child reschedule];
|
||||
}
|
||||
END_FOR_IN(children)
|
||||
}
|
||||
[lock unlock];
|
||||
}
|
||||
else
|
||||
{
|
||||
//FIXME: Raise exception.
|
||||
}
|
||||
}
|
||||
|
||||
- (void)release
|
||||
{
|
||||
[super release];
|
||||
}
|
||||
- (void)dealloc
|
||||
{
|
||||
/* Some avahi internals might still reference the poll structure and could
|
||||
* try to create additional watchers and timers on the runloop, so we should
|
||||
* clean it up properly:
|
||||
*/
|
||||
poll->userdata = (void*)NULL;
|
||||
[self removeFromRunLoop: runLoop
|
||||
forMode: mode];
|
||||
FOR_IN(GSAvahiWatcher*, child, children)
|
||||
{
|
||||
[child setContext: nil];
|
||||
}
|
||||
END_FOR_IN(children)
|
||||
free(poll);
|
||||
poll = NULL;
|
||||
[children release];
|
||||
[mode release];
|
||||
[lock release];
|
||||
[super dealloc];
|
||||
}
|
||||
@end
|
2932
Source/GSMDNSNetServices.m
Normal file
2932
Source/GSMDNSNetServices.m
Normal file
File diff suppressed because it is too large
Load diff
|
@ -22,7 +22,7 @@
|
|||
Boston, MA 02111 USA.
|
||||
*/
|
||||
|
||||
#import <common.h>
|
||||
#import "common.h"
|
||||
|
||||
const char *gnustep_base_version = STRINGIFY (GNUSTEP_BASE_VERSION);
|
||||
|
||||
|
|
|
@ -53,5 +53,5 @@ endif
|
|||
GNUSTEP_BASE_HAVE_GNUTLS=@HAVE_GNUTLS@
|
||||
GNUSTEP_BASE_HAVE_LIBXML=@HAVE_LIBXML@
|
||||
GNUSTEP_BASE_HAVE_MDNS=@HAVE_MDNS@
|
||||
|
||||
GNUSTEP_BASE_HAVE_AVAHI=@HAVE_AVAHI@
|
||||
endif # BASE_MAKE_LOADED
|
||||
|
|
37
configure.ac
37
configure.ac
|
@ -2585,22 +2585,45 @@ AC_SUBST(HAVE_GNUTLS)
|
|||
# Check for NSNetServices
|
||||
#--------------------------------------------------------------------
|
||||
HAVE_MDNS=0
|
||||
HAVE_AVAHI=0
|
||||
AC_ARG_ENABLE(zeroconf,
|
||||
[ --disable-zeroconf Disable NSNetServices support],,
|
||||
enable_zeroconf=yes)
|
||||
|
||||
AC_ARG_WITH(zeroconf-api,
|
||||
[ --with-zeroconf-api=API force use of a specific zeroconf API (mdns or avahi)],
|
||||
zeroconf_api="$withval", zeroconf_api="any")
|
||||
if test $enable_zeroconf = yes; then
|
||||
AC_CHECK_HEADERS(dns_sd.h, have_mdns=yes, have_mdns=no)
|
||||
if test "$have_mdns" = "yes"; then
|
||||
AC_CHECK_LIB(dns_sd, DNSServiceBrowse, have_mdns=yes, have_mdns=no)
|
||||
if test "$zeroconf_api" = "any" || test "$zeroconf_api" = "mdns"; then
|
||||
AC_CHECK_HEADERS(dns_sd.h, have_mdns=yes, have_mdns=no)
|
||||
if test "$have_mdns" = "yes"; then
|
||||
LIBS="-ldns_sd $LIBS"
|
||||
HAVE_MDNS=1
|
||||
AC_CHECK_LIB(dns_sd, DNSServiceBrowse, have_mdns=yes, have_mdns=no)
|
||||
if test "$have_mdns" = "yes"; then
|
||||
MDNS_LIBS="-ldns_sd"
|
||||
HAVE_MDNS=1
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
if test "$zeroconf_api" = "any" || test "$zeroconf_api" = "avahi"; then
|
||||
AC_CHECK_HEADERS(avahi-client/client.h, have_avahi=yes, have_avahi=no)
|
||||
if test "$have_avahi" = "yes"; then
|
||||
AC_CHECK_LIB(avahi-client, avahi_client_new, have_avahi=yes, have_avahi=no)
|
||||
if test "$have_avahi" = "yes"; then
|
||||
AVAHI_LIBS="-lavahi-common -lavahi-client"
|
||||
HAVE_AVAHI=1
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
# If we have both APIs, perfer Avahi, because the mDNS API is most certainly the compatability one
|
||||
if test "$have_avahi" = "yes" && test "$have_mdns" = "yes"; then
|
||||
LIBS="$AVAHI_LIBS $LIBS"
|
||||
HAVE_MDNS=0
|
||||
else
|
||||
# One of those will be empty.
|
||||
LIBS="$AVAHI_LIBS $MDNS_LIBS $LIBS"
|
||||
fi
|
||||
fi
|
||||
AC_SUBST(HAVE_MDNS)
|
||||
|
||||
AC_SUBST(HAVE_AVAHI)
|
||||
#--------------------------------------------------------------------
|
||||
# Check for International Components for Unicode
|
||||
#--------------------------------------------------------------------
|
||||
|
|
Loading…
Reference in a new issue