1 | // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file |
2 | // for details. All rights reserved. Use of this source code is governed by a |
3 | // BSD-style license that can be found in the LICENSE file. |
4 | |
5 | #include "bin/vmservice_impl.h" |
6 | |
7 | #include "include/dart_api.h" |
8 | |
9 | #include "bin/builtin.h" |
10 | #include "bin/dartutils.h" |
11 | #include "bin/isolate_data.h" |
12 | #include "bin/platform.h" |
13 | #include "bin/thread.h" |
14 | #include "bin/utils.h" |
15 | #include "platform/text_buffer.h" |
16 | #include "platform/utils.h" |
17 | |
18 | namespace dart { |
19 | namespace bin { |
20 | |
21 | #define RETURN_ERROR_HANDLE(handle) \ |
22 | if (Dart_IsError(handle)) { \ |
23 | return handle; \ |
24 | } |
25 | |
26 | #define SHUTDOWN_ON_ERROR(handle) \ |
27 | if (Dart_IsError(handle)) { \ |
28 | error_msg_ = Utils::StrDup(Dart_GetError(handle)); \ |
29 | Dart_ExitScope(); \ |
30 | Dart_ShutdownIsolate(); \ |
31 | return false; \ |
32 | } |
33 | |
34 | static const char* const kVMServiceIOLibraryUri = "dart:vmservice_io" ; |
35 | |
36 | void NotifyServerState(Dart_NativeArguments args) { |
37 | Dart_EnterScope(); |
38 | const char* uri_chars; |
39 | Dart_Handle uri_arg = Dart_GetNativeArgument(args, 0); |
40 | if (Dart_IsError(uri_arg)) { |
41 | VmService::SetServerAddress("" ); |
42 | Dart_ExitScope(); |
43 | return; |
44 | } |
45 | Dart_Handle result = Dart_StringToCString(uri_arg, &uri_chars); |
46 | if (Dart_IsError(result)) { |
47 | VmService::SetServerAddress("" ); |
48 | Dart_ExitScope(); |
49 | return; |
50 | } |
51 | VmService::SetServerAddress(uri_chars); |
52 | Dart_ExitScope(); |
53 | } |
54 | |
55 | static void Shutdown(Dart_NativeArguments args) { |
56 | // NO-OP. |
57 | } |
58 | |
59 | struct VmServiceIONativeEntry { |
60 | const char* name; |
61 | int num_arguments; |
62 | Dart_NativeFunction function; |
63 | }; |
64 | |
65 | static VmServiceIONativeEntry _VmServiceIONativeEntries[] = { |
66 | {"VMServiceIO_NotifyServerState" , 1, NotifyServerState}, |
67 | {"VMServiceIO_Shutdown" , 0, Shutdown}, |
68 | }; |
69 | |
70 | static Dart_NativeFunction VmServiceIONativeResolver(Dart_Handle name, |
71 | int num_arguments, |
72 | bool* auto_setup_scope) { |
73 | const char* function_name = NULL; |
74 | Dart_Handle result = Dart_StringToCString(name, &function_name); |
75 | ASSERT(!Dart_IsError(result)); |
76 | ASSERT(function_name != NULL); |
77 | *auto_setup_scope = true; |
78 | intptr_t n = |
79 | sizeof(_VmServiceIONativeEntries) / sizeof(_VmServiceIONativeEntries[0]); |
80 | for (intptr_t i = 0; i < n; i++) { |
81 | VmServiceIONativeEntry entry = _VmServiceIONativeEntries[i]; |
82 | if ((strcmp(function_name, entry.name) == 0) && |
83 | (num_arguments == entry.num_arguments)) { |
84 | return entry.function; |
85 | } |
86 | } |
87 | return NULL; |
88 | } |
89 | |
90 | const uint8_t* VmServiceIONativeSymbol(Dart_NativeFunction nf) { |
91 | intptr_t n = |
92 | sizeof(_VmServiceIONativeEntries) / sizeof(_VmServiceIONativeEntries[0]); |
93 | for (intptr_t i = 0; i < n; i++) { |
94 | VmServiceIONativeEntry entry = _VmServiceIONativeEntries[i]; |
95 | if (reinterpret_cast<Dart_NativeFunction>(entry.function) == nf) { |
96 | return reinterpret_cast<const uint8_t*>(entry.name); |
97 | } |
98 | } |
99 | return NULL; |
100 | } |
101 | |
102 | const char* VmService::error_msg_ = NULL; |
103 | char VmService::server_uri_[kServerUriStringBufferSize]; |
104 | |
105 | void VmService::SetNativeResolver() { |
106 | Dart_Handle url = DartUtils::NewString(kVMServiceIOLibraryUri); |
107 | Dart_Handle library = Dart_LookupLibrary(url); |
108 | if (!Dart_IsError(library)) { |
109 | Dart_SetNativeResolver(library, VmServiceIONativeResolver, |
110 | VmServiceIONativeSymbol); |
111 | } |
112 | } |
113 | |
114 | bool VmService::Setup(const char* server_ip, |
115 | intptr_t server_port, |
116 | bool dev_mode_server, |
117 | bool auth_codes_disabled, |
118 | const char* write_service_info_filename, |
119 | bool trace_loading, |
120 | bool deterministic, |
121 | bool enable_service_port_fallback) { |
122 | Dart_Isolate isolate = Dart_CurrentIsolate(); |
123 | ASSERT(isolate != NULL); |
124 | SetServerAddress("" ); |
125 | |
126 | Dart_Handle result; |
127 | |
128 | // Prepare builtin and its dependent libraries for use to resolve URIs. |
129 | // Set up various closures, e.g: printing, timers etc. |
130 | // Set up 'package root' for URI resolution. |
131 | result = DartUtils::PrepareForScriptLoading(/*is_service_isolate=*/true, |
132 | trace_loading); |
133 | SHUTDOWN_ON_ERROR(result); |
134 | |
135 | Dart_Handle url = DartUtils::NewString(kVMServiceIOLibraryUri); |
136 | Dart_Handle library = Dart_LookupLibrary(url); |
137 | SHUTDOWN_ON_ERROR(library); |
138 | result = Dart_SetRootLibrary(library); |
139 | SHUTDOWN_ON_ERROR(library); |
140 | result = Dart_SetNativeResolver(library, VmServiceIONativeResolver, |
141 | VmServiceIONativeSymbol); |
142 | SHUTDOWN_ON_ERROR(result); |
143 | |
144 | // Make runnable. |
145 | Dart_ExitScope(); |
146 | Dart_ExitIsolate(); |
147 | error_msg_ = Dart_IsolateMakeRunnable(isolate); |
148 | if (error_msg_ != NULL) { |
149 | Dart_EnterIsolate(isolate); |
150 | Dart_ShutdownIsolate(); |
151 | return false; |
152 | } |
153 | Dart_EnterIsolate(isolate); |
154 | Dart_EnterScope(); |
155 | |
156 | library = Dart_RootLibrary(); |
157 | SHUTDOWN_ON_ERROR(library); |
158 | |
159 | // Set HTTP server state. |
160 | result = DartUtils::SetStringField(library, "_ip" , server_ip); |
161 | SHUTDOWN_ON_ERROR(result); |
162 | // If we have a port specified, start the server immediately. |
163 | bool auto_start = server_port >= 0; |
164 | if (server_port < 0) { |
165 | // Adjust server_port to port 0 which will result in the first available |
166 | // port when the HTTP server is started. |
167 | server_port = 0; |
168 | } |
169 | result = DartUtils::SetIntegerField(library, "_port" , server_port); |
170 | SHUTDOWN_ON_ERROR(result); |
171 | result = Dart_SetField(library, DartUtils::NewString("_autoStart" ), |
172 | Dart_NewBoolean(auto_start)); |
173 | SHUTDOWN_ON_ERROR(result); |
174 | result = Dart_SetField(library, DartUtils::NewString("_originCheckDisabled" ), |
175 | Dart_NewBoolean(dev_mode_server)); |
176 | SHUTDOWN_ON_ERROR(result); |
177 | |
178 | result = Dart_SetField(library, DartUtils::NewString("_authCodesDisabled" ), |
179 | Dart_NewBoolean(auth_codes_disabled)); |
180 | SHUTDOWN_ON_ERROR(result); |
181 | |
182 | result = |
183 | Dart_SetField(library, DartUtils::NewString("_enableServicePortFallback" ), |
184 | Dart_NewBoolean(enable_service_port_fallback)); |
185 | SHUTDOWN_ON_ERROR(result); |
186 | |
187 | if (write_service_info_filename != nullptr) { |
188 | result = DartUtils::SetStringField(library, "_serviceInfoFilename" , |
189 | write_service_info_filename); |
190 | SHUTDOWN_ON_ERROR(result); |
191 | } |
192 | // Are we running on Windows? |
193 | #if defined(HOST_OS_WINDOWS) |
194 | Dart_Handle is_windows = Dart_True(); |
195 | #else |
196 | Dart_Handle is_windows = Dart_False(); |
197 | #endif |
198 | result = |
199 | Dart_SetField(library, DartUtils::NewString("_isWindows" ), is_windows); |
200 | SHUTDOWN_ON_ERROR(result); |
201 | |
202 | // Are we running on Fuchsia? |
203 | #if defined(HOST_OS_FUCHSIA) |
204 | Dart_Handle is_fuchsia = Dart_True(); |
205 | #else |
206 | Dart_Handle is_fuchsia = Dart_False(); |
207 | #endif |
208 | result = |
209 | Dart_SetField(library, DartUtils::NewString("_isFuchsia" ), is_fuchsia); |
210 | SHUTDOWN_ON_ERROR(result); |
211 | |
212 | // Get _getWatchSignalInternal from dart:io. |
213 | Dart_Handle dart_io_str = Dart_NewStringFromCString(DartUtils::kIOLibURL); |
214 | SHUTDOWN_ON_ERROR(dart_io_str); |
215 | Dart_Handle io_lib = Dart_LookupLibrary(dart_io_str); |
216 | SHUTDOWN_ON_ERROR(io_lib); |
217 | Dart_Handle function_name = |
218 | Dart_NewStringFromCString("_getWatchSignalInternal" ); |
219 | SHUTDOWN_ON_ERROR(function_name); |
220 | Dart_Handle signal_watch = Dart_Invoke(io_lib, function_name, 0, NULL); |
221 | SHUTDOWN_ON_ERROR(signal_watch); |
222 | Dart_Handle field_name = Dart_NewStringFromCString("_signalWatch" ); |
223 | SHUTDOWN_ON_ERROR(field_name); |
224 | result = Dart_SetField(library, field_name, signal_watch); |
225 | SHUTDOWN_ON_ERROR(field_name); |
226 | return true; |
227 | } |
228 | |
229 | const char* VmService::GetErrorMessage() { |
230 | return (error_msg_ == NULL) ? "No error." : error_msg_; |
231 | } |
232 | |
233 | void VmService::SetServerAddress(const char* server_uri) { |
234 | if (server_uri == NULL) { |
235 | server_uri = "" ; |
236 | } |
237 | const intptr_t server_uri_len = strlen(server_uri); |
238 | if (server_uri_len >= (kServerUriStringBufferSize - 1)) { |
239 | FATAL1("vm-service: Server URI exceeded length: %s\n" , server_uri); |
240 | } |
241 | strncpy(server_uri_, server_uri, kServerUriStringBufferSize); |
242 | server_uri_[kServerUriStringBufferSize - 1] = '\0'; |
243 | } |
244 | |
245 | } // namespace bin |
246 | } // namespace dart |
247 | |