123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636 |
- #ifdef SHOULD_COMPILE_LOOKIN_SERVER
- #import "Lookin_PTChannel.h"
- #import "Lookin_PTPrivate.h"
- #include <sys/ioctl.h>
- #include <sys/un.h>
- #include <err.h>
- #include <fcntl.h>
- #include <arpa/inet.h>
- #import <objc/runtime.h>
- // Read member of sockaddr_in without knowing the family
- #define PT_SOCKADDR_ACCESS(ss, member4, member6) \
- (((ss)->ss_family == AF_INET) ? ( \
- ((const struct sockaddr_in *)(ss))->member4 \
- ) : ( \
- ((const struct sockaddr_in6 *)(ss))->member6 \
- ))
- // Connection state (storage: uint8_t)
- #define kConnStateNone 0
- #define kConnStateConnecting 1
- #define kConnStateConnected 2
- #define kConnStateListening 3
- // Delegate support optimization (storage: uint8_t)
- #define kDelegateFlagImplements_ioFrameChannel_shouldAcceptFrameOfType_tag_payloadSize 1
- #define kDelegateFlagImplements_ioFrameChannel_didEndWithError 2
- #define kDelegateFlagImplements_ioFrameChannel_didAcceptConnection_fromAddress 4
- #pragma mark -
- // Note: We are careful about the size of this struct as each connected peer
- // implies one allocation of this struct.
- @interface Lookin_PTChannel () {
- dispatch_io_t dispatchObj_channel_;
- dispatch_source_t dispatchObj_source_;
- NSError *endError_; // 64 bit
- @public // here be hacks
- id<Lookin_PTChannelDelegate> delegate_; // 64 bit
- uint8_t delegateFlags_; // 8 bit
- @private
- uint8_t connState_; // 8 bit
- //char padding_[6]; // 48 bit -- only if allocation speed is important
- }
- - (id)initWithProtocol:(Lookin_PTProtocol*)protocol delegate:(id<Lookin_PTChannelDelegate>)delegate;
- - (BOOL)acceptIncomingConnection:(dispatch_fd_t)serverSocketFD;
- @end
- static const uint8_t kUserInfoKey;
- #pragma mark -
- @interface Lookin_PTData ()
- - (id)initWithMappedDispatchData:(dispatch_data_t)mappedContiguousData data:(void*)data length:(size_t)length;
- @end
- #pragma mark -
- @interface Lookin_PTAddress () {
- struct sockaddr_storage sockaddr_;
- }
- - (id)initWithSockaddr:(const struct sockaddr_storage*)addr;
- @end
- #pragma mark -
- @implementation Lookin_PTChannel
- @synthesize protocol = protocol_;
- + (Lookin_PTChannel*)channelWithDelegate:(id<Lookin_PTChannelDelegate>)delegate {
- return [[Lookin_PTChannel alloc] initWithProtocol:[Lookin_PTProtocol sharedProtocolForQueue:dispatch_get_main_queue()] delegate:delegate];
- }
- - (id)initWithProtocol:(Lookin_PTProtocol*)protocol delegate:(id<Lookin_PTChannelDelegate>)delegate {
- if (!(self = [super init])) return nil;
- protocol_ = protocol;
- self.delegate = delegate;
- return self;
- }
- - (id)initWithProtocol:(Lookin_PTProtocol*)protocol {
- if (!(self = [super init])) return nil;
- protocol_ = protocol;
- return self;
- }
- - (id)init {
- return [self initWithProtocol:[Lookin_PTProtocol sharedProtocolForQueue:dispatch_get_main_queue()]];
- }
- - (void)dealloc {
- #if PT_DISPATCH_RETAIN_RELEASE
- if (dispatchObj_channel_) dispatch_release(dispatchObj_channel_);
- else if (dispatchObj_source_) dispatch_release(dispatchObj_source_);
- #endif
- }
- - (BOOL)isConnected {
- return connState_ == kConnStateConnecting || connState_ == kConnStateConnected;
- }
- - (BOOL)isListening {
- return connState_ == kConnStateListening;
- }
- - (id)userInfo {
- return objc_getAssociatedObject(self, (void*)&kUserInfoKey);
- }
- - (void)setUserInfo:(id)userInfo {
- objc_setAssociatedObject(self, (const void*)&kUserInfoKey, userInfo, OBJC_ASSOCIATION_RETAIN);
- }
- - (void)setConnState:(char)connState {
- connState_ = connState;
- }
- - (void)setDispatchChannel:(dispatch_io_t)channel {
- assert(connState_ == kConnStateConnecting || connState_ == kConnStateConnected || connState_ == kConnStateNone);
- dispatch_io_t prevChannel = dispatchObj_channel_;
- if (prevChannel != channel) {
- dispatchObj_channel_ = channel;
- #if PT_DISPATCH_RETAIN_RELEASE
- if (dispatchObj_channel_) dispatch_retain(dispatchObj_channel_);
- if (prevChannel) dispatch_release(prevChannel);
- #endif
- if (!dispatchObj_channel_ && !dispatchObj_source_) {
- connState_ = kConnStateNone;
- }
- }
- }
- - (void)setDispatchSource:(dispatch_source_t)source {
- assert(connState_ == kConnStateListening || connState_ == kConnStateNone);
- dispatch_source_t prevSource = dispatchObj_source_;
- if (prevSource != source) {
- dispatchObj_source_ = source;
- #if PT_DISPATCH_RETAIN_RELEASE
- if (dispatchObj_source_) dispatch_retain(dispatchObj_source_);
- if (prevSource) dispatch_release(prevSource);
- #endif
- if (!dispatchObj_channel_ && !dispatchObj_source_) {
- connState_ = kConnStateNone;
- }
- }
- }
- - (id<Lookin_PTChannelDelegate>)delegate {
- return delegate_;
- }
- - (void)setDelegate:(id<Lookin_PTChannelDelegate>)delegate {
- delegate_ = delegate;
- delegateFlags_ = 0;
- if (!delegate_) {
- return;
- }
-
- if ([delegate respondsToSelector:@selector(ioFrameChannel:shouldAcceptFrameOfType:tag:payloadSize:)]) {
- delegateFlags_ |= kDelegateFlagImplements_ioFrameChannel_shouldAcceptFrameOfType_tag_payloadSize;
- }
-
- if (delegate_ && [delegate respondsToSelector:@selector(ioFrameChannel:didEndWithError:)]) {
- delegateFlags_ |= kDelegateFlagImplements_ioFrameChannel_didEndWithError;
- }
-
- if (delegate_ && [delegate respondsToSelector:@selector(ioFrameChannel:didAcceptConnection:fromAddress:)]) {
- delegateFlags_ |= kDelegateFlagImplements_ioFrameChannel_didAcceptConnection_fromAddress;
- }
- }
- //- (void)setFileDescriptor:(dispatch_fd_t)fd {
- // [self setDispatchChannel:dispatch_io_create(DISPATCH_IO_STREAM, fd, protocol_.queue, ^(int error) {
- // close(fd);
- // })];
- //}
- #pragma mark - Connecting
- - (void)connectToPort:(int)port overUSBHub:(Lookin_PTUSBHub*)usbHub deviceID:(NSNumber*)deviceID callback:(void(^)(NSError *error))callback {
- assert(protocol_ != NULL);
- if (connState_ != kConnStateNone) {
- if (callback) callback([NSError errorWithDomain:NSPOSIXErrorDomain code:EPERM userInfo:nil]);
- return;
- }
- connState_ = kConnStateConnecting;
- [usbHub connectToDevice:deviceID port:port onStart:^(NSError *err, dispatch_io_t dispatchChannel) {
- NSError *error = err;
- if (!error) {
- [self startReadingFromConnectedChannel:dispatchChannel error:&error];
- } else {
- self->connState_ = kConnStateNone;
- }
- if (callback) callback(error);
- } onEnd:^(NSError *error) {
- if (self->delegateFlags_ & kDelegateFlagImplements_ioFrameChannel_didEndWithError) {
- [self->delegate_ ioFrameChannel:self didEndWithError:error];
- }
- self->endError_ = nil;
- }];
- }
- - (void)connectToPort:(in_port_t)port IPv4Address:(in_addr_t)address callback:(void(^)(NSError *error, Lookin_PTAddress *address))callback {
- assert(protocol_ != NULL);
- if (connState_ != kConnStateNone) {
- if (callback) callback([NSError errorWithDomain:NSPOSIXErrorDomain code:EPERM userInfo:nil], nil);
- return;
- }
- connState_ = kConnStateConnecting;
-
- int error = 0;
-
- // Create socket
- dispatch_fd_t fd = socket(AF_INET, SOCK_STREAM, 0);
- if (fd == -1) {
- perror("socket(AF_INET, SOCK_STREAM, 0) failed");
- error = errno;
- if (callback) callback([[NSError alloc] initWithDomain:NSPOSIXErrorDomain code:errno userInfo:nil], nil);
- return;
- }
-
- // Connect socket
- struct sockaddr_in addr;
- bzero((char *)&addr, sizeof(addr));
-
- addr.sin_len = sizeof(addr);
- addr.sin_family = AF_INET;
- addr.sin_port = htons(port);
- //addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
- //addr.sin_addr.s_addr = htonl(INADDR_ANY);
- addr.sin_addr.s_addr = htonl(address);
-
- // prevent SIGPIPE
- int on = 1;
- setsockopt(fd, SOL_SOCKET, SO_NOSIGPIPE, &on, sizeof(on));
-
- // int socket, const struct sockaddr *address, socklen_t address_len
- if (connect(fd, (const struct sockaddr *)&addr, addr.sin_len) == -1) {
- //perror("connect");
- error = errno;
- close(fd);
- if (callback) callback([[NSError alloc] initWithDomain:NSPOSIXErrorDomain code:error userInfo:nil], nil);
- return;
- }
-
- // get actual address
- //if (getsockname(fd, (struct sockaddr*)&addr, (socklen_t*)&addr.sin_len) == -1) {
- // error = errno;
- // close(fd);
- // if (callback) callback([[NSError alloc] initWithDomain:NSPOSIXErrorDomain code:error userInfo:nil], nil);
- // return;
- //}
-
- dispatch_io_t dispatchChannel = dispatch_io_create(DISPATCH_IO_STREAM, fd, protocol_.queue, ^(int error) {
- close(fd);
- if (self->delegateFlags_ & kDelegateFlagImplements_ioFrameChannel_didEndWithError) {
- NSError *err = error == 0 ? self->endError_ : [[NSError alloc] initWithDomain:NSPOSIXErrorDomain code:error userInfo:nil];
- [self->delegate_ ioFrameChannel:self didEndWithError:err];
- self->endError_ = nil;
- }
- });
-
- if (!dispatchChannel) {
- close(fd);
- if (callback) callback([[NSError alloc] initWithDomain:@"PTError" code:0 userInfo:nil], nil);
- return;
- }
-
- // Success
- NSError *err = nil;
- Lookin_PTAddress *ptAddr = [[Lookin_PTAddress alloc] initWithSockaddr:(struct sockaddr_storage*)&addr];
- [self startReadingFromConnectedChannel:dispatchChannel error:&err];
- if (callback) callback(err, ptAddr);
- }
- #pragma mark - Listening and serving
- - (void)listenOnPort:(in_port_t)port IPv4Address:(in_addr_t)address callback:(void(^)(NSError *error))callback {
- assert(dispatchObj_source_ == nil);
-
- // Create socket
- dispatch_fd_t fd = socket(AF_INET, SOCK_STREAM, 0);
- if (fd == -1) {
- if (callback) callback([NSError errorWithDomain:NSPOSIXErrorDomain code:errno userInfo:nil]);
- return;
- }
-
- // Connect socket
- struct sockaddr_in addr;
- bzero((char *)&addr, sizeof(addr));
-
- addr.sin_family = AF_INET;
- addr.sin_port = htons(port);
- //addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
- //addr.sin_addr.s_addr = htonl(INADDR_ANY);
- addr.sin_addr.s_addr = htonl(address);
-
- socklen_t socklen = sizeof(addr);
-
- int on = 1;
-
- if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) == -1) {
- close(fd);
- if (callback) callback([NSError errorWithDomain:NSPOSIXErrorDomain code:errno userInfo:nil]);
- return;
- }
-
- if (fcntl(fd, F_SETFL, O_NONBLOCK) == -1) {
- close(fd);
- if (callback) callback([NSError errorWithDomain:NSPOSIXErrorDomain code:errno userInfo:nil]);
- return;
- }
-
- if (bind(fd, (struct sockaddr*)&addr, socklen) != 0) {
- close(fd);
- if (callback) callback([NSError errorWithDomain:NSPOSIXErrorDomain code:errno userInfo:nil]);
- return;
- }
-
- if (listen(fd, 512) != 0) {
- close(fd);
- if (callback) callback([NSError errorWithDomain:NSPOSIXErrorDomain code:errno userInfo:nil]);
- return;
- }
-
- [self setDispatchSource:dispatch_source_create(DISPATCH_SOURCE_TYPE_READ, fd, 0, protocol_.queue)];
-
- dispatch_source_set_event_handler(dispatchObj_source_, ^{
- unsigned long nconns = dispatch_source_get_data(self->dispatchObj_source_);
- while ([self acceptIncomingConnection:fd] && --nconns);
- });
-
- dispatch_source_set_cancel_handler(dispatchObj_source_, ^{
- // Captures *self*, effectively holding a reference to *self* until cancelled.
- self->dispatchObj_source_ = nil;
- close(fd);
- if (self->delegateFlags_ & kDelegateFlagImplements_ioFrameChannel_didEndWithError) {
- [self->delegate_ ioFrameChannel:self didEndWithError:self->endError_];
- self->endError_ = nil;
- }
- });
-
- dispatch_resume(dispatchObj_source_);
- //NSLog(@"%@ opened on fd #%d", self, fd);
-
- connState_ = kConnStateListening;
- if (callback) callback(nil);
- }
- - (BOOL)acceptIncomingConnection:(dispatch_fd_t)serverSocketFD {
- struct sockaddr_in addr;
- socklen_t addrLen = sizeof(addr);
- dispatch_fd_t clientSocketFD = accept(serverSocketFD, (struct sockaddr*)&addr, &addrLen);
-
- if (clientSocketFD == -1) {
- perror("accept()");
- return NO;
- }
-
- // prevent SIGPIPE
- int on = 1;
- setsockopt(clientSocketFD, SOL_SOCKET, SO_NOSIGPIPE, &on, sizeof(on));
-
- if (fcntl(clientSocketFD, F_SETFL, O_NONBLOCK) == -1) {
- perror("fcntl(.. O_NONBLOCK)");
- close(clientSocketFD);
- return NO;
- }
-
- if (delegateFlags_ & kDelegateFlagImplements_ioFrameChannel_didAcceptConnection_fromAddress) {
- Lookin_PTChannel *peerChannel = [[Lookin_PTChannel alloc] initWithProtocol:protocol_ delegate:delegate_];
- __block Lookin_PTChannel *localChannelRef = self;
- dispatch_io_t dispatchChannel = dispatch_io_create(DISPATCH_IO_STREAM, clientSocketFD, protocol_.queue, ^(int error) {
- // Important note: This block captures *self*, thus a reference is held to
- // *self* until the fd is truly closed.
- localChannelRef = nil;
- close(clientSocketFD);
-
- if (peerChannel->delegateFlags_ & kDelegateFlagImplements_ioFrameChannel_didEndWithError) {
- NSError *err = error == 0 ? peerChannel->endError_ : [[NSError alloc] initWithDomain:NSPOSIXErrorDomain code:error userInfo:nil];
- [peerChannel->delegate_ ioFrameChannel:peerChannel didEndWithError:err];
- peerChannel->endError_ = nil;
- }
- });
-
- [peerChannel setConnState:kConnStateConnected];
- [peerChannel setDispatchChannel:dispatchChannel];
-
- assert(((struct sockaddr_storage*)&addr)->ss_len == addrLen);
- Lookin_PTAddress *address = [[Lookin_PTAddress alloc] initWithSockaddr:(struct sockaddr_storage*)&addr];
- [delegate_ ioFrameChannel:self didAcceptConnection:peerChannel fromAddress:address];
-
- NSError *err = nil;
- if (![peerChannel startReadingFromConnectedChannel:dispatchChannel error:&err]) {
- NSLog(@"startReadingFromConnectedChannel failed in accept: %@", err);
- }
- } else {
- close(clientSocketFD);
- }
- return YES;
- }
- #pragma mark - Closing the channel
- - (void)close {
- if ((connState_ == kConnStateConnecting || connState_ == kConnStateConnected) && dispatchObj_channel_) {
- dispatch_io_close(dispatchObj_channel_, DISPATCH_IO_STOP);
- [self setDispatchChannel:NULL];
- } else if (connState_ == kConnStateListening && dispatchObj_source_) {
- dispatch_source_cancel(dispatchObj_source_);
- }
- }
- - (void)cancel {
- if ((connState_ == kConnStateConnecting || connState_ == kConnStateConnected) && dispatchObj_channel_) {
- dispatch_io_close(dispatchObj_channel_, 0);
- [self setDispatchChannel:NULL];
- } else if (connState_ == kConnStateListening && dispatchObj_source_) {
- dispatch_source_cancel(dispatchObj_source_);
- }
- }
- #pragma mark - Reading
- - (BOOL)startReadingFromConnectedChannel:(dispatch_io_t)channel error:(__autoreleasing NSError**)error {
- if (connState_ != kConnStateNone && connState_ != kConnStateConnecting && connState_ != kConnStateConnected) {
- if (error) *error = [NSError errorWithDomain:NSPOSIXErrorDomain code:EPERM userInfo:nil];
- return NO;
- }
-
- if (dispatchObj_channel_ != channel) {
- [self close];
- [self setDispatchChannel:channel];
- }
-
- connState_ = kConnStateConnected;
-
- // helper
- BOOL(^handleError)(NSError*,BOOL) = ^BOOL(NSError *error, BOOL isEOS) {
- if (error) {
- //NSLog(@"Error while communicating: %@", error);
- self->endError_ = error;
- [self close];
- return YES;
- } else if (isEOS) {
- [self cancel];
- return YES;
- }
- return NO;
- };
-
- [protocol_ readFramesOverChannel:channel onFrame:^(NSError *error, uint32_t type, uint32_t tag, uint32_t payloadSize, dispatch_block_t resumeReadingFrames) {
- if (handleError(error, type == PTFrameTypeEndOfStream)) {
- return;
- }
-
- BOOL accepted = (channel == self->dispatchObj_channel_);
- if (accepted && (self->delegateFlags_ & kDelegateFlagImplements_ioFrameChannel_shouldAcceptFrameOfType_tag_payloadSize)) {
- accepted = [self->delegate_ ioFrameChannel:self shouldAcceptFrameOfType:type tag:tag payloadSize:payloadSize];
- }
-
- if (payloadSize == 0) {
- if (accepted && self->delegate_) {
- [self->delegate_ ioFrameChannel:self didReceiveFrameOfType:type tag:tag payload:nil];
- } else {
- // simply ignore the frame
- }
- resumeReadingFrames();
- } else {
- // has payload
- if (!accepted) {
- // Read and discard payload, ignoring frame
- [self->protocol_ readAndDiscardDataOfSize:payloadSize overChannel:channel callback:^(NSError *error, BOOL endOfStream) {
- if (!handleError(error, endOfStream)) {
- resumeReadingFrames();
- }
- }];
- } else {
- [self->protocol_ readPayloadOfSize:payloadSize overChannel:channel callback:^(NSError *error, dispatch_data_t contiguousData, const uint8_t *buffer, size_t bufferSize) {
- if (handleError(error, bufferSize == 0)) {
- return;
- }
-
- if (self->delegate_) {
- Lookin_PTData *payload = [[Lookin_PTData alloc] initWithMappedDispatchData:contiguousData data:(void*)buffer length:bufferSize];
- [self->delegate_ ioFrameChannel:self didReceiveFrameOfType:type tag:tag payload:payload];
- }
-
- resumeReadingFrames();
- }];
- }
- }
- }];
-
- return YES;
- }
- #pragma mark - Sending
- - (void)sendFrameOfType:(uint32_t)frameType tag:(uint32_t)tag withPayload:(dispatch_data_t)payload callback:(void(^)(NSError *error))callback {
- if (connState_ == kConnStateConnecting || connState_ == kConnStateConnected) {
- [protocol_ sendFrameOfType:frameType tag:tag withPayload:payload overChannel:dispatchObj_channel_ callback:callback];
- } else if (callback) {
- callback([NSError errorWithDomain:NSPOSIXErrorDomain code:EPERM userInfo:nil]);
- }
- }
- #pragma mark - NSObject
- - (NSString*)description {
- id userInfo = objc_getAssociatedObject(self, (void*)&kUserInfoKey);
- return [NSString stringWithFormat:@"<Lookin_PTChannel: %p (%@)%s%@>", self, ( connState_ == kConnStateConnecting ? @"connecting"
- : connState_ == kConnStateConnected ? @"connected"
- : connState_ == kConnStateListening ? @"listening"
- : @"closed"),
- userInfo ? " " : "", userInfo ? userInfo : @""];
- }
- @end
- #pragma mark -
- @implementation Lookin_PTAddress
- - (id)initWithSockaddr:(const struct sockaddr_storage*)addr {
- if (!(self = [super init])) return nil;
- assert(addr);
- memcpy((void*)&sockaddr_, (const void*)addr, addr->ss_len);
- return self;
- }
- - (NSString*)name {
- if (sockaddr_.ss_len) {
- const void *sin_addr = NULL;
- size_t bufsize = 0;
- if (sockaddr_.ss_family == AF_INET6) {
- bufsize = INET6_ADDRSTRLEN;
- sin_addr = (const void *)&((const struct sockaddr_in6*)&sockaddr_)->sin6_addr;
- } else {
- bufsize = INET_ADDRSTRLEN;
- sin_addr = (const void *)&((const struct sockaddr_in*)&sockaddr_)->sin_addr;
- }
- char *buf = CFAllocatorAllocate(kCFAllocatorDefault, bufsize+1, 0);
- if (inet_ntop(sockaddr_.ss_family, sin_addr, buf, (unsigned int)bufsize-1) == NULL) {
- CFAllocatorDeallocate(kCFAllocatorDefault, buf);
- return nil;
- }
- return [[NSString alloc] initWithBytesNoCopy:(void*)buf length:strlen(buf) encoding:NSUTF8StringEncoding freeWhenDone:YES];
- } else {
- return nil;
- }
- }
- - (NSInteger)port {
- if (sockaddr_.ss_len) {
- return ntohs(PT_SOCKADDR_ACCESS(&sockaddr_, sin_port, sin6_port));
- } else {
- return 0;
- }
- }
- - (NSString*)description {
- if (sockaddr_.ss_len) {
- return [NSString stringWithFormat:@"%@:%u", self.name, (unsigned)self.port];
- } else {
- return @"(?)";
- }
- }
- @end
- #pragma mark -
- @implementation Lookin_PTData
- @synthesize dispatchData = dispatchData_;
- @synthesize data = data_;
- @synthesize length = length_;
- - (id)initWithMappedDispatchData:(dispatch_data_t)mappedContiguousData data:(void*)data length:(size_t)length {
- if (!(self = [super init])) return nil;
- dispatchData_ = mappedContiguousData;
- #if PT_DISPATCH_RETAIN_RELEASE
- if (dispatchData_) dispatch_retain(dispatchData_);
- #endif
- data_ = data;
- length_ = length;
- return self;
- }
- - (void)dealloc {
- #if PT_DISPATCH_RETAIN_RELEASE
- if (dispatchData_) dispatch_release(dispatchData_);
- #endif
- data_ = NULL;
- length_ = 0;
- }
- #pragma mark - NSObject
- - (NSString*)description {
- return [NSString stringWithFormat:@"<Lookin_PTData: %p (%zu bytes)>", self, length_];
- }
- @end
- #endif /* SHOULD_COMPILE_LOOKIN_SERVER */
|