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