Skip to content

Commit

Permalink
Merge branch 'release-1.1.0'
Browse files Browse the repository at this point in the history
  • Loading branch information
odrobnik committed Dec 18, 2013
2 parents 95e8298 + f34f70d commit 9b038cf
Show file tree
Hide file tree
Showing 12 changed files with 456 additions and 63 deletions.
13 changes: 13 additions & 0 deletions .travis.yml
@@ -0,0 +1,13 @@
---
language: objective-c

before_script:
- sudo easy_install cpp-coveralls

script:
- xctool project DTBonjour.xcodeproj -scheme "DTBonjour (iOS)" build -sdk iphonesimulator6.1 -arch i386 ONLY_ACTIVE_ARCH=NO
- xctool project DTBonjour.xcodeproj -scheme "DTBonjour (OS X)" build -arch x86_64 ONLY_ACTIVE_ARCH=NO
- appledoc -o /tmp .

after_success:
- ./coveralls.rb --extension m --exclude-folder Demo --exclude-folder Test --exclude-folder Externals
15 changes: 5 additions & 10 deletions AppledocSettings.plist
Expand Up @@ -30,23 +30,18 @@
<true/>
<key>--no-repeat-first-par</key>
<true/>
<key>--include</key>
<array>
<string>./Documentation/Change Log-template.markdown</string>
</array>
<key>--ignore</key>
<array>
<string>*.m</string>
<string>Core/Externals</string>
<string>Demo</string>
</array>
<key>--index-desc</key>
<string>Readme.markdown</string>
<key>--include</key>
<array>
<string>./Documentation/Setup Guide-template.markdown</string>
<string>./Documentation/Known Issues-template.markdown</string>
<string>./Documentation/DTCoreText_Demo_App.png</string>
<string>./Documentation/DTCoreText_Linker_Flags.png</string>
<string>./Documentation/DTCoreText_Search_Paths.png</string>
<string>./Documentation/DTCoreText_Reference.png</string>
</array>
<string>readme.markdown</string>
<key>--warn-invalid-crossref</key>
<false/>
</dict>
Expand Down
4 changes: 2 additions & 2 deletions Core/Source/DTBonjourDataChunk.m
Expand Up @@ -123,7 +123,7 @@ - (BOOL)_encodeObject:(id)object error:(NSError **)error
{
if (error)
{
NSString *errorMsg = [NSString stringWithFormat:@"Unknown encoding type %d", _encoding];
NSString *errorMsg = [NSString stringWithFormat:@"Unknown encoding type %d", (int)_encoding];
NSDictionary *userInfo = @{NSLocalizedDescriptionKey:errorMsg};
*error = [NSError errorWithDomain:DTBonjourDataConnectionErrorDomain code:1 userInfo:userInfo];
}
Expand Down Expand Up @@ -251,7 +251,7 @@ - (void)_decodeHeader
*/

_sequenceNumber = [headers[@"Sequence-Number:"] unsignedIntegerValue];
_contentLength = [headers[@"Content-Length"] longLongValue];
_contentLength = [[[NSNumberFormatter new] numberFromString:headers[@"Content-Length"]] unsignedIntegerValue];
_totalBytes = _rangeOfHeader.length + _contentLength;
}

Expand Down
27 changes: 24 additions & 3 deletions Core/Source/DTBonjourDataConnection.h
Expand Up @@ -12,17 +12,30 @@
/**
Type of encoding to use for sending objects
*/
typedef enum
typedef NS_ENUM(NSUInteger, DTBonjourDataConnectionContentType)
{
/**
Encode sent objects with NSCoding
*/
DTBonjourDataConnectionContentTypeNSCoding = 0,

/**
Encode sent objects as JSON. Note that not all kinds of Objective-C objects can be represented as JSON.
*/
DTBonjourDataConnectionContentTypeJSON,
} DTBonjourDataConnectionContentType;
};

extern NSString * DTBonjourDataConnectionErrorDomain;
extern CGFloat DTBonjourDataConnectionDefaultTimeout;

@class DTBonjourDataConnection, DTBonjourDataChunk;


/**
Protocol to inform delegate of a DTBonjourDataConnection about what is happening
*/
@protocol DTBonjourDataConnectionDelegate <NSObject>

@optional

// sending
Expand Down Expand Up @@ -130,11 +143,19 @@ extern NSString * DTBonjourDataConnectionErrorDomain;
*/

