diff --git a/src/apps/remotedesktop/RemoteDesktop.cpp b/src/apps/remotedesktop/RemoteDesktop.cpp index da08c4092b..0ed18d8d5e 100644 --- a/src/apps/remotedesktop/RemoteDesktop.cpp +++ b/src/apps/remotedesktop/RemoteDesktop.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2009-2014, Haiku, Inc. + * Copyright 2009-2017, Haiku, Inc. * Distributed under the terms of the MIT License. * * Authors: @@ -25,16 +25,20 @@ void print_usage(const char *app) { - printf("usage:\t%s --listenOnly [-p ]\n", app); - printf("\t%s [-p ] [-s ] [-c ]\n", - app); + printf("usage:\t%s [-p ] [-w ] [-h ]\n", app); + printf("usage:\t%s -s [] [-p ] [-w ]" + " [-h ] [-c ]\n", app); printf("\t%s --help\n\n", app); printf("Connect to & run applications from a different computer\n\n"); printf("Arguments available for use:\n\n"); - printf("\t-p\t\tspecify the port to communicate on\n"); - printf("\t-c\t\tsend a command to the other computer\n"); - printf("\t-s\t\tuse ssh & specify the ssh port to communicate on\n"); + printf("\t-p\t\tspecify the port to communicate on (default 10900)\n"); + printf("\t-c\t\tsend a command to the other computer (default Terminal)\n"); + printf("\t-s\t\tuse SSH, optionally specify the SSH port to use (22)\n"); + printf("\t-w\t\tmake the virtual desktop use the specified width\n"); + printf("\t-h\t\tmake the virtual desktop use the specified height\n"); + printf("\nIf no width and height are specified, the window is opened with" + " the size of the the local screen.\n"); } @@ -46,14 +50,17 @@ main(int argc, char *argv[]) return 1; } - bool listenOnly = false; - uint32 listenPort = 10900; - uint32 sshPort = 22; - const char* command = NULL; + uint16 port = 10900; + uint16 sshPort = 22; + int32 width = -1; + int32 height = -1; + bool useSSH = false; + const char *command = NULL; + const char *host = argv[1]; for (int32 i = 2; i < argc; i++) { if (strcmp(argv[i], "-p") == 0) { - if (argc < i + 1 || sscanf(argv[i + 1], "%" B_PRIu32, &listenPort) + if (argc < i + 1 || sscanf(argv[i + 1], "%" B_SCNu16, &port) != 1) { print_usage(argv[0]); return 2; @@ -63,9 +70,9 @@ main(int argc, char *argv[]) continue; } - if (strcmp(argv[i], "-s") == 0) { - if (argc < i + 1 || sscanf(argv[i + 1], "%" B_PRIu32, &sshPort) - != 1) { + if (strcmp(argv[i], "-w") == 0) { + if (argc < i + 1 || sscanf(argv[i + 1], "%" B_SCNd32, &width) != 1) + { print_usage(argv[0]); return 2; } @@ -74,6 +81,27 @@ main(int argc, char *argv[]) continue; } + if (strcmp(argv[i], "-h") == 0) { + if (argc < i + 1 || sscanf(argv[i + 1], "%" B_SCNd32, &height) != 1) + { + print_usage(argv[0]); + return 2; + } + + i++; + continue; + } + + if (strcmp(argv[i], "-s") == 0) { + if (argc >= i + 1 + && sscanf(argv[i + 1], "%" B_SCNu16, &sshPort) == 1) { + i++; + } + + useSSH = true; + continue; + } + if (strcmp(argv[i], "-c") == 0) { if (argc < i + 1) { print_usage(argv[0]); @@ -85,17 +113,17 @@ main(int argc, char *argv[]) continue; } - if (strcmp(argv[i], "--listenOnly") == 0) { - listenOnly = true; - continue; - } + print_usage(argv[0]); + return 2; + } + if (command != NULL && !useSSH) { print_usage(argv[0]); return 2; } pid_t sshPID = -1; - if (!listenOnly) { + if (useSSH) { BPath terminalPath; if (command == NULL) { if (find_directory(B_SYSTEM_APPS_DIRECTORY, &terminalPath) @@ -112,8 +140,8 @@ main(int argc, char *argv[]) char shellCommand[4096]; snprintf(shellCommand, sizeof(shellCommand), - "echo connected; export TARGET_SCREEN=localhost:%" B_PRIu32 - "; %s\n", listenPort, command); + "echo connected; export TARGET_SCREEN=%" B_PRIu16 "; %s\n", port, + command); int pipes[4]; if (pipe(&pipes[0]) != 0 || pipe(&pipes[2]) != 0) { @@ -138,18 +166,14 @@ main(int argc, char *argv[]) close(pipes[i]); char localRedirect[50]; - sprintf(localRedirect, "localhost:%" B_PRIu32 ":localhost:%" - B_PRIu32, listenPort + 1, listenPort + 1); - - char remoteRedirect[50]; - sprintf(remoteRedirect, "localhost:%" B_PRIu32 ":localhost:%" - B_PRIu32, listenPort, listenPort); + sprintf(localRedirect, "localhost:%" B_PRIu16 ":localhost:%" + B_PRIu16, port, port); char portNumber[10]; - sprintf(portNumber, "%" B_PRIu32, sshPort); + sprintf(portNumber, "%" B_PRIu16, sshPort); int result = execl("ssh", "-C", "-L", localRedirect, - "-R", remoteRedirect, "-p", portNumber, argv[1], + "-p", portNumber, "-o", "ExitOnForwardFailure=yes", host, shellCommand, NULL); // we don't get here unless there was an error in executing @@ -162,12 +186,19 @@ main(int argc, char *argv[]) char buffer[10]; read(pipes[0], buffer, sizeof(buffer)); // block until connected/error message from ssh + + host = "localhost"; } } BApplication app("application/x-vnd.Haiku-RemoteDesktop"); - BScreen screen; - BWindow *window = new(std::nothrow) BWindow(screen.Frame(), "RemoteDesktop", + BRect windowFrame = BRect(0, 0, width - 1, height - 1); + if (!windowFrame.IsValid()) { + BScreen screen; + windowFrame = screen.Frame(); + } + + BWindow *window = new(std::nothrow) BWindow(windowFrame, "RemoteDesktop", B_TITLED_WINDOW, B_QUIT_ON_WINDOW_CLOSE); if (window == NULL) { @@ -175,8 +206,8 @@ main(int argc, char *argv[]) return 4; } - RemoteView *view = new(std::nothrow) RemoteView(window->Bounds(), - listenPort); + RemoteView *view = new(std::nothrow) RemoteView(window->Bounds(), host, + port); if (view == NULL) { printf("no memory to allocate remote view\n"); return 4; @@ -195,7 +226,7 @@ main(int argc, char *argv[]) app.Run(); if (sshPID >= 0) - kill(sshPID, SIGINT); + kill(sshPID, SIGHUP); return 0; } diff --git a/src/apps/remotedesktop/RemoteView.cpp b/src/apps/remotedesktop/RemoteView.cpp index 399300a721..793e31aac8 100644 --- a/src/apps/remotedesktop/RemoteView.cpp +++ b/src/apps/remotedesktop/RemoteView.cpp @@ -54,15 +54,14 @@ typedef struct engine_state { } engine_state; -RemoteView::RemoteView(BRect frame, uint16 listenPort) +RemoteView::RemoteView(BRect frame, const char *remoteHost, uint16 remotePort) : BView(frame, "RemoteView", B_FOLLOW_NONE, B_WILL_DRAW), fInitStatus(B_NO_INIT), fIsConnected(false), fReceiveBuffer(NULL), fSendBuffer(NULL), - fReceiveEndpoint(NULL), - fSendEndpoint(NULL), + fEndpoint(NULL), fReceiver(NULL), fSender(NULL), fStopThread(false), @@ -94,38 +93,34 @@ RemoteView::RemoteView(BRect frame, uint16 listenPort) if (fInitStatus != B_OK) return; - fReceiveEndpoint = new(std::nothrow) BNetEndpoint(); - if (fReceiveEndpoint == NULL) { + fEndpoint = new(std::nothrow) BNetEndpoint(); + if (fEndpoint == NULL) { fInitStatus = B_NO_MEMORY; TRACE_ERROR("no memory available\n"); return; } - fInitStatus = fReceiveEndpoint->Bind(listenPort); - if (fInitStatus != B_OK) - return; - - fReceiver = new(std::nothrow) NetReceiver(fReceiveEndpoint, fReceiveBuffer); - if (fReceiver == NULL) { - fInitStatus = B_NO_MEMORY; - TRACE_ERROR("no memory available\n"); + fInitStatus = fEndpoint->Connect(remoteHost, remotePort); + if (fInitStatus != B_OK) { + TRACE_ERROR("failed to connect to %s:%" B_PRIu16 "\n", + remoteHost, remotePort); return; } - fSendEndpoint = new(std::nothrow) BNetEndpoint(); - if (fSendEndpoint == NULL) { - fInitStatus = B_NO_MEMORY; - TRACE_ERROR("no memory available\n"); - return; - } - - fSender = new(std::nothrow) NetSender(fSendEndpoint, fSendBuffer); + fSender = new(std::nothrow) NetSender(fEndpoint, fSendBuffer); if (fSender == NULL) { fInitStatus = B_NO_MEMORY; TRACE_ERROR("no memory available\n"); return; } + fReceiver = new(std::nothrow) NetReceiver(fEndpoint, fReceiveBuffer); + if (fReceiver == NULL) { + fInitStatus = B_NO_MEMORY; + TRACE_ERROR("no memory available\n"); + return; + } + BRect bounds = frame.OffsetToCopy(0, 0); fOffscreenBitmap = new(std::nothrow) BBitmap(bounds, B_BITMAP_ACCEPTS_VIEWS, B_RGB32); @@ -171,8 +166,7 @@ RemoteView::~RemoteView() delete fSendBuffer; delete fSender; - delete fReceiveEndpoint; - delete fSendEndpoint; + delete fEndpoint; delete fOffscreenBitmap; delete fCursorBitmap; @@ -447,6 +441,9 @@ RemoteView::_DrawThread() // cursor BPoint cursorHotSpot(0, 0); + reply.Start(RP_INIT_CONNECTION); + reply.Flush(); + while (!fStopThread) { uint16 code; status_t status = message.NextMessage(code); @@ -470,34 +467,6 @@ RemoteView::_DrawThread() switch (code) { case RP_INIT_CONNECTION: { - uint16 port; - status_t result = message.Read(port); - if (result != B_OK) { - TRACE_ERROR("failed to read remote port\n"); - continue; - } - - BNetEndpoint *endpoint = fReceiver->Endpoint(); - if (endpoint == NULL) { - TRACE_ERROR("receiver not connected anymore\n"); - continue; - } - - in_addr remoteHost; - char hostName[MAXHOSTNAMELEN + 1]; - BNetAddress address(endpoint->RemoteAddr()); - address.GetAddr(remoteHost); - address.GetAddr(hostName, NULL); - address.SetTo(remoteHost, port); - - TRACE("connecting to host \"%s\" port %u\n", hostName, port); - result = fSendEndpoint->Connect(address); - if (result != B_OK) { - TRACE_ERROR("failed to connect to host \"%s\" port %u\n", - hostName, port); - continue; - } - BRect bounds = fOffscreenBitmap->Bounds(); reply.Start(RP_UPDATE_DISPLAY_MODE); reply.Add(bounds.IntegerWidth() + 1); diff --git a/src/apps/remotedesktop/RemoteView.h b/src/apps/remotedesktop/RemoteView.h index 8ce29b149d..50a32534c0 100644 --- a/src/apps/remotedesktop/RemoteView.h +++ b/src/apps/remotedesktop/RemoteView.h @@ -22,7 +22,9 @@ struct engine_state; class RemoteView : public BView { public: - RemoteView(BRect frame, uint16 listenPort); + RemoteView(BRect frame, + const char *remoteHost, + uint16 remotePort); virtual ~RemoteView(); status_t InitCheck(); @@ -64,8 +66,7 @@ static int32 _DrawEntry(void *data); StreamingRingBuffer * fReceiveBuffer; StreamingRingBuffer * fSendBuffer; - BNetEndpoint * fReceiveEndpoint; - BNetEndpoint * fSendEndpoint; + BNetEndpoint * fEndpoint; NetReceiver * fReceiver; NetSender * fSender; diff --git a/src/servers/app/ServerTokenSpace.h b/src/servers/app/ServerTokenSpace.h index 46ef4d51a0..df070aa99a 100644 --- a/src/servers/app/ServerTokenSpace.h +++ b/src/servers/app/ServerTokenSpace.h @@ -17,6 +17,7 @@ using BPrivate::BTokenSpace; const int32 kCursorToken = 3; const int32 kBitmapToken = 4; const int32 kPictureToken = 5; +const int32 kRemoteDrawingEngineToken = 6; extern BTokenSpace gTokenSpace; diff --git a/src/servers/app/drawing/interface/remote/NetReceiver.cpp b/src/servers/app/drawing/interface/remote/NetReceiver.cpp index 2b5064d5d8..54ce480145 100644 --- a/src/servers/app/drawing/interface/remote/NetReceiver.cpp +++ b/src/servers/app/drawing/interface/remote/NetReceiver.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2009, Haiku, Inc. + * Copyright 2009, 2017, Haiku, Inc. * Distributed under the terms of the MIT License. * * Authors: @@ -21,13 +21,16 @@ #define TRACE_ERROR(x...) debug_printf("NetReceiver: " x) -NetReceiver::NetReceiver(BNetEndpoint *listener, StreamingRingBuffer *target) +NetReceiver::NetReceiver(BNetEndpoint *listener, StreamingRingBuffer *target, + NewConnectionCallback newConnectionCallback, void *newConnectionCookie) : fListener(listener), fTarget(target), fReceiverThread(-1), fStopThread(false), - fEndpoint(NULL) + fNewConnectionCallback(newConnectionCallback), + fNewConnectionCookie(newConnectionCookie), + fEndpoint(newConnectionCallback == NULL ? listener : NULL) { fReceiverThread = spawn_thread(_NetworkReceiverEntry, "network receiver", B_NORMAL_PRIORITY, this); @@ -38,79 +41,94 @@ NetReceiver::NetReceiver(BNetEndpoint *listener, StreamingRingBuffer *target) NetReceiver::~NetReceiver() { fStopThread = true; + delete fEndpoint; - if (fEndpoint != NULL) - fEndpoint->Close(); - - //int32 result; - //wait_for_thread(fReceiverThread, &result); - // TODO: find out why closing the endpoint doesn't notify the waiter - - kill_thread(fReceiverThread); + suspend_thread(fReceiverThread); + resume_thread(fReceiverThread); } int32 NetReceiver::_NetworkReceiverEntry(void *data) { - return ((NetReceiver *)data)->_NetworkReceiver(); + NetReceiver *receiver = (NetReceiver *)data; + if (receiver->fNewConnectionCallback) + return receiver->_Listen(); + else + return receiver->_Transfer(); } status_t -NetReceiver::_NetworkReceiver() +NetReceiver::_Listen() { - static const uint16_t shutdown_message[] = { RP_CLOSE_CONNECTION, 0, 0 }; - status_t result = fListener->Listen(); if (result != B_OK) { TRACE_ERROR("failed to listen on port: %s\n", strerror(result)); - fTarget->Write(shutdown_message, sizeof(shutdown_message)); return result; } while (!fStopThread) { - fEndpoint = fListener->Accept(5000); - if (fEndpoint == NULL) { - fTarget->Write(shutdown_message, sizeof(shutdown_message)); - return B_ERROR; + if (fEndpoint != NULL) { + TRACE("closing previous connection\n"); + delete fEndpoint; + fEndpoint = NULL; + } + + fEndpoint = fListener->Accept(5000); + if (fEndpoint == NULL) { + TRACE("got NULL endpoint from accept\n"); + continue; } - int32 errorCount = 0; TRACE("new endpoint connection: %p\n", fEndpoint); - while (!fStopThread) { - uint8 buffer[4096]; - int32 readSize = fEndpoint->Receive(buffer, sizeof(buffer)); - if (readSize < 0) { - TRACE_ERROR("read failed, closing connection: %s\n", - strerror(readSize)); - BNetEndpoint *endpoint = fEndpoint; - fEndpoint = NULL; - delete endpoint; - fTarget->Write(shutdown_message, sizeof(shutdown_message)); - return readSize; + + if (fNewConnectionCallback != NULL + && fNewConnectionCallback(fNewConnectionCookie, *fEndpoint) != B_OK) + { + TRACE("connection callback rejected connection\n"); + continue; + } + + _Transfer(); + } + + return B_OK; +} + + +status_t +NetReceiver::_Transfer() +{ + int32 errorCount = 0; + + while (!fStopThread) { + uint8 buffer[4096]; + int32 readSize = fEndpoint->Receive(buffer, sizeof(buffer)); + if (readSize < 0) { + TRACE_ERROR("read failed, closing connection: %s\n", + strerror(readSize)); + return readSize; + } + + if (readSize == 0) { + TRACE("read 0 bytes, retrying\n"); + snooze(100 * 1000); + errorCount++; + if (errorCount == 5) { + TRACE_ERROR("failed to read, assuming disconnect\n"); + return B_ERROR; } - if (readSize == 0) { - TRACE("read 0 bytes, retrying\n"); - snooze(100 * 1000); - errorCount++; - if (errorCount == 5) { - TRACE_ERROR("failed to read, assuming disconnect\n"); - break; - } + continue; + } - continue; - } - - errorCount = 0; - status_t result = fTarget->Write(buffer, readSize); - if (result != B_OK) { - TRACE_ERROR("writing to ring buffer failed: %s\n", - strerror(result)); - fTarget->Write(shutdown_message, sizeof(shutdown_message)); - return result; - } + errorCount = 0; + status_t result = fTarget->Write(buffer, readSize); + if (result != B_OK) { + TRACE_ERROR("writing to ring buffer failed: %s\n", + strerror(result)); + return result; } } diff --git a/src/servers/app/drawing/interface/remote/NetReceiver.h b/src/servers/app/drawing/interface/remote/NetReceiver.h index 21799a0791..5482bb88cb 100644 --- a/src/servers/app/drawing/interface/remote/NetReceiver.h +++ b/src/servers/app/drawing/interface/remote/NetReceiver.h @@ -14,17 +14,23 @@ class BNetEndpoint; class StreamingRingBuffer; +typedef status_t (*NewConnectionCallback)(void *cookie, BNetEndpoint &endpoint); + + class NetReceiver { public: - NetReceiver(BNetEndpoint *listener, - StreamingRingBuffer *target); + NetReceiver(BNetEndpoint *endpoint, + StreamingRingBuffer *target, + NewConnectionCallback callback = NULL, + void *newConnectionCookie = NULL); ~NetReceiver(); BNetEndpoint * Endpoint() { return fEndpoint; } private: static int32 _NetworkReceiverEntry(void *data); - status_t _NetworkReceiver(); + status_t _Listen(); + status_t _Transfer(); BNetEndpoint * fListener; StreamingRingBuffer * fTarget; @@ -32,6 +38,9 @@ static int32 _NetworkReceiverEntry(void *data); thread_id fReceiverThread; bool fStopThread; + NewConnectionCallback fNewConnectionCallback; + void * fNewConnectionCookie; + BNetEndpoint * fEndpoint; }; diff --git a/src/servers/app/drawing/interface/remote/NetSender.cpp b/src/servers/app/drawing/interface/remote/NetSender.cpp index 4e2dbb3ac6..54602e2d74 100644 --- a/src/servers/app/drawing/interface/remote/NetSender.cpp +++ b/src/servers/app/drawing/interface/remote/NetSender.cpp @@ -36,8 +36,9 @@ NetSender::NetSender(BNetEndpoint *endpoint, StreamingRingBuffer *source) NetSender::~NetSender() { fStopThread = true; - int32 result; - wait_for_thread(fSenderThread, &result); + + suspend_thread(fSenderThread); + resume_thread(fSenderThread); } diff --git a/src/servers/app/drawing/interface/remote/RemoteDrawingEngine.cpp b/src/servers/app/drawing/interface/remote/RemoteDrawingEngine.cpp index a089179265..b20b76cf36 100644 --- a/src/servers/app/drawing/interface/remote/RemoteDrawingEngine.cpp +++ b/src/servers/app/drawing/interface/remote/RemoteDrawingEngine.cpp @@ -11,6 +11,7 @@ #include "BitmapDrawingEngine.h" #include "DrawState.h" +#include "ServerTokenSpace.h" #include #include @@ -18,11 +19,16 @@ #include +#define TRACE(x...) /*debug_printf("RemoteDrawingEngine: " x)*/ +#define TRACE_ALWAYS(x...) debug_printf("RemoteDrawingEngine: " x) +#define TRACE_ERROR(x...) debug_printf("RemoteDrawingEngine: " x) + + RemoteDrawingEngine::RemoteDrawingEngine(RemoteHWInterface* interface) : DrawingEngine(interface), fHWInterface(interface), - fToken((addr_t)this), + fToken(gTokenSpace.NewToken(kRemoteDrawingEngineToken, this)), fExtendWidth(0), fCallbackAdded(false), fResultNotify(-1), diff --git a/src/servers/app/drawing/interface/remote/RemoteDrawingEngine.h b/src/servers/app/drawing/interface/remote/RemoteDrawingEngine.h index ac7cd76f24..b03a0a0e6c 100644 --- a/src/servers/app/drawing/interface/remote/RemoteDrawingEngine.h +++ b/src/servers/app/drawing/interface/remote/RemoteDrawingEngine.h @@ -161,7 +161,7 @@ private: UtilityBitmap**& bitmaps); RemoteHWInterface* fHWInterface; - addr_t fToken; + int32 fToken; DrawState fState; BRegion fClippingRegion; diff --git a/src/servers/app/drawing/interface/remote/RemoteHWInterface.cpp b/src/servers/app/drawing/interface/remote/RemoteHWInterface.cpp index 33b72b17e6..6a46793998 100644 --- a/src/servers/app/drawing/interface/remote/RemoteHWInterface.cpp +++ b/src/servers/app/drawing/interface/remote/RemoteHWInterface.cpp @@ -38,14 +38,11 @@ RemoteHWInterface::RemoteHWInterface(const char* target) : HWInterface(), fTarget(target), - fRemoteHost(NULL), - fRemotePort(10900), fIsConnected(false), fProtocolVersion(100), fConnectionSpeed(0), fListenPort(10901), - fSendEndpoint(NULL), - fReceiveEndpoint(NULL), + fListenEndpoint(NULL), fSendBuffer(NULL), fReceiveBuffer(NULL), fSender(NULL), @@ -58,32 +55,20 @@ RemoteHWInterface::RemoteHWInterface(const char* target) fDisplayMode.virtual_height = 480; fDisplayMode.space = B_RGB32; - fRemoteHost = strdup(fTarget); - char *portStart = strchr(fRemoteHost, ':'); - if (portStart != NULL) { - portStart[0] = 0; - portStart++; - if (sscanf(portStart, "%" B_PRIu32, &fRemotePort) != 1) { - fInitStatus = B_BAD_VALUE; - return; - } - fListenPort = fRemotePort + 1; + + if (sscanf(fTarget, "%" B_SCNu16, &fListenPort) != 1) { + fInitStatus = B_BAD_VALUE; + return; } - fSendEndpoint = new(std::nothrow) BNetEndpoint(); - if (fSendEndpoint == NULL) { + fListenEndpoint = new(std::nothrow) BNetEndpoint(); + if (fListenEndpoint == NULL) { fInitStatus = B_NO_MEMORY; return; } - fReceiveEndpoint = new(std::nothrow) BNetEndpoint(); - if (fReceiveEndpoint == NULL) { - fInitStatus = B_NO_MEMORY; - return; - } - - fInitStatus = fReceiveEndpoint->Bind(fListenPort); + fInitStatus = fListenEndpoint->Bind(fListenPort); if (fInitStatus != B_OK) return; @@ -107,13 +92,8 @@ RemoteHWInterface::RemoteHWInterface(const char* target) if (fInitStatus != B_OK) return; - fSender = new(std::nothrow) NetSender(fSendEndpoint, fSendBuffer); - if (fSender == NULL) { - fInitStatus = B_NO_MEMORY; - return; - } - - fReceiver = new(std::nothrow) NetReceiver(fReceiveEndpoint, fReceiveBuffer); + fReceiver = new(std::nothrow) NetReceiver(fListenEndpoint, fReceiveBuffer, + _NewConnectionCallback, this); if (fReceiver == NULL) { fInitStatus = B_NO_MEMORY; return; @@ -125,11 +105,6 @@ RemoteHWInterface::RemoteHWInterface(const char* target) return; } - fSendEndpoint->SetTimeout(3 * 1000 * 1000); - fInitStatus = _Connect(); - if (fInitStatus != B_OK) - return; - fEventThread = spawn_thread(_EventThreadEntry, "remote event thread", B_NORMAL_PRIORITY, this); if (fEventThread < 0) { @@ -149,12 +124,9 @@ RemoteHWInterface::~RemoteHWInterface() delete fSendBuffer; delete fSender; - delete fReceiveEndpoint; - delete fSendEndpoint; + delete fListenEndpoint; delete fEventStream; - - free(fRemoteHost); } @@ -273,10 +245,28 @@ RemoteHWInterface::_EventThread() } switch (code) { + case RP_INIT_CONNECTION: + { + RemoteMessage reply(NULL, fSendBuffer); + reply.Start(RP_INIT_CONNECTION); + status_t result = reply.Flush(); + TRACE("init connection result: %s\n", strerror(result)); + break; + } + case RP_UPDATE_DISPLAY_MODE: { - // TODO: implement, we only handle it in the context of the - // initial mode setup on connect + int32 width, height; + message.Read(width); + result = message.Read(height); + if (result != B_OK) { + TRACE_ERROR("failed to read display mode\n"); + break; + } + + fIsConnected = true; + fDisplayMode.virtual_width = width; + fDisplayMode.virtual_height = height; break; } @@ -298,49 +288,32 @@ RemoteHWInterface::_EventThread() status_t -RemoteHWInterface::_Connect() +RemoteHWInterface::_NewConnectionCallback(void *cookie, BNetEndpoint &endpoint) { - TRACE("connecting to host \"%s\" port %" B_PRIu32 "\n", fRemoteHost, fRemotePort); - status_t result = fSendEndpoint->Connect(fRemoteHost, (uint16)fRemotePort); - if (result != B_OK) { - TRACE_ERROR("failed to connect to host \"%s\" port %" B_PRIu32 "\n", - fRemoteHost, fRemotePort); - return result; + return ((RemoteHWInterface *)cookie)->_NewConnection(endpoint); +} + + +status_t +RemoteHWInterface::_NewConnection(BNetEndpoint &endpoint) +{ + if (fSender != NULL) { + delete fSender; + fSender = NULL; } - RemoteMessage message(fReceiveBuffer, fSendBuffer); - message.Start(RP_INIT_CONNECTION); - message.Add(fListenPort); - result = message.Flush(); - if (result != B_OK) { - TRACE_ERROR("failed to send init connection message\n"); - return result; + fSendBuffer->MakeEmpty(); + + BNetEndpoint *sendEndpoint = new(std::nothrow) BNetEndpoint(endpoint); + if (sendEndpoint == NULL) + return B_NO_MEMORY; + + fSender = new(std::nothrow) NetSender(sendEndpoint, fSendBuffer); + if (fSender == NULL) { + delete sendEndpoint; + return B_NO_MEMORY; } - uint16 code; - result = message.NextMessage(code); - if (result != B_OK) { - TRACE_ERROR("failed to read message from receiver: %s\n", - strerror(result)); - return result; - } - - TRACE("code %u with %lu bytes of data\n", code, message.DataLeft()); - if (code != RP_UPDATE_DISPLAY_MODE) { - TRACE_ERROR("invalid connection init code %u\n", code); - return B_ERROR; - } - - int32 width, height; - message.Read(width); - result = message.Read(height); - if (result != B_OK) { - TRACE_ERROR("failed to get initial display mode\n"); - return result; - } - - fDisplayMode.virtual_width = width; - fDisplayMode.virtual_height = height; return B_OK; } @@ -355,10 +328,8 @@ RemoteHWInterface::_Disconnect() fIsConnected = false; } - if (fSendEndpoint != NULL) - fSendEndpoint->Close(); - if (fReceiveEndpoint != NULL) - fReceiveEndpoint->Close(); + if (fListenEndpoint != NULL) + fListenEndpoint->Close(); } diff --git a/src/servers/app/drawing/interface/remote/RemoteHWInterface.h b/src/servers/app/drawing/interface/remote/RemoteHWInterface.h index 50661e0ab5..ae70ae2ec8 100644 --- a/src/servers/app/drawing/interface/remote/RemoteHWInterface.h +++ b/src/servers/app/drawing/interface/remote/RemoteHWInterface.h @@ -97,13 +97,14 @@ static int _CallbackCompare(const uint32* key, static int32 _EventThreadEntry(void* data); status_t _EventThread(); - status_t _Connect(); +static status_t _NewConnectionCallback(void *cookie, + BNetEndpoint &endpoint); + status_t _NewConnection(BNetEndpoint &endpoint); + void _Disconnect(); - const char* fTarget; - char* fRemoteHost; - uint32 fRemotePort; + const char* fTarget; status_t fInitStatus; bool fIsConnected; uint32 fProtocolVersion; @@ -111,9 +112,7 @@ static int32 _EventThreadEntry(void* data); display_mode fDisplayMode; uint16 fListenPort; - BNetEndpoint* fSendEndpoint; - BNetEndpoint* fReceiveEndpoint; - + BNetEndpoint* fListenEndpoint; StreamingRingBuffer* fSendBuffer; StreamingRingBuffer* fReceiveBuffer; diff --git a/src/servers/app/drawing/interface/remote/StreamingRingBuffer.cpp b/src/servers/app/drawing/interface/remote/StreamingRingBuffer.cpp index 601bc2293e..e2aa0e47a1 100644 --- a/src/servers/app/drawing/interface/remote/StreamingRingBuffer.cpp +++ b/src/servers/app/drawing/interface/remote/StreamingRingBuffer.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2009, Haiku, Inc. + * Copyright 2009, 2017, Haiku, Inc. * Distributed under the terms of the MIT License. * * Authors: @@ -14,14 +14,23 @@ #include #include -#define TRACE(x...) /*debug_printf("StreamingRingBuffer: "x)*/ -#define TRACE_ERROR(x...) debug_printf("StreamingRingBuffer: "x) + +#ifdef CLIENT_COMPILE +#define TRACE_ALWAYS(x...) printf("StreamingRingBuffer: " x) +#else +#define TRACE_ALWAYS(x...) debug_printf("StreamingRingBuffer: " x) +#endif + +#define TRACE(x...) /*TRACE_ALWAYS(x)*/ +#define TRACE_ERROR(x...) TRACE_ALWAYS(x) StreamingRingBuffer::StreamingRingBuffer(size_t bufferSize) : fReaderWaiting(false), fWriterWaiting(false), + fCancelRead(false), + fCancelWrite(false), fReaderNotifier(-1), fWriterNotifier(-1), fReaderLocker("StreamingRingBuffer reader"), @@ -91,14 +100,23 @@ StreamingRingBuffer::Read(void *buffer, size_t length, bool onlyBlockOnNoData) do { TRACE("waiting in reader\n"); result = acquire_sem(fReaderNotifier); - TRACE("done waiting in reader with status: 0x%08lx\n", result); + TRACE("done waiting in reader with status: %#" B_PRIx32 "\n", + result); } while (result == B_INTERRUPTED); if (result != B_OK) return result; - if (!dataLock.Lock()) + if (!dataLock.Lock()) { + TRACE_ERROR("failed to acquire data lock\n"); return B_ERROR; + } + + if (fCancelRead) { + TRACE("read canceled\n"); + fCancelRead = false; + return B_CANCELED; + } continue; } @@ -147,14 +165,23 @@ StreamingRingBuffer::Write(const void *buffer, size_t length) do { TRACE("waiting in writer\n"); result = acquire_sem(fWriterNotifier); - TRACE("done waiting in writer with status: 0x%08lx\n", result); + TRACE("done waiting in writer with status: %#" B_PRIx32 "\n", + result); } while (result == B_INTERRUPTED); if (result != B_OK) return result; - if (!dataLock.Lock()) + if (!dataLock.Lock()) { + TRACE_ERROR("failed to acquire data lock\n"); return B_ERROR; + } + + if (fCancelWrite) { + TRACE("write canceled\n"); + fCancelWrite = false; + return B_CANCELED; + } continue; } @@ -174,3 +201,27 @@ StreamingRingBuffer::Write(const void *buffer, size_t length) return B_OK; } + + +void +StreamingRingBuffer::MakeEmpty() +{ + BAutolock dataLock(fDataLocker); + if (!dataLock.IsLocked()) + return; + + fReadPosition = fWritePosition = 0; + fReadable = 0; + + if (fWriterWaiting) { + release_sem_etc(fWriterNotifier, 1, 0); + fWriterWaiting = false; + fCancelWrite = true; + } + + if (fReaderWaiting) { + release_sem_etc(fReaderNotifier, 1, 0); + fReaderWaiting = false; + fCancelRead = true; + } +} diff --git a/src/servers/app/drawing/interface/remote/StreamingRingBuffer.h b/src/servers/app/drawing/interface/remote/StreamingRingBuffer.h index a38744b085..a84f879301 100644 --- a/src/servers/app/drawing/interface/remote/StreamingRingBuffer.h +++ b/src/servers/app/drawing/interface/remote/StreamingRingBuffer.h @@ -24,12 +24,13 @@ public: bool onlyBlockOnNoData = false); status_t Write(const void *buffer, size_t length); -private: - bool _Lock(); - void _Unlock(); + void MakeEmpty(); +private: bool fReaderWaiting; bool fWriterWaiting; + bool fCancelRead; + bool fCancelWrite; sem_id fReaderNotifier; sem_id fWriterNotifier;