-
-
Notifications
You must be signed in to change notification settings - Fork 213
/
Copy pathportal.vala
227 lines (191 loc) · 6.1 KB
/
portal.vala
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
namespace Frida.Portal {
private static Application application;
private static bool output_version = false;
private static string? cluster_address = null;
private static string? cluster_certpath = null;
private static string? cluster_token = null;
private static string? control_address = null;
private static string? control_certpath = null;
private static string? control_origin = null;
private static string? control_token = null;
private static string? control_asset_root = null;
#if !WINDOWS && !TVOS
private static bool daemonize = false;
#endif
private delegate void ReadyHandler (bool success);
const OptionEntry[] options = {
{ "version", 0, 0, OptionArg.NONE, ref output_version, "Output version information and exit", null },
{ "cluster-endpoint", 0, 0, OptionArg.STRING, ref cluster_address, "Expose cluster endpoint on ADDRESS", "ADDRESS" },
{ "cluster-certificate", 0, 0, OptionArg.FILENAME, ref cluster_certpath, "Enable TLS on cluster endpoint using CERTIFICATE",
"CERTIFICATE" },
{ "cluster-token", 0, 0, OptionArg.STRING, ref cluster_token, "Require authentication on cluster endpoint using TOKEN",
"TOKEN" },
{ "control-endpoint", 0, 0, OptionArg.STRING, ref control_address, "Expose control endpoint on ADDRESS", "ADDRESS" },
{ "control-certificate", 0, 0, OptionArg.FILENAME, ref control_certpath, "Enable TLS on control endpoint using CERTIFICATE",
"CERTIFICATE" },
{ "control-origin", 0, 0, OptionArg.STRING, ref control_origin, "Only accept control endpoint requests with “Origin” " +
"header matching ORIGIN (by default any origin will be accepted)", "ORIGIN" },
{ "control-token", 0, 0, OptionArg.STRING, ref control_token, "Require authentication on control endpoint using TOKEN",
"TOKEN" },
{ "control-asset-root", 0, 0, OptionArg.FILENAME, ref control_asset_root, "Serve static files inside ROOT on control " +
"endpoint (by default no files are served)", "ROOT" },
#if !WINDOWS && !TVOS
{ "daemonize", 'D', 0, OptionArg.NONE, ref daemonize, "Detach and become a daemon", null },
#endif
{ null }
};
private static int main (string[] args) {
#if HAVE_GIOOPENSSL
GIOOpenSSL.register ();
#endif
try {
var ctx = new OptionContext ();
ctx.set_help_enabled (true);
ctx.add_main_entries (options, null);
ctx.parse (ref args);
} catch (OptionError e) {
printerr ("%s\n", e.message);
printerr ("Run '%s --help' to see a full list of available command line options.\n", args[0]);
return 1;
}
if (output_version) {
stdout.printf ("%s\n", version_string ());
return 0;
}
EndpointParameters cluster_params, control_params;
try {
cluster_params = new EndpointParameters (cluster_address, 0, parse_certificate (cluster_certpath), null,
(cluster_token != null) ? new StaticAuthenticationService (cluster_token) : null);
control_params = new EndpointParameters (control_address, 0, parse_certificate (control_certpath), control_origin,
(control_token != null) ? new StaticAuthenticationService (control_token) : null,
(control_asset_root != null) ? File.new_for_path (control_asset_root) : null);
} catch (GLib.Error e) {
printerr ("%s\n", e.message);
return 2;
}
ReadyHandler? on_ready = null;
#if !WINDOWS && !TVOS
if (daemonize) {
var sync_fds = new int[2];
try {
Unix.open_pipe (sync_fds, 0);
Unix.set_fd_nonblocking (sync_fds[0], true);
Unix.set_fd_nonblocking (sync_fds[1], true);
} catch (GLib.Error e) {
assert_not_reached ();
}
var sync_in = new UnixInputStream (sync_fds[0], true);
var sync_out = new UnixOutputStream (sync_fds[1], true);
var pid = Posix.fork ();
if (pid != 0) {
try {
var status = new uint8[1];
sync_in.read (status);
return status[0];
} catch (GLib.Error e) {
return 3;
}
}
sync_in = null;
on_ready = (success) => {
if (success) {
Posix.setsid ();
var null_in = Posix.open ("/dev/null", Posix.O_RDONLY);
var null_out = Posix.open ("/dev/null", Posix.O_WRONLY);
Posix.dup2 (null_in, Posix.STDIN_FILENO);
Posix.dup2 (null_out, Posix.STDOUT_FILENO);
Posix.dup2 (null_out, Posix.STDERR_FILENO);
Posix.close (null_in);
Posix.close (null_out);
}
var status = new uint8[1];
status[0] = success ? 0 : 1;
try {
sync_out.write (status);
} catch (GLib.Error e) {
}
sync_out = null;
};
}
#endif
application = new Application (new PortalService (cluster_params, control_params));
Posix.signal (Posix.Signal.INT, (sig) => {
application.stop ();
});
Posix.signal (Posix.Signal.TERM, (sig) => {
application.stop ();
});
if (on_ready != null) {
application.ready.connect (success => {
on_ready (success);
on_ready = null;
});
}
return application.run ();
}
private class Application : Object {
public signal void ready (bool success);
public PortalService service {
get;
construct;
}
private Cancellable io_cancellable = new Cancellable ();
private MainLoop loop = new MainLoop ();
private int exit_code;
private bool stopping;
public Application (PortalService service) {
Object (service: service);
}
public int run () {
Idle.add (() => {
start.begin ();
return false;
});
exit_code = 0;
loop.run ();
return exit_code;
}
private async void start () {
try {
yield service.start (io_cancellable);
} catch (GLib.Error e) {
if (e is IOError.CANCELLED)
return;
printerr ("Unable to start: %s\n", e.message);
exit_code = 4;
loop.quit ();
ready (false);
return;
}
Idle.add (() => {
ready (true);
return false;
});
}
public void stop () {
Idle.add (() => {
perform_stop.begin ();
return false;
});
}
private async void perform_stop () {
if (stopping)
return;
stopping = true;
io_cancellable.cancel ();
try {
yield service.stop ();
} catch (GLib.Error e) {
}
Idle.add (() => {
loop.quit ();
return false;
});
}
}
private TlsCertificate? parse_certificate (string? path) throws GLib.Error {
if (path == null)
return null;
return new TlsCertificate.from_file (path);
}
}