diff --git a/kordophone/Bridge/MBIMPingPongWebSocket.m b/kordophone/Bridge/MBIMPingPongWebSocket.m index 3e36fae..b36fba8 100644 --- a/kordophone/Bridge/MBIMPingPongWebSocket.m +++ b/kordophone/Bridge/MBIMPingPongWebSocket.m @@ -102,8 +102,10 @@ #pragma mark - Override AsyncSocket Delegate - (void)socket:(GCDAsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag { + // xxx: sheesh: really need to get off of CococaHTTPServer. + NSData *maskingKey = [self valueForKey:@"maskingKey"]; BOOL nextFrameMasked = [[self valueForKey:@"nextFrameMasked"] boolValue]; - NSUInteger nextOpCode = [[self valueForKey:@"nextOpCode"] unsignedIntValue]; // sheesh. + NSUInteger nextOpCode = [[self valueForKey:@"nextOpCode"] unsignedIntValue]; NSLog(@"tag: %ld, nextOpCode: %lu", tag, (unsigned long)nextOpCode); @@ -113,10 +115,10 @@ NSData *payload = data; // If the frame was masked, we need to unmask it - if (nextFrameMasked && pendingPingPayload) { + if (nextFrameMasked && maskingKey) { NSMutableData *unmaskedPayload = [data mutableCopy]; UInt8 *payloadBytes = [unmaskedPayload mutableBytes]; - UInt8 *maskBytes = (UInt8 *)[pendingPingPayload bytes]; + UInt8 *maskBytes = (UInt8 *)[maskingKey bytes]; for (NSUInteger i = 0; i < [data length]; i++) { payloadBytes[i] ^= maskBytes[i % 4]; @@ -131,29 +133,60 @@ return; } - // Let the parent handle the frame parsing logic first - [super socket:sock didReadData:data withTag:tag]; - - // After the parent has processed, check if we need to handle ping/pong - if (tag == TAG_MSG_WITH_LENGTH) { - // The parent just finished reading a complete message - if (nextOpCode == WS_OP_PING) { - // This was a ping frame - the parent would have tried to process it as text - // We need to send a pong response - NSData *payload = data; - - // If the frame was masked, unmask it (parent already did this) - [self sendPongWithPayload:payload socket:sock]; - - // Don't call didReceiveMessage for ping frames - return; - } - else if (nextOpCode == WS_OP_PONG) { - // This was a pong frame - just log it and continue - NSLog(@"Received pong frame with payload length: %lu", (unsigned long)[data length]); - return; - } + // Intercept after masking key is read for ping/pong frames + if (tag == TAG_MSG_MASKING_KEY && (nextOpCode == WS_OP_PING || nextOpCode == WS_OP_PONG)) { + // Store the masking key + maskingKey = [data copy]; + // We need to determine the payload length and read it + // The parent class should have stored this somewhere, but we'll need to track it + // For now, let's assume short payload and read what was scheduled + return; } + + // Intercept the payload length phase for ping/pong frames + if (tag == TAG_PAYLOAD_LENGTH && (nextOpCode == WS_OP_PING || nextOpCode == WS_OP_PONG)) { + UInt8 frame = *(UInt8 *)[data bytes]; + BOOL masked = (frame & 0x80) != 0; + NSUInteger length = frame & 0x7F; + nextFrameMasked = masked; + + if (length <= 125) { + if (nextFrameMasked) { + [asyncSocket readDataToLength:4 withTimeout:TIMEOUT_NONE tag:TAG_MSG_MASKING_KEY]; + } + [asyncSocket readDataToLength:length withTimeout:TIMEOUT_NONE tag:TAG_PING_PAYLOAD]; + } + else if (length == 126) { + [asyncSocket readDataToLength:2 withTimeout:TIMEOUT_NONE tag:TAG_PAYLOAD_LENGTH16]; + } + else { + [asyncSocket readDataToLength:8 withTimeout:TIMEOUT_NONE tag:TAG_PAYLOAD_LENGTH64]; + } + return; + } + + // Handle extended length for ping/pong + if ((tag == TAG_PAYLOAD_LENGTH16 || tag == TAG_PAYLOAD_LENGTH64) && (nextOpCode == WS_OP_PING || nextOpCode == WS_OP_PONG)) { + NSUInteger length = 0; + if (tag == TAG_PAYLOAD_LENGTH16) { + UInt8 *pFrame = (UInt8 *)[data bytes]; + length = ((NSUInteger)pFrame[0] << 8) | (NSUInteger)pFrame[1]; + } else { + // For 64-bit length, this is complex - for now just close + [self didClose]; + return; + } + + if (nextFrameMasked) { + [asyncSocket readDataToLength:4 withTimeout:TIMEOUT_NONE tag:TAG_MSG_MASKING_KEY]; + } + [asyncSocket readDataToLength:length withTimeout:TIMEOUT_NONE tag:TAG_PING_PAYLOAD]; + return; + } + + // For all other cases, call the parent implementation + [super socket:sock didReadData:data withTag:tag]; + }