33static void my_alloc_cb(
uv_handle_t* handle,
size_t suggested_size, uv_buf_t*
buf)
35 buf->base = (
char*)malloc(suggested_size);
36 buf->len = suggested_size;
49 LOG(error) <<
"Error in write callback: " << uv_strerror(status);
65 if (nread == UV_EOF) {
66 LOG(detail) <<
"websocket_server_callback: communication with driver closed upon EOF";
71 LOG(error) <<
"websocket_server_callback: Error while reading from websocket" << uv_strerror((
int)nread);
80 LOG(error) <<
"Error while parsing request: " << err.what;
89 LOG(error) <<
"uv_write error: " << uv_err_name(status);
128 float* positions = (
float*)
frame;
133 char isClicked = *
frame;
138 int movement = *
frame;
148 int lat = *((
int*)
frame);
149 lat = lat < 20 ? 20 : lat;
183 mServerContext{context}
190 throw WSError{400,
"Bad Request"};
201void populateHeader(std::map<std::string, std::string>& headers, std::string_view
const& k, std::string_view
const&
v)
205 std::transform(kk.begin(), kk.end(), kk.begin(),
206 [](
unsigned char c) { return std::tolower(c); });
207 if (kk !=
"sec-websocket-accept" && kk !=
"sec-websocket-key") {
208 std::transform(vv.begin(), vv.end(), vv.begin(),
209 [](
unsigned char c) { return std::tolower(c); });
211 headers.insert(std::make_pair(kk, vv));
216 auto* renderer =
reinterpret_cast<GuiRenderer*
>(ctx->data);
219 void* frame =
nullptr;
220 void* draw_data =
nullptr;
222 uint64_t frameStart = uv_hrtime();
223 uint64_t frameLatency = frameStart - renderer->gui->frameLast;
226 if (renderer->gui->lastFrame ==
nullptr || frameLatency / 1000000 > 15) {
227 renderer->gui->plugin->pollGUIPreRender(renderer->gui->window, (
float)frameLatency / 1000000000.0f);
228 draw_data = renderer->gui->plugin->pollGUIRender(renderer->gui->callback);
229 renderer->gui->plugin->pollGUIPostRender(renderer->gui->window, draw_data);
231 draw_data = renderer->gui->lastFrame;
234 renderer->gui->plugin->getFrameRaw(draw_data, &frame, &
size, renderer->updateTextures);
236 renderer->updateTextures =
false;
237 std::vector<uv_buf_t> outputs;
239 renderer->handler->write(outputs);
242 renderer->guiConnected =
true;
244 if (frameLatency / 1000000 > 15) {
245 uint64_t frameEnd = uv_hrtime();
246 *(renderer->gui->frameCost) = (frameEnd - frameStart) / 1000000.f;
247 *(renderer->gui->frameLatency) = frameLatency / 1000000.f;
248 renderer->gui->frameLast = frameStart;
249 renderer->gui->lastFrame = draw_data;
261 if (
mHeaders[
"upgrade"] !=
"websocket") {
262 throw WSError{400,
"Bad Request: not a websocket upgrade"};
265 if (
mHeaders[
"connection"].find(
"upgrade") == std::string::npos) {
266 throw WSError{400,
"Bad Request: connection not for upgrade"};
268 if (
mHeaders[
"sec-websocket-protocol"] !=
"dpl") {
269 throw WSError{400,
"Bad Request: websocket protocol not \"dpl\"."};
271 if (
mHeaders.count(
"sec-websocket-key") == 0) {
272 throw WSError{400,
"Bad Request: sec-websocket-key missing"};
274 if (
mHeaders[
"sec-websocket-version"] !=
"13") {
275 throw WSError{400,
"Bad Request: wrong protocol version"};
278 LOG(
debug) <<
"Got upgrade request with nonce " <<
mHeaders[
"sec-websocket-key"].c_str();
282 uv_buf_t bfr = uv_buf_init(strdup(reply.data()), reply.size());
283 auto* info_req = (uv_write_t*)malloc(
sizeof(uv_write_t));
299 LOG(info) <<
"Connection not bound to a PID";
302 renderer->handler =
this;
304 renderer->drawTimer.data = renderer;
312 LOGP(warning,
"Connection not bound to a PID however {} is not set. Skipping.",
314 throw WSError{418,
"Remote GUI not enabled"};
328 LOG(error) <<
"uv_write error: " << uv_err_name(status);
341 LOG(error) <<
"uv_write error: " << uv_err_name(status);
345 auto*
buffers = (std::vector<uv_buf_t>*)
h->data;
357 uv_buf_t bfr = uv_buf_init(strdup(
message), s);
358 auto* write_req = (uv_write_t*)malloc(
sizeof(uv_write_t));
359 write_req->data = bfr.base;
365 if (outputs.empty()) {
368 auto* write_req = (uv_write_t*)malloc(
sizeof(uv_write_t));
369 auto*
buffers =
new std::vector<uv_buf_t>;
378 static constexpr auto errorFMT =
"HTTP/1.1 {} {}\r\ncontent-type: text/plain\r\n\r\n{}: {}\r\n";
380 char* reply = strdup(
error.data());
381 uv_buf_t bfr = uv_buf_init(reply,
error.size());
382 auto* error_rep = (uv_write_t*)malloc(
sizeof(uv_write_t));
383 error_rep->data = reply;
389 LOG(
debug) <<
"Closing websocket connection to server";
397 assert(context->client);
401 if (nread == UV_EOF) {
402 LOG(
debug) <<
"EOF received from server, closing.";
410 LOG(error) <<
"Error while reading from websocket";
416 LOG(
debug) <<
"Data received from server";
421 LOG(error) <<
"Error while parsing request: " << err.what;
427 : mNonce{
"dGhlIHNhbXBsZSBub25jZQ=="}
444 std::vector<std::pair<std::string, std::string>> headers = {
446 {{
"x-dpl-id"}, spec.
id},
447 {{
"x-dpl-name"}, spec.name}};
449 this->
write(handShakeString.c_str(), handShakeString.size());
454 if (s !=
"HTTP/1.1") {
474 LOG(info) << k <<
": " <<
v;
481 if (
mHeaders[
"upgrade"] !=
"websocket") {
485 if (
mHeaders[
"connection"].find(
"upgrade") == std::string::npos) {
488 if (
mHeaders.count(
"sec-websocket-accept") == 0) {
493 if (
mHeaders[
"sec-websocket-accept"] != expectedAccept) {
494 throw runtime_error_f(R
"(Invalid accept received: "%s", expected "%s")", mHeaders["sec-websocket-accept"].c_str(), expectedAccept.c_str());
497 LOG(info) <<
"Correctly handshaken websocket connection.";
517 LOG(error) <<
"uv_write error: " << uv_err_name(status);
523 if (context->buf.base) {
524 free(context->buf.base);
537 LOG(error) <<
"uv_write error: " << uv_err_name(status);
541 if (context->buffers.size()) {
542 for (
auto&
b : context->buffers) {
560 context->buf = uv_buf_init(strdup(
message), s);
561 auto* write_req = (uv_write_t*)malloc(
sizeof(uv_write_t));
562 write_req->data = context;
568 if (outputs.empty()) {
571 auto* write_req = (uv_write_t*)malloc(
sizeof(uv_write_t));
573 context->buffers.swap(outputs);
574 write_req->data = context;
575 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.
std::string encode_websocket_handshake_reply(char const *nonce)
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 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< 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"