🌐 English

    WebSocket API#

    Oasis supports WebSocket servers and clients.

    A WebSocket server can also be used by attaching it to a specific URL of an HTTP server using the createHttpWsService API.

    Header File#

    OasisNet.h

    WsEventDelegate Interface#

    In the Oasis WebSocket service, users process WebSocket events through an object derived from the WsEventDelegate interface.

    class WsEventDelegate : public std::enable_shared_from_this<WsEventDelegate>
    {
    public:
        WsEventDelegate();
        virtual ~WsEventDelegate();
    
    public: 
        virtual void onOpen(const WsEventRef &evt);
        virtual void onMessage(const WsEventRef &evt);
        virtual void onError(const WsEventRef &evt);
        virtual void onClose(const WsEventRef &evt);
    };
    
    void onOpen ( const WsEventRef & evt )
    OasisNet.h
    Called when the WebSocket is opened.
    Parameters
    evt  The WebSocket event object.
    void onMessage ( const WsEventRef & evt )
    OasisNet.h
    Called when a message is received.
    Parameters
    evt  The WebSocket event object.

    Below is an example of onMessage processing for an Echo server.

    void EchoWsEventDelegate::onMessage(const WsEventRef &evt)  
    {
      if(wsEventMessageType(evt) == kWsMessageText) {
        std::vector<uint8_t> data;
        if(wsEventData(evt, data) > 0) {
          std::string str = "Echo: ";
          str += std::string(data.data(), data.data()+data.size());
          wsSendText(evt, str.c_str());
        }
      }
    }
    
    void onError ( const WsEventRef & evt )
    OasisNet.h
    Called when an error occurs.
    Parameters
    evt  The WebSocket event object.
    void onClose ( const WsEventRef & evt )
    OasisNet.h
    Called when the WebSocket connection is closed.
    Parameters
    evt  The WebSocket event object.

    WsEvent#

    ws_message_t wsEventMessageType ( const WsEventRef & evt )
    OasisNet.h
    Obtains the message type.
    Parameters
    evt  The WebSocket event object.
    Return Value
    Returns the message type.

    The message types are as follows:

    ws_message_t Value Description
    kWsMessageUnknown 0 Unknown type.
    kWsMessageText 1 Text type.
    kWsMessageBinary 2 Binary type.
    kWsMessagePing 3 Ping type.
    kWsMessagePong 4 Pong (response to Ping) type.
    uint16_t wsEventStatusCode ( const WsEventRef & evt )
    OasisNet.h
    Parameters
    evt  The WebSocket event object.
    Return Value
    Returns the status code.

    The status codes are as follows:

    kWsStatusCode_StatusCode
    Value
    Description
    NormalClosure 1000 Normal closure.
    EndPointGoingAway 1001 Endpoint connection error. Occurs when the server is closed or the browser window is closed.
    EndPointTerminatingConnectionDueToProtocolError 1002 Connection termination due to a protocol error.
    EndPointTerminatingConnectionDueToUnknownOpcode 1003 Connection termination due to inability to process data due to an unknown Opcode.
    NoStatusCodePresent 1005 No status code is present in the close frame.
    ConnectionClosedAbnormally 1006 The connection was terminated abnormally without a close frame.
    EndPointTerminatingConnectionDueToInconsistentData 1007 Connection termination due to receiving data that differs from the message type. For example, when non-UTF-8 data is received for a UTF-8 type message.
    EndPointTerminatingConnectionDueToPolicy 1008 Connection termination due to general reasons such as security.
    EndPointTerminatingConnectionDueToTooBigData 1009 Connection termination that occurs when data too large to process is received.
    ClientTerminatingConnectionDueToLackOfExtensions 1010 The client terminates the connection because it cannot be processed during the extension verification process on the server side.
    ServerTerminatingConnectionDueToUnexpectedCondition 1011 The server terminates the connection because it cannot process the request.
    TlsHandshakeFailure 1015 Connection termination due to a TLS handshake error.
    ssize_t wsEventDataLength ( const WsEventRef & evt )
    OasisNet.h
    Obtains the message data length.
    Parameters
    evt  The WebSocket event object.
    Return Value
    Returns the message data length.
    ssize_t wsEventText ( const WsEventRef & evt , std::string & str )
    OasisNet.h
    Obtains the text message.
    Parameters
    evt  The WebSocket event object.
    str  OUT Returns the text message.
    Return Value
    The text length. Returns -1 if it is not a text type.
    const uint8_t * wsEventData ( const WsEventRef & evt )
    OasisNet.h
    Obtains the message data.
    Parameters
    evt  The WebSocket event object.
    Return Value
    Returns the message data pointer.
    ssize_t wsEventData ( const WsEventRef & evt , std::vector<uint8_t> & data )
    OasisNet.h
    Obtains the general message data.
    Parameters
    evt  The WebSocket event object.
    data  OUT Returns the data after storing it in a vector.
    Return Value
    Returns the data size.
    WsRemoteRef wsEventGetRemote ( const WsEventRef & evt )
    OasisNet.h
    Obtains the remote object connected to the WebSocket.
    Parameters
    evt  The WebSocket event object.
    Return Value
    Returns the WebSocket remote object.
    ssize_t wsSendText ( const WsEventRef & evt , const char * text )
    OasisNet.h
    Transmits a text message. It returns immediately and transmission takes place in the background. If an error occurs, the onError event is called.
    Parameters
    evt  The WebSocket event object.
    text  The string pointer to transmit.
    Return Value
    Returns the text message length on success. The actual transmission result can be known via the event call. Returns -1 on failure.
    ssize_t wsSendData ( const WsEventRef & evt , const uint8_t * data , size_t length )
    OasisNet.h
    Transmits data. It returns immediately and transmission takes place in the background. If an error occurs, the onError event is called.
    Parameters
    evt  The WebSocket event object.
    data  The data pointer to transmit.
    length  The data length. Measured in bytes.
    Return Value
    Returns the data length on success. The actual transmission result can be known via the event call. Returns -1 on failure.
    ssize_t wsPing ( const WsEventRef & evt , const uint8_t * data , size_t length )
    OasisNet.h
    Transmits a PING message.
    Parameters
    evt  The WebSocket event object.
    data  The user-defined data pointer to be added to the PING message.
    length  The data length. Measured in bytes.
    Return Value
    Returns the PING data size on success. Returns -1 on failure.
    int32_t wsClose ( const WsEventRef & evt , uint16_t status_code = kWsStatusCode_NormalClosure , const uint8_t * reason_data = nullptr , size_t reason_data_length = 0 )
    OasisNet.h
    Closes the WebSocket connection.
    Parameters
    evt  The WebSocket event object.
    status_code  The status code to be used for closing the connection.
    reason_data  The explanation data.
    reason_data_length  The length of the explanation data.
    Return Value
    • 0: Success
    • -1: Failure

    Server Functions#

    WsServerRef createWsServer ( key_value_map_t & parameters , const std::shared_ptr<WsEventDelegate> & delegate )
    OasisNet.h
    Creates a WebSocket server.
    Parameters
    parameters  The key-value map required to create the WebSocket server.
    delegate  The user-defined object derived from WsEventDelegate for handling events that occurred in the WebSocket.
    Return Value
    Returns the WebSocket server object on success. Returns nullptr on failure.

    The key-value map required to create a WebSocket server is as follows:

    Key
    Default
    M
    Description
    websocket-protocols
     
    The protocol name defined by the user. If this field is not empty, the WebSocket connection must match this field value for the connection to be established.
    websocket-fragment-size-max
    65535
     
    The maximum fragment size.

    When creating a secure WebSocket server using TLS, the following key-value map is additionally required:

    Key
    Default
    M
    Description
    tls-enabled
    0
    Specifies whether to enable TLS. It is enabled if "1", and TLS is not used if "0". When using it, key values such as certificate paths must be valid.
    tls-version
    1.2
    The TLS version. Enter "1.2".
    tls-client-verify
    0
     
    Specifies whether to validate the certificate of the connecting client. If "1", connections are allowed only for names registered in the tls-certificate-request-authority-names key.
    tls-certificate-request-authority-names
     
    The list of authority names (CN) separated by \0xa. For example, it is formatted like "MediaStek-Root-CA\x0aMediaStek Inc.".
    ca-certs-file-path
     
    The path to the ROOT CA certificate files in PEM format separated by \0xa. For example, it is formatted like "/data/certs/cacerts.pem\x0a/data/certs/RootCA.pem".
    cert-file-path
    The path to the public certificate file in PEM format such as RSA, ECDSA, DSS, etc.
    pkey-file-path
    The path to the private key file in PEM format.
    int32_t startWsServer ( const WsServerRef & ws_server )
    OasisNet.h
    Starts the WebSocket server.
    Parameters
    ws_server  The WebSocket server object.
    Return Value
    • 0: Success
    • -1: Failure
    int32_t stopWsServer ( const WsServerRef & ws_server )
    OasisNet.h
    Stops the WebSocket server.
    Parameters
    ws_server  The WebSocket server object.
    Return Value
    • 0: Success
    • -1: Failure
    int32_t destroyWsServer ( WsServerRef & ws_server )
    OasisNet.h
    Releases the WebSocket server.
    Parameters
    ws_server  IN OUT The WebSocket server object. Returns nullptr after releasing.
    Return Value
    • 0: Success
    • -1: Failure

    Client Functions#

    WsConnectionRef wsOpenConnection ( const char * url , key_value_map_t & parameters , const std::shared_ptr<WsEventDelegate> & delegate , int32_t timeout )
    OasisNet.h
    Creates a WebSocket client object and connects to a WebSocket server.
    Parameters
    url  The WebSocket server URL. The format is ws://&lt;ServerAddress>[:&lt;PortNumber>] or wss://&lt;ServerAddress>[:&lt;PortNumber>]. wss is a connection that uses TLS. For example, it is formatted like wss://echo.websocket.org.
    parameters  The key-value map required for the WebSocket client connection.
    delegate  The user-defined object derived from WsEventDelegate for handling events that occurred in the WebSocket.
    timeout  The maximum waiting time until connected. Measured in milliseconds. If it is -1, it waits indefinitely when connecting to the server, but does not wait until the WebSocket protocol negotiation process is completed. If it is 0, it waits until connected to the server and the WebSocket connection is completed. The onOpen or onError event callback of the delegate is called. If the value is greater than 0, it waits for the specified time until connected to the server. Afterwards, it waits for the specified time until the WebSocket connection is completed. If time elapses, it returns a timeout (ETIMEDOUT) error to errno. Depending on the connection result, the onOpen or onError event callback of the delegate is called.
    Return Value
    Returns the WebSocket client object on success. Returns nullptr on failure.

    The key-value map required for wsOpenConnection is as follows:

    Key
    Default
    M
    Description
    tls-disable-certificate-validation
    0
     
    Does not validate the certificate of the server.
    tls-use-sni
    0
     
    Includes the FQDN of the server in the Hello Handshake when connecting to the server.
    int32_t wsCloseConnection ( WsConnectionRef & connection , uint16_t status_code = kWsStatusCode_NormalClosure , const uint8_t * reason_data = nullptr , size_t reason_data_length = 0 )
    OasisNet.h
    Closes the WebSocket connection.
    Parameters
    connection  The WebSocket client object.
    status_code  The status code to be used for closing the connection.
    reason_data  The explanation data.
    reason_data_length  The length of the explanation data.
    Return Value
    • 0: Success
    • -1: Failure
    ssize_t wsSendText ( const WsConnectionRef & connection , const char * text )
    OasisNet.h
    Transmits a text message to the WebSocket server. It returns immediately and the actual transmission takes place in the background.
    Parameters
    connection  The WebSocket client object.
    text  The string to transmit.
    Return Value
    Returns the message length on success. Returns -1 on failure.
    ssize_t wsSendData ( const WsConnectionRef & connection , const uint8_t * data , size_t length )
    OasisNet.h
    Transmits a general data message to the WebSocket server. It returns immediately and the actual transmission takes place in the background.
    Parameters
    connection  The WebSocket client object.
    data  The data pointer.
    length  The data length. Measured in bytes.
    Return Value
    Returns the message length on success. Returns -1 on failure.
    ssize_t wsPing ( const WsConnectionRef & connection , const uint8_t * data , size_t length )
    OasisNet.h
    Transmits a PING message to the WebSocket server.
    Parameters
    connection  The WebSocket client object.
    data  The user-defined data pointer to be added to the PING message.
    length  The data length. Measured in bytes.
    Return Value

    Example#

    Below is an example of a WebSocket server.

    #include "OasisAPI.h"
    #include "OasisLog.h"
    #include "OasisWeb.h"
    
    #include <thread>
    #include <mutex>
    #include <memory>
    #include <condition_variable>
    
    #define DLOG_THIS   0x00080000
    
    #undef DLOG_FLAGS
    #define  DLOG_FLAGS (DLOG_FLAGS_DEFAULT|DLOG_THIS/**/)
    
    #undef DLOG_TAG
    #define DLOG_TAG "WSS"
    
    #define USE_RSA 1
    #define USE_ECDSA 0
    #define USE_DSS 0
    
    using namespace oasis;
    
    static bool continuing = true;
    
    
    //for WebSocket upstream
    class MyWsEventDelegate : public WsEventDelegate
    {
    public:
        MyWsEventDelegate() {}
        virtual ~MyWsEventDelegate() {}
    
    public: 
        virtual void onOpen(const WsEventRef &evt) {
            DLOG(DLOG_THIS, "Open\n");
        }
    
        virtual void onMessage(const WsEventRef &evt)  {
            DLOG(DLOG_THIS, "Message\n");
    
            if(wsEventMessageType(evt) == kWsMessageText) {
                std::vector<uint8_t> data;
                if(wsEventData(evt, data) > 0) {
                    std::string str(data.data(), data.data()+data.size());
                    wsSendText(evt, str.c_str());
                }
            }
        }
    
        virtual void onError(const WsEventRef &evt) {
            DLOG(DLOG_THIS, "Error\n");
        }
    
        virtual void onClose(const WsEventRef &evt) {
            DLOG(DLOG_THIS, "Close\n");
        }
    };
    
    
    void cancel_handler(int signum)
    {
        continuing = false;
    }
    
    
    int main(int argc, char* argv[])
    {
        int32_t c, err;
        uint16_t port;
        std::thread t3;
        key_value_map_t parameters, fields;
    
    
        if(argc < 2) {
            printf("USAGE: %s <port number>\n", argv[0]);
            return 255;
        }
    
        port = (uint16_t)atoi(argv[1]);
        if(port == 0) {
            printf("USAGE: %s <port number>\n", argv[0]);
            return 255;
        }
    
        signal(SIGINT, cancel_handler);
    
        parameters["offs-disable"] = "1";
        if(oasis::initialize(parameters) < 0) {
            DLOG(DLOG_ERROR, "Oasis init failed\n");
            return -1;
        }
    
        parameters.clear();
    
        parameters["port"] = std::to_string(port);
        parameters["ca-certs-file-path"] = "/data/certs/RootCA.pem";
    
    #if USE_RSA
            parameters["cert-file-path"] = "/data/certs/fullchain.pem";
            parameters["pkey-file-path"] = "/data/certs/privkey.pem";
    #elif USE_ECDSA
            parameters["cert-file-path"] = "/data/certs/ec_fullchain.pem";
            parameters["pkey-file-path"] = "/data/certs/ec_pkey.pem";
    #elif USE_DSS
            parameters["cert-file-path"] = "/data/certs/dsa_fullchain.pem";
            parameters["pkey-file-path"] = "/data/certs/dsa_pkey.pem";
    #else
            #error "No certficates!"
    #endif
    
        std::shared_ptr<MyWsEventDelegate> delegate = std::make_shared<MyWsEventDelegate>();
    
        WsServerRef server = createWsServer(parameters, delegate);
        if(!server) {
            DLOG(DLOG_ERROR, "failed to create a websocket server\n");
            return -1;
        }
    
        if(startWsServer(server) < 0) {
            DLOG(DLOG_ERROR, "start failed\n");
            goto done;
        }
    
        do {
        usleep(10000);
        } while (continuing);
    
        stopWsServer(server);
    
    done:
    
        destroyWsServer(server);
    
        oasis::finalize();
    
        return 0;
    }
    

    Below is an example of a WebSocket client.

    #include "OasisAPI.h"
    #include "OasisLog.h"
    #include "OasisWeb.h"
    
    #include <thread>
    #include <mutex>
    #include <memory>
    #include <condition_variable>
    
    #define DLOG_THIS   0x00080000
    
    #undef DLOG_FLAGS
    #define  DLOG_FLAGS (DLOG_FLAGS_DEFAULT|DLOG_THIS/**/)
    
    #undef DLOG_TAG
    #define DLOG_TAG "WSC"
    
    
    using namespace oasis;
    
    
    static TTYRaw tty_;
    
    static bool continuing = true;
    static bool ws_closed = false;
    
    
    //for WebSocket upstream
    class MyWsEventDelegate : public WsEventDelegate
    {
    public:
        MyWsEventDelegate() {}
        virtual ~MyWsEventDelegate() {}
    
    public: 
        virtual void onOpen(const WsEventRef &evt) {
            DLOG(DLOG_THIS, "Open\n");
        }
    
        virtual void onMessage(const WsEventRef &evt)  {
            DLOG(DLOG_VERBOSE, "Message\n");
            if(wsEventMessageType(evt) == kWsMessageText) {
                std::string str;
                wsEventText(evt, str);
                DLOG0(DLOG_THIS, "==> %s\n", str.c_str());
            }
        }
    
        virtual void onError(const WsEventRef &evt) {
            DLOG(DLOG_THIS, "Error: %d\n", wsEventStatusCode(evt));
        }
    
        virtual void onClose(const WsEventRef &evt) {
            DLOG(DLOG_THIS, "Close: %d\n", wsEventStatusCode(evt));
            ws_closed = true;
        }
    };
    
    void cancel_handler(int signum)
    {
        continuing = false;
    }
    
    
    int main(int argc, char* argv[])
    {
        int32_t err;
    
        int32_t status_code;
        std::string reason_string;
        std::string content_type; 
    
        int32_t wait_count = 0;
    
        key_value_map_t parameters, fields;
    
        std::string url = "wss://echo.websocket.org/";
    
        if(argc >= 2) {
            url = argv[1];
        }
    
        signal(SIGINT, cancel_handler);
    
        parameters["offs-disable"] = "1";
        if(oasis::initialize(parameters) < 0) {
            DLOG(DLOG_ERROR, "Oasis init failed\n");
            return -1;
        }
    
        parameters.clear();
    
        parameters["ca-certs-file-path"] = "/data/certs/cacerts.pem\x0a/data/certs/RootCA.pem";
        parameters["cert-file-path"] = "/data/certs/client_fullchain.pem";
        parameters["pkey-file-path"] = "/data/certs/client_privkey.pem";
    
        parameters["tls-disable-certificate-validation"] = "1";
        parameters["tls-use-sni"] = "1";
    
        //websocket-protocols
        parameters["websocket-fragment-size-max"] = std::to_string(8192);
    
        WsConnectionRef conn;
        char buffer[512];
    
        std::shared_ptr<MyWsEventDelegate> delegate = std::make_shared<MyWsEventDelegate>();
    
        conn = wsOpenConnection(url.c_str(), parameters, delegate, 10000);
        if(conn) {
    
            DLOG(DLOG_THIS, "connected.\n");
    
            strpcy(buffer, "hello, world!");
            wsSendText(conn, (const char*)buffer);
    
            DLOG(DLOG_THIS, "closing...\n");
            wsCloseConnection(conn);
    
            //need sometime to be closed.
            int32_t max_wait = 20; //2 seconds
            do {
                usleep(10000);
            } while(ws_closed == false && max_wait-- > 0);
    
        }
    
        conn = nullptr;
    
        oasis::finalize();
    
        return 0;
    }