Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Data sending slowed down after using BlueSSLService #101

Open
SmartSystemElectronics opened this issue Dec 16, 2022 · 7 comments
Open

Data sending slowed down after using BlueSSLService #101

SmartSystemElectronics opened this issue Dec 16, 2022 · 7 comments

Comments

@SmartSystemElectronics
Copy link

I actually use the LocalSocketBlue, but I wanted to use this library. After integrating, connecting to the server and sending data was seriously slowed down. How can I solve this?

@dannys42
Copy link
Contributor

I don't know why this would be. Would you be able to make some sample code that can demonstrate this?

@SmartSystemElectronics
Copy link
Author

Thats Ok. I will share my codes with you...


import Foundation
import Socket
import SSLService
import Dispatch
import XCTest

class LocalSocketBlue {

    

    static var isActiveLocalSocket = true
    //static let isActiveLocalSocket = false
    
    static let bufferSize = 4096
    
    let clientPort = 4446
    let serverPort = 4448
    
    
    //

    var configuration: SSLService.Configuration? = nil

    var serverSocket: Socket? = nil
    var continueRunningValue = true
    var connectedSockets = [Int32: Socket]()
    let socketLockQueue = DispatchQueue(label: "com.ibm.serverSwift.socketLockQueue")
    
    
    var continueRunning: Bool {
        set(newValue) {
            socketLockQueue.sync {
                self.continueRunningValue = newValue
            }
        }
        get {
            return socketLockQueue.sync {
                self.continueRunningValue
            }
        }
    }
    
    init() {
        continueRunningValue = true
    }


    
    deinit {
        // Close all open sockets...
        for socket in connectedSockets.values {
            socket.close()
        }
        self.serverSocket?.close()
    }
    
    
    let mycertpath = Bundle.main.path(forResource: "keyStore", ofType: "p12")
    
