1 /* 2 * Copyright 2009-2014, 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 --listenOnly [-p <listenPort>]\n", app); 29 printf("\t%s <user@host> [-p <listenPort>] [-s <sshPort>] [-c <command>]\n", 30 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\n"); 36 printf("\t-c\t\tsend a command to the other computer\n"); 37 printf("\t-s\t\tuse ssh & specify the ssh port to communicate on\n"); 38 } 39 40 41 int 42 main(int argc, char *argv[]) 43 { 44 if (argc < 2 || strcmp(argv[1], "--help") == 0) { 45 print_usage(argv[0]); 46 return 1; 47 } 48 49 bool listenOnly = false; 50 uint32 listenPort = 10900; 51 uint32 sshPort = 22; 52 const char* command = NULL; 53 54 for (int32 i = 2; i < argc; i++) { 55 if (strcmp(argv[i], "-p") == 0) { 56 if (argc < i + 1 || sscanf(argv[i + 1], "%" B_PRIu32, &listenPort) 57 != 1) { 58 print_usage(argv[0]); 59 return 2; 60 } 61 62 i++; 63 continue; 64 } 65 66 if (strcmp(argv[i], "-s") == 0) { 67 if (argc < i + 1 || sscanf(argv[i + 1], "%" B_PRIu32, &sshPort) 68 != 1) { 69 print_usage(argv[0]); 70 return 2; 71 } 72 73 i++; 74 continue; 75 } 76 77 if (strcmp(argv[i], "-c") == 0) { 78 if (argc < i + 1) { 79 print_usage(argv[0]); 80 return 2; 81 } 82 83 i++; 84 command = argv[i]; 85 continue; 86 } 87 88 if (strcmp(argv[i], "--listenOnly") == 0) { 89 listenOnly = true; 90 continue; 91 } 92 93 print_usage(argv[0]); 94 return 2; 95 } 96 97 pid_t sshPID = -1; 98 if (!listenOnly) { 99 BPath terminalPath; 100 if (command == NULL) { 101 if (find_directory(B_SYSTEM_APPS_DIRECTORY, &terminalPath) 102 != B_OK) { 103 printf("failed to determine system-apps directory\n"); 104 return 3; 105 } 106 if (terminalPath.Append("Terminal") != B_OK) { 107 printf("failed to append to system-apps path\n"); 108 return 3; 109 } 110 command = terminalPath.Path(); 111 } 112 113 char shellCommand[4096]; 114 snprintf(shellCommand, sizeof(shellCommand), 115 "echo connected; export TARGET_SCREEN=localhost:%" B_PRIu32 116 "; %s\n", listenPort, command); 117 118 int pipes[4]; 119 if (pipe(&pipes[0]) != 0 || pipe(&pipes[2]) != 0) { 120 printf("failed to create redirection pipes\n"); 121 return 3; 122 } 123 124 sshPID = fork(); 125 if (sshPID < 0) { 126 printf("failed to fork ssh process\n"); 127 return 3; 128 } 129 130 if (sshPID == 0) { 131 // child code, redirect std* and execute ssh 132 close(STDOUT_FILENO); 133 close(STDIN_FILENO); 134 dup2(pipes[1], STDOUT_FILENO); 135 dup2(pipes[1], STDERR_FILENO); 136 dup2(pipes[2], STDIN_FILENO); 137 for (int32 i = 0; i < 4; i++) 138 close(pipes[i]); 139 140 char localRedirect[50]; 141 sprintf(localRedirect, "localhost:%" B_PRIu32 ":localhost:%" 142 B_PRIu32, listenPort + 1, listenPort + 1); 143 144 char remoteRedirect[50]; 145 sprintf(remoteRedirect, "localhost:%" B_PRIu32 ":localhost:%" 146 B_PRIu32, listenPort, listenPort); 147 148 char portNumber[10]; 149 sprintf(portNumber, "%" B_PRIu32, sshPort); 150 151 int result = execl("ssh", "-C", "-L", localRedirect, 152 "-R", remoteRedirect, "-p", portNumber, argv[1], 153 shellCommand, NULL); 154 155 // we don't get here unless there was an error in executing 156 printf("failed to execute ssh process in child\n"); 157 return result; 158 } else { 159 close(pipes[1]); 160 close(pipes[2]); 161 162 char buffer[10]; 163 read(pipes[0], buffer, sizeof(buffer)); 164 // block until connected/error message from ssh 165 } 166 } 167 168 BApplication app("application/x-vnd.Haiku-RemoteDesktop"); 169 BScreen screen; 170 BWindow *window = new(std::nothrow) BWindow(screen.Frame(), "RemoteDesktop", 171 B_TITLED_WINDOW, B_QUIT_ON_WINDOW_CLOSE); 172 173 if (window == NULL) { 174 printf("no memory to allocate window\n"); 175 return 4; 176 } 177 178 RemoteView *view = new(std::nothrow) RemoteView(window->Bounds(), 179 listenPort); 180 if (view == NULL) { 181 printf("no memory to allocate remote view\n"); 182 return 4; 183 } 184 185 status_t init = view->InitCheck(); 186 if (init != B_OK) { 187 printf("initialization of remote view failed: %s\n", strerror(init)); 188 delete view; 189 return 5; 190 } 191 192 window->AddChild(view); 193 view->MakeFocus(); 194 window->Show(); 195 app.Run(); 196 197 if (sshPID >= 0) 198 kill(sshPID, SIGINT); 199 200 return 0; 201 } 202