341 lines
12 KiB
C
341 lines
12 KiB
C
/**
|
|
* @file kWebSocket.h
|
|
* @brief Declares the kWebSocket class.
|
|
*
|
|
* @internal
|
|
* Copyright (C) 2017-2021 by LMI Technologies Inc.
|
|
* Licensed under the MIT License.
|
|
* Redistributed files must retain the above copyright notice.
|
|
*/
|
|
#ifndef K_API_WEBSOCKET_H
|
|
#define K_API_WEBSOCKET_H
|
|
|
|
#include <kApi/kApiDef.h>
|
|
#include <kApi/Io/kNetwork.h>
|
|
|
|
/**
|
|
* @struct kWebSocketDataType
|
|
* @extends kValue
|
|
* @ingroup kApi-Io
|
|
* @brief Represents Websocket message content type.
|
|
*/
|
|
typedef k32s kWebSocketDataType;
|
|
|
|
/** @relates kWebSocketDataType @{ */
|
|
#define kWEB_SOCKET_DATA_TYPE_NULL (0x0) ///< Unknown content type.
|
|
#define kWEB_SOCKET_DATA_TYPE_UTF8 (0x1) ///< UTF-8 content.
|
|
#define kWEB_SOCKET_DATA_TYPE_BINARY (0x2) ///< Binary content.
|
|
/** @} */
|
|
|
|
#include <kApi/Io/kWebSocket.x.h>
|
|
|
|
/**
|
|
* @class kWebSocket
|
|
* @extends kStream
|
|
* @ingroup kApi-Io
|
|
* @brief Represents a WebSocket.
|
|
*
|
|
* The kWebSocket class implements support for WebSocket protocol (RFC 6455). This protocol enables client
|
|
* software, typically running in a web browser, to communicate with servers more efficiently than would otherwise
|
|
* be possible over HTTP.
|
|
*
|
|
* kWebSocket can be used in either a client or a server role. In a server context, a kWebSocket instance can be created
|
|
* from an HTTP request as follows:
|
|
*
|
|
@code {.c}
|
|
kStatus App_HttpRequestHandler(App app, kHttpServer server, kHttpServerChannel channel)
|
|
{
|
|
kWebSocket webSocket = kNULL;
|
|
kStatus status;
|
|
|
|
if (kHttpServerRequest_IsWebSocketUpgrade(kHttpServerChannel_Request(channel)))
|
|
{
|
|
kCheck(kHttpServerChannel_ProcessWebSocketRequest(channel, kTRUE, &webSocket));
|
|
|
|
if (!kIsNull(webSocket))
|
|
{
|
|
//create a thread to handle the websocket connection
|
|
...
|
|
}
|
|
}
|
|
|
|
return kOK;
|
|
}
|
|
@endcode
|
|
*
|
|
* The WebSocket protocol is message-based. kWebSocket supports reading/writing complete messages using
|
|
* the kWebSocket_ReadMessage and kWebSocket_WriteMessage methods.
|
|
*
|
|
* The WebSocket protocol also supports subdividing messages into multiple frames, enabling endpoints to
|
|
* stream messages of unknown length. Accordingly, kWebSocket inherits from the kStream base class
|
|
* and includes special methods that can be used in conjunction with kStream methods
|
|
* to support streaming reads/writes.
|
|
@code {.c}
|
|
//Example: streaming read
|
|
kStatus ReadMessage(kWebSocket webSocket)
|
|
{
|
|
kByte buffer[256];
|
|
kSize bytesRead;
|
|
|
|
//wait for a new message to arrive (1s timeout)
|
|
kCheck(kWebSocket_Receive(webSocket, 1000000));
|
|
|
|
//read out the message; kStream_ReadSome will return kERROR_NOT_FOUND at the end of the message
|
|
while (kSuccess(kStream_ReadSome(webSocket, &buffer[0], 1, sizeof(buffer), &bytesRead)))
|
|
{
|
|
//process content
|
|
...
|
|
}
|
|
|
|
return kOK;
|
|
}
|
|
|
|
//Example: object serialization
|
|
kStatus WriteObject(kWebSocket webSocket, kObject object)
|
|
{
|
|
kDat6Serializer writer = kNULL;
|
|
|
|
kTry
|
|
{
|
|
//attach serializer to websocket stream
|
|
kTest(kDat6Serializer_Construct(&writer, webSocket, kNULL));
|
|
|
|
//serialize object; will write to websocket, generating frames as needed
|
|
kTest(kSerializer_WriteObject(writer, object));
|
|
|
|
//end the current websocket message (send final frame) and flush
|
|
kTest(kWebSocket_Send(webSocket));
|
|
}
|
|
kFinally
|
|
{
|
|
kObject_Destroy(writer);
|
|
|
|
kEndFinally();
|
|
}
|
|
|
|
return kOK;
|
|
}
|
|
|
|
@endcode
|
|
*/
|
|
//typedef kStream kWebSocket; --forward-declared in kApiDef.x.h
|
|
|
|
/**
|
|
* Constructs a WebSocket that can be used to connect to a server.
|
|
*
|
|
* @public @memberof kWebSocket
|
|
* @param webSocket Destination for constructed object handle.
|
|
* @param allocator Memory allocator (or kNULL for default).
|
|
* @return Operation status.
|
|
*/
|
|
kFx(kStatus) kWebSocket_Construct(kWebSocket* webSocket, kAlloc allocator);
|
|
|
|
/**
|
|
* Sets the size of write buffers.
|
|
*
|
|
* Socket buffers decouple the sender and receiver, so that the sender does not need to block
|
|
* while waiting for the receiver to receive all bytes. Client buffers improve the efficiency
|
|
* of the client when performing several small write operations.
|
|
*
|
|
* By default, the client buffer size is zero and the socket buffer size is determined by the
|
|
* underlying operating system.
|
|
*
|
|
* @public @memberof kWebSocket
|
|
* @param webSocket WebSocket object.
|
|
* @param socketSize Size of the write buffer maintained by the underlying socket (-1 to leave unchanged).
|
|
* @param clientSize Size of the write buffer maintained by the client object (-1 to leave unchanged).
|
|
* @return Operation status.
|
|
*/
|
|
kFx(kStatus) kWebSocket_SetWriteBuffers(kWebSocket webSocket, kSSize socketSize, kSSize clientSize);
|
|
|
|
/**
|
|
* Sets the size of the read buffers.
|
|
*
|
|
* Socket buffers decouple the sender and receiver, so that the sender does not need to block
|
|
* while waiting for the receiver to receive all bytes. Client buffers improve the efficiency
|
|
* of the client when performing several small read operations.
|
|
*
|
|
* @public @memberof kWebSocket
|
|
* @param webSocket WebSocket object.
|
|
* @param socketSize Size of the read buffer maintained by the underlying socket (-1 to leave unchanged).
|
|
* @param clientSize Size of the read buffer maintained by the client object (-1 to leave unchanged).
|
|
* @return Operation status.
|
|
*/
|
|
kFx(kStatus) kWebSocket_SetReadBuffers(kWebSocket webSocket, kSSize socketSize, kSSize clientSize);
|
|
|
|
/**
|
|
* Connects a WebSocket to an HTTP server.
|
|
*
|
|
* @public @memberof kWebSocket
|
|
* @param webSocket WebSocket object.
|
|
* @param address HTTP server address.
|
|
* @param port HTTP server port number.
|
|
* @param host HTTP request host (distinguishes between multiple hosts at same address).
|
|
* @param uri HTTP request URI.
|
|
* @param timeout Timeout, in microseconds.
|
|
* @return Operation status.
|
|
*/
|
|
kFx(kStatus) kWebSocket_Connect(kWebSocket webSocket, kIpAddress address, k32u port, const kChar* host, const kChar* uri, k64u timeout);
|
|
|
|
/**
|
|
* Closes the WebSocket connection.
|
|
*
|
|
* Use of this method is optional. Websockets can technically be closed by destroying the
|
|
* underlying TCP client. The Close method (which implements a closing handshake) is
|
|
* recommended in RFC 6455 to achieve a "clean" close.
|
|
*
|
|
* @public @memberof kWebSocket
|
|
* @param webSocket WebSocket object.
|
|
* @return Operation status.
|
|
*/
|
|
kFx(kStatus) kWebSocket_Close(kWebSocket webSocket);
|
|
|
|
/**
|
|
* Sets the data transfer type used for send operations.
|
|
*
|
|
* In UTF-8 mode, it is the caller's responsibility to ensure that message
|
|
* data is valid UTF-8.
|
|
*
|
|
* If this method is not called, kWebSocket defaults to Binary mode.
|
|
*
|
|
* The send type cannot be changed while a message is in progress (i.e., between
|
|
* kStream_Write and kWebSocket_Send).
|
|
*
|
|
* @public @memberof kWebSocket
|
|
* @param webSocket WebSocket object.
|
|
* @param type Frame type.
|
|
* @return Operation status.
|
|
*/
|
|
kFx(kStatus) kWebSocket_SetSendType(kWebSocket webSocket, kWebSocketDataType type);
|
|
|
|
/**
|
|
* Sends any buffered data and ends the current message.
|
|
*
|
|
* Websocket communication consists of <em>messages</em>, where each message can be transmitted
|
|
* in one or more <em>frames</em>.
|
|
*
|
|
* The kStream_Write method can be used to write data to a WebSocket. If the WebSocket
|
|
* has a client buffer and the buffer is filled, the buffered data will be sent as a WebSocket frame.
|
|
* If the WebSocket does not have a client buffer, each call to kStream_Write will generate a
|
|
* WebSocket frame.
|
|
*
|
|
* The kWebSocket_Send method generates an end-of-message frame that includes any data remaining
|
|
* in the WebSocket buffer. If no data remains, an empty end-of-message frame will be generated.
|
|
* All message data is flushed to the underlying TCP object as part of kWebSocket_Send;
|
|
* the kStream_Flush method has no effect.
|
|
*
|
|
* @public @memberof kWebSocket
|
|
* @param webSocket WebSocket object.
|
|
* @return Operation status.
|
|
*/
|
|
kFx(kStatus) kWebSocket_Send(kWebSocket webSocket);
|
|
|
|
/**
|
|
* Blocks until a new message is available for reading.
|
|
*
|
|
* The Receive method should be used to wait for a new message. Once a new message
|
|
* has been detected, kStream methods can be used to read out the data. When the message
|
|
* has been completely read out, additional kStream read calls will return kERROR_NOT_FOUND.
|
|
* At this point, kWebSocket_Receive can be used to wait for another message.
|
|
*
|
|
* Multi-frame WebSocket messages will be treated as a single message. If kWebSocket_Receive
|
|
* is called before the previous message has been completely read out, any remaining data
|
|
* in the previous message will be discarded before waiting for a new message.
|
|
*
|
|
* If this function returns successfully, the kWebSocket_ReceiveType method can optionally be
|
|
* used to determine the type of incoming data.
|
|
*
|
|
* @public @memberof kWebSocket
|
|
* @param webSocket WebSocket object.
|
|
* @param timeout Timeout, in microseconds.
|
|
* @return Operation status.
|
|
*/
|
|
kFx(kStatus) kWebSocket_Receive(kWebSocket webSocket, k64u timeout);
|
|
|
|
/**
|
|
* Writes a complete WebSocket message.
|
|
*
|
|
* This method can be used as an alternative to kStream_Write/kWebSocket_Send.
|
|
*
|
|
* This method can be used to generate a WebSocket message from a single input buffer.
|
|
* The WebSocket's internal client buffer is bypassed.
|
|
*
|
|
* @public @memberof kWebSocket
|
|
* @param webSocket WebSocket object.
|
|
* @param buffer Bytes to be written.
|
|
* @param size Count of bytes to be written.
|
|
* @return Operation status.
|
|
*/
|
|
kFx(kStatus) kWebSocket_WriteMessage(kWebSocket webSocket, const void* buffer, kSize size);
|
|
|
|
/**
|
|
* Blocks until a whole message has been read (or until a timeout occurs).
|
|
*
|
|
* This method can be used as an alternative to kWebSocket_Receive/kStream_Read.
|
|
*
|
|
* The 'memory' argument provides an interface to accept the received message data. This
|
|
* enables the caller to accept a message without knowing the message size beforehand. A
|
|
* kMemory object can be used to accept data into an arbitrary memory location.
|
|
*
|
|
* The timeout parameter determines the length of time to wait for the first message
|
|
* header to arrive.
|
|
*
|
|
* @public @memberof kWebSocket
|
|
* @param webSocket WebSocket object.
|
|
* @param memory Memory stream object that will receive message data.
|
|
* @param timeout Timeout, in microseconds.
|
|
* @return Operation status.
|
|
*/
|
|
kFx(kStatus) kWebSocket_ReadMessage(kWebSocket webSocket, kMemory memory, k64u timeout);
|
|
|
|
/**
|
|
* Cancels any pending I/O operations.
|
|
*
|
|
* This method is thread-safe.
|
|
*
|
|
* @public @memberof kWebSocket
|
|
* @return Operation status.
|
|
*/
|
|
kFx(kStatus) kWebSocket_Cancel(kWebSocket webSocket);
|
|
|
|
/**
|
|
* Sends a ping message.
|
|
*
|
|
* Use the LastPong method to determine if/when a corresponding pong message
|
|
* has been received.
|
|
*
|
|
* @public @memberof kWebSocket
|
|
* @param webSocket WebSocket object.
|
|
* @return Operation status.
|
|
*/
|
|
kFx(kStatus) kWebSocket_SendPing(kWebSocket webSocket);
|
|
|
|
/**
|
|
* Reports the time at which the most recent pong message arrived.
|
|
*
|
|
* @public @memberof kWebSocket
|
|
* @param webSocket WebSocket object.
|
|
* @return Time at which last pong arrived, in microseconds (or 0, if never).
|
|
*/
|
|
kFx(k64u) kWebSocket_LastPong(kWebSocket webSocket);
|
|
|
|
/**
|
|
* Reports the message data type currently used for sending.
|
|
*
|
|
* @public @memberof kWebSocket
|
|
* @param webSocket WebSocket object.
|
|
* @return Frame type used for sending.
|
|
*/
|
|
kFx(kWebSocketDataType) kWebSocket_SendType(kWebSocket webSocket);
|
|
|
|
/**
|
|
* Reports the data type of the most recently received data message.
|
|
*
|
|
* @public @memberof kWebSocket
|
|
* @param webSocket WebSocket object.
|
|
* @return Frame type of the last received message.
|
|
*/
|
|
kFx(kWebSocketDataType) kWebSocket_ReceiveType(kWebSocket webSocket);
|
|
|
|
#endif
|