| 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 | |