34static void my_alloc_cb(
uv_handle_t* handle,
size_t suggested_size, uv_buf_t*
buf)
36 buf->base = (
char*)malloc(suggested_size);
37 buf->len = suggested_size;
50 LOG(error) <<
"Error in write callback: " << uv_strerror(status);
66 if (nread == UV_EOF) {
67 LOG(detail) <<
"websocket_server_callback: communication with driver closed upon EOF";
72 LOG(error) <<
"websocket_server_callback: Error while reading from websocket" << uv_strerror((
int)nread);
81 LOG(error) <<
"Error while parsing request: " << err.what;
90 LOG(error) <<
"uv_write error: " << uv_err_name(status);
129 float* positions = (
float*)
frame;
134 char isClicked = *
frame;
139 int movement = *
frame;
149 int lat = *((
int*)
frame);
150 lat = lat < 20 ? 20 : lat;
184 mServerContext{context}
191 throw WSError{400,
"Bad Request"};
197 if (s !=
"/" && s !=
"/status") {
203void populateHeader(std::map<std::string, std::string>& headers, std::string_view
const& k, std::string_view
const&
v)
207 std::transform(kk.begin(), kk.end(), kk.begin(),
208 [](
unsigned char c) { return std::tolower(c); });
209 if (kk !=
"sec-websocket-accept" && kk !=
"sec-websocket-key") {
210 std::transform(vv.begin(), vv.end(), vv.begin(),
211 [](
unsigned char c) { return std::tolower(c); });
213 headers.insert(std::make_pair(kk, vv));
218 auto* renderer =
reinterpret_cast<GuiRenderer*
>(ctx->data);
221 void* frame =
nullptr;
222 void* draw_data =
nullptr;
224 uint64_t frameStart = uv_hrtime();
225 uint64_t frameLatency = frameStart - renderer->gui->frameLast;
228 if (renderer->gui->lastFrame ==
nullptr || frameLatency / 1000000 > 15) {
229 renderer->gui->plugin->pollGUIPreRender(renderer->gui->window, (
float)frameLatency / 1000000000.0f);
230 draw_data = renderer->gui->plugin->pollGUIRender(renderer->gui->callback);
231 renderer->gui->plugin->pollGUIPostRender(renderer->gui->window, draw_data);
233 draw_data = renderer->gui->lastFrame;
236 renderer->gui->plugin->getFrameRaw(draw_data, &frame, &
size, renderer->updateTextures);
238 renderer->updateTextures =
false;
239 std::vector<uv_buf_t> outputs;
241 renderer->handler->write(outputs);
244 renderer->guiConnected =
true;
246 if (frameLatency / 1000000 > 15) {
247 uint64_t frameEnd = uv_hrtime();
248 *(renderer->gui->frameCost) = (frameEnd - frameStart) / 1000000.f;
249 *(renderer->gui->frameLatency) = frameLatency / 1000000.f;
250 renderer->gui->frameLast = frameStart;
251 renderer->gui->lastFrame = draw_data;
263 if (
mHeaders[
"upgrade"] !=
"websocket") {
264 throw WSError{400,
"Bad Request: not a websocket upgrade"};
267 if (
mHeaders[
"connection"].find(
"upgrade") == std::string::npos) {
268 throw WSError{400,
"Bad Request: connection not for upgrade"};
270 if (
mHeaders[
"sec-websocket-protocol"] !=
"dpl") {
271 throw WSError{400,
"Bad Request: websocket protocol not \"dpl\"."};
273 if (
mHeaders.count(
"sec-websocket-key") == 0) {
274 throw WSError{400,
"Bad Request: sec-websocket-key missing"};
276 if (
mHeaders[
"sec-websocket-version"] !=
"13") {
277 throw WSError{400,
"Bad Request: wrong protocol version"};
280 LOG(
debug) <<
"Got upgrade request with nonce " <<
mHeaders[
"sec-websocket-key"].c_str();
284 uv_buf_t bfr = uv_buf_init(strdup(reply.data()), reply.size());
285 auto* info_req = (uv_write_t*)malloc(
sizeof(uv_write_t));
303 mHandler = std::unique_ptr<WebSocketHandler>(statusHandler);
307 LOG(info) <<
"Connection not bound to a PID";
310 renderer->handler =
this;
312 renderer->drawTimer.data = renderer;
320 LOGP(warning,
"Connection not bound to a PID however {} is not set. Skipping.",
322 throw WSError{418,
"Remote GUI not enabled"};
336 LOG(error) <<
"uv_write error: " << uv_err_name(status);
349 LOG(error) <<
"uv_write error: " << uv_err_name(status);
353 auto*
buffers = (std::vector<uv_buf_t>*)
h->data;
365 uv_buf_t bfr = uv_buf_init(strdup(
message), s);
366 auto* write_req = (uv_write_t*)malloc(
sizeof(uv_write_t));
367 write_req->data = bfr.base;
373 if (outputs.empty()) {
376 auto* write_req = (uv_write_t*)malloc(
sizeof(uv_write_t));
377 auto*
buffers =
new std::vector<uv_buf_t>;
386 static constexpr auto errorFMT =
"HTTP/1.1 {} {}\r\ncontent-type: text/plain\r\n\r\n{}: {}\r\n";
388 char* reply = strdup(
error.data());
389 uv_buf_t bfr = uv_buf_init(reply,
error.size());
390 auto* error_rep = (uv_write_t*)malloc(
sizeof(uv_write_t));
391 error_rep->data = reply;
397 LOG(
debug) <<
"Closing websocket connection to server";
405 assert(context->client);
409 if (nread == UV_EOF) {
410 LOG(
debug) <<
"EOF received from server, closing.";
418 LOG(error) <<
"Error while reading from websocket";
424 LOG(
debug) <<
"Data received from server";
429 LOG(error) <<
"Error while parsing request: " << err.what;
435 : mNonce{
"dGhlIHNhbXBsZSBub25jZQ=="}
452 std::vector<std::pair<std::string, std::string>> headers = {
454 {{
"x-dpl-id"}, spec.
id},
455 {{
"x-dpl-name"}, spec.name}};
457 this->
write(handShakeString.c_str(), handShakeString.size());
462 if (s !=
"HTTP/1.1") {
482 LOG(info) << k <<
": " <<
v;
489 if (
mHeaders[
"upgrade"] !=
"websocket") {
493 if (
mHeaders[
"connection"].find(
"upgrade") == std::string::npos) {
496 if (
mHeaders.count(
"sec-websocket-accept") == 0) {
501 if (
mHeaders[
"sec-websocket-accept"] != expectedAccept) {
502 throw runtime_error_f(R
"(Invalid accept received: "%s", expected "%s")", mHeaders["sec-websocket-accept"].c_str(), expectedAccept.c_str());
505 LOG(info) <<
"Correctly handshaken websocket connection.";
525 LOG(error) <<
"uv_write error: " << uv_err_name(status);
531 if (context->buf.base) {
532 free(context->buf.base);
545 LOG(error) <<
"uv_write error: " << uv_err_name(status);
549 if (context->buffers.size()) {
550 for (
auto&
b : context->buffers) {
568 context->buf = uv_buf_init(strdup(
message), s);
569 auto* write_req = (uv_write_t*)malloc(
sizeof(uv_write_t));
570 write_req->data = context;
576 if (outputs.empty()) {
579 auto* write_req = (uv_write_t*)malloc(
sizeof(uv_write_t));
581 context->buffers.swap(outputs);
582 write_req->data = context;
583 uv_write(write_req, (uv_stream_t*)
mStream, &context->buffers.at(0),
struct uv_handle_s uv_handle_t
Class for time synchronization of RawReader instances.
GLboolean GLboolean GLboolean b
GLuint GLsizei const GLchar * message
GLenum GLuint GLenum GLsizei const GLchar * buf
Defining PrimaryVertex explicitly as messageable.
RuntimeErrorRef runtime_error(const char *)
void ws_handshake_done_callback(uv_write_t *h, int status)
void populateHeader(std::map< std::string, std::string > &headers, std::string_view const &k, std::string_view const &v)
void websocket_client_callback(uv_stream_t *stream, ssize_t nread, const uv_buf_t *buf)
void close_client_websocket(uv_handle_t *stream)
void encode_websocket_frames(std::vector< uv_buf_t > &outputs, char const *src, size_t size, WebSocketOpCode opcode, uint32_t mask)
void websocket_server_close_callback(uv_handle_t *handle)
Free any resource associated with the device - driver channel.
void ws_error_write_callback(uv_write_t *h, int status)
void parse_http_request(char *start, size_t size, HTTPParser *parser)
std::string encode_websocket_handshake_request(const char *endpoint, const char *protocol, int version, char const *nonce, std::vector< std::pair< std::string, std::string > > headers)
void ws_client_bulk_write_callback(uv_write_t *h, int status)
void decode_websocket(char *start, size_t size, WebSocketHandler &handler)
void ws_server_write_callback(uv_write_t *h, int status)
void remoteGuiCallback(uv_timer_s *ctx)
RuntimeError & error_from_ref(RuntimeErrorRef)
void ws_client_write_callback(uv_write_t *h, int status)
void ws_server_bulk_write_callback(uv_write_t *h, int status)
void websocket_server_callback(uv_stream_t *stream, ssize_t nread, const uv_buf_t *buf)
Actually replies to any incoming websocket stuff.
RuntimeErrorRef runtime_error_f(const char *,...)
std::string encode_websocket_handshake_reply(char const *nonce, const char *protocol)
std::string to_string(gsl::span< T, Size > span)
std::vector< uv_buf_t > buffers
virtual void charIn(char key)=0
virtual void updateMousePos(float x, float y)=0
virtual void keyEvent(char key, bool down)=0
virtual void updateMouseWheel(int direction)=0
virtual void updateMouseButton(bool isClicked)=0
virtual void updateWindowSize(int x, int y)=0
std::string id
The id of the device, including time-pipelining and suffix.
Running state information of a given device.
Context for the client callbacks.
std::vector< StatusWebSocketHandler * > statusHandlers
std::vector< DeviceInfo > * infos
std::vector< DeviceControl > * controls
An handler for a websocket message stream.
DriverServerContext & mContext
void endChunk() override
Invoked whenever we have no more input to process.
void frame(char const *frame, size_t s) override
void beginChunk() override
Invoked before processing the next round of input.
void control(char const *frame, size_t s) override
FIXME: not implemented.
void headers(std::map< std::string, std::string > const &headers) override
Invoked when all the headers are received.
void beginFragmentation() override
FIXME: not implemented.
~GUIWebSocketHandler() override
void endFragmentation() override
FIXME: not implemented.
GUIWebSocketHandler(DriverServerContext &context, GuiRenderer *renderer)
std::set< GuiRenderer * > renderers
static std::string calculateAccept(const char *nonce)
Helper to calculate the reply to a nonce.
std::unique_ptr< WebSocketHandler > mHandler
void endHeaders() override
void replyVersion(std::string_view const &s) override
std::function< void()> mHandshake
std::atomic< bool > mHandshaken
void connect(ServiceRegistryRef ref, uv_stream_t *stream, std::function< void()> handshake, std::unique_ptr< WebSocketHandler > handler)
std::unique_ptr< DriverClientContext > mContext
void body(char *data, size_t s) override
Actual handling of WS frames happens inside here.
void replyCode(std::string_view const &s) override
void dumpHeaders()
Dump headers.
void write(char const *, size_t)
Helper to write a message to the server.
void header(std::string_view const &k, std::string_view const &v) override
std::map< std::string, std::string > mHeaders
void method(std::string_view const &s) override
void body(char *data, size_t s) override
Actual handling of WS frames happens inside here.
void header(std::string_view const &k, std::string_view const &v) override
WSDPLHandler(uv_stream_t *stream, DriverServerContext *context)
void endHeaders() override
DriverServerContext * mServerContext
void target(std::string_view const &s) override
std::unique_ptr< WebSocketHandler > mHandler
void write(char const *, size_t)
Helper to write a message to the associated client.
std::map< std::string, std::string > mHeaders
An handler for a websocket message stream.
LOG(info)<< "Compressed in "<< sw.CpuTime()<< " s"