    func createConfiguration() {
        
        MyApp.writeLog(LocalSocketBlue.TAG, "create configuration")
    
        self.configuration = SSLService.Configuration(withChainFilePath: self.mycertpath, withPassword: "123456", usingSelfSignedCerts: true)

    }
    
    
    func startServerListeningToPort() {
        
        print("CERT PATH : "+(myCertEndPath ?? "no file"))

        
        CommunicationManager.connectionMgrDQUtlty.async { [unowned self] in
            
            do {
                // Create an IPV4 socket...
                                
                
                if Bundle.main.bundleIdentifier != "com.myapp.bundle1" {
                
                    try self.serverSocket = Socket.create(family: .inet, type: .stream, proto: .tcp)
                
                } else {
                    
                    try self.serverSocket = Socket.create(family: .inet)
                    self.createConfiguration()
                    serverSocket?.delegate = try SSLService(usingConfiguration: self.configuration! )

                }
                
                guard let socket = self.serverSocket else {
                    
                    MyApp.writeLog(LocalSocketBlue.TAG, "Unable to unwrap socket...")
                    return
                }
                
                
                
                try socket.listen(on: self.serverPort)
                
                MyApp.writeLog(LocalSocketBlue.TAG, "Listening on port: \(socket.listeningPort)")
            
                repeat {

                    let newSocket = try socket.acceptClientConnection()

                    MyApp.writeLog(LocalSocketBlue.TAG,"Accepted connection from: \(newSocket.remoteHostname) on port \(newSocket.remotePort)")
                    //print(LocalSocketBlue.TAG,"Socket Signature: \(String(describing: newSocket.signature?.description))")
                    
                    self.addNewConnection(socket: newSocket)
                    
                } while self.continueRunning
                
            } catch let error {
                guard let socketError = error as? Socket.Error else {
                    MyApp.writeLog(LocalSocketBlue.TAG, "Unexpected error...  \(error)")
                    return
                }
                
                if self.continueRunning {
                    
                    MyApp.writeLog(LocalSocketBlue.TAG, "Error reported:\n \(socketError.description)")
                    
                }
            }
        }
        //dispatchMain()
    }
    
    
    
    
    func addNewConnection(socket: Socket) {
        //print(LocalSocketBlue.TAG, "->addNewConnection()")
        // Add the new socket to the list of connected sockets...
        
        
        MyApp.writeLog(LocalSocketBlue.TAG, "add new connection")
        
        socketLockQueue.sync { [unowned self, socket] in
            self.connectedSockets[socket.socketfd] = socket
        }
        
        var shouldKeepRunning = true
        
        var readData = Data(capacity: LocalSocketBlue.bufferSize)
        
        var mResponse = String()
        
        do {
            // Write the welcome string...
            //try socket.write(from: "Hello, type 'QUIT' to end session\nor 'SHUTDOWN' to stop server.\n")
            var bytesRead = -1
            repeat {
                do{
                    let isr = try socket.isReadableOrWritable()
                    if(isr.readable){
                        bytesRead = try socket.read(into: &readData)
                        
                        
                        if bytesRead > 0 {
                            guard let response = String(data: readData, encoding: .utf8) else {
                                
                                MyApp.writeLog(LocalSocketBlue.TAG, "Error decoding response...")
                                readData.count = 0
                                break
                            }
                            
                            MyApp.writeLog(LocalSocketBlue.TAG, "response: \(response)")

                            
                            mResponse.append(response)
                            //print(LocalSocketBlue.TAG + "response.count: \(response.count)")
                            
                            let isrd = try socket.isReadableOrWritable()
                            
                            if(!isrd.readable){
                                MyApp.writeLog(LocalSocketBlue.TAG, "messageReceived str1: \(mResponse)")
                                if(String(response.suffix(1)) == "\r\n"){

                                    MyApp.writeLog(LocalSocketBlue.TAG, "shouldKeepRunning false-1")

                                    shouldKeepRunning = false
                                    break
                                }
                                
                            }
                        
                        } else {
                            
                            MyApp.writeLog(LocalSocketBlue.TAG, "shouldKeepRunning false-2")
                            
                            shouldKeepRunning = false
                            break
                        }
                        
                        readData.count = 0
                    } else {
                        usleep(10000)
                        //print(LocalSocketBlue.TAG, "socket is not readable")
                    }
                    
                } catch let exc {
                    MyApp.writeLog(LocalSocketBlue.TAG, "Socket ex: \(exc.localizedDescription)")
                    usleep(10000)
                }
                
            } while shouldKeepRunning
            
            //print(LocalSocketBlue.TAG, "Socket: \(socket.remoteHostname) closed...")
            socket.close()
            
            var message:CloudMessageShell?
            
            do{
                let mrstr = mResponse.data(using: .utf8)!
                
                message = try JSONDecoder().decode(CloudMessageShell.self, from: mrstr)
                MyApp.writeLog(LocalSocketBlue.TAG, "messageReceived str: \(mResponse)")
            } catch _ {
                //print("SPI_LocalSocket| listen() message decode e: \(e.localizedDescription)")
                
                //let strdata = String(data: data, encoding: String.Encoding.utf8)
                let newstr = mResponse.split(separator: "\r\n")
                if(newstr.count > 0){
                    let mdata = newstr[0].data(using: .utf8)!
                    do{
                        message = try JSONDecoder().decode(CloudMessageShell.self, from: mdata)
                    } catch let ex{
                        MyApp.writeLog(LocalSocketBlue.TAG, "listen() message decode ex: \(ex)")
                        
                    }
                }
            }
            
            if(message != nil){
                if(message?.Message != nil && (message?.Message?.contains("ConnectionTest"))!) {
                    if(MyApp.currentAccount?.deviceId == nil || (MyApp.currentAccount?.deviceId!.isEmpty)!){
                        if(message?.DeviceId != nil && !(message?.DeviceId!.isEmpty)!){
                            MyApp.currentAccount?.deviceId = message?.DeviceId
                            MyApp.writeProfileSettings()
                        } else if (message?.From != nil && !(message?.From!.isEmpty)!){
                            MyApp.currentAccount?.deviceId = message?.From
                            MyApp.writeProfileSettings()
                        }
                        MyApp.writeLog(LocalSocketBlue.TAG,"listen() ConnectionTest Connected")
                    }
                    
                    if(self.isConnectedSocketHandler != nil){
                        MyApp.writeLog(LocalSocketBlue.TAG, "listen()->isConnectedSocketHandler!(true)")
                        self.isConnectedSocketHandler!(true)
                        self.isConnectedSocketHandler = nil
                    }
                    
                } else {
                    let msg = CMessage(String(data: try JSONEncoder().encode(message),encoding: .utf8)!)
                    
                    MyApp.writeLog(LocalSocketBlue.TAG, "listen()->CommunicationManager.messageReceived(): \(msg)" )
                    
                    CommunicationManager.messageReceived(P2PConnectionStatus.LocalHost, msg)
                }
            } else {
                MyApp.writeLog(LocalSocketBlue.TAG,"listen() message = nil")
            }
            
            self.socketLockQueue.sync { [unowned self, socket] in
                self.connectedSockets[socket.socketfd] = nil
            }
            
        }
        catch let error {
            guard let socketError = error as? Socket.Error else {
                MyApp.writeLog(LocalSocketBlue.TAG, "Unexpected error by connection at \(socket.remoteHostname):\(socket.remotePort)...")
                return
            }
            if self.continueRunning {
                MyApp.writeLog(LocalSocketBlue.TAG, "Error reported by connection at \(socket.remoteHostname):\(socket.remotePort):\n \(socketError.description)")
            }
        }
    }
    