/**
Opens the connection and establishes the input and output streams.
Opens the connection and establishes the input and output streams. Cancels the
opening after a timeout of `DTBonjourDataConnectionDefaultTimeout` seconds.
@returns `YES` if the connection could be established.
*/
- (BOOL)open;

/**
Opens the connection and establishes the input and output streams.
@param timeout Timeout in seconds after which to cancel the stream opening.
@returns `YES` if the connection could be established.
*/
- (BOOL)openWithTimeout:(CGFloat)timeout;

/**
Closes the connection
*/
Expand Down
183 changes: 136 additions & 47 deletions Core/Source/DTBonjourDataConnection.m
Expand Up @@ -12,8 +12,88 @@

#import <Foundation/NSJSONSerialization.h>

#define kDTBonjourQNetworkAdditionsCheckSEL NSSelectorFromString(@"netService:didAcceptConnectionWithInputStream:outputStream:")

CGFloat DTBonjourDataConnectionDefaultTimeout = 60.0;
NSString * DTBonjourDataConnectionErrorDomain = @"DTBonjourDataConnection";

@interface NSNetService (QNetworkAdditions)

- (BOOL)qNetworkAdditions_getInputStream:(out NSInputStream **)inputStreamPtr
outputStream:(out NSOutputStream **)outputStreamPtr;

@end

@implementation NSNetService (QNetworkAdditions)

- (BOOL)qNetworkAdditions_getInputStream:(out NSInputStream **)inputStreamPtr
outputStream:(out NSOutputStream **)outputStreamPtr
// The following works around three problems with
// -[NSNetService getInputStream:outputStream:]:
//
// o <rdar://problem/6868813> -- Currently the returns the streams with
// +1 retain count, which is counter to Cocoa conventions and results in
// leaks when you use it in ARC code.
//
// o <rdar://problem/9821932> -- If you create two pairs of streams from
// one NSNetService and then attempt to open all the streams simultaneously,
// some of the streams might fail to open.
//
// o <rdar://problem/9856751> -- If you create streams using
// -[NSNetService getInputStream:outputStream:], start to open them, and
// then release the last reference to the original NSNetService, the
// streams never finish opening. This problem is exacerbated under ARC
// because ARC is better about keeping things out of the autorelease pool.
{
BOOL result;
CFReadStreamRef readStream;
CFWriteStreamRef writeStream;

result = NO;

readStream = NULL;
writeStream = NULL;

if ( (inputStreamPtr != NULL) || (outputStreamPtr != NULL) ) {
CFNetServiceRef netService;

netService = CFNetServiceCreate(
NULL,
(__bridge CFStringRef) [self domain],
(__bridge CFStringRef) [self type],
(__bridge CFStringRef) [self name],
0
);
if (netService != NULL) {
CFStreamCreatePairWithSocketToNetService(
NULL,
netService,
((inputStreamPtr != nil) ? &readStream : NULL),
((outputStreamPtr != nil) ? &writeStream : NULL)
);
CFRelease(netService);
}

// We have failed if the client requested an input stream and didn't
// get one, or requested an output stream and didn't get one. We also
// fail if the client requested neither the input nor the output
// stream, but we don't get here in that case.

result = ! ((( inputStreamPtr != NULL) && ( readStream == NULL)) ||
((outputStreamPtr != NULL) && (writeStream == NULL)));
}
if (inputStreamPtr != NULL) {
*inputStreamPtr = CFBridgingRelease(readStream);
}
if (outputStreamPtr != NULL) {
*outputStreamPtr = CFBridgingRelease(writeStream);
}

return result;
}

@end

@interface DTBonjourDataConnection () <NSStreamDelegate>

@end
Expand Down Expand Up @@ -82,11 +162,27 @@ - (id)initWithService:(NSNetService *)service

if (self)
{
if (![service getInputStream:&_inputStream outputStream:&_outputStream])
{
return nil;
}

NSInputStream *in;
NSOutputStream *out;

if (![[service delegate] respondsToSelector:kDTBonjourQNetworkAdditionsCheckSEL])
{
// Older iOS/OSX versions need a patch for getting input and output
// streams see the `QNetworkAdditions` above. (If the delegate does not
// implement the `kDTBonjourQNetworkAdditionsCheck` selector, we can
// simply use the patched version.
if ([service qNetworkAdditions_getInputStream:&in outputStream:&out])
return nil;
}
else
{
// iOS7/OSX10.9
if (![service getInputStream:&in outputStream:&out])
return nil;
}

_inputStream = in;
_outputStream = out;
_outputQueue = [[NSMutableArray alloc] init];
}

