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