Adding RemoteDesktop client. It wraps a port forwarding ssh call to provide

security and compression for the session. This allows to keep these layers
separate from the actual protocol. This needs to be run from the command line,
as it will request ssh auth there. After connecting it will export the needed
env variable and run the specified shell (Terminal by default) on the remote
host to make it connect to the local client app.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@33418 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Michael Lotz 2009-10-04 14:21:01 +00:00
parent 68667bf48a
commit b3901807e8
6 changed files with 1552 additions and 0 deletions

View File

@ -42,6 +42,7 @@ HaikuSubInclude poorman ;
HaikuSubInclude powerstatus ;
HaikuSubInclude processcontroller ;
HaikuSubInclude pulse ;
HaikuSubInclude remotedesktop ;
HaikuSubInclude resedit ;
HaikuSubInclude screenshot ;
HaikuSubInclude showimage ;

View File

@ -0,0 +1,25 @@
SubDir HAIKU_TOP src apps remotedesktop ;
local defines = [ FDefines CLIENT_COMPILE ] ;
local serverDir = [ FDirName $(HAIKU_TOP) src servers app drawing remote ] ;
SubDirC++Flags $(defines) ;
UsePrivateHeaders shared ;
UseHeaders $(serverDir) ;
Application RemoteDesktop :
RemoteDesktop.cpp
RemoteMessage.cpp
RemoteView.cpp
NetReceiver.cpp
NetSender.cpp
StreamingRingBuffer.cpp
: be bnetapi $(TARGET_LIBSUPC++)
: RemoteDesktop.rdef
;
SEARCH on [ FGristFiles NetReceiver.cpp NetSender.cpp RemoteMessage.cpp
StreamingRingBuffer.cpp ] = $(serverDir) ;

View File

@ -0,0 +1,176 @@
/*
* Copyright 2009, Haiku, Inc.
* Distributed under the terms of the MIT License.
*
* Authors:
* Michael Lotz <mmlr@mlotz.ch>
*/
#include <Application.h>
#include <Screen.h>
#include <Window.h>
#include "RemoteView.h"
#include <new>
#include <signal.h>
#include <stdio.h>
#include <string.h>
#include <sys/wait.h>
#include <unistd.h>
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);
}
int
main(int argc, char *argv[])
{
if (argc < 2) {
print_usage(argv[0]);
return 1;
}
bool listenOnly = false;
uint32 listenPort = 10900;
uint32 sshPort = 22;
const char *command = "/system/apps/Terminal";
for (int32 i = 2; i < argc; i++) {
if (strcmp(argv[i], "-p") == 0) {
if (argc < i + 1 || sscanf(argv[i + 1], "%lu", &listenPort) != 1) {
print_usage(argv[0]);
return 2;
}
i++;
continue;
}
if (strcmp(argv[i], "-s") == 0) {
if (argc < i + 1 || sscanf(argv[i + 1], "%lu", &sshPort) != 1) {
print_usage(argv[0]);
return 2;
}
i++;
continue;
}
if (strcmp(argv[i], "-c") == 0) {
if (argc < i + 1) {
print_usage(argv[0]);
return 2;
}
i++;
command = argv[i];
continue;
}
if (strcmp(argv[i], "--listenOnly") == 0) {
listenOnly = true;
continue;
}
print_usage(argv[0]);
return 2;
}
pid_t sshPID = -1;
if (!listenOnly) {
char shellCommand[4096];
snprintf(shellCommand, sizeof(shellCommand),
"echo connected; export TARGET_SCREEN=localhost:%lu; %s\n",
listenPort, command);
int pipes[4];
if (pipe(&pipes[0]) != 0 || pipe(&pipes[2]) != 0) {
printf("failed to create redirection pipes\n");
return 3;
}
sshPID = fork();
if (sshPID < 0) {
printf("failed to fork ssh process\n");
return 3;
}
if (sshPID == 0) {
// child code, redirect std* and execute ssh
close(STDOUT_FILENO);
close(STDIN_FILENO);
dup2(pipes[1], STDOUT_FILENO);
dup2(pipes[1], STDERR_FILENO);
dup2(pipes[2], STDIN_FILENO);
for (int32 i = 0; i < 4; i++)
close(pipes[i]);
char localRedirect[50];
sprintf(localRedirect, "localhost:%lu:localhost:%lu",
listenPort + 1, listenPort + 1);
char remoteRedirect[50];
sprintf(remoteRedirect, "localhost:%lu:localhost:%lu",
listenPort, listenPort);
char portNumber[10];
sprintf(portNumber, "%lu", sshPort);
int result = execl("ssh", "-C", "-L", localRedirect,
"-R", remoteRedirect, "-p", portNumber, argv[1],
shellCommand, NULL);
// we don't get here unless there was an error in executing
printf("failed to execute ssh process in child\n");
return result;
} else {
close(pipes[1]);
close(pipes[2]);
char buffer[10];
read(pipes[0], buffer, sizeof(buffer));
// block until connected/error message from ssh
}
}
BApplication app("application/x-vnd.Haiku-RemoteDesktop");
BScreen screen;
BWindow *window = new(std::nothrow) BWindow(screen.Frame(), "RemoteDesktop",
B_TITLED_WINDOW, B_QUIT_ON_WINDOW_CLOSE);
if (window == NULL) {
printf("no memory to allocate window\n");
return 4;
}
RemoteView *view = new(std::nothrow) RemoteView(window->Bounds(),
listenPort);
if (view == NULL) {
printf("no memory to allocate remote view\n");
return 4;
}
status_t init = view->InitCheck();
if (init != B_OK) {
printf("initialization of remote view failed: %s\n", strerror(init));
delete view;
return 5;
}
window->AddChild(view);
view->MakeFocus();
window->Show();
app.Run();
if (sshPID >= 0)
kill(sshPID, SIGINT);
return 0;
}

