pingpong: need to handle the first part of the frame first
This commit is contained in:
@@ -101,116 +101,62 @@
|
|||||||
|
|
||||||
#pragma mark - Override AsyncSocket Delegate
|
#pragma mark - Override AsyncSocket Delegate
|
||||||
|
|
||||||
- (void)socket:(GCDAsyncSocket *)asyncSocket didReadData:(NSData *)data withTag:(long)tag {
|
- (void)socket:(GCDAsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag {
|
||||||
|
BOOL nextFrameMasked = [[self valueForKey:@"nextFrameMasked"] boolValue];
|
||||||
NSUInteger nextOpCode = [[self valueForKey:@"nextOpCode"] unsignedIntValue]; // sheesh.
|
NSUInteger nextOpCode = [[self valueForKey:@"nextOpCode"] unsignedIntValue]; // sheesh.
|
||||||
|
|
||||||
NSLog(@"tag: %ld, nextOpCode: %ld", tag, nextOpCode);
|
NSLog(@"tag: %ld, nextOpCode: %lu", tag, (unsigned long)nextOpCode);
|
||||||
|
|
||||||
// Handle our custom ping/pong tags
|
// Handle our custom ping payload tag
|
||||||
if (tag == TAG_PING_PAYLOAD) {
|
if (tag == TAG_PING_PAYLOAD) {
|
||||||
// We've read the ping payload, now send the pong response
|
// We've read the ping payload, now send the pong response
|
||||||
[self sendPongWithPayload:data socket:asyncSocket];
|
NSData *payload = data;
|
||||||
|
|
||||||
|
// If the frame was masked, we need to unmask it
|
||||||
|
if (nextFrameMasked && pendingPingPayload) {
|
||||||
|
NSMutableData *unmaskedPayload = [data mutableCopy];
|
||||||
|
UInt8 *payloadBytes = [unmaskedPayload mutableBytes];
|
||||||
|
UInt8 *maskBytes = (UInt8 *)[pendingPingPayload bytes];
|
||||||
|
|
||||||
|
for (NSUInteger i = 0; i < [data length]; i++) {
|
||||||
|
payloadBytes[i] ^= maskBytes[i % 4];
|
||||||
|
}
|
||||||
|
payload = [unmaskedPayload copy];
|
||||||
|
}
|
||||||
|
|
||||||
|
[self sendPongWithPayload:payload socket:sock];
|
||||||
|
|
||||||
// Continue reading the next frame
|
// Continue reading the next frame
|
||||||
[asyncSocket readDataToLength:1 withTimeout:TIMEOUT_NONE tag:TAG_PAYLOAD_PREFIX];
|
[asyncSocket readDataToLength:1 withTimeout:TIMEOUT_NONE tag:TAG_PAYLOAD_PREFIX];
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tag == TAG_PONG_SENT) {
|
// Let the parent handle the frame parsing logic first
|
||||||
// Pong was sent successfully, continue normal operation
|
[super socket:sock didReadData:data withTag:tag];
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// For TAG_PAYLOAD_PREFIX, we need to intercept and handle ping frames
|
// After the parent has processed, check if we need to handle ping/pong
|
||||||
if (tag == TAG_PAYLOAD_PREFIX) {
|
if (tag == TAG_MSG_WITH_LENGTH) {
|
||||||
UInt8 *pFrame = (UInt8 *)[data bytes];
|
// The parent just finished reading a complete message
|
||||||
UInt8 frame = *pFrame;
|
|
||||||
|
|
||||||
// Check if this is a valid WebSocket frame
|
|
||||||
if (![self isValidWebSocketFrame:frame]) {
|
|
||||||
[self didClose];
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
NSUInteger opcode = frame & 0x0F;
|
|
||||||
|
|
||||||
// Handle ping frames specially
|
|
||||||
if (opcode == WS_OP_PING) {
|
|
||||||
// Read the payload length byte next
|
|
||||||
[asyncSocket readDataToLength:1 withTimeout:TIMEOUT_NONE tag:TAG_PAYLOAD_LENGTH];
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handle pong frames (just log and continue)
|
|
||||||
if (opcode == WS_OP_PONG) {
|
|
||||||
NSLog(@"Received pong frame");
|
|
||||||
// Read the payload length byte next, but we'll ignore pong payloads
|
|
||||||
[asyncSocket readDataToLength:1 withTimeout:TIMEOUT_NONE tag:TAG_PAYLOAD_LENGTH];
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// For TAG_PAYLOAD_LENGTH, check if we're handling a ping
|
|
||||||
if (tag == TAG_PAYLOAD_LENGTH) {
|
|
||||||
UInt8 frame = *(UInt8 *)[data bytes];
|
|
||||||
BOOL masked = (frame & 0x80) != 0;
|
|
||||||
NSUInteger length = frame & 0x7F;
|
|
||||||
|
|
||||||
// If we were processing a ping frame, handle the payload reading
|
|
||||||
if (nextOpCode == WS_OP_PING) {
|
if (nextOpCode == WS_OP_PING) {
|
||||||
if (length <= 125) {
|
// This was a ping frame - the parent would have tried to process it as text
|
||||||
if (masked) {
|
// We need to send a pong response
|
||||||
// Read masking key first, then payload
|
NSData *payload = data;
|
||||||
[asyncSocket readDataToLength:4 withTimeout:TIMEOUT_NONE tag:TAG_MSG_MASKING_KEY];
|
|
||||||
}
|
|
||||||
// Read ping payload
|
|
||||||
[asyncSocket readDataToLength:length withTimeout:TIMEOUT_NONE tag:TAG_PING_PAYLOAD];
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
else if (length == 126) {
|
|
||||||
[asyncSocket readDataToLength:2 withTimeout:TIMEOUT_NONE tag:TAG_PAYLOAD_LENGTH16];
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
[asyncSocket readDataToLength:8 withTimeout:TIMEOUT_NONE tag:TAG_PAYLOAD_LENGTH64];
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// If we were processing a pong frame, just skip it
|
// If the frame was masked, unmask it (parent already did this)
|
||||||
if (nextOpCode == WS_OP_PONG) {
|
[self sendPongWithPayload:payload socket:sock];
|
||||||
if (length <= 125) {
|
|
||||||
if (masked) {
|
// Don't call didReceiveMessage for ping frames
|
||||||
[asyncSocket readDataToLength:4 withTimeout:TIMEOUT_NONE tag:TAG_MSG_MASKING_KEY];
|
return;
|
||||||
}
|
}
|
||||||
// Skip pong payload and continue to next frame
|
else if (nextOpCode == WS_OP_PONG) {
|
||||||
[asyncSocket readDataToLength:length withTimeout:TIMEOUT_NONE tag:TAG_PAYLOAD_PREFIX];
|
// This was a pong frame - just log it and continue
|
||||||
return;
|
NSLog(@"Received pong frame with payload length: %lu", (unsigned long)[data length]);
|
||||||
}
|
return;
|
||||||
else if (length == 126) {
|
|
||||||
[asyncSocket readDataToLength:2 withTimeout:TIMEOUT_NONE tag:TAG_PAYLOAD_LENGTH16];
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
[asyncSocket readDataToLength:8 withTimeout:TIMEOUT_NONE tag:TAG_PAYLOAD_LENGTH64];
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle masking key reading for ping frames
|
|
||||||
if (tag == TAG_MSG_MASKING_KEY && nextOpCode == WS_OP_PING) {
|
|
||||||
// Store the masking key and read the actual payload
|
|
||||||
pendingPingPayload = [data copy];
|
|
||||||
// The payload length was already determined, read it
|
|
||||||
// Note: This is a simplified version - you'd need to track the actual length
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// For all other cases, call the parent implementation
|
|
||||||
[super socket:asyncSocket didReadData:data withTag:tag];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#pragma mark - Helper Methods
|
#pragma mark - Helper Methods
|
||||||
|
|
||||||
// Expose the isValidWebSocketFrame method since it's private in the parent
|
// Expose the isValidWebSocketFrame method since it's private in the parent
|
||||||
|
|||||||
Reference in New Issue
Block a user