2016-05-16 76 views
2

我正在使用Apple的CFNetworking獲取TLS流。我在將Objective-C代碼移植到Swift時遇到了一些麻煩。Apple TLS與Objective-C和Swift的區別

使用完全相同的步驟,它在使用Objective-C時起作用,但在嘗試使用Swift時握手始終失敗。

工作對象 -

- (void)connect() 
{ 
    CFReadStreamRef readStream; 
    CFWriteStreamRef writeStream; 
    CFStreamCreatePairWithSocketToHost(kCFAllocatorDefault, 
             (__bridge CFStringRef)hostAddress, 
             port, 
             &readStream, 
             &writeStream); 

    self.inputStream = (__bridge_transfer NSInputStream *)readStream; 
    self.outputStream = (__bridge_transfer NSOutputStream *)writeStream; 

    [self.inputStream setProperty:NSStreamSocketSecurityLevelNegotiatedSSL 
         forKey:NSStreamSocketSecurityLevelKey]; 
    [self.outputStream setProperty:NSStreamSocketSecurityLevelNegotiatedSSL 
         forKey:NSStreamSocketSecurityLevelKey]; 

    [self.inputStream setDelegate:self]; 
    [self.outputStream setDelegate:self]; 

    [self.inputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] 
           forMode:NSDefaultRunLoopMode]; 

    [self.outputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] 
           forMode:NSDefaultRunLoopMode]; 

    [self.inputStream open]; 
    [self.outputStream open]; 
} 

非工作斯威夫特

func connect() { 
    var readStream: Unmanaged<CFReadStream>? 
    var writeStream: Unmanaged<CFWriteStream>? 

    let host = "some_host" 
    let hostAsCFString = host as NSString 
    CFStreamCreatePairWithSocketToHost(kCFAllocatorDefault, 
             hostAsCFString, 
             1337, 
             &readStream, 
             &writeStream) 

    inputStream = readStream!.takeRetainedValue() 
    outputStream = writeStream!.takeRetainedValue() 

    inputStream!.delegate = self 
    outputStream!.delegate = self 

    inputStream!.setProperty(NSStreamSocketSecurityLevelNegotiatedSSL, 
          forKey: NSStreamSocketSecurityLevelKey) 
    outputStream!.setProperty(NSStreamSocketSecurityLevelNegotiatedSSL, 
           forKey: NSStreamSocketSecurityLevelKey) 

    inputStream!.scheduleInRunLoop(.currentRunLoop(), forMode: NSDefaultRunLoopMode) 
    outputStream!.scheduleInRunLoop(.currentRunLoop(), forMode: NSDefaultRunLoopMode) 

    inputStream!.open() 
    outputStream!.open() 
} 

兩者都試圖連接到同一臺服務器和同一端口。

的Wireshark的屏幕抓取:

工作對象 -

Working Wireshark screen grab

非工作斯威夫特

Non working Wireshark screen grab

我爲正在發生的事情是很笨。我不知道爲什麼Obj-C版本使用TLS v1.2啓動Client Hello,但Swift嘗試使用TLS v1.0,然後放棄。不知道爲什麼Swift版本需要這麼長時間才能發送客戶端Hello,Keepalive數據包是先發送的?任何幫助將不勝感激。

+1

這可能不會改變任何內容,但是您設置NSStreamSocketSecurityLevelNegotiatedSSL和委託的順序在您的ObjC和Swift版本之間交換。 – zneak

+0

這並不重要。握手直到在流的任一端上進行第一次讀取或寫入調用纔開始。 – nathansizemore

+0

這個'connect()'方法被調用的上下文怎麼樣?它在主線程上嗎? –

回答

2

原來沒有什麼區別,我只是一個白癡。一旦NSStreamEvent.OpenCompleted事件被輸入輸出流調用,我立即調用outputStream.write()。這是寫入SSL握手的緩衝區,並搞砸了。

直到我爲Obj-c和Swift創建了一個MVP,它才表明如果你花時間創建一個有效的MVP,那麼在編寫它時可能會弄清楚它。現在,如果我只能在握手完成後找到通知的方式,則始終可以避免此問題。