UNPKG

11.8 kBtext/x-cView Raw
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
43using grpc::node::CreateSliceFromString;
44
45using v8::FunctionTemplate;
46using v8::Local;
47using v8::Value;
48using v8::Number;
49using v8::Object;
50using v8::Uint32;
51using v8::String;
52
53typedef struct log_args {
54 gpr_log_func_args core_args;
55 gpr_timespec timestamp;
56} log_args;
57
58typedef 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
68logger_state grpc_logger_state;
69
70static char *pem_root_certs = NULL;
71
72void 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
106void 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
126NAN_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
136NAN_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
148NAN_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
159static 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 */
171NAN_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
185NAUV_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
212void 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
229void 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 */
246NAN_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
259NAN_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
268NAN_METHOD(ForcePoll) {
269 grpc::node::CompletionQueueForcePoll();
270}
271
272void 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
318NODE_MODULE(grpc_node, init)