|
|
@@ -13,28 +13,44 @@
|
|
|
*/
|
|
|
|
|
|
#import <Foundation/Foundation.h>
|
|
|
-#import "LocalSocketClient.h"
|
|
|
+
|
|
|
#include <sys/socket.h>
|
|
|
#include <sys/un.h>
|
|
|
#include <stdio.h>
|
|
|
#include <string.h>
|
|
|
|
|
|
+#import "LocalSocketClient.h"
|
|
|
+
|
|
|
+@interface LocalSocketClient()
|
|
|
+{
|
|
|
+ NSString* _socketPath;
|
|
|
+ LineProcessor* _lineProcessor;
|
|
|
+
|
|
|
+ int _sock;
|
|
|
+ dispatch_queue_t _localSocketQueue;
|
|
|
+ dispatch_source_t _readSource;
|
|
|
+ dispatch_source_t _writeSource;
|
|
|
+ NSMutableData* _inBuffer;
|
|
|
+ NSMutableData* _outBuffer;
|
|
|
+}
|
|
|
+@end
|
|
|
+
|
|
|
@implementation LocalSocketClient
|
|
|
|
|
|
-- (instancetype)init:(NSString*)socketPath lineProcessor:(LineProcessor*)lineProcessor
|
|
|
+- (instancetype)initWithSocketPath:(NSString*)socketPath lineProcessor:(LineProcessor*)lineProcessor
|
|
|
{
|
|
|
NSLog(@"Initiating local socket client.");
|
|
|
self = [super init];
|
|
|
|
|
|
if(self) {
|
|
|
- self.socketPath = socketPath;
|
|
|
- self.lineProcessor = lineProcessor;
|
|
|
+ _socketPath = socketPath;
|
|
|
+ _lineProcessor = lineProcessor;
|
|
|
|
|
|
- self.sock = -1;
|
|
|
- self.localSocketQueue = dispatch_queue_create("localSocketQueue", DISPATCH_QUEUE_SERIAL);
|
|
|
+ _sock = -1;
|
|
|
+ _localSocketQueue = dispatch_queue_create("localSocketQueue", DISPATCH_QUEUE_SERIAL);
|
|
|
|
|
|
- self.inBuffer = [NSMutableData data];
|
|
|
- self.outBuffer = [NSMutableData data];
|
|
|
+ _inBuffer = [NSMutableData data];
|
|
|
+ _outBuffer = [NSMutableData data];
|
|
|
}
|
|
|
|
|
|
return self;
|
|
|
@@ -42,8 +58,8 @@
|
|
|
|
|
|
- (BOOL)isConnected
|
|
|
{
|
|
|
- NSLog(@"Checking is connected: %@", self.sock != -1 ? @"YES" : @"NO");
|
|
|
- return self.sock != -1;
|
|
|
+ NSLog(@"Checking is connected: %@", _sock != -1 ? @"YES" : @"NO");
|
|
|
+ return _sock != -1;
|
|
|
}
|
|
|
|
|
|
- (void)start
|
|
|
@@ -54,44 +70,44 @@
|
|
|
}
|
|
|
|
|
|
struct sockaddr_un localSocketAddr;
|
|
|
- unsigned long socketPathByteCount = [self.socketPath lengthOfBytesUsingEncoding:NSUTF8StringEncoding]; // add 1 for the NUL terminator char
|
|
|
+ unsigned long socketPathByteCount = [_socketPath lengthOfBytesUsingEncoding:NSUTF8StringEncoding]; // add 1 for the NUL terminator char
|
|
|
int maxByteCount = sizeof(localSocketAddr.sun_path);
|
|
|
|
|
|
if(socketPathByteCount > maxByteCount) {
|
|
|
// LOG THAT THE SOCKET PATH IS TOO LONG HERE
|
|
|
- NSLog(@"Socket path '%@' is too long: maximum socket path length is %i, this path is of length %lu", self.socketPath, maxByteCount, socketPathByteCount);
|
|
|
+ NSLog(@"Socket path '%@' is too long: maximum socket path length is %i, this path is of length %lu", _socketPath, maxByteCount, socketPathByteCount);
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
NSLog(@"Opening local socket...");
|
|
|
|
|
|
// LOG THAT THE SOCKET IS BEING OPENED HERE
|
|
|
- self.sock = socket(AF_LOCAL, SOCK_STREAM, 0);
|
|
|
+ _sock = socket(AF_LOCAL, SOCK_STREAM, 0);
|
|
|
|
|
|
- if(self.sock == -1) {
|
|
|
+ if(_sock == -1) {
|
|
|
NSLog(@"Cannot open socket: '%@'", [self strErr]);
|
|
|
[self restart];
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
- NSLog(@"Local socket opened. Connecting to '%@' ...", self.socketPath);
|
|
|
+ NSLog(@"Local socket opened. Connecting to '%@' ...", _socketPath);
|
|
|
|
|
|
localSocketAddr.sun_family = AF_LOCAL & 0xff;
|
|
|
|
|
|
- const char* pathBytes = [self.socketPath UTF8String];
|
|
|
+ const char* pathBytes = [_socketPath UTF8String];
|
|
|
strcpy(localSocketAddr.sun_path, pathBytes);
|
|
|
|
|
|
- int connectionStatus = connect(self.sock, (struct sockaddr*)&localSocketAddr, sizeof(localSocketAddr));
|
|
|
+ int connectionStatus = connect(_sock, (struct sockaddr*)&localSocketAddr, sizeof(localSocketAddr));
|
|
|
|
|
|
if(connectionStatus == -1) {
|
|
|
- NSLog(@"Could not connect to '%@': '%@'", self.socketPath, [self strErr]);
|
|
|
+ NSLog(@"Could not connect to '%@': '%@'", _socketPath, [self strErr]);
|
|
|
[self restart];
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
- int flags = fcntl(self.sock, F_GETFL, 0);
|
|
|
+ int flags = fcntl(_sock, F_GETFL, 0);
|
|
|
|
|
|
- if(fcntl(self.sock, F_SETFL, flags | O_NONBLOCK) == -1) {
|
|
|
+ if(fcntl(_sock, F_SETFL, flags | O_NONBLOCK) == -1) {
|
|
|
NSLog(@"Could not set socket to non-blocking mode: '%@'", [self strErr]);
|
|
|
[self restart];
|
|
|
return;
|
|
|
@@ -99,17 +115,17 @@
|
|
|
|
|
|
NSLog(@"Connected to socket. Setting up dispatch sources...");
|
|
|
|
|
|
- self.readSource = dispatch_source_create(DISPATCH_SOURCE_TYPE_READ, self.sock, 0, self.localSocketQueue);
|
|
|
- dispatch_source_set_event_handler(self.readSource, ^(void){ [self readFromSocket]; });
|
|
|
- dispatch_source_set_cancel_handler(self.readSource, ^(void){
|
|
|
- self.readSource = nil;
|
|
|
+ _readSource = dispatch_source_create(DISPATCH_SOURCE_TYPE_READ, _sock, 0, _localSocketQueue);
|
|
|
+ dispatch_source_set_event_handler(_readSource, ^(void){ [self readFromSocket]; });
|
|
|
+ dispatch_source_set_cancel_handler(_readSource, ^(void){
|
|
|
+ self->_readSource = nil;
|
|
|
[self closeConnection];
|
|
|
});
|
|
|
|
|
|
- self.writeSource = dispatch_source_create(DISPATCH_SOURCE_TYPE_WRITE, self.sock, 0, self.localSocketQueue);
|
|
|
- dispatch_source_set_event_handler(self.writeSource, ^(void){ [self writeToSocket]; });
|
|
|
- dispatch_source_set_cancel_handler(self.writeSource, ^(void){
|
|
|
- self.writeSource = nil;
|
|
|
+ _writeSource = dispatch_source_create(DISPATCH_SOURCE_TYPE_WRITE, _sock, 0, _localSocketQueue);
|
|
|
+ dispatch_source_set_event_handler(_writeSource, ^(void){ [self writeToSocket]; });
|
|
|
+ dispatch_source_set_cancel_handler(_writeSource, ^(void){
|
|
|
+ self->_writeSource = nil;
|
|
|
[self closeConnection];
|
|
|
});
|
|
|
|
|
|
@@ -119,7 +135,7 @@
|
|
|
|
|
|
NSLog(@"Starting to read from socket");
|
|
|
|
|
|
- dispatch_resume(self.readSource);
|
|
|
+ dispatch_resume(_readSource);
|
|
|
[self askOnSocket:@"" query:@"GET_STRINGS"];
|
|
|
}
|
|
|
|
|
|
@@ -138,35 +154,35 @@
|
|
|
{
|
|
|
NSLog(@"Closing connection.");
|
|
|
|
|
|
- if(self.readSource) {
|
|
|
+ if(_readSource) {
|
|
|
// Since dispatch_source_cancel works asynchronously, if we deallocate the dispatch source here then we can
|
|
|
// cause a crash. So instead we strongly hold a reference to the read source and deallocate it asynchronously
|
|
|
// with the handler.
|
|
|
- __block dispatch_source_t previousReadSource = self.readSource;
|
|
|
- dispatch_source_set_cancel_handler(self.readSource, ^{
|
|
|
+ __block dispatch_source_t previousReadSource = _readSource;
|
|
|
+ dispatch_source_set_cancel_handler(_readSource, ^{
|
|
|
previousReadSource = nil;
|
|
|
});
|
|
|
- dispatch_source_cancel(self.readSource);
|
|
|
+ dispatch_source_cancel(_readSource);
|
|
|
// The readSource is still alive due to the other reference and will be deallocated by the cancel handler
|
|
|
- self.readSource = nil;
|
|
|
+ _readSource = nil;
|
|
|
}
|
|
|
|
|
|
- if(self.writeSource) {
|
|
|
+ if(_writeSource) {
|
|
|
// Same deal with the write source
|
|
|
- __block dispatch_source_t previousWriteSource = self.writeSource;
|
|
|
- dispatch_source_set_cancel_handler(self.writeSource, ^{
|
|
|
+ __block dispatch_source_t previousWriteSource = _writeSource;
|
|
|
+ dispatch_source_set_cancel_handler(_writeSource, ^{
|
|
|
previousWriteSource = nil;
|
|
|
});
|
|
|
- dispatch_source_cancel(self.writeSource);
|
|
|
- self.writeSource = nil;
|
|
|
+ dispatch_source_cancel(_writeSource);
|
|
|
+ _writeSource = nil;
|
|
|
}
|
|
|
|
|
|
- [self.inBuffer setLength:0];
|
|
|
- [self.outBuffer setLength: 0];
|
|
|
+ [_inBuffer setLength:0];
|
|
|
+ [_outBuffer setLength: 0];
|
|
|
|
|
|
- if(self.sock != -1) {
|
|
|
- close(self.sock);
|
|
|
- self.sock = -1;
|
|
|
+ if(_sock != -1) {
|
|
|
+ close(_sock);
|
|
|
+ _sock = -1;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -186,21 +202,21 @@
|
|
|
- (void)askOnSocket:(NSString *)path query:(NSString *)verb
|
|
|
{
|
|
|
NSString *line = [NSString stringWithFormat:@"%@:%@\n", verb, path];
|
|
|
- dispatch_async(self.localSocketQueue, ^(void) {
|
|
|
+ dispatch_async(_localSocketQueue, ^(void) {
|
|
|
if(![self isConnected]) {
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
- BOOL writeSourceIsSuspended = [self.outBuffer length] == 0;
|
|
|
+ BOOL writeSourceIsSuspended = [self->_outBuffer length] == 0;
|
|
|
|
|
|
- [self.outBuffer appendData:[line dataUsingEncoding:NSUTF8StringEncoding]];
|
|
|
+ [self->_outBuffer appendData:[line dataUsingEncoding:NSUTF8StringEncoding]];
|
|
|
|
|
|
NSLog(@"Writing to out buffer: '%@'", line);
|
|
|
- NSLog(@"Out buffer now %li bytes", [self.outBuffer length]);
|
|
|
+ NSLog(@"Out buffer now %li bytes", [self->_outBuffer length]);
|
|
|
|
|
|
if(writeSourceIsSuspended) {
|
|
|
NSLog(@"Resuming write dispatch source.");
|
|
|
- dispatch_resume(self.writeSource);
|
|
|
+ dispatch_resume(self->_writeSource);
|
|
|
}
|
|
|
});
|
|
|
}
|
|
|
@@ -211,17 +227,17 @@
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
- if([self.outBuffer length] == 0) {
|
|
|
+ if([_outBuffer length] == 0) {
|
|
|
NSLog(@"Empty out buffer, suspending write dispatch source.");
|
|
|
- dispatch_suspend(self.writeSource);
|
|
|
+ dispatch_suspend(_writeSource);
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
- NSLog(@"About to write %li bytes from outbuffer to socket.", [self.outBuffer length]);
|
|
|
+ NSLog(@"About to write %li bytes from outbuffer to socket.", [_outBuffer length]);
|
|
|
|
|
|
- long bytesWritten = write(self.sock, [self.outBuffer bytes], [self.outBuffer length]);
|
|
|
- char lineWritten[[self.outBuffer length]];
|
|
|
- memcpy(lineWritten, [self.outBuffer bytes], [self.outBuffer length]);
|
|
|
+ long bytesWritten = write(_sock, [_outBuffer bytes], [_outBuffer length]);
|
|
|
+ char lineWritten[[_outBuffer length]];
|
|
|
+ memcpy(lineWritten, [_outBuffer bytes], [_outBuffer length]);
|
|
|
NSLog(@"Wrote %li bytes to socket. Line written was: '%@'", bytesWritten, [NSString stringWithUTF8String:lineWritten]);
|
|
|
|
|
|
if(bytesWritten == 0) {
|
|
|
@@ -240,13 +256,13 @@
|
|
|
[self restart];
|
|
|
}
|
|
|
} else if(bytesWritten > 0) {
|
|
|
- [self.outBuffer replaceBytesInRange:NSMakeRange(0, bytesWritten) withBytes:NULL length:0];
|
|
|
+ [_outBuffer replaceBytesInRange:NSMakeRange(0, bytesWritten) withBytes:NULL length:0];
|
|
|
|
|
|
- NSLog(@"Out buffer cleared. Now count is %li bytes.", [self.outBuffer length]);
|
|
|
+ NSLog(@"Out buffer cleared. Now count is %li bytes.", [_outBuffer length]);
|
|
|
|
|
|
- if([self.outBuffer length] == 0) {
|
|
|
+ if([_outBuffer length] == 0) {
|
|
|
NSLog(@"Out buffer has been emptied, suspending write dispatch source.");
|
|
|
- dispatch_suspend(self.writeSource);
|
|
|
+ dispatch_suspend(_writeSource);
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
@@ -277,7 +293,7 @@
|
|
|
char buffer[bufferLength];
|
|
|
|
|
|
while(true) {
|
|
|
- long bytesRead = read(self.sock, buffer, bufferLength);
|
|
|
+ long bytesRead = read(_sock, buffer, bufferLength);
|
|
|
|
|
|
NSLog(@"Read %li bytes from socket.", bytesRead);
|
|
|
|
|
|
@@ -297,7 +313,7 @@
|
|
|
return;
|
|
|
}
|
|
|
} else {
|
|
|
- [self.inBuffer appendBytes:buffer length:bytesRead];
|
|
|
+ [_inBuffer appendBytes:buffer length:bytesRead];
|
|
|
[self processInBuffer];
|
|
|
}
|
|
|
}
|
|
|
@@ -305,22 +321,22 @@
|
|
|
|
|
|
- (void)processInBuffer
|
|
|
{
|
|
|
- NSLog(@"Processing in buffer. In buffer length %li", [self.inBuffer length]);
|
|
|
+ NSLog(@"Processing in buffer. In buffer length %li", [_inBuffer length]);
|
|
|
UInt8 separator[] = {0xa}; // Byte value for "\n"
|
|
|
while(true) {
|
|
|
- NSRange firstSeparatorIndex = [self.inBuffer rangeOfData:[NSData dataWithBytes:separator length:1] options:0 range:NSMakeRange(0, [self.inBuffer length])];
|
|
|
+ NSRange firstSeparatorIndex = [_inBuffer rangeOfData:[NSData dataWithBytes:separator length:1] options:0 range:NSMakeRange(0, [_inBuffer length])];
|
|
|
|
|
|
if(firstSeparatorIndex.location == NSNotFound) {
|
|
|
NSLog(@"No separator found. Stopping.");
|
|
|
return; // No separator, nope out
|
|
|
} else {
|
|
|
- unsigned char *buffer = [self.inBuffer mutableBytes];
|
|
|
+ unsigned char *buffer = [_inBuffer mutableBytes];
|
|
|
buffer[firstSeparatorIndex.location] = 0; // Add NULL terminator, so we can use C string methods
|
|
|
|
|
|
- NSString *newLine = [NSString stringWithUTF8String:[self.inBuffer bytes]];
|
|
|
+ NSString *newLine = [NSString stringWithUTF8String:[_inBuffer bytes]];
|
|
|
|
|
|
- [self.inBuffer replaceBytesInRange:NSMakeRange(0, firstSeparatorIndex.location + 1) withBytes:NULL length:0];
|
|
|
- [self.lineProcessor process:newLine];
|
|
|
+ [_inBuffer replaceBytesInRange:NSMakeRange(0, firstSeparatorIndex.location + 1) withBytes:NULL length:0];
|
|
|
+ [_lineProcessor process:newLine];
|
|
|
}
|
|
|
}
|
|
|
}
|