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