xref: /haiku/src/apps/remotedesktop/RemoteDesktop.cpp (revision 7ee53ed3bd2222305c93a4959f8c587c373ed97c)
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