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
27namespace Poco {
28namespace Net {
29
30
31WebSocketImpl::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
45WebSocketImpl::~WebSocketImpl()
46{
47 try
48 {
49 _pStreamSocketImpl->release();
50 reset();
51 }
52 catch (...)
53 {
54 poco_unexpected();
55 }
56}
57
58
59int 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
109int WebSocketImpl::receiveHeader(char mask[4], bool& useMask)
110{
111 char header[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
172int 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
188int 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
201int 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
214int 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
232int 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
249SocketImpl* WebSocketImpl::acceptConnection(SocketAddress& clientAddr)
250{
251 throw Poco::InvalidAccessException("Cannot acceptConnection() on a WebSocketImpl");
252}
253
254
255void WebSocketImpl::connect(const SocketAddress& address)
256{
257 throw Poco::InvalidAccessException("Cannot connect() a WebSocketImpl");
258}
259
260
261void WebSocketImpl::connect(const SocketAddress& address, const Poco::Timespan& timeout)
262{
263 throw Poco::InvalidAccessException("Cannot connect() a WebSocketImpl");
264}
265
266
267void WebSocketImpl::connectNB(const SocketAddress& address)
268{
269 throw Poco::InvalidAccessException("Cannot connectNB() a WebSocketImpl");
270}
271
272
273void WebSocketImpl::bind(const SocketAddress& address, bool reuseAddress)
274{
275 throw Poco::InvalidAccessException("Cannot bind() a WebSocketImpl");
276}
277
278
279void WebSocketImpl::bind(const SocketAddress& address, bool reuseAddress, bool reusePort)
280{
281 throw Poco::InvalidAccessException("Cannot bind() a WebSocketImpl");
282}
283
284
285void WebSocketImpl::bind6(const SocketAddress& address, bool reuseAddress, bool ipV6Only)
286{
287 throw Poco::InvalidAccessException("Cannot bind6() a WebSocketImpl");
288}
289
290
291void WebSocketImpl::bind6(const SocketAddress& address, bool reuseAddress, bool reusePort, bool ipV6Only)
292{
293 throw Poco::InvalidAccessException("Cannot bind6() a WebSocketImpl");
294}
295
296
297void WebSocketImpl::listen(int backlog)
298{
299 throw Poco::InvalidAccessException("Cannot listen() on a WebSocketImpl");
300}
301
302
303void WebSocketImpl::close()
304{
305 _pStreamSocketImpl->close();
306 reset();
307}
308
309
310void WebSocketImpl::shutdownReceive()
311{
312 _pStreamSocketImpl->shutdownReceive();
313}
314
315
316void WebSocketImpl::shutdownSend()
317{
318 _pStreamSocketImpl->shutdownSend();
319}
320
321
322void WebSocketImpl::shutdown()
323{
324 _pStreamSocketImpl->shutdown();
325}
326
327
328int 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
334int WebSocketImpl::receiveFrom(void* buffer, int length, SocketAddress& address, int flags)
335{
336 throw Poco::InvalidAccessException("Cannot receiveFrom() on a WebSocketImpl");
337}
338
339
340void WebSocketImpl::sendUrgent(unsigned char data)
341{
342 throw Poco::InvalidAccessException("Cannot sendUrgent() on a WebSocketImpl");
343}
344
345
346bool WebSocketImpl::secure() const
347{
348 return _pStreamSocketImpl->secure();
349}
350
351
352void WebSocketImpl::setSendTimeout(const Poco::Timespan& timeout)
353{
354 _pStreamSocketImpl->setSendTimeout(timeout);
355}
356
357
358Poco::Timespan WebSocketImpl::getSendTimeout()
359{
360 return _pStreamSocketImpl->getSendTimeout();
361}
362
363
364void WebSocketImpl::setReceiveTimeout(const Poco::Timespan& timeout)
365{
366 _pStreamSocketImpl->setReceiveTimeout(timeout);
367}
368
369
370Poco::Timespan WebSocketImpl::getReceiveTimeout()
371{
372 return _pStreamSocketImpl->getReceiveTimeout();
373}
374
375
376int WebSocketImpl::available()
377{
378 return _pStreamSocketImpl->available();
379}
380
381
382} } // namespace Poco::Net
383