View File

@ -0,0 +1,15 @@
resource app_signature "application/x-vnd.Haiku-RemoteDesktop";
resource app_version {
major = 0,
middle = 1,
minor = 0,
variety = B_APPV_ALPHA,
internal = 0,
short_info = "RemoteDesktop",
long_info = "RemoteDesktop ©2009 Haiku, Inc."
};
resource app_flags B_MULTIPLE_LAUNCH;

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,86 @@
/*
* Copyright 2009, Haiku, Inc.
* Distributed under the terms of the MIT License.
*
* Authors:
* Michael Lotz <mmlr@mlotz.ch>
*/
#ifndef REMOTE_VIEW_H
#define REMOTE_VIEW_H
#include <Cursor.h>
#include <NetEndpoint.h>
#include <ObjectList.h>
#include <View.h>
class BBitmap;
class NetReceiver;
class NetSender;
class StreamingRingBuffer;
struct engine_state;
class RemoteView : public BView {
public:
RemoteView(BRect frame, uint16 listenPort);
virtual ~RemoteView();
status_t InitCheck();
virtual void AttachedToWindow();
virtual void Draw(BRect updateRect);
virtual void MouseMoved(BPoint where, uint32 code,
const BMessage *dragMessage);
virtual void MouseDown(BPoint where);
virtual void MouseUp(BPoint where);
virtual void KeyDown(const char *bytes, int32 numBytes);
virtual void KeyUp(const char *bytes, int32 numBytes);
virtual void MessageReceived(BMessage *message);
private:
void _SendMouseMessage(uint16 code,
BPoint where);
void _SendKeyMessage(uint16 code,
const char *bytes, int32 numBytes);
static int _StateCompareByKey(const uint32 *key,
const engine_state *state);
void _CreateState(uint32 token);
void _DeleteState(uint32 token);
engine_state * _FindState(uint32 token);
static int32 _DrawEntry(void *data);
void _DrawThread();
BRect _BuildInvalidateRect(BPoint *points,
int32 pointCount);
status_t fInitStatus;
bool fIsConnected;
StreamingRingBuffer * fReceiveBuffer;
StreamingRingBuffer * fSendBuffer;
BNetEndpoint * fReceiveEndpoint;
BNetEndpoint * fSendEndpoint;
NetReceiver * fReceiver;
NetSender * fSender;
bool fStopThread;
thread_id fDrawThread;
BBitmap * fOffscreenBitmap;
BView * fOffscreen;
BCursor fViewCursor;
BBitmap * fCursorBitmap;
BRect fCursorFrame;
bool fCursorVisible;
BObjectList<engine_state> fStates;
};
#endif // REMOTE_VIEW_H