Built motion from commit 6a09e18b.|2.6.11
[motion2.git] / legacy-libs / grpc / ext / node_grpc.cc
1 /*
2  *
3  * Copyright 2015 gRPC authors.
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  *     http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  *
17  */
18
19 #include <queue>
20
21 #include <nan.h>
22 #include <node.h>
23 #include <v8.h>
24 #include "grpc/grpc.h"
25 #include "grpc/grpc_security.h"
26 #include "grpc/support/alloc.h"
27 #include "grpc/support/log.h"
28 #include "grpc/support/time.h"
29
30 // TODO(murgatroid99): Remove this when the endpoint API becomes public
31 #include "src/core/lib/iomgr/pollset_uv.h"
32
33 #include "call.h"
34 #include "call_credentials.h"
35 #include "channel.h"
36 #include "channel_credentials.h"
37 #include "completion_queue.h"
38 #include "server.h"
39 #include "server_credentials.h"
40 #include "slice.h"
41 #include "timeval.h"
42
43 using grpc::node::CreateSliceFromString;
44
45 using v8::FunctionTemplate;
46 using v8::Local;
47 using v8::Value;
48 using v8::Number;
49 using v8::Object;
50 using v8::Uint32;
51 using v8::String;
52
53 typedef struct log_args {
54   gpr_log_func_args core_args;
55   gpr_timespec timestamp;
56 } log_args;
57
58 typedef struct logger_state {
59   Nan::Callback *callback;
60   Nan::AsyncResource *async_resource;
61   std::queue<log_args *> *pending_args;
62   uv_mutex_t mutex;
63   uv_async_t async;
64   // Indicates that a logger has been set
65   bool logger_set;
66 } logger_state;
67
68 logger_state grpc_logger_state;
69
70 static char *pem_root_certs = NULL;
71
72 void InitOpTypeConstants(Local<Object> exports) {
73   Nan::HandleScope scope;
74   Local<Object> op_type = Nan::New<Object>();
75   Nan::Set(exports, Nan::New("opType").ToLocalChecked(), op_type);
76   Local<Value> SEND_INITIAL_METADATA(
77       Nan::New<Uint32, uint32_t>(GRPC_OP_SEND_INITIAL_METADATA));
78   Nan::Set(op_type, Nan::New("SEND_INITIAL_METADATA").ToLocalChecked(),
79            SEND_INITIAL_METADATA);
80   Local<Value> SEND_MESSAGE(Nan::New<Uint32, uint32_t>(GRPC_OP_SEND_MESSAGE));
81   Nan::Set(op_type, Nan::New("SEND_MESSAGE").ToLocalChecked(), SEND_MESSAGE);
82   Local<Value> SEND_CLOSE_FROM_CLIENT(
83       Nan::New<Uint32, uint32_t>(GRPC_OP_SEND_CLOSE_FROM_CLIENT));
84   Nan::Set(op_type, Nan::New("SEND_CLOSE_FROM_CLIENT").ToLocalChecked(),
85            SEND_CLOSE_FROM_CLIENT);
86   Local<Value> SEND_STATUS_FROM_SERVER(
87       Nan::New<Uint32, uint32_t>(GRPC_OP_SEND_STATUS_FROM_SERVER));
88   Nan::Set(op_type, Nan::New("SEND_STATUS_FROM_SERVER").ToLocalChecked(),
89            SEND_STATUS_FROM_SERVER);
90   Local<Value> RECV_INITIAL_METADATA(
91       Nan::New<Uint32, uint32_t>(GRPC_OP_RECV_INITIAL_METADATA));
92   Nan::Set(op_type, Nan::New("RECV_INITIAL_METADATA").ToLocalChecked(),
93            RECV_INITIAL_METADATA);
94   Local<Value> RECV_MESSAGE(Nan::New<Uint32, uint32_t>(GRPC_OP_RECV_MESSAGE));
95   Nan::Set(op_type, Nan::New("RECV_MESSAGE").ToLocalChecked(), RECV_MESSAGE);
96   Local<Value> RECV_STATUS_ON_CLIENT(
97       Nan::New<Uint32, uint32_t>(GRPC_OP_RECV_STATUS_ON_CLIENT));
98   Nan::Set(op_type, Nan::New("RECV_STATUS_ON_CLIENT").ToLocalChecked(),
99            RECV_STATUS_ON_CLIENT);
100   Local<Value> RECV_CLOSE_ON_SERVER(
101       Nan::New<Uint32, uint32_t>(GRPC_OP_RECV_CLOSE_ON_SERVER));
102   Nan::Set(op_type, Nan::New("RECV_CLOSE_ON_SERVER").ToLocalChecked(),
103            RECV_CLOSE_ON_SERVER);
104 }
105
106 void InitConnectivityStateConstants(Local<Object> exports) {
107   Nan::HandleScope scope;
108   Local<Object> channel_state = Nan::New<Object>();
109   Nan::Set(exports, Nan::New("connectivityState").ToLocalChecked(),
110            channel_state);
111   Local<Value> IDLE(Nan::New<Uint32, uint32_t>(GRPC_CHANNEL_IDLE));
112   Nan::Set(channel_state, Nan::New("IDLE").ToLocalChecked(), IDLE);
113   Local<Value> CONNECTING(Nan::New<Uint32, uint32_t>(GRPC_CHANNEL_CONNECTING));
114   Nan::Set(channel_state, Nan::New("CONNECTING").ToLocalChecked(), CONNECTING);
115   Local<Value> READY(Nan::New<Uint32, uint32_t>(GRPC_CHANNEL_READY));
116   Nan::Set(channel_state, Nan::New("READY").ToLocalChecked(), READY);
117   Local<Value> TRANSIENT_FAILURE(
118       Nan::New<Uint32, uint32_t>(GRPC_CHANNEL_TRANSIENT_FAILURE));
119   Nan::Set(channel_state, Nan::New("TRANSIENT_FAILURE").ToLocalChecked(),
120            TRANSIENT_FAILURE);
121   Local<Value> FATAL_FAILURE(Nan::New<Uint32, uint32_t>(GRPC_CHANNEL_SHUTDOWN));
122   Nan::Set(channel_state, Nan::New("FATAL_FAILURE").ToLocalChecked(),
123            FATAL_FAILURE);
124 }
125
126 NAN_METHOD(MetadataKeyIsLegal) {
127   if (!info[0]->IsString()) {
128     return Nan::ThrowTypeError("headerKeyIsLegal's argument must be a string");
129   }
130   Local<String> key = Nan::To<String>(info[0]).ToLocalChecked();
131   grpc_slice slice = CreateSliceFromString(key);
132   info.GetReturnValue().Set(static_cast<bool>(grpc_header_key_is_legal(slice)));
133   grpc_slice_unref(slice);
134 }
135
136 NAN_METHOD(MetadataNonbinValueIsLegal) {
137   if (!info[0]->IsString()) {
138     return Nan::ThrowTypeError(
139         "metadataNonbinValueIsLegal's argument must be a string");
140   }
141   Local<String> value = Nan::To<String>(info[0]).ToLocalChecked();
142   grpc_slice slice = CreateSliceFromString(value);
143   info.GetReturnValue().Set(
144       static_cast<bool>(grpc_header_nonbin_value_is_legal(slice)));
145   grpc_slice_unref(slice);
146 }
147
148 NAN_METHOD(MetadataKeyIsBinary) {
149   if (!info[0]->IsString()) {
150     return Nan::ThrowTypeError(
151         "metadataKeyIsLegal's argument must be a string");
152   }
153   Local<String> key = Nan::To<String>(info[0]).ToLocalChecked();
154   grpc_slice slice = CreateSliceFromString(key);
155   info.GetReturnValue().Set(static_cast<bool>(grpc_is_binary_header(slice)));
156   grpc_slice_unref(slice);
157 }
158
159 static grpc_ssl_roots_override_result get_ssl_roots_override(
160     char **pem_root_certs_ptr) {
161   *pem_root_certs_ptr = pem_root_certs;
162   if (pem_root_certs == NULL) {
163     return GRPC_SSL_ROOTS_OVERRIDE_FAIL;
164   } else {
165     return GRPC_SSL_ROOTS_OVERRIDE_OK;
166   }
167 }
168
169 /* This should only be called once, and only before creating any
170  *ServerCredentials */
171 NAN_METHOD(SetDefaultRootsPem) {
172   if (!info[0]->IsString()) {
173     return Nan::ThrowTypeError(
174         "setDefaultRootsPem's argument must be a string");
175   }
176   Nan::Utf8String utf8_roots(info[0]);
177   size_t length = static_cast<size_t>(utf8_roots.length());
178   if (length > 0) {
179     const char *data = *utf8_roots;
180     pem_root_certs = (char *)gpr_malloc((length + 1) * sizeof(char));
181     memcpy(pem_root_certs, data, length + 1);
182   }
183 }
184
185 NAUV_WORK_CB(LogMessagesCallback) {
186   Nan::HandleScope scope;
187   std::queue<log_args *> args;
188   uv_mutex_lock(&grpc_logger_state.mutex);
189   grpc_logger_state.pending_args->swap(args);
190   uv_mutex_unlock(&grpc_logger_state.mutex);
191   /* Call the callback with each log message */
192   while (!args.empty()) {
193     log_args *arg = args.front();
194     args.pop();
195     Local<Value> file = Nan::New(arg->core_args.file).ToLocalChecked();
196     Local<Value> line = Nan::New<Uint32, uint32_t>(arg->core_args.line);
197     Local<Value> severity =
198         Nan::New(gpr_log_severity_string(arg->core_args.severity))
199             .ToLocalChecked();
200     Local<Value> message = Nan::New(arg->core_args.message).ToLocalChecked();
201     Local<Value> timestamp =
202         Nan::New<v8::Date>(grpc::node::TimespecToMilliseconds(arg->timestamp))
203             .ToLocalChecked();
204     const int argc = 5;
205     Local<Value> argv[argc] = {file, line, severity, message, timestamp};
206     grpc_logger_state.callback->Call(argc, argv, grpc_logger_state.async_resource);
207     delete[] arg->core_args.message;
208     delete arg;
209   }
210 }
211
212 void node_log_func(gpr_log_func_args *args) {
213   // TODO(mlumish): Use the core's log formatter when it becomes available
214   log_args *args_copy = new log_args;
215   size_t message_len = strlen(args->message) + 1;
216   char *message = new char[message_len];
217   memcpy(message, args->message, message_len);
218   memcpy(&args_copy->core_args, args, sizeof(gpr_log_func_args));
219   args_copy->core_args.message = message;
220   args_copy->timestamp = gpr_now(GPR_CLOCK_REALTIME);
221
222   uv_mutex_lock(&grpc_logger_state.mutex);
223   grpc_logger_state.pending_args->push(args_copy);
224   uv_mutex_unlock(&grpc_logger_state.mutex);
225
226   uv_async_send(&grpc_logger_state.async);
227 }
228
229 void init_logger() {
230   memset(&grpc_logger_state, 0, sizeof(logger_state));
231   grpc_logger_state.pending_args = new std::queue<log_args *>();
232   uv_mutex_init(&grpc_logger_state.mutex);
233   uv_async_init(uv_default_loop(), &grpc_logger_state.async,
234                 LogMessagesCallback);
235   uv_unref((uv_handle_t *)&grpc_logger_state.async);
236   grpc_logger_state.logger_set = false;
237
238   gpr_log_verbosity_init();
239 }
240
241 /* This registers a JavaScript logger for messages from the gRPC core. Because
242    that handler has to be run in the context of the JavaScript event loop, it
243    will be run asynchronously. To minimize the problems that could cause for
244    debugging, we leave core to do its default synchronous logging until a
245    JavaScript logger is set */
246 NAN_METHOD(SetDefaultLoggerCallback) {
247   if (!info[0]->IsFunction()) {
248     return Nan::ThrowTypeError(
249         "setDefaultLoggerCallback's argument must be a function");
250   }
251   if (!grpc_logger_state.logger_set) {
252     gpr_set_log_function(node_log_func);
253     grpc_logger_state.logger_set = true;
254   }
255   grpc_logger_state.callback = new Nan::Callback(info[0].As<v8::Function>());
256   grpc_logger_state.async_resource = new Nan::AsyncResource("grpc:logger");
257 }
258
259 NAN_METHOD(SetLogVerbosity) {
260   if (!info[0]->IsUint32()) {
261     return Nan::ThrowTypeError("setLogVerbosity's argument must be a number");
262   }
263   gpr_log_severity severity =
264       static_cast<gpr_log_severity>(Nan::To<uint32_t>(info[0]).FromJust());
265   gpr_set_log_verbosity(severity);
266 }
267
268 NAN_METHOD(ForcePoll) {
269   grpc::node::CompletionQueueForcePoll();
270 }
271
272 void init(Local<Object> exports) {
273   Nan::HandleScope scope;
274   grpc_init();
275   grpc_set_ssl_roots_override_callback(get_ssl_roots_override);
276   init_logger();
277
278   InitOpTypeConstants(exports);
279   InitConnectivityStateConstants(exports);
280
281   grpc_pollset_work_run_loop = 0;
282
283   grpc::node::Call::Init(exports);
284   grpc::node::CallCredentials::Init(exports);
285   grpc::node::Channel::Init(exports);
286   grpc::node::ChannelCredentials::Init(exports);
287   grpc::node::Server::Init(exports);
288   grpc::node::ServerCredentials::Init(exports);
289
290   grpc::node::CompletionQueueInit(exports);
291
292   // Attach a few utility functions directly to the module
293   Nan::Set(exports, Nan::New("metadataKeyIsLegal").ToLocalChecked(),
294            Nan::GetFunction(Nan::New<FunctionTemplate>(MetadataKeyIsLegal))
295                .ToLocalChecked());
296   Nan::Set(
297       exports, Nan::New("metadataNonbinValueIsLegal").ToLocalChecked(),
298       Nan::GetFunction(Nan::New<FunctionTemplate>(MetadataNonbinValueIsLegal))
299           .ToLocalChecked());
300   Nan::Set(exports, Nan::New("metadataKeyIsBinary").ToLocalChecked(),
301            Nan::GetFunction(Nan::New<FunctionTemplate>(MetadataKeyIsBinary))
302                .ToLocalChecked());
303   Nan::Set(exports, Nan::New("setDefaultRootsPem").ToLocalChecked(),
304            Nan::GetFunction(Nan::New<FunctionTemplate>(SetDefaultRootsPem))
305                .ToLocalChecked());
306   Nan::Set(
307       exports, Nan::New("setDefaultLoggerCallback").ToLocalChecked(),
308       Nan::GetFunction(Nan::New<FunctionTemplate>(SetDefaultLoggerCallback))
309           .ToLocalChecked());
310   Nan::Set(exports, Nan::New("setLogVerbosity").ToLocalChecked(),
311            Nan::GetFunction(Nan::New<FunctionTemplate>(SetLogVerbosity))
312                .ToLocalChecked());
313   Nan::Set(exports, Nan::New("forcePoll").ToLocalChecked(),
314            Nan::GetFunction(Nan::New<FunctionTemplate>(ForcePoll))
315                .ToLocalChecked());
316 }
317
318 NODE_MODULE(grpc_node, init)