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