    func shutdownServer() {
        MyApp.writeLog(LocalSocketBlue.TAG, "\nShutdown in progress...")
        
        self.continueRunning = false
        
        // Close all open sockets...
        for socket in connectedSockets.values {
            
            self.socketLockQueue.sync { [unowned self, socket] in
                self.connectedSockets[socket.socketfd] = nil
                socket.close()
            }
        }
        
        //DispatchQueue.main.sync {
        //    exit(0)
        //}
        
    }
    
    public func stopListening(){
        
    }

    static var sendQueue = ThreadSafeArray<CMessage>()
    
    typealias StringListHandler = (_ strListHandler:[String]) -> Void
    var isConnectedSocketHandler:ConnectivityManager.BoolValueHandler?
    var mTo:String?
    
    var clientSocket:Socket?
    
    public func send(_ mMessage:CMessage) {
        
        MyApp.writeLog(LocalSocketBlue.TAG,"->send() \(mMessage.Message)")
        MyApp.writeLog(LocalSocketBlue.TAG,"->send() from: \(mMessage.From)")
        MyApp.writeLog(LocalSocketBlue.TAG,"->send() to: \(mMessage.To)")
        MyApp.writeLog(LocalSocketBlue.TAG,"->send() deviceId: \(mMessage.DeviceId)")

        continueRunning = true
        mMessage.sendTime = Utils.getCurrentTimeInMillis()
        LocalSocketBlue.sendQueue.append(mMessage)
        checkSendQueue()
    }
    
    public func connectionTest(hostId:String, isConnectedSocket:@escaping ConnectivityManager.BoolValueHandler) {
        MyApp.writeLog(LocalSocketBlue.TAG, "->connectionTest()")
        
        mTo = hostId
        
        isConnectedSocketHandler = isConnectedSocket
        
        let mCommand = CMessage.CCommand(Commands.ConnectionTest,"-","-")
        
        let message = CMessage()
        
        message.isCloud = false
        let ipAdr = ConnectivityManager.getIPAddress()
        if(ipAdr != nil && LocalSocketBlue.isValidIP(s: ipAdr!)){
            message.From = ipAdr
        }
        
        message.To = hostId
        message.DeviceId = DeviceIdUtils.getDeviceUUID()
        
        do {
            message.Message = String(data: try JSONEncoder().encode(mCommand), encoding: .utf8)!
        } catch let e {
            MyApp.writeLog(LocalSocketBlue.TAG, "connectionTest() createMessage ex: \(e)")
        }
        
        message.Id = UUID().uuidString
        
        CommunicationManager.sendMessage(message: message, connectionStatus: P2PConnectionStatus.LocalHost)
    }
    
    public static var isAlreadyChecking = false
    
