1 | // |
2 | // WebSocketImpl.cpp |
3 | // |
4 | // Library: Net |
5 | // Package: WebSocket |
6 | // Module: WebSocketImpl |
7 | // |
8 | // Copyright (c) 2012, Applied Informatics Software Engineering GmbH. |
9 | // and Contributors. |
10 | // |
11 | // SPDX-License-Identifier: BSL-1.0 |
12 | // |
13 | |
14 | |
15 | #include "Poco/Net/WebSocketImpl.h" |
16 | #include "Poco/Net/NetException.h" |
17 | #include "Poco/Net/WebSocket.h" |
18 | #include "Poco/Net/HTTPSession.h" |
19 | #include "Poco/Buffer.h" |
20 | #include "Poco/BinaryWriter.h" |
21 | #include "Poco/BinaryReader.h" |
22 | #include "Poco/MemoryStream.h" |
23 | #include "Poco/Format.h" |
24 | #include <cstring> |
25 | |
26 | |
27 | namespace Poco { |
28 | namespace Net { |
29 | |
30 | |
31 | WebSocketImpl::WebSocketImpl(StreamSocketImpl* pStreamSocketImpl, HTTPSession& session, bool mustMaskPayload): |
32 | StreamSocketImpl(pStreamSocketImpl->sockfd()), |
33 | _pStreamSocketImpl(pStreamSocketImpl), |
34 | _buffer(0), |
35 | _bufferOffset(0), |
36 | _frameFlags(0), |
37 | _mustMaskPayload(mustMaskPayload) |
38 | { |
39 | poco_check_ptr(pStreamSocketImpl); |
40 | _pStreamSocketImpl->duplicate(); |
41 | session.drainBuffer(_buffer); |
42 | } |
43 | |
44 | |
45 | WebSocketImpl::~WebSocketImpl() |
46 | { |
47 | try |
48 | { |
49 | _pStreamSocketImpl->release(); |
50 | reset(); |
51 | } |
52 | catch (...) |
53 | { |
54 | poco_unexpected(); |
55 | } |
56 | } |
57 | |
58 | |
59 | int WebSocketImpl::sendBytes(const void* buffer, int length, int flags) |
60 | { |
61 | Poco::Buffer<char> frame(length + MAX_HEADER_LENGTH); |
62 | Poco::MemoryOutputStream ostr(frame.begin(), frame.size()); |
63 | Poco::BinaryWriter writer(ostr, Poco::BinaryWriter::NETWORK_BYTE_ORDER); |
64 | |
65 | if (flags == 0) flags = WebSocket::FRAME_BINARY; |
66 | flags &= 0xff; |
67 | writer << static_cast<Poco::UInt8>(flags); |
68 | Poco::UInt8 lengthByte(0); |
69 | if (_mustMaskPayload) |
70 | { |
71 | lengthByte |= FRAME_FLAG_MASK; |
72 | } |
73 | if (length < 126) |
74 | { |
75 | lengthByte |= static_cast<Poco::UInt8>(length); |
76 | writer << lengthByte; |
77 | } |
78 | else if (length < 65536) |
79 | { |
80 | lengthByte |= 126; |
81 | writer << lengthByte << static_cast<Poco::UInt16>(length); |
82 | } |
83 | else |
84 | { |
85 | lengthByte |= 127; |
86 | writer << lengthByte << static_cast<Poco::UInt64>(length); |
87 | } |
88 | if (_mustMaskPayload) |
89 | { |
90 | const Poco::UInt32 mask = _rnd.next(); |
91 | const char* m = reinterpret_cast<const char*>(&mask); |
92 | const char* b = reinterpret_cast<const char*>(buffer); |
93 | writer.writeRaw(m, 4); |
94 | char* p = frame.begin() + ostr.charsWritten(); |
95 | for (int i = 0; i < length; i++) |
96 | { |
97 | p[i] = b[i] ^ m[i % 4]; |
98 | } |
99 | } |
100 | else |
101 | { |
102 | std::memcpy(frame.begin() + ostr.charsWritten(), buffer, length); |
103 | } |
104 | _pStreamSocketImpl->sendBytes(frame.begin(), length + static_cast<int>(ostr.charsWritten())); |
105 | return length; |
106 | } |
107 | |
108 | |
109 | int WebSocketImpl::(char mask[4], bool& useMask) |
110 | { |
111 | char [MAX_HEADER_LENGTH]; |
112 | int n = receiveNBytes(header, 2); |
113 | if (n <= 0) |
114 | { |
115 | _frameFlags = 0; |
116 | return n; |
117 | } |
118 | poco_assert (n == 2); |
119 | Poco::UInt8 flags = static_cast<Poco::UInt8>(header[0]); |
120 | _frameFlags = flags; |
121 | Poco::UInt8 lengthByte = static_cast<Poco::UInt8>(header[1]); |
122 | useMask = ((lengthByte & FRAME_FLAG_MASK) != 0); |
123 | int payloadLength; |
124 | lengthByte &= 0x7f; |
125 | if (lengthByte == 127) |
126 | { |
127 | n = receiveNBytes(header + 2, 8); |
128 | if (n <= 0) |
129 | { |
130 | _frameFlags = 0; |
131 | return n; |
132 | } |
133 | Poco::MemoryInputStream istr(header + 2, 8); |
134 | Poco::BinaryReader reader(istr, Poco::BinaryReader::NETWORK_BYTE_ORDER); |
135 | Poco::UInt64 l; |
136 | reader >> l; |
137 | payloadLength = static_cast<int>(l); |
138 | } |
139 | else if (lengthByte == 126) |
140 | { |
141 | n = receiveNBytes(header + 2, 2); |
142 | if (n <= 0) |
143 | { |
144 | _frameFlags = 0; |
145 | return n; |
146 | } |
147 | Poco::MemoryInputStream istr(header + 2, 2); |
148 | Poco::BinaryReader reader(istr, Poco::BinaryReader::NETWORK_BYTE_ORDER); |
149 | Poco::UInt16 l; |
150 | reader >> l; |
151 | payloadLength = static_cast<int>(l); |
152 | } |
153 | else |
154 | { |
155 | payloadLength = lengthByte; |
156 | } |
157 | |
158 | if (useMask) |
159 | { |
160 | n = receiveNBytes(mask, 4); |
161 | if (n <= 0) |
162 | { |
163 | _frameFlags = 0; |
164 | return n; |
165 | } |
166 | } |
167 | |
168 | return payloadLength; |
169 | } |
170 | |
171 | |
172 | int WebSocketImpl::receivePayload(char *buffer, int payloadLength, char mask[4], bool useMask) |
173 | { |
174 | int received = receiveNBytes(reinterpret_cast<char*>(buffer), payloadLength); |
175 | if (received <= 0) throw WebSocketException("Incomplete frame received" , WebSocket::WS_ERR_INCOMPLETE_FRAME); |
176 | |
177 | if (useMask) |
178 | { |
179 | for (int i = 0; i < received; i++) |
180 | { |
181 | buffer[i] ^= mask[i % 4]; |
182 | } |
183 | } |
184 | return received; |
185 | } |
186 | |
187 | |
188 | int WebSocketImpl::receiveBytes(void* buffer, int length, int) |
189 | { |
190 | char mask[4]; |
191 | bool useMask; |
192 | int payloadLength = receiveHeader(mask, useMask); |
193 | if (payloadLength <= 0) |
194 | return payloadLength; |
195 | if (payloadLength > length) |
196 | throw WebSocketException(Poco::format("Insufficient buffer for payload size %hu" , payloadLength), WebSocket::WS_ERR_PAYLOAD_TOO_BIG); |
197 | return receivePayload(reinterpret_cast<char*>(buffer), payloadLength, mask, useMask); |
198 | } |
199 | |
200 | |
201 | int WebSocketImpl::receiveBytes(Poco::Buffer<char>& buffer, int) |
202 | { |
203 | char mask[4]; |
204 | bool useMask; |
205 | int payloadLength = receiveHeader(mask, useMask); |
206 | if (payloadLength <= 0) |
207 | return payloadLength; |
208 | int oldSize = static_cast<int>(buffer.size()); |
209 | buffer.resize(oldSize + payloadLength); |
210 | return receivePayload(buffer.begin() + oldSize, payloadLength, mask, useMask); |
211 | } |
212 | |
213 | |
214 | int WebSocketImpl::receiveNBytes(void* buffer, int bytes) |
215 | { |
216 | int received = receiveSomeBytes(reinterpret_cast<char*>(buffer), bytes); |
217 | if (received > 0) |
218 | { |
219 | while (received < bytes) |
220 | { |
221 | int n = receiveSomeBytes(reinterpret_cast<char*>(buffer) + received, bytes - received); |
222 | if (n > 0) |
223 | received += n; |
224 | else |
225 | throw WebSocketException("Incomplete frame received" , WebSocket::WS_ERR_INCOMPLETE_FRAME); |
226 | } |
227 | } |
228 | return received; |
229 | } |
230 | |
231 | |
232 | int WebSocketImpl::receiveSomeBytes(char* buffer, int bytes) |
233 | { |
234 | int n = static_cast<int>(_buffer.size()) - _bufferOffset; |
235 | if (n > 0) |
236 | { |
237 | if (bytes < n) n = bytes; |
238 | std::memcpy(buffer, _buffer.begin() + _bufferOffset, n); |
239 | _bufferOffset += n; |
240 | return n; |
241 | } |
242 | else |
243 | { |
244 | return _pStreamSocketImpl->receiveBytes(buffer, bytes); |
245 | } |
246 | } |
247 | |
248 | |
249 | SocketImpl* WebSocketImpl::acceptConnection(SocketAddress& clientAddr) |
250 | { |
251 | throw Poco::InvalidAccessException("Cannot acceptConnection() on a WebSocketImpl" ); |
252 | } |
253 | |
254 | |
255 | void WebSocketImpl::connect(const SocketAddress& address) |
256 | { |
257 | throw Poco::InvalidAccessException("Cannot connect() a WebSocketImpl" ); |
258 | } |
259 | |
260 | |
261 | void WebSocketImpl::connect(const SocketAddress& address, const Poco::Timespan& timeout) |
262 | { |
263 | throw Poco::InvalidAccessException("Cannot connect() a WebSocketImpl" ); |
264 | } |
265 | |
266 | |
267 | void WebSocketImpl::connectNB(const SocketAddress& address) |
268 | { |
269 | throw Poco::InvalidAccessException("Cannot connectNB() a WebSocketImpl" ); |
270 | } |
271 | |
272 | |
273 | void WebSocketImpl::bind(const SocketAddress& address, bool reuseAddress) |
274 | { |
275 | throw Poco::InvalidAccessException("Cannot bind() a WebSocketImpl" ); |
276 | } |
277 | |
278 | |
279 | void WebSocketImpl::bind(const SocketAddress& address, bool reuseAddress, bool reusePort) |
280 | { |
281 | throw Poco::InvalidAccessException("Cannot bind() a WebSocketImpl" ); |
282 | } |
283 | |
284 | |
285 | void WebSocketImpl::bind6(const SocketAddress& address, bool reuseAddress, bool ipV6Only) |
286 | { |
287 | throw Poco::InvalidAccessException("Cannot bind6() a WebSocketImpl" ); |
288 | } |
289 | |
290 | |
291 | void WebSocketImpl::bind6(const SocketAddress& address, bool reuseAddress, bool reusePort, bool ipV6Only) |
292 | { |
293 | throw Poco::InvalidAccessException("Cannot bind6() a WebSocketImpl" ); |
294 | } |
295 | |
296 | |
297 | void WebSocketImpl::listen(int backlog) |
298 | { |
299 | throw Poco::InvalidAccessException("Cannot listen() on a WebSocketImpl" ); |
300 | } |
301 | |
302 | |
303 | void WebSocketImpl::close() |
304 | { |
305 | _pStreamSocketImpl->close(); |
306 | reset(); |
307 | } |
308 | |
309 | |
310 | void WebSocketImpl::shutdownReceive() |
311 | { |
312 | _pStreamSocketImpl->shutdownReceive(); |
313 | } |
314 | |
315 | |
316 | void WebSocketImpl::shutdownSend() |
317 | { |
318 | _pStreamSocketImpl->shutdownSend(); |
319 | } |
320 | |
321 | |
322 | void WebSocketImpl::shutdown() |
323 | { |
324 | _pStreamSocketImpl->shutdown(); |
325 | } |
326 | |
327 | |
328 | int WebSocketImpl::sendTo(const void* buffer, int length, const SocketAddress& address, int flags) |
329 | { |
330 | throw Poco::InvalidAccessException("Cannot sendTo() on a WebSocketImpl" ); |
331 | } |
332 | |
333 | |
334 | int WebSocketImpl::receiveFrom(void* buffer, int length, SocketAddress& address, int flags) |
335 | { |
336 | throw Poco::InvalidAccessException("Cannot receiveFrom() on a WebSocketImpl" ); |
337 | } |
338 | |
339 | |
340 | void WebSocketImpl::sendUrgent(unsigned char data) |
341 | { |
342 | throw Poco::InvalidAccessException("Cannot sendUrgent() on a WebSocketImpl" ); |
343 | } |
344 | |
345 | |
346 | bool WebSocketImpl::secure() const |
347 | { |
348 | return _pStreamSocketImpl->secure(); |
349 | } |
350 | |
351 | |
352 | void WebSocketImpl::setSendTimeout(const Poco::Timespan& timeout) |
353 | { |
354 | _pStreamSocketImpl->setSendTimeout(timeout); |
355 | } |
356 | |
357 | |
358 | Poco::Timespan WebSocketImpl::getSendTimeout() |
359 | { |
360 | return _pStreamSocketImpl->getSendTimeout(); |
361 | } |
362 | |
363 | |
364 | void WebSocketImpl::setReceiveTimeout(const Poco::Timespan& timeout) |
365 | { |
366 | _pStreamSocketImpl->setReceiveTimeout(timeout); |
367 | } |
368 | |
369 | |
370 | Poco::Timespan WebSocketImpl::getReceiveTimeout() |
371 | { |
372 | return _pStreamSocketImpl->getReceiveTimeout(); |
373 | } |
374 | |
375 | |
376 | int WebSocketImpl::available() |
377 | { |
378 | return _pStreamSocketImpl->available(); |
379 | } |
380 | |
381 | |
382 | } } // namespace Poco::Net |
383 | |