web_socket_transport.c
Go to the documentation of this file.
1 /**
2  * @file web_socket_transport.c
3  * @brief WebSocket transport layer
4  *
5  * @section License
6  *
7  * SPDX-License-Identifier: GPL-2.0-or-later
8  *
9  * Copyright (C) 2010-2024 Oryx Embedded SARL. All rights reserved.
10  *
11  * This file is part of CycloneTCP Open.
12  *
13  * This program is free software; you can redistribute it and/or
14  * modify it under the terms of the GNU General Public License
15  * as published by the Free Software Foundation; either version 2
16  * of the License, or (at your option) any later version.
17  *
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, write to the Free Software Foundation,
25  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
26  *
27  * @author Oryx Embedded SARL (www.oryx-embedded.com)
28  * @version 2.4.4
29  **/
30 
31 //Switch to the appropriate trace level
32 #define TRACE_LEVEL WEB_SOCKET_TRACE_LEVEL
33 
34 //Dependencies
35 #include "core/net.h"
36 #include "web_socket/web_socket.h"
38 #include "debug.h"
39 
40 //Check TCP/IP stack configuration
41 #if (WEB_SOCKET_SUPPORT == ENABLED)
42 
43 
44 /**
45  * @brief Open network connection
46  * @param[in] webSocket Handle to a WebSocket
47  * @return Error code
48  **/
49 
51 {
52  error_t error;
53 
54  //Invalid socket handle?
55  if(webSocket->socket == NULL)
56  {
57  //Open a TCP socket
59  //Failed to open socket?
60  if(webSocket->socket == NULL)
61  return ERROR_OPEN_FAILED;
62 
63  //Associate the WebSocket with the relevant interface
64  error = socketBindToInterface(webSocket->socket, webSocket->interface);
65  //Any error to report?
66  if(error)
67  return error;
68  }
69 
70  //Set timeout
71  error = socketSetTimeout(webSocket->socket, webSocket->timeout);
72  //Any error to report?
73  if(error)
74  return error;
75 
76 #if (WEB_SOCKET_TLS_SUPPORT == ENABLED)
77  //TLS-secured connection?
78  if(webSocket->tlsInitCallback != NULL)
79  {
80  TlsConnectionEnd connectionEnd;
81 
82  //Allocate TLS context
83  webSocket->tlsContext = tlsInit();
84  //Failed to allocate TLS context?
85  if(webSocket->tlsContext == NULL)
86  return ERROR_OUT_OF_MEMORY;
87 
88  //Client or server operation?
89  if(webSocket->endpoint == WS_ENDPOINT_CLIENT)
90  connectionEnd = TLS_CONNECTION_END_CLIENT;
91  else
92  connectionEnd = TLS_CONNECTION_END_SERVER;
93 
94  //Select the relevant operation mode
95  error = tlsSetConnectionEnd(webSocket->tlsContext, connectionEnd);
96  //Any error to report?
97  if(error)
98  return error;
99 
100  //Bind TLS to the relevant socket
101  error = tlsSetSocket(webSocket->tlsContext, webSocket->socket);
102  //Any error to report?
103  if(error)
104  return error;
105 
106  //Restore TLS session, if any
107  error = tlsRestoreSessionState(webSocket->tlsContext, &webSocket->tlsSession);
108  //Any error to report?
109  if(error)
110  return error;
111 
112  //Invoke user-defined callback, if any
113  if(webSocket->tlsInitCallback != NULL)
114  {
115  //Perform TLS related initialization
116  error = webSocket->tlsInitCallback(webSocket, webSocket->tlsContext);
117  //Any error to report?
118  if(error)
119  return error;
120  }
121  }
122 #endif
123 
124  //Successful initialization
125  return NO_ERROR;
126 }
127 
128 
129 /**
130  * @brief Establish network connection
131  * @param[in] webSocket Handle to a WebSocket
132  * @param[in] serverIpAddr IP address of the WebSocket server to connect to
133  * @param[in] serverPort TCP port number that will be used to establish the
134  * connection
135  * @return Error code
136  **/
137 
139  const IpAddr *serverIpAddr, uint16_t serverPort)
140 {
141  error_t error;
142 
143  //Connect to WebSocket server
144  error = socketConnect(webSocket->socket, serverIpAddr, serverPort);
145 
146 #if (WEB_SOCKET_TLS_SUPPORT == ENABLED)
147  //TLS-secured connection?
148  if(webSocket->tlsInitCallback != NULL)
149  {
150  //Check status code
151  if(!error)
152  {
153  //Establish TLS connection
154  error = tlsConnect(webSocket->tlsContext);
155  }
156  }
157 #endif
158 
159  //Return status code
160  return error;
161 }
162 
163 
164 /**
165  * @brief Shutdown network connection
166  * @param[in] webSocket Handle to a WebSocket
167  * @return Error code
168  **/
169 
171 {
172  error_t error;
173  size_t n;
174 
175  //Initialize status code
176  error = NO_ERROR;
177 
178 #if (WEB_SOCKET_TLS_SUPPORT == ENABLED)
179  //Check whether a secure connection is being used
180  if(webSocket->tlsContext != NULL)
181  {
182  //Shutdown TLS connection
183  error = tlsShutdown(webSocket->tlsContext);
184  }
185 #endif
186 
187  //Check status code
188  if(!error)
189  {
190  //Further transmissions are disallowed
191  error = socketShutdown(webSocket->socket, SOCKET_SD_SEND);
192  }
193 
194  //Receive data until until the peer has also performed an orderly shutdown
195  while(!error)
196  {
197  //Discard data
198  error = socketReceive(webSocket->socket, webSocket->rxContext.buffer,
200  }
201 
202  //Check whether the connection has been properly closed
203  if(error == ERROR_END_OF_STREAM)
204  error = NO_ERROR;
205 
206  //Return status code
207  return error;
208 }
209 
210 
211 /**
212  * @brief Close network connection
213  * @param[in] webSocket Handle to a WebSocket
214  **/
215 
217 {
218 #if (WEB_SOCKET_TLS_SUPPORT == ENABLED)
219  //Check whether a secure connection is being used
220  if(webSocket->tlsContext != NULL)
221  {
222  //Save TLS session
223  tlsSaveSessionState(webSocket->tlsContext, &webSocket->tlsSession);
224 
225  //Release TLS context
226  tlsFree(webSocket->tlsContext);
227  webSocket->tlsContext = NULL;
228  }
229 #endif
230 
231  //Close TCP connection
232  if(webSocket->socket != NULL)
233  {
234  socketClose(webSocket->socket);
235  webSocket->socket = NULL;
236  }
237 }
238 
239 
240 /**
241  * @brief Send data using the relevant transport protocol
242  * @param[in] webSocket Handle to a WebSocket
243  * @param[in] data Pointer to a buffer containing the data to be transmitted
244  * @param[in] length Number of bytes to be transmitted
245  * @param[out] written Actual number of bytes written (optional parameter)
246  * @param[in] flags Set of flags that influences the behavior of this function
247  * @return Error code
248  **/
249 
250 error_t webSocketSendData(WebSocket *webSocket, const void *data,
251  size_t length, size_t *written, uint_t flags)
252 {
253  error_t error;
254 
255 #if (WEB_SOCKET_TLS_SUPPORT == ENABLED)
256  //Check whether a secure connection is being used
257  if(webSocket->tlsContext != NULL)
258  {
259  //Use TLS to transmit data
260  error = tlsWrite(webSocket->tlsContext, data, length, written, flags);
261  }
262  else
263 #endif
264  {
265  //Transmit data
266  error = socketSend(webSocket->socket, data, length, written, flags);
267  }
268 
269  //Return status code
270  return error;
271 }
272 
273 
274 /**
275  * @brief Receive data using the relevant transport protocol
276  * @param[in] webSocket Handle to a WebSocket
277  * @param[out] data Buffer into which received data will be placed
278  * @param[in] size Maximum number of bytes that can be received
279  * @param[out] received Number of bytes that have been received
280  * @param[in] flags Set of flags that influences the behavior of this function
281  * @return Error code
282  **/
283 
285  size_t size, size_t *received, uint_t flags)
286 {
287  error_t error;
288 
289 #if (WEB_SOCKET_TLS_SUPPORT == ENABLED)
290  //Check whether a secure connection is being used
291  if(webSocket->tlsContext != NULL)
292  {
293  //Use TLS to receive data
294  error = tlsRead(webSocket->tlsContext, data, size, received, flags);
295  }
296  else
297 #endif
298  {
299  //Receive data
300  error = socketReceive(webSocket->socket, data, size, received, flags);
301  }
302 
303  //Return status code
304  return error;
305 }
306 
307 #endif
error_t socketSend(Socket *socket, const void *data, size_t length, size_t *written, uint_t flags)
Send data to a connected socket.
Definition: socket.c:1486
TlsContext * tlsInit(void)
TLS context initialization.
Definition: tls.c:65
#define WEB_SOCKET_BUFFER_SIZE
Definition: web_socket.h:82
error_t tlsSetConnectionEnd(TlsContext *context, TlsConnectionEnd entity)
Set operation mode (client or server)
Definition: tls.c:349
error_t webSocketOpenConnection(WebSocket *webSocket)
Open network connection.
IP network address.
Definition: ip.h:90
WebSocket API (client and server)
TlsConnectionEnd
TLS connection end.
Definition: tls.h:967
uint8_t data[]
Definition: ethernet.h:222
void socketClose(Socket *socket)
Close an existing socket.
Definition: socket.c:2062
@ ERROR_OUT_OF_MEMORY
Definition: error.h:63
@ ERROR_END_OF_STREAM
Definition: error.h:210
void webSocketCloseConnection(WebSocket *webSocket)
Close network connection.
@ SOCKET_TYPE_STREAM
Definition: socket.h:92
error_t tlsRestoreSessionState(TlsContext *context, const TlsSessionState *session)
Restore TLS session.
Definition: tls.c:2700
error_t webSocketSendData(WebSocket *webSocket, const void *data, size_t length, size_t *written, uint_t flags)
Send data using the relevant transport protocol.
@ ERROR_OPEN_FAILED
Definition: error.h:75
@ SOCKET_SD_SEND
Definition: socket.h:160
error_t tlsShutdown(TlsContext *context)
Gracefully close TLS session.
Definition: tls.c:2307
#define tlsSetSocket(context, socket)
Definition: tls.h:927
error_t
Error codes.
Definition: error.h:43
error_t socketReceive(Socket *socket, void *data, size_t size, size_t *received, uint_t flags)
Receive data from a connected socket.
Definition: socket.c:1692
@ TLS_CONNECTION_END_SERVER
Definition: tls.h:969
error_t webSocketEstablishConnection(WebSocket *webSocket, const IpAddr *serverIpAddr, uint16_t serverPort)
Establish network connection.
error_t webSocketReceiveData(WebSocket *webSocket, void *data, size_t size, size_t *received, uint_t flags)
Receive data using the relevant transport protocol.
error_t socketConnect(Socket *socket, const IpAddr *remoteIpAddr, uint16_t remotePort)
Establish a connection to a specified socket.
Definition: socket.c:1349
error_t socketShutdown(Socket *socket, uint_t how)
Disable reception, transmission, or both.
Definition: socket.c:2020
error_t tlsSaveSessionState(const TlsContext *context, TlsSessionState *session)
Save TLS session.
Definition: tls.c:2631
uint8_t length
Definition: tcp.h:368
Socket * socketOpen(uint_t type, uint_t protocol)
Create a socket (UDP or TCP)
Definition: socket.c:125
error_t tlsRead(TlsContext *context, void *data, size_t size, size_t *received, uint_t flags)
Receive application data from a the remote host using TLS.
Definition: tls.c:1989
@ WS_ENDPOINT_CLIENT
Definition: web_socket.h:191
#define WebSocket
Definition: web_socket.h:177
#define socketBindToInterface
Definition: net_legacy.h:193
uint8_t flags
Definition: tcp.h:351
uint8_t n
@ TLS_CONNECTION_END_CLIENT
Definition: tls.h:968
error_t tlsWrite(TlsContext *context, const void *data, size_t length, size_t *written, uint_t flags)
Send application data to the remote host using TLS.
Definition: tls.c:1854
void tlsFree(TlsContext *context)
Release TLS context.
Definition: tls.c:2469
error_t webSocketShutdownConnection(WebSocket *webSocket)
Shutdown network connection.
WebSocket transport layer.
unsigned int uint_t
Definition: compiler_port.h:50
TCP/IP stack core.
@ SOCKET_IP_PROTO_TCP
Definition: socket.h:107
error_t socketSetTimeout(Socket *socket, systime_t timeout)
Set timeout value for blocking operations.
Definition: socket.c:148
error_t tlsConnect(TlsContext *context)
Initiate the TLS handshake.
Definition: tls.c:1763
@ NO_ERROR
Success.
Definition: error.h:44
Debugging facilities.