Expand All @@ -113,7 +209,7 @@ - (void)dealloc
[self close];
}

- (BOOL)open
- (BOOL)openWithTimeout:(CGFloat)timeout
{
[_inputStream setDelegate:self];
[_outputStream setDelegate:self];
Expand All @@ -122,9 +218,24 @@ - (BOOL)open
[_inputStream open];
[_outputStream open];

__weak id weakSelf = self;
double delayInSeconds = timeout;
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC));
dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
// No connection after timeout, closing.
if (![weakSelf isOpen]) {
[weakSelf close];
}
});

return YES;
}

- (BOOL)open
{
return [self openWithTimeout:DTBonjourDataConnectionDefaultTimeout];
}

- (void)close
{
if (!_inputStream&&!_outputStream)
Expand All @@ -142,50 +253,23 @@ - (void)close
_outputStream = nil;

if ([_delegate respondsToSelector:@selector(connectionDidClose:)])
{
[_delegate connectionDidClose:self];
}
}

- (BOOL)isOpen
{
if (!_inputStream)
{
return NO;
}

NSStreamStatus inputStatus = [_inputStream streamStatus];

switch (inputStatus)
{
case NSStreamStatusNotOpen:
case NSStreamStatusAtEnd:
case NSStreamStatusClosed:
case NSStreamStatusError:
{
return NO;
}

default:
break;
}

NSStreamStatus outputStatus = [_outputStream streamStatus];

switch (outputStatus)
{
case NSStreamStatusNotOpen:
case NSStreamStatusAtEnd:
case NSStreamStatusClosed:
case NSStreamStatusError:
{
return NO;
}

default:
break;
}

NSStreamStatus outputStatus = [_outputStream streamStatus];

if (NSStreamStatusOpen != inputStatus)
return NO;

if (NSStreamStatusOpen != outputStatus)
return NO;

return YES;
}

Expand All @@ -198,7 +282,7 @@ - (void)_startOutput

DTBonjourDataChunk *chunk = _outputQueue[0];

if (chunk.numberOfTransferredBytes==0)
if (0 == chunk.numberOfTransferredBytes)
{
// nothing sent yet
if ([_delegate respondsToSelector:@selector(connection:willStartSendingChunk:)])
Expand All @@ -207,7 +291,7 @@ - (void)_startOutput
}
}

NSUInteger writtenBytes = [chunk writeToOutputStream:_outputStream];
NSInteger writtenBytes = [chunk writeToOutputStream:_outputStream];

if (writtenBytes > 0)
{
Expand Down Expand Up @@ -252,12 +336,13 @@ - (BOOL)sendObject:(id)object error:(NSError **)error
return NO;
}

DTBonjourDataChunk *newChunk = [[DTBonjourDataChunk alloc] initWithObject:object encoding:self.sendingContentType error:error];
DTBonjourDataChunk *newChunk = [[DTBonjourDataChunk alloc]
initWithObject:object
encoding:self.sendingContentType
error:error];

if (!newChunk)
{
return NO;
}

newChunk.sequenceNumber = _chunkSequenceNumber;

Expand All @@ -267,7 +352,9 @@ - (BOOL)sendObject:(id)object error:(NSError **)error

if (queueWasEmpty && _outputStream.streamStatus == NSStreamStatusOpen)
{
[self _startOutput];
dispatch_async(dispatch_get_main_queue(), ^{
[self _startOutput];
});
}

return YES;
Expand Down Expand Up @@ -341,6 +428,8 @@ - (void)stream:(NSStream *)aStream handleEvent:(NSStreamEvent)streamEvent
case NSStreamEventErrorOccurred:
{
NSLog(@"Error occurred: %@", [aStream.streamError localizedDescription]);

// Intentional fall-through.
}

case NSStreamEventEndEncountered:
Expand Down
2 changes: 1 addition & 1 deletion DTBonjour.podspec
@@ -1,6 +1,6 @@
Pod::Spec.new do |spec|
spec.name = 'DTBonjour'
spec.version = '1.0.0'
spec.version = '1.1.0'
spec.summary = "Client/Server Communication of NSObjects over WiFi."
spec.homepage = "https://github.com/Cocoanetics/DTBonjour"
spec.author = { "Oliver Drobnik" => "oliver@drobnik.com" }
Expand Down

0 comments on commit 9b038cf

Please sign in to comment.