1 /* 2 * Copyright 2009-2017, Haiku, Inc. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Michael Lotz <mmlr@mlotz.ch> 7 */ 8 9 #include <Application.h> 10 #include <FindDirectory.h> 11 #include <Path.h> 12 #include <Screen.h> 13 #include <Window.h> 14 15 #include "RemoteView.h" 16 17 #include <new> 18 #include <signal.h> 19 #include <stdio.h> 20 #include <string.h> 21 #include <sys/wait.h> 22 #include <unistd.h> 23 24 25 void 26 print_usage(const char *app) 27 { 28 printf("usage:\t%s <host> [-p <port>] [-w <width>] [-h <height>]\n", app); 29 printf("usage:\t%s <user@host> -s [<sshPort>] [-p <port>] [-w <width>]" 30 " [-h <height>] [-c <command>]\n", app); 31 printf("\t%s --help\n\n", app); 32 33 printf("Connect to & run applications from a different computer\n\n"); 34 printf("Arguments available for use:\n\n"); 35 printf("\t-p\t\tspecify the port to communicate on (default 10900)\n"); 36 printf("\t-c\t\tsend a command to the other computer (default Terminal)\n"); 37 printf("\t-s\t\tuse SSH, optionally specify the SSH port to use (22)\n"); 38 printf("\t-w\t\tmake the virtual desktop use the specified width\n"); 39 printf("\t-h\t\tmake the virtual desktop use the specified height\n"); 40 printf("\nIf no width and height are specified, the window is opened with" 41 " the size of the the local screen.\n"); 42 } 43 44 45 int 46 main(int argc, char *argv[]) 47 { 48 if (argc < 2 || strcmp(argv[1], "--help") == 0) { 49 print_usage(argv[0]); 50 return 1; 51 } 52 53 uint16 port = 10900; 54 uint16 sshPort = 22; 55 int32 width = -1; 56 int32 height = -1; 57 bool useSSH = false; 58 const char *command = NULL; 59 const char *host = argv[1]; 60 61 for (int32 i = 2; i < argc; i++) { 62 if (strcmp(argv[i], "-p") == 0) { 63 if (argc < i + 1 || sscanf(argv[i + 1], "%" B_SCNu16, &port) 64 != 1) { 65 print_usage(argv[0]); 66 return 2; 67 } 68 69 i++; 70 continue; 71 } 72 73 if (strcmp(argv[i], "-w") == 0) { 74 if (argc < i + 1 || sscanf(argv[i + 1], "%" B_SCNd32, &width) != 1) 75 { 76 print_usage(argv[0]); 77 return 2; 78 } 79 80 i++; 81 continue; 82 } 83 84 if (strcmp(argv[i], "-h") == 0) { 85 if (argc < i + 1 || sscanf(argv[i + 1], "%" B_SCNd32, &height) != 1) 86 { 87 print_usage(argv[0]); 88 return 2; 89 } 90 91 i++; 92 continue; 93 } 94 95 if (strcmp(argv[i], "-s") == 0) { 96 if (argc >= i + 1 97 && sscanf(argv[i + 1], "%" B_SCNu16, &sshPort) == 1) { 98 i++; 99 } 100 101 useSSH = true; 102 continue; 103 } 104 105 if (strcmp(argv[i], "-c") == 0) { 106 if (argc < i + 1) { 107 print_usage(argv[0]); 108 return 2; 109 } 110 111 i++; 112 command = argv[i]; 113 continue; 114 } 115 116 print_usage(argv[0]); 117 return 2; 118 } 119 120 if (command != NULL && !useSSH) { 121 print_usage(argv[0]); 122 return 2; 123 } 124 125 pid_t sshPID = -1; 126 if (useSSH) { 127 BPath terminalPath; 128 if (command == NULL) { 129 if (find_directory(B_SYSTEM_APPS_DIRECTORY, &terminalPath) 130 != B_OK) { 131 printf("failed to determine system-apps directory\n"); 132 return 3; 133 } 134 if (terminalPath.Append("Terminal") != B_OK) { 135 printf("failed to append to system-apps path\n"); 136 return 3; 137 } 138 command = terminalPath.Path(); 139 } 140 141 char shellCommand[4096]; 142 snprintf(shellCommand, sizeof(shellCommand), 143 "echo connected; export TARGET_SCREEN=%" B_PRIu16 "; %s\n", port, 144 command); 145 146 int pipes[4]; 147 if (pipe(&pipes[0]) != 0 || pipe(&pipes[2]) != 0) { 148 printf("failed to create redirection pipes\n"); 149 return 3; 150 } 151 152 sshPID = fork(); 153 if (sshPID < 0) { 154 printf("failed to fork ssh process\n"); 155 return 3; 156 } 157 158 if (sshPID == 0) { 159 // child code, redirect std* and execute ssh 160 close(STDOUT_FILENO); 161 close(STDIN_FILENO); 162 dup2(pipes[1], STDOUT_FILENO); 163 dup2(pipes[1], STDERR_FILENO); 164 dup2(pipes[2], STDIN_FILENO); 165 for (int32 i = 0; i < 4; i++) 166 close(pipes[i]); 167 168 char localRedirect[50]; 169 sprintf(localRedirect, "localhost:%" B_PRIu16 ":localhost:%" 170 B_PRIu16, port, port); 171 172 char portNumber[10]; 173 sprintf(portNumber, "%" B_PRIu16, sshPort); 174 175 int result = execl("ssh", "-C", "-L", localRedirect, 176 "-p", portNumber, "-o", "ExitOnForwardFailure=yes", host, 177 shellCommand, NULL); 178 179 // we don't get here unless there was an error in executing 180 printf("failed to execute ssh process in child\n"); 181 return result; 182 } else { 183 close(pipes[1]); 184 close(pipes[2]); 185 186 char buffer[10]; 187 read(pipes[0], buffer, sizeof(buffer)); 188 // block until connected/error message from ssh 189 190 host = "localhost"; 191 } 192 } 193 194 BApplication app("application/x-vnd.Haiku-RemoteDesktop"); 195 BRect windowFrame = BRect(0, 0, width - 1, height - 1); 196 if (!windowFrame.IsValid()) { 197 BScreen screen; 198 windowFrame = screen.Frame(); 199 } 200 201 BWindow *window = new(std::nothrow) BWindow(windowFrame, "RemoteDesktop", 202 B_TITLED_WINDOW, B_QUIT_ON_WINDOW_CLOSE); 203 204 if (window == NULL) { 205 printf("no memory to allocate window\n"); 206 return 4; 207 } 208 209 RemoteView *view = new(std::nothrow) RemoteView(window->Bounds(), host, 210 port); 211 if (view == NULL) { 212 printf("no memory to allocate remote view\n"); 213 return 4; 214 } 215 216 status_t init = view->InitCheck(); 217 if (init != B_OK) { 218 printf("initialization of remote view failed: %s\n", strerror(init)); 219 delete view; 220 return 5; 221 } 222 223 window->AddChild(view); 224 view->MakeFocus(); 225 window->Show(); 226 app.Run(); 227 228 if (sshPID >= 0) 229 kill(sshPID, SIGHUP); 230 231 return 0; 232 } 233