SwiftNIO: Issue to enhancr WebSocket server logic to support secured connection

I am able to build prototype of WebSocket server in iOS device using below sample example. it worked

https://github.com/apple/swift-nio/blob/main/Sources/NIOWebSocketServer/main.swift

But I tried enhancing the logic to support SSL connection using approach given in following link: https://cocoapods.org/pods/SwiftNIOSSL. it didn't work when tried connection through client (postman) to url: wss://127.0.01:60259, it gives below error

Error: write EPROTO 5812094680:error:100000f7:SSL routines:OPENSSL_internal:WRONG_VERSION_NUMBER:../../../../src/third_party/boringssl/src/ssl/tls_record.cc:242:

When I use url ws://127.0.01:60259 (without SSL), it connects. Not sure what is missing in code for SSL connection

Note: generated certificate and private key is valid as I have tested same with WebSocket server created using ws library part of node based application

Please help here. below is the code (Removed irrelevant/personal code)

import Foundation
import NIOCore
import NIOPosix
import NIOHTTP1
import NIOWebSocket
import NIOSSL


private final class HTTPHandler: ChannelInboundHandler, RemovableChannelHandler {
    

    private var responseBody: ByteBuffer!

    func handlerAdded(context: ChannelHandlerContext) {
        //some code
    }

    func handlerRemoved(context: ChannelHandlerContext) {
        self.responseBody = nil
    }
    func channelActive(context: ChannelHandlerContext) {
       //save of client channel
    }
    
    func channelInactive(context: ChannelHandlerContext) {
        //removing of client channel
    }
    
    func channelRead(context: ChannelHandlerContext, data: NIOAny) {
        Handle read
    }

    private func respond405(context: ChannelHandlerContext) {
        //handle respond
    }
}

private final class WebSocketServerHandler: ChannelInboundHandler {

    
    func channelInactive(context: ChannelHandlerContext) {
        // Remove the disconnected client from the list of connected clients

    }
    

    public func handlerAdded(context: ChannelHandlerContext) {
        self.sendMessage(context: context)
    }

    public func channelRead(context: ChannelHandlerContext, data: NIOAny) {
        //read messages
    }


    public func channelReadComplete(context: ChannelHandlerContext) {
        context.flush()
    }


    private func receivedClose(context: ChannelHandlerContext, frame: WebSocketFrame) {
        // Handle a received close frame. In websockets, we're just going to send the close
    
    }

}

//This start function eventually called when a button is clicked and its part of a class
    func start() {
        do{
            let wshandler = WebSocketServerHandler()
            NioWSServerSSL.wshandler = wshandler
            let group = MultiThreadedEventLoopGroup(numberOfThreads: 1)

            let upgrader = NIOWebSocketServerUpgrader(shouldUpgrade: { (channel: Channel, head: HTTPRequestHead) in channel.eventLoop.makeSucceededFuture(HTTPHeaders()) },
                                             upgradePipelineHandler: { (channel: Channel, _: HTTPRequestHead) in
                                                channel.pipeline.addHandler(wshandler)
                                             })
		
			//Note:  generated key.pem and cert.pem using openssl and this is just for development purpose
            let path = ">>>path where the key.pem and cert.pem is stores"
            let configuration = TLSConfiguration.makeServerConfiguration(
                certificateChain: try NIOSSLCertificate.fromPEMFile("\(path)/cert.pem").map { .certificate($0) },
                privateKey: .file("\(path)/key.pem")
            )
            let sslContext = try NIOSSLContext(configuration: configuration)
            
            let bootstrap = ServerBootstrap(group: group)
                // Specify backlog and enable SO_REUSEADDR for the server itself
                .serverChannelOption(ChannelOptions.backlog, value: 256)
                .serverChannelOption(ChannelOptions.socketOption(.so_reuseaddr), value: 1)

                // Set the handlers that are applied to the accepted Channels
                .childChannelInitializer { channel in
                    let httpHandler = HTTPHandler()
                    let sslHandler = NIOSSLServerHandler(context: sslContext)
                    let config: NIOHTTPServerUpgradeConfiguration = (
                                    upgraders: [ upgrader ],
                                    completionHandler: { _ in
                                        channel.pipeline.removeHandler(httpHandler, promise: nil)
                                    }
                                )
                    return channel.pipeline.configureHTTPServerPipeline(withServerUpgrade: config).flatMap {
                        channel.pipeline.addHandler(httpHandler).flatMap {
                            channel.pipeline.addHandler(sslHandler)
                        }
                    }
                }

                // Enable SO_REUSEADDR for the accepted Channels
                .childChannelOption(ChannelOptions.socketOption(.so_reuseaddr), value: 1)

           
            let channel =  try bootstrap.bind(host: "127.0.0.1", port: 60259).wait()
            //let channel =  try bootstrap.bind(host: "127.0.0.1", port: 12346).wait()

            guard let localAddress = channel.localAddress else {
                fatalError("Address was unable to bind. Please check that the socket was not closed or that the address family was understood.")
            }
            print("Server started and listening on \(localAddress)")
        }
        catch {
            print("Error with Web socket connection \(error)")
        }

    }


Got the solution. below line should be called immediate after sslHandler object is defined. could now able to do secured WebSocket connection

_ = channel.pipeline.addHandler(sslHandler)

I’m glad you found a solution.

I do, however, have a question: Why use SwiftNIO for this? Network framework supports WebSocket directly. Is there something specific that you gain from bringing in NIO?

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

SwiftNIO: Issue to enhancr WebSocket server logic to support secured connection
 
 
Q