    func checkSendQueue(){
        MyApp.writeLog(LocalSocketBlue.TAG,"->checkSendQueue() count: \(LocalSocketBlue.sendQueue.count)")
        
        /*
         for msg in LocalSocketBlue.sendQueue {
         print(LocalSocketBlue.TAG,"->checkSendQueue() msg: \(msg.Message ?? "yok")")
         }
         */
        //print(LocalSocketBlue.TAG,"->checkSendQueue() : \(LocalSocketBlue.sendQueue.count)")
        
        if let mfrst = LocalSocketBlue.sendQueue.first {
            if mfrst.sendTime! + 5000 < Utils.getCurrentTimeInMillis() {
                LocalSocketBlue.sendQueue.remove(at: 0)
                MyApp.writeLog(LocalSocketBlue.TAG, "sendQueue.remove() timeDiff>5000")
            }
        }
        
        
        if LocalSocketBlue.isAlreadyChecking {
            MyApp.writeLog(LocalSocketBlue.TAG,"->checkSendQueue() alreadyChecking return")
            return
        }
        
        CommunicationManager.connectionMgrDQ.async { [self] in
            while(LocalSocketBlue.sendQueue.count > 0){
                MyApp.writeLog(LocalSocketBlue.TAG, "checkSendQueue() while >>>>>>>>>>>>>>>>>>>")
                LocalSocketBlue.isAlreadyChecking = true
                do {
                    if(LocalSocketBlue.sendQueue.first != nil && LocalSocketBlue.sendQueue.first!.sendTime! + 5000 < Utils.getCurrentTimeInMillis()){
                        LocalSocketBlue.sendQueue.remove(at: 0)
                        MyApp.writeLog(LocalSocketBlue.TAG, "sendQueue.remove() timeDiff>5000")
                    } else {
                        if(self.clientSocket != nil && self.clientSocket!.isConnected) {
                            
                            MyApp.writeLog(LocalSocketBlue.TAG,"checkSendQueue() already connected")
                            
                            if(self.clientSocket != nil && LocalSocketBlue.sendQueue.count > 0){
                                try self.clientSocket!.write(from: String(data: try JSONEncoder().encode(LocalSocketBlue.sendQueue.first), encoding: .utf8)!)
                                if(self.clientSocket != nil){
                                    try self.clientSocket!.write(from: "\r")
                                }
                                MyApp.writeLog(LocalSocketBlue.TAG,"checkSendQueue() sended")
                            }
                            //usleep(100)
                            let lock = NSLock()
                            lock.lock()
                            if LocalSocketBlue.sendQueue.count > 0 && LocalSocketBlue.sendQueue.first != nil {
                                LocalSocketBlue.sendQueue.remove(at: 0)
                                MyApp.writeLog(LocalSocketBlue.TAG, "checkSendQueue() sendQueue.removeFirst()")
                            }
                            lock.unlock()
                            
                            usleep(100000)  // Be nice to the server
                            if let cSocket = self.clientSocket {
                                MyApp.writeLog(LocalSocketBlue.TAG, "checkSendQueue() clientSocket.close()")
                                cSocket.close()
                            }
                            
                        } else {
                            
                            MyApp.writeLog(LocalSocketBlue.TAG,"checkSendQueue() clientSocket not connected")
                            
                            self.clientSocket = try Socket.create(family: .inet)
                            
                            
                            if Bundle.main.bundleIdentifier == "com.myapp.bundle1" {
                                
                                //let myConfig = SSLService.Configuration(withChainFilePath: self.myCertEndPath, withPassword: "123456", usingSelfSignedCerts: true, clientAllowsSelfSignedCertificates: true, cipherSuite: nil)
                        
                                
                                do {
                                    
                                    self.configuration = SSLService.Configuration(clientAllowsSelfSignedCertificates: true)
                                    
                                    let service = try SSLService(usingConfiguration: self.configuration!)
                                    
                                    self.clientSocket?.delegate = service
                                    
                                    
                                } catch let error {
                                    
                                    MyApp.writeLog("SPI_LocalSocketBlue|", "error in client: \(error)")
                                    
                                }
                                
                            }

                            MyApp.writeLog(LocalSocketBlue.TAG,"checkSendQueue() clientSocket init")
                            usleep(10000)
                            if(self.mTo == nil || self.mTo!.isEmpty){
                                self.mTo = MyApp.currentAccount?.hostId
                            }
                            
                            if let cSocket = self.clientSocket {
                                MyApp.writeLog(LocalSocketBlue.TAG,"checkSendQueue() clientSocket init success")
                                
                                //let signature = try Socket.Signature(protocolFamily: .inet, socketType: .stream, proto: .tcp, hostname: self.mTo, port: Int32(self.clientPort))!

                                
                                
                                if let mmto = self.mTo {
                                    
                                    do {
                                        
                                        try cSocket.connect(to: mmto, port: Int32(self.clientPort), timeout: 5000)
                                        
                                        //try cSocket.connect(using: signature)
                                        
                                    } catch let  error {
                                        
                                        MyApp.writeLog("SPI_LocalSocketBlue|", "error: \(error)")
                                        
                                    }
                                    
                                    
                                }
                                
                                MyApp.writeLog(LocalSocketBlue.TAG, "checkSendQueue() Connected to IP: \(cSocket.remoteHostname)")
                            } else {
                                MyApp.writeLog(LocalSocketBlue.TAG,"checkSendQueue() clientSocket init fail")
                            }
                            
                        }
                    }
                    
                } catch let e {
                    MyApp.writeLog(LocalSocketBlue.TAG,"checkSendQueue() ex: \(e)")
                    self.clientSocket = nil
                    usleep(100000)
                }
            }
            LocalSocketBlue.isAlreadyChecking = false
            MyApp.writeLog(LocalSocketBlue.TAG,"checkSendQueue() isAlreadyChecking=false ----------------------------")
        }
    }
    
    public static func isValidIP(s: String) -> Bool {
        //print(TAG,"->isValidIP() ipAdrr: \(s)")
        let parts = s.components(separatedBy: ".")
        let nums = parts.compactMap { Int($0) }
        return parts.count == 4 && nums.count == 4 && nums.filter { $0 >= 0 && $0 < 256}.count == 4
    }
    
    func lock(_ obj: AnyObject, _ blk:() -> ()) {
        objc_sync_enter(obj)
        blk()
        objc_sync_exit(obj)
    }
}



} 

@dannys42
Copy link
Contributor

There's quite a lot of code here and it's unclear what you're trying to accomplish. Delays and locks are generally not things you want in performant network code, so I suspect there's a problem with the structure of this code. It would be helpful if you could make a small project that I can run that clearly demonstrates the problem you're seeing. i.e. are you finding connections slow or data transfer, reads or writes, etc?

If you need a sample server to test against, you can do it by:

  • Create key pairs: openssl req -newkey rsa:2048 -new -nodes -x509 -days 3650 -keyout key.pem -out cert.pem

  • Run server: openssl s_server -accept 8018 -cert /tmp/cert.pem -key /tmp/key.pem

This sever will print to console anything you send to it. This can be useful for write tests.

You can also run the server like this:

  • yes "hello world" | openssl s_server -accept 8018 -cert /tmp/cert.pem -key /tmp/key.pem

This will continuously send "hello world" to the client that connects. This can be useful for read tests.

@SmartSystemElectronics
Copy link
Author

SmartSystemElectronics commented Jan 4, 2023

Obviously, this example is almost the same as the example in this link https://github.com/Kitura/BlueSocket#complete-example I just adapted what you have done in this link (https://github.com/Kitura/BlueSSLService/blob/master/Tests/SSLServiceTests/SSLServiceTests.swift) the example in BlueSocket. Do you think I did wrong? Or should I initialize the server and client for SSLService in another way? Since there is no example for ios on the homepage in BlueSSLService(there are some examples only Linux), it made more sense to adapt it.

@SmartSystemElectronics
Copy link
Author

In this code;

do {
                             
      try cSocket.connect(to: mmto, port: Int32(self.clientPort), timeout: 5000)
      
      //try cSocket.connect(using: signature)
      
  } catch let  error {
      
      EchoServer.writeLog("error: \(error)")
      
  }

gives me error:

Sometimes gives this error: error: Error code: -9968(0x-26F0), Operation now in progress

@SmartSystemElectronics
Copy link
Author

I developed dummy local socket test app in xcode. If you want to see, I can share my codes with you. It just sends connectionTest messages with server and waits response. The messages sometimes come, sometimes not. If it doesn't arrive me, above error shows. So, how can I fix this?

@dannys42
Copy link
Contributor

Yes, if you can post it as a github project that would help.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants