RemoteDesktop: Switch connection direction and simplify client.

Instead of the server connecting back to a listening client, make it
into a more traditional setup with the server listening on a port and
the client connecting to it.

The client can now either connect directly, unencrypted and without the
ability to trigger listening and specifying a command, or through SSH,
as before with the possibilty to run a target application and causing
the creation of the listener.

With the direction change, there's only the need for one, local, port
forward with SSH, which simplifies things.
This commit is contained in:
Michael Lotz 2017-11-21 20:44:56 +01:00
parent b140a1c340
commit 5ed41cffff
13 changed files with 305 additions and 247 deletions

View File

@ -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 <listenPort>]\n", app);
printf("\t%s <user@host> [-p <listenPort>] [-s <sshPort>] [-c <command>]\n",
app);
printf("usage:\t%s <host> [-p <port>] [-w <width>] [-h <height>]\n", app);
printf("usage:\t%s <user@host> -s [<sshPort>] [-p <port>] [-w <width>]"
" [-h <height>] [-c <command>]\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;
}

View File

@ -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);

View File

@ -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;

View File

@ -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;

View File

@ -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;
}
}

View File

@ -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;
};

View File

@ -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);
}

View File

@ -11,6 +11,7 @@
#include "BitmapDrawingEngine.h"
#include "DrawState.h"
#include "ServerTokenSpace.h"
#include <Bitmap.h>
#include <utf8_functions.h>
@ -18,11 +19,16 @@
#include <new>
#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),

View File

@ -161,7 +161,7 @@ private:
UtilityBitmap**& bitmaps);
RemoteHWInterface* fHWInterface;
addr_t fToken;
int32 fToken;
DrawState fState;
BRegion fClippingRegion;

View File

@ -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();
}

View File

@ -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;

View File

@ -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 <stdlib.h>
#include <string.h>
#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;
}
}

View File

@ -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;