forked from RaveTek/Eaglercraft-1.20-Websocket
-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathwebsocket_transport.c
276 lines (229 loc) · 7.29 KB
/
websocket_transport.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
#define TRACE_LEVEL WEB_SOCKET_TRACE_LEVEL
//Dependencies
#include "core/net.h"
#include "web_socket/websocket.h"
#include "web_socket/websocket_transport.h"
#include "debug.h"
//Check TCP/IP stack configuration
#if (WEB_SOCKET_SUPPORT == ENABLED)
/**
* @brief Open network connection
* @param[in] webSocket Handle to a WebSocket
* @return Error code
**/
error_t webSocketOpenConnection(WebSocket *webSocket)
{
error_t error;
//Invalid socket handle?
if(webSocket->socket == NULL)
{
//Open a TCP socket
webSocket->socket = socketOpen(SOCKET_TYPE_STREAM, SOCKET_IP_PROTO_TCP);
//Failed to open socket?
if(webSocket->socket == NULL)
return ERROR_OPEN_FAILED;
//Associate the WebSocket with the relevant interface
error = socketBindToInterface(webSocket->socket, webSocket->interface);
//Any error to report?
if(error)
return error;
}
//Set timeout
error = socketSetTimeout(webSocket->socket, webSocket->timeout);
//Any error to report?
if(error)
return error;
#if (WEB_SOCKET_TLS_SUPPORT == ENABLED)
//TLS-secured connection?
if(webSocket->tlsInitCallback != NULL)
{
TlsConnectionEnd connectionEnd;
//Allocate TLS context
webSocket->tlsContext = tlsInit();
//Failed to allocate TLS context?
if(webSocket->tlsContext == NULL)
return ERROR_OUT_OF_MEMORY;
//Client or server operation?
if(webSocket->endpoint == WS_ENDPOINT_CLIENT)
connectionEnd = TLS_CONNECTION_END_CLIENT;
else
connectionEnd = TLS_CONNECTION_END_SERVER;
//Select the relevant operation mode
error = tlsSetConnectionEnd(webSocket->tlsContext, connectionEnd);
//Any error to report?
if(error)
return error;
//Bind TLS to the relevant socket
error = tlsSetSocket(webSocket->tlsContext, webSocket->socket);
//Any error to report?
if(error)
return error;
//Restore TLS session, if any
error = tlsRestoreSessionState(webSocket->tlsContext, &webSocket->tlsSession);
//Any error to report?
if(error)
return error;
//Invoke user-defined callback, if any
if(webSocket->tlsInitCallback != NULL)
{
//Perform TLS related initialization
error = webSocket->tlsInitCallback(webSocket, webSocket->tlsContext);
//Any error to report?
if(error)
return error;
}
}
#endif
//Successful initialization
return NO_ERROR;
}
/**
* @brief Establish network connection
* @param[in] webSocket Handle to a WebSocket
* @param[in] serverIpAddr IP address of the WebSocket server to connect to
* @param[in] serverPort TCP port number that will be used to establish the
* connection
* @return Error code
**/
error_t webSocketEstablishConnection(WebSocket *webSocket,
const IpAddr *serverIpAddr, uint16_t serverPort)
{
error_t error;
//Connect to WebSocket server
error = socketConnect(webSocket->socket, serverIpAddr, serverPort);
#if (WEB_SOCKET_TLS_SUPPORT == ENABLED)
//TLS-secured connection?
if(webSocket->tlsInitCallback != NULL)
{
//Check status code
if(!error)
{
//Establish TLS connection
error = tlsConnect(webSocket->tlsContext);
}
}
#endif
//Return status code
return error;
}
/**
* @brief Shutdown network connection
* @param[in] webSocket Handle to a WebSocket
* @return Error code
**/
error_t webSocketShutdownConnection(WebSocket *webSocket)
{
error_t error;
size_t n;
//Initialize status code
error = NO_ERROR;
#if (WEB_SOCKET_TLS_SUPPORT == ENABLED)
//Check whether a secure connection is being used
if(webSocket->tlsContext != NULL)
{
//Shutdown TLS connection
error = tlsShutdown(webSocket->tlsContext);
}
#endif
//Check status code
if(!error)
{
//Further transmissions are disallowed
error = socketShutdown(webSocket->socket, SOCKET_SD_SEND);
}
//Receive data until until the peer has also performed an orderly shutdown
while(!error)
{
//Discard data
error = socketReceive(webSocket->socket, webSocket->rxContext.buffer,
WEB_SOCKET_BUFFER_SIZE, &n, 0);
}
//Check whether the connection has been properly closed
if(error == ERROR_END_OF_STREAM)
error = NO_ERROR;
//Return status code
return error;
}
/**
* @brief Close network connection
* @param[in] webSocket Handle to a WebSocket
**/
void webSocketCloseConnection(WebSocket *webSocket)
{
#if (WEB_SOCKET_TLS_SUPPORT == ENABLED)
//Check whether a secure connection is being used
if(webSocket->tlsContext != NULL)
{
//Save TLS session
tlsSaveSessionState(webSocket->tlsContext, &webSocket->tlsSession);
//Release TLS context
tlsFree(webSocket->tlsContext);
webSocket->tlsContext = NULL;
}
#endif
//Close TCP connection
if(webSocket->socket != NULL)
{
socketClose(webSocket->socket);
webSocket->socket = NULL;
}
}
/**
* @brief Send data using the relevant transport protocol
* @param[in] webSocket Handle to a WebSocket
* @param[in] data Pointer to a buffer containing the data to be transmitted
* @param[in] length Number of bytes to be transmitted
* @param[out] written Actual number of bytes written (optional parameter)
* @param[in] flags Set of flags that influences the behavior of this function
* @return Error code
**/
error_t webSocketSendData(WebSocket *webSocket, const void *data,
size_t length, size_t *written, uint_t flags)
{
error_t error;
#if (WEB_SOCKET_TLS_SUPPORT == ENABLED)
//Check whether a secure connection is being used
if(webSocket->tlsContext != NULL)
{
//Use TLS to transmit data
error = tlsWrite(webSocket->tlsContext, data, length, written, flags);
}
else
#endif
{
//Transmit data
error = socketSend(webSocket->socket, data, length, written, flags);
}
//Return status code
return error;
}
/**
* @brief Receive data using the relevant transport protocol
* @param[in] webSocket Handle to a WebSocket
* @param[out] data Buffer into which received data will be placed
* @param[in] size Maximum number of bytes that can be received
* @param[out] received Number of bytes that have been received
* @param[in] flags Set of flags that influences the behavior of this function
* @return Error code
**/
error_t webSocketReceiveData(WebSocket *webSocket, void *data,
size_t size, size_t *received, uint_t flags)
{
error_t error;
#if (WEB_SOCKET_TLS_SUPPORT == ENABLED)
//Check whether a secure connection is being used
if(webSocket->tlsContext != NULL)
{
//Use TLS to receive data
error = tlsRead(webSocket->tlsContext, data, size, received, flags);
}
else
#endif
{
//Receive data
error = socketReceive(webSocket->socket, data, size, received, flags);
}
//Return status code
return error;
}
#endif