Обратный вызов CFSocket Objective-C не вызывается при приеме сокета - PullRequest
0 голосов
/ 24 января 2019

У меня возникла проблема при попытке использовать CFSockets API в CoreFoundation. Я пытаюсь прослушать порт и принять входящие соединения. Похоже, это работает с приведенным ниже кодом, так как запуск nc localhost 8118 оставляет терминал в подключенном состоянии. Однако метод обратного вызова handleConnect() никогда не вызывается. Я не вижу, что я делаю неправильно после прочтения документации Apple ... мой код:

#import <Foundation/Foundation.h>
#import <CoreFoundation/CoreFoundation.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include "SocketManager.h"

@implementation SocketManager

- (instancetype)init
    {
        self = [super init];
        if (self) {
            self.port = 8118;
    }
        return self;
}

-(void)startListening
{
    CFSocketContext ctxt = {0, CFBridgingRetain(self), NULL, NULL, NULL};
    self.ipv4ListeningSocket = CFSocketCreate(kCFAllocatorDefault, PF_INET, SOCK_STREAM, IPPROTO_TCP, kCFSocketAcceptCallBack, (CFSocketCallBack)&handleConnect, &ctxt);
    int yes = 1;
    setsockopt(CFSocketGetNative(self.ipv4ListeningSocket), SOL_SOCKET, SO_REUSEADDR, (void *)&yes, sizeof(yes));

    struct sockaddr_in addr4;
    memset(&addr4, 0, sizeof(addr4));
    addr4.sin_len = sizeof(addr4);
    addr4.sin_family = AF_INET;
    addr4.sin_port = htons(self.port);
    addr4.sin_addr.s_addr = htonl(INADDR_ANY);
    NSData *address4 = [NSData dataWithBytes:&addr4 length:sizeof(addr4)];

    if (kCFSocketSuccess == CFSocketSetAddress(self.ipv4ListeningSocket, (CFDataRef)address4)) {
        if (0 == [self port]) {
            // now that the binding was successful, we get the port number
            // -- we will need it for the v6 endpoint and for the NSNetService
            NSData *addr = (__bridge_transfer NSData *)CFSocketCopyAddress(self.ipv4ListeningSocket);
            memcpy(&addr4, [addr bytes], [addr length]);
            self.port = ntohs(addr4.sin_port);
        }
    } else {
        if (self.ipv4ListeningSocket) CFRelease(self.ipv4ListeningSocket);
        self.ipv4ListeningSocket = NULL;
    }

    // set up the run loop sources for the sockets
    CFRunLoopRef cfrl = CFRunLoopGetCurrent();

    if (self.ipv4ListeningSocket) {
        CFRunLoopSourceRef source4 =     CFSocketCreateRunLoopSource(kCFAllocatorDefault, self.ipv4ListeningSocket, 0);
    CFRunLoopAddSource(cfrl, source4, kCFRunLoopCommonModes);
    CFRelease(source4);
    }

}

static void handleConnect(CFSocketRef socket, CFSocketCallBackType type, CFDataRef address, const void *data, void *info)
{
    NSLog(@"RECIEVED CONNECTION REQUEST \n");
    if (kCFSocketAcceptCallBack == type) {
        // for an AcceptCallBack, the data parameter is a pointer to a CFSocketNativeHandle
        CFSocketNativeHandle nativeSocketHandle = *(CFSocketNativeHandle *)data;
        uint8_t name[SOCK_MAXADDRLEN];
        socklen_t namelen = sizeof(name);
        NSData *peer = nil;
        if (0 == getpeername(nativeSocketHandle, (struct sockaddr *)name, &namelen)) {
            peer = [NSData dataWithBytes:name length:namelen];
        }
        CFReadStreamRef readStream = NULL;
        CFWriteStreamRef writeStream = NULL;
        CFStreamCreatePairWithSocket(kCFAllocatorDefault, nativeSocketHandle, &readStream, &writeStream);
        if (readStream && writeStream) {
            CFReadStreamSetProperty(readStream, kCFStreamPropertyShouldCloseNativeSocket, kCFBooleanTrue);
            CFWriteStreamSetProperty(writeStream, kCFStreamPropertyShouldCloseNativeSocket, kCFBooleanTrue);
            //[server handleNewConnectionFromAddress:peer inputStream:(__bridge NSInputStream *)readStream outputStream:(__bridge NSOutputStream *)writeStream];
        } else {
            // on any failure, need to destroy the CFSocketNativeHandle
            // since we are not going to use it any more
            close(nativeSocketHandle);
        }
        if (readStream) CFRelease(readStream);
        if (writeStream) CFRelease(writeStream);
    } else {
        NSLog(@"No idea");
    }

}

@end
...