haiku/src/apps/remotedesktop/RemoteDesktop.cpp

233 lines
5.1 KiB
C++

/*
* Copyright 2009-2017, Haiku, Inc.
* Distributed under the terms of the MIT License.
*
* Authors:
* Michael Lotz <mmlr@mlotz.ch>
*/
#include <Application.h>
#include <FindDirectory.h>
#include <Path.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 <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 (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");
}
int
main(int argc, char *argv[])
{
if (argc < 2 || strcmp(argv[1], "--help") == 0) {
print_usage(argv[0]);
return 1;
}
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_SCNu16, &port)
!= 1) {
print_usage(argv[0]);
return 2;
}
i++;
continue;
}
if (strcmp(argv[i], "-w") == 0) {
if (argc < i + 1 || sscanf(argv[i + 1], "%" B_SCNd32, &width) != 1)
{
print_usage(argv[0]);
return 2;
}
i++;
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]);
return 2;
}
i++;
command = argv[i];
continue;
}
print_usage(argv[0]);
return 2;
}
if (command != NULL && !useSSH) {
print_usage(argv[0]);
return 2;
}
pid_t sshPID = -1;
if (useSSH) {
BPath terminalPath;
if (command == NULL) {
if (find_directory(B_SYSTEM_APPS_DIRECTORY, &terminalPath)
!= B_OK) {
printf("failed to determine system-apps directory\n");
return 3;
}
if (terminalPath.Append("Terminal") != B_OK) {
printf("failed to append to system-apps path\n");
return 3;
}
command = terminalPath.Path();
}
char shellCommand[4096];
snprintf(shellCommand, sizeof(shellCommand),
"echo connected; export TARGET_SCREEN=%" B_PRIu16 "; %s\n", port,
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:%" B_PRIu16 ":localhost:%"
B_PRIu16, port, port);
char portNumber[10];
sprintf(portNumber, "%" B_PRIu16, sshPort);
int result = execl("ssh", "-C", "-L", localRedirect,
"-p", portNumber, "-o", "ExitOnForwardFailure=yes", host,
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
host = "localhost";
}
}
BApplication app("application/x-vnd.Haiku-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) {
printf("no memory to allocate window\n");
return 4;
}
RemoteView *view = new(std::nothrow) RemoteView(window->Bounds(), host,
port);
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, SIGHUP);
return 0;
}