BlueSSLService
BlueSSLService copied to clipboard
Data sending slowed down after using BlueSSLService
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?
I don't know why this would be. Would you be able to make some sample code that can demonstrate this?
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)
}
}
}
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.
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.
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
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?
Yes, if you can post it as a github project that would help.