commit 6964f7f7dab7c07c2a2b35e0db01aa777147be66
parent 1f042b19e6449935a4cbfead730c85d1222b3ee2
Author: Kyle Milz <kyle@Kyles-MacBook-Pro.local>
Date: Sun, 20 Sep 2015 00:30:50 -0600
ios: start moving connection reuse message passing
Diffstat:
1 file changed, 262 insertions(+), 180 deletions(-)
diff --git a/ios-ng/shlist/Network.m b/ios-ng/shlist/Network.m
@@ -2,13 +2,27 @@
#import "DataStructures.h"
#import "AddressBook.h"
-@interface Network ()
+@interface Network () {
+ NSData *msg_data;
+ NSString *msg_string;
+ uint8_t msg_buffer[1024];
+ unsigned int msg_buf_position;
+
+ uint8_t msg_total_bytes_tmp[2];
+ unsigned short msg_total_bytes;
+ unsigned int msg_total_bytes_pos;
+
+ uint8_t msg_type_tmp[2];
+ unsigned short msg_type;
+ unsigned int msg_type_pos;
+
+ int connected;
+}
@property (strong, retain) NSMutableData *data;
@property (strong, retain) AddressBook *address_book;
@property NSMutableDictionary *phnum_to_name_map;
-
@property (strong, nonatomic) NSString *phone_number;
@property (strong, nonatomic) NSData *device_id;
@@ -19,25 +33,16 @@
- (id) init
{
if (self = [super init]) {
- /*
- CFReadStreamRef readStream;
- CFWriteStreamRef writeStream;
+ connected = 0;
+ msg_buf_position = 0;
- CFStringRef host_name = CFSTR("absentmindedproductions.ca");
+ msg_total_bytes = 0;
+ msg_total_bytes_pos = 0;
- CFStreamCreatePairWithSocketToHost(NULL, host_name, 5437, &readStream, &writeStream);
- inputShlistStream = (__bridge NSInputStream *)readStream;
- outputShlistStream = (__bridge NSOutputStream *)writeStream;
+ msg_type = 0;
+ msg_type_pos = 0;
- [inputShlistStream setDelegate:self];
- [outputShlistStream setDelegate:self];
-
- [inputShlistStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
- [outputShlistStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
-
- [inputShlistStream open];
- [outputShlistStream open];
- */
+ // [self connect];
// get instance and wait for privacy window to clear
_address_book = [AddressBook shared_address_book];
@@ -72,12 +77,36 @@
return self;
}
+- (void) connect
+{
+ CFReadStreamRef readStream;
+ CFWriteStreamRef writeStream;
+
+ CFStringRef host_name = CFSTR("absentmindedproductions.ca");
+
+ CFStreamCreatePairWithSocketToHost(NULL, host_name, 5437, &readStream, &writeStream);
+ inputShlistStream = (__bridge NSInputStream *)readStream;
+ outputShlistStream = (__bridge NSOutputStream *)writeStream;
+
+ [inputShlistStream setDelegate:self];
+ [outputShlistStream setDelegate:self];
+
+ [inputShlistStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
+ [outputShlistStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
+
+ [inputShlistStream open];
+ [outputShlistStream open];
+
+ NSLog(@"info: network: finished connecting to absentmindedproductions.ca");
+}
+
- (bool) prepare
{
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
// NSString *phone_num_file = [documentsDirectory stringByAppendingPathComponent:@"phone_num"];
+ _phone_number = @"4037082094";
NSString *device_id_file = [documentsDirectory stringByAppendingPathComponent:@"shlist_key"];
// NSError *error = nil;
@@ -97,10 +126,11 @@
// actual phone number
const char *phone_number = "4037082094";
- _phone_number = @"4037082094";
[msg appendBytes:phone_number length:10];
- [self writeToServer:msg];
+ if (connected == 0)
+ [self connect];
+ [outputShlistStream write:[msg bytes] maxLength:[msg length]];
NSLog(@"info: sent registration message");
// we don't have a device id so we can't do anything yet
@@ -113,11 +143,11 @@
return true;
}
-- (void) send_message:(uint16_t)msg_type contents:(NSData *)payload
+- (void) send_message:(uint16_t)send_msg_type contents:(NSData *)payload
{
NSMutableData *msg = [NSMutableData data];
- uint16_t msg_type_network = htons(msg_type);
+ uint16_t msg_type_network = htons(send_msg_type);
[msg appendBytes:&msg_type_network length:2];
int payload_length = 0;
@@ -135,168 +165,261 @@
[msg appendData:payload];
}
- [self writeToServer:msg];
+ if (connected == 0) {
+ NSLog(@"info: network: not connected in send_message, reconnecting...");
+ [self connect];
+ }
+ if ([outputShlistStream write:[msg bytes] maxLength:[msg length]] == -1)
+ NSLog(@"warn: network: write error occurred");
}
- (void)stream:(NSStream *)stream handleEvent:(NSStreamEvent)eventCode
{
- switch (eventCode) {
+ NSString *stream_name;
+ if (stream == inputShlistStream)
+ stream_name = @"input";
+ else if (stream == outputShlistStream)
+ stream_name = @"output";
+
+ switch (eventCode) {
case NSStreamEventNone:
break;
case NSStreamEventOpenCompleted:
- if (stream == inputShlistStream) {
- NSLog(@"info: input stream opened");
- }
- else if (stream == outputShlistStream) {
- NSLog(@"info: output stream opened");
- }
+ NSLog(@"info: network: %@ stream opened", stream_name);
+ connected = 1;
break;
case NSStreamEventHasBytesAvailable:
if (stream == inputShlistStream) {
- /*
if (![inputShlistStream hasBytesAvailable]) {
+ NSLog(@"warn: network: input stream had no bytes available");
break;
}
- */
- NSInteger len;
- uint16_t msg_metadata[2];
+ // advance the message state machine by at least one byte
+ [self process_response_bytes];
+ }
+ break;
+ case NSStreamEventHasSpaceAvailable:
+ NSLog(@"info: network: stream has space available");
+ break;
+ case NSStreamEventErrorOccurred:
+ NSLog(@"info: network: stream error occurred");
+ // I saw this case when trying to connect to a down server
+ break;
+ case NSStreamEventEndEncountered:
- len = [inputShlistStream read:(uint8_t *)&msg_metadata maxLength:4];
- if (len != 4) {
- NSLog(@"warn: read: msg metadata was %li bytes, expected 4",
- (long)len);
- break;
- }
+ // close both sides of the connection on end
+ NSLog(@"ShlistServer::NSStreamEventEndEncountered");
+ [inputShlistStream close];
+ [outputShlistStream close];
- uint16_t msg_type = ntohs(msg_metadata[0]);
- uint16_t msg_length = ntohs(msg_metadata[1]);
- if (msg_type > 6) {
- NSLog(@"warn: read: out of range msg type %i", msg_type);
- break;
- }
+ [inputShlistStream removeFromRunLoop:[NSRunLoop currentRunLoop]
+ forMode:NSDefaultRunLoopMode];
+ [outputShlistStream removeFromRunLoop:[NSRunLoop currentRunLoop]
+ forMode:NSDefaultRunLoopMode];
+ // [inputShlistStream release];
+ // [outputShlistStream release];
- if (msg_length > 1024) {
- NSLog(@"warn: read: message too large: %i bytes", msg_length);
- break;
- }
+ inputShlistStream = nil; // stream is ivar, so reinit it
+ outputShlistStream = nil; // stream is ivar, so reinit it
+ connected = 0;
- // guaranteed valid message type and size from here forward
- NSLog(@"info: read: got msg type %i (%i bytes)", msg_type, msg_length);
+ break;
+ default:
+ break;
+ }
+}
- uint8_t *buffer = malloc(msg_length);
- if (buffer == nil) {
- NSLog(@"warn: read: couldn't allocate receiving buffer size %i",
- msg_length);
- break;
+- (void) process_response_bytes
+{
+ uint8_t *buffer = malloc(1024);
+ while ([inputShlistStream hasBytesAvailable]) {
+
+ unsigned int buffer_pos = 0;
+ NSInteger buffer_length;
+
+ buffer_length = [inputShlistStream read:buffer maxLength:1024];
+ if (buffer_length < 0) {
+ NSLog(@"warn: network: read returned < 0: %i", buffer_length);
+ // XXX: should this be break instead?
+ continue;
}
- len = [inputShlistStream read:buffer maxLength:msg_length];
- if (len != msg_length) {
- NSLog(@"warn: read: main message read byte mismatch: %li vs %i",
- (long)len, msg_length);
- break;
+ if (buffer_length == 0) {
+ NSLog(@"warn: network: buffer length was zero!");
+ // maybe break here instead?
+ continue;
}
- NSString *output = [[NSString alloc] initWithBytes:buffer length:len encoding:NSASCIIStringEncoding];
- NSData *data = [[NSData alloc] initWithBytes:buffer length:msg_length];
+ NSLog(@"info: network: processing %i bytes", buffer_length);
- if (output == nil) {
- NSLog(@"warn: read: couldn't allocate output string");
- break;
+ // start receiving a new message
+ if (msg_type_pos == 0) {
+ msg_type_tmp[0] = buffer[buffer_pos];
+ msg_type_pos = 1;
+ buffer_pos++;
+
+ if (buffer_length == 1)
+ // we've exhausted the buffer
+ continue;
}
- // NSLog(@"info: read: message is %@", output);
-
- if (msg_type == 0) {
- // write key to file
- NSLog(@"info: read: writing new keyfile to disk");
-
- NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
- NSString *documentsDirectory = [paths objectAtIndex:0];
-
- NSString *destinationPath = [documentsDirectory stringByAppendingPathComponent:@"shlist_key"];
- // if (![[NSFileManager defaultManager] fileExistsAtPath:destinationPath]) {
- [data writeToFile:destinationPath atomically:YES];
- // }
-
- // set this so we're ready to send other message types
- _device_id = data;
-
- // do a bulk list update
- [self send_message:3 contents:nil];
+
+ // if we got here buffer_length > 1
+ if (msg_type_pos == 1) {
+ msg_type_pos = 2;
+ msg_type_tmp[1] = buffer[buffer_pos];
+
+ // we read a single byte from the buffer
+ buffer_pos++;
+
+ // both bytes are available for reading
+ msg_type = ntohs(*(uint16_t *)msg_type_tmp);
+ if (msg_type > 7) {
+ NSLog(@"warn: network: out of range msg type %i", buffer[0]);
+
+ // bad message type, reset message buffer
+ msg_type_pos = 0;
+ msg_buf_position = 0;
+ msg_total_bytes_pos = 0;
+ continue;
+ }
+ NSLog(@"info: network: got message type %i", msg_type);
+
+ if (buffer_pos == buffer_length)
+ // we've run out of bytes to process
+ continue;
}
- if (msg_type == 1) {
- NSLog(@"info: got new list response, not doing anything with it");
+ // if we got here buffer_pos < buffer_length
+ if (msg_total_bytes_pos == 0) {
+ msg_total_bytes_pos = 1;
+ msg_total_bytes_tmp[0] = buffer[buffer_pos];
+ buffer_pos++;
+
+ if (buffer_pos == buffer_length)
+ // no more bytes to process
+ continue;
}
- if (msg_type == 3) {
- [self handle_bulk_list_update:output];
+ if (msg_total_bytes_pos == 1) {
+ msg_total_bytes_pos = 2;
+ msg_total_bytes_tmp[1] = buffer[buffer_pos];
+ buffer_pos++;
+
+ msg_total_bytes = ntohs(*(uint16_t *)msg_total_bytes_tmp);
+ if (msg_total_bytes > 1024 || msg_total_bytes == 0) {
+ NSLog(@"warn: network: out of range message length: 0 < %i < 1024",
+ msg_total_bytes);
+
+ // bad message type, reset message buffer
+ msg_type_pos = 0;
+ msg_buf_position = 0;
+ msg_total_bytes_pos = 0;
+ continue;
+ }
+ NSLog(@"info: network: message length is %i bytes", msg_total_bytes);
+
+ if (buffer_pos == buffer_length)
+ // no more bytes to process
+ continue;
}
- if (msg_type == 4) {
- NSLog(@"info: join list response '%@'", output);
+ unsigned int remaining_bytes = buffer_length - buffer_pos;
+
+ if (msg_buf_position + remaining_bytes >= msg_total_bytes) {
+ NSLog(@"info: network: buffer length has enough space to read complete message");
- SharedList *shlist = [[SharedList alloc] init];
- shlist.id = data;
+ unsigned int bytes_for_complete_message = msg_total_bytes - msg_buf_position;
+ memcpy(msg_buffer + msg_buf_position, &buffer[buffer_pos], bytes_for_complete_message);
+ msg_buf_position += bytes_for_complete_message;
- // XXX: these need to be sent from the server
- shlist.items_ready = 0;
- shlist.items_total = 99;
- // shlist.list_name = <network>;
- // shlist.members = <network>;
+ msg_data = [[NSData alloc] initWithBytes:msg_buffer length:msg_total_bytes];
+ msg_string = [[NSString alloc] initWithBytes:msg_buffer length:msg_total_bytes encoding:NSASCIIStringEncoding];
- [shlist_tvc finished_join_list_request:shlist];
+ [self handle_message];
+
+ // reset parsing fields, leave buffer position fields alone though
+ msg_buf_position = 0;
+ msg_type_pos = 0;
+ msg_total_bytes_pos = 0;
+
+ // lop off anything else that's remaining in the read buffer
+ continue;
}
- if (msg_type == 5) {
- NSLog(@"info: leave list response '%@'", output);
+ // copy any remaining data into msg buffer
+ memcpy(msg_buffer + msg_buf_position, &buffer[buffer_pos], remaining_bytes);
+ msg_buf_position += remaining_bytes;
+ }
- NSArray *fields = [output componentsSeparatedByString:@"\0"];
+ // free temporary buffer, not msg_buffer
+ free(buffer);
+}
- if ([fields count] != 2) {
- NSLog(@"warn: leave list response had wrong number (%i) of fields",
- [fields count]);
- break;
- }
+- (void) handle_message
+{
+ // assert msg_type_pos == 2 and msg_total_bytes_pos == 2 and msg_buf_position == msg_total_bytes
- SharedList *shlist = [[SharedList alloc] init];
- shlist.id = [[fields objectAtIndex:0] dataUsingEncoding:NSUTF8StringEncoding];
+ if (msg_type == 0) {
+ // write key to file
+ NSLog(@"info: read: writing new keyfile to disk");
- // XXX: these need to be sent from the server
- // shlist.list_name = <network>;
- // shlist.members = <network>;
+ NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
+ NSString *documentsDirectory = [paths objectAtIndex:0];
- [shlist_tvc finished_leave_list_request:shlist];
- }
+ NSString *destinationPath = [documentsDirectory stringByAppendingPathComponent:@"shlist_key"];
+ // if (![[NSFileManager defaultManager] fileExistsAtPath:destinationPath]) {
+ [msg_data writeToFile:destinationPath atomically:YES];
+ // }
+
+ // set this so we're ready to send other message types
+ _device_id = msg_data;
+
+ // do a bulk list update
+ [self send_message:3 contents:nil];
}
- break;
- case NSStreamEventHasSpaceAvailable:
- [self _writeData];
- break;
- case NSStreamEventErrorOccurred:
- NSLog(@"ShlistServer::NSStreamEventErrorOccurred");
- // I saw this case when trying to connect to a down server
- break;
- case NSStreamEventEndEncountered:
- {
- NSLog(@"ShlistServer::NSStreamEventEndEncountered");
- [inputShlistStream close];
- [outputShlistStream close];
- [inputShlistStream removeFromRunLoop:[NSRunLoop currentRunLoop]
- forMode:NSDefaultRunLoopMode];
- [outputShlistStream removeFromRunLoop:[NSRunLoop currentRunLoop]
- forMode:NSDefaultRunLoopMode];
- // [inputShlistStream release];
- // [outputShlistStream release];
+ if (msg_type == 1) {
+ NSLog(@"info: got new list response, not doing anything with it");
+ }
- inputShlistStream = nil; // stream is ivar, so reinit it
- outputShlistStream = nil; // stream is ivar, so reinit it
+ if (msg_type == 3) {
+ [self handle_bulk_list_update:msg_string];
+ }
- break;
+ if (msg_type == 4) {
+ NSLog(@"info: join list response '%@'", msg_string);
+
+ SharedList *shlist = [[SharedList alloc] init];
+ shlist.id = msg_data;
+
+ // XXX: these need to be sent from the server
+ shlist.items_ready = 0;
+ shlist.items_total = 99;
+ // shlist.list_name = <network>;
+ // shlist.members = <network>;
+
+ [shlist_tvc finished_join_list_request:shlist];
}
- default:
- break;
+
+ if (msg_type == 5) {
+ NSLog(@"info: leave list response '%@'", msg_string);
+
+ NSArray *fields = [msg_string componentsSeparatedByString:@"\0"];
+
+ if ([fields count] != 2) {
+ NSLog(@"warn: leave list response had wrong number (%i) of fields",
+ [fields count]);
+ return;
+ }
+
+ SharedList *shlist = [[SharedList alloc] init];
+ shlist.id = [[fields objectAtIndex:0] dataUsingEncoding:NSUTF8StringEncoding];
+
+ // XXX: these need to be sent from the server
+ // shlist.list_name = <network>;
+ // shlist.members = <network>;
+
+ [shlist_tvc finished_leave_list_request:shlist];
}
}
@@ -415,45 +538,4 @@
outputShlistStream = nil; // stream is ivar, so reinit it
}
-- (void) _readData
-{
-}
-
-- (void) _writeData
-{
- NSLog(@"_writeData");
-}
-
-- (void) writeToServer:(NSData *)data
-{
- CFReadStreamRef readStream;
- CFWriteStreamRef writeStream;
-
- CFStringRef host_name = CFSTR("absentmindedproductions.ca");
-
- CFStreamCreatePairWithSocketToHost(NULL, host_name, 5437, &readStream, &writeStream);
- inputShlistStream = (__bridge NSInputStream *)readStream;
- outputShlistStream = (__bridge NSOutputStream *)writeStream;
-
- [inputShlistStream setDelegate:self];
- [outputShlistStream setDelegate:self];
-
- [inputShlistStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
- [outputShlistStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
-
- [inputShlistStream open];
- [outputShlistStream open];
-
- // const char bytes[] = "\x00\x00\xff\0x00";
- //string literals have implicit trailing '\0'
- // size_t length = (sizeof bytes) - 1;
-
- // NSData *data = [NSData dataWithBytes:bytes length:length];
- NSLog(@"writeToServer()");
- [outputShlistStream write:[data bytes] maxLength:[data length]];
-}
-
-// - (void) readFromServer:
-
-
@end