blob: 34cde9ffab06dbced9893e455b412d45a986ae63 [file] [log] [blame]
murgatroid99749666e2015-01-12 18:25:58 -08001/*
2 *
Craig Tiller06059952015-02-18 08:34:56 -08003 * Copyright 2015, Google Inc.
murgatroid99749666e2015-01-12 18:25:58 -08004 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are
8 * met:
9 *
10 * * Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * * Redistributions in binary form must reproduce the above
13 * copyright notice, this list of conditions and the following disclaimer
14 * in the documentation and/or other materials provided with the
15 * distribution.
16 * * Neither the name of Google Inc. nor the names of its
17 * contributors may be used to endorse or promote products derived from
18 * this software without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 *
32 */
33
murgatroid99d4d67ad2015-02-09 10:43:21 -080034#include <memory>
35
murgatroid99e5061512015-01-12 18:14:35 -080036#include "server.h"
37
38#include <node.h>
39#include <nan.h>
40
murgatroid99e5061512015-01-12 18:14:35 -080041#include <vector>
42#include "grpc/grpc.h"
43#include "grpc/grpc_security.h"
murgatroid9977659062015-02-11 09:26:25 -080044#include "grpc/support/log.h"
murgatroid99e5061512015-01-12 18:14:35 -080045#include "call.h"
46#include "completion_queue_async_worker.h"
murgatroid99e5061512015-01-12 18:14:35 -080047#include "server_credentials.h"
murgatroid99016bb502015-02-09 15:55:10 -080048#include "timeval.h"
murgatroid99e5061512015-01-12 18:14:35 -080049
50namespace grpc {
51namespace node {
52
murgatroid99d4d67ad2015-02-09 10:43:21 -080053using std::unique_ptr;
murgatroid99e5061512015-01-12 18:14:35 -080054using v8::Array;
55using v8::Boolean;
murgatroid99016bb502015-02-09 15:55:10 -080056using v8::Date;
murgatroid99e5061512015-01-12 18:14:35 -080057using v8::Exception;
58using v8::Function;
59using v8::FunctionTemplate;
60using v8::Handle;
61using v8::HandleScope;
62using v8::Local;
63using v8::Number;
64using v8::Object;
65using v8::Persistent;
66using v8::String;
67using v8::Value;
68
murgatroid99f28066b2015-03-04 14:42:31 -080069NanCallback *Server::constructor;
murgatroid99e5061512015-01-12 18:14:35 -080070Persistent<FunctionTemplate> Server::fun_tpl;
71
murgatroid99d4d67ad2015-02-09 10:43:21 -080072class NewCallOp : public Op {
73 public:
74 NewCallOp() {
75 call = NULL;
76 grpc_call_details_init(&details);
77 grpc_metadata_array_init(&request_metadata);
78 }
79
80 ~NewCallOp() {
81 grpc_call_details_destroy(&details);
murgatroid99016bb502015-02-09 15:55:10 -080082 grpc_metadata_array_destroy(&request_metadata);
murgatroid99d4d67ad2015-02-09 10:43:21 -080083 }
84
85 Handle<Value> GetNodeValue() const {
86 NanEscapableScope();
murgatroid99016bb502015-02-09 15:55:10 -080087 if (call == NULL) {
murgatroid99d4d67ad2015-02-09 10:43:21 -080088 return NanEscapeScope(NanNull());
89 }
90 Handle<Object> obj = NanNew<Object>();
91 obj->Set(NanNew("call"), Call::WrapStruct(call));
92 obj->Set(NanNew("method"), NanNew(details.method));
93 obj->Set(NanNew("host"), NanNew(details.host));
94 obj->Set(NanNew("deadline"),
95 NanNew<Date>(TimespecToMilliseconds(details.deadline)));
96 obj->Set(NanNew("metadata"), ParseMetadata(&request_metadata));
97 return NanEscapeScope(obj);
98 }
99
100 bool ParseOp(Handle<Value> value, grpc_op *out,
murgatroid9917be5892015-02-13 10:19:10 -0800101 shared_ptr<Resources> resources) {
murgatroid99d4d67ad2015-02-09 10:43:21 -0800102 return true;
103 }
104
105 grpc_call *call;
106 grpc_call_details details;
107 grpc_metadata_array request_metadata;
murgatroid99016bb502015-02-09 15:55:10 -0800108
109 protected:
110 std::string GetTypeString() const {
111 return "new call";
112 }
113};
murgatroid99d4d67ad2015-02-09 10:43:21 -0800114
murgatroid99cd35c4c2015-05-28 13:39:25 -0700115Server::Server(grpc_server *server) : wrapped_server(server) {
116 shutdown_queue = grpc_completion_queue_create();
117 grpc_server_register_completion_queue(server, shutdown_queue);
118}
murgatroid99e5061512015-01-12 18:14:35 -0800119
murgatroid99cd35c4c2015-05-28 13:39:25 -0700120Server::~Server() {
121 this->ShutdownServer();
122 grpc_completion_queue_shutdown(this->shutdown_queue);
123 grpc_server_destroy(wrapped_server);
124 grpc_completion_queue_destroy(this->shutdown_queue);
125}
murgatroid99e5061512015-01-12 18:14:35 -0800126
127void Server::Init(Handle<Object> exports) {
128 NanScope();
murgatroid99f28066b2015-03-04 14:42:31 -0800129 Local<FunctionTemplate> tpl = NanNew<FunctionTemplate>(New);
130 tpl->SetClassName(NanNew("Server"));
murgatroid99e5061512015-01-12 18:14:35 -0800131 tpl->InstanceTemplate()->SetInternalFieldCount(1);
132 NanSetPrototypeTemplate(tpl, "requestCall",
murgatroid99f28066b2015-03-04 14:42:31 -0800133 NanNew<FunctionTemplate>(RequestCall)->GetFunction());
murgatroid99e5061512015-01-12 18:14:35 -0800134
murgatroid99f28066b2015-03-04 14:42:31 -0800135 NanSetPrototypeTemplate(
136 tpl, "addHttp2Port",
137 NanNew<FunctionTemplate>(AddHttp2Port)->GetFunction());
murgatroid99e5061512015-01-12 18:14:35 -0800138
Craig Tillere8e304e2015-01-13 14:41:29 -0800139 NanSetPrototypeTemplate(
140 tpl, "addSecureHttp2Port",
murgatroid99f28066b2015-03-04 14:42:31 -0800141 NanNew<FunctionTemplate>(AddSecureHttp2Port)->GetFunction());
murgatroid99e5061512015-01-12 18:14:35 -0800142
143 NanSetPrototypeTemplate(tpl, "start",
murgatroid99f28066b2015-03-04 14:42:31 -0800144 NanNew<FunctionTemplate>(Start)->GetFunction());
murgatroid99e5061512015-01-12 18:14:35 -0800145
146 NanSetPrototypeTemplate(tpl, "shutdown",
murgatroid99f28066b2015-03-04 14:42:31 -0800147 NanNew<FunctionTemplate>(Shutdown)->GetFunction());
murgatroid99e5061512015-01-12 18:14:35 -0800148
149 NanAssignPersistent(fun_tpl, tpl);
murgatroid99f28066b2015-03-04 14:42:31 -0800150 Handle<Function> ctr = tpl->GetFunction();
151 constructor = new NanCallback(ctr);
152 exports->Set(NanNew("Server"), ctr);
murgatroid99e5061512015-01-12 18:14:35 -0800153}
154
155bool Server::HasInstance(Handle<Value> val) {
156 return NanHasInstance(fun_tpl, val);
157}
158
murgatroid99cd35c4c2015-05-28 13:39:25 -0700159void Server::ShutdownServer() {
160 if (this->wrapped_server != NULL) {
161 grpc_server_shutdown_and_notify(this->wrapped_server,
162 this->shutdown_queue,
163 NULL);
Craig Tiller354398f2015-07-13 09:16:03 -0700164 grpc_completion_queue_pluck(this->shutdown_queue, NULL,
165 gpr_inf_future(GPR_CLOCK_REALTIME));
murgatroid99cd35c4c2015-05-28 13:39:25 -0700166 this->wrapped_server = NULL;
167 }
168}
169
murgatroid99e5061512015-01-12 18:14:35 -0800170NAN_METHOD(Server::New) {
171 NanScope();
172
173 /* If this is not a constructor call, make a constructor call and return
174 the result */
175 if (!args.IsConstructCall()) {
176 const int argc = 1;
Craig Tillere8e304e2015-01-13 14:41:29 -0800177 Local<Value> argv[argc] = {args[0]};
murgatroid99f28066b2015-03-04 14:42:31 -0800178 NanReturnValue(constructor->GetFunction()->NewInstance(argc, argv));
murgatroid99e5061512015-01-12 18:14:35 -0800179 }
180 grpc_server *wrapped_server;
181 grpc_completion_queue *queue = CompletionQueueAsyncWorker::GetQueue();
182 if (args[0]->IsUndefined()) {
Craig Tillerf5081452015-05-06 12:42:47 -0700183 wrapped_server = grpc_server_create(NULL);
murgatroid99e5061512015-01-12 18:14:35 -0800184 } else if (args[0]->IsObject()) {
murgatroid99da02a672015-03-02 17:28:02 -0800185 Handle<Object> args_hash(args[0]->ToObject());
murgatroid99e5061512015-01-12 18:14:35 -0800186 Handle<Array> keys(args_hash->GetOwnPropertyNames());
187 grpc_channel_args channel_args;
188 channel_args.num_args = keys->Length();
Craig Tillere8e304e2015-01-13 14:41:29 -0800189 channel_args.args = reinterpret_cast<grpc_arg *>(
murgatroid99e5061512015-01-12 18:14:35 -0800190 calloc(channel_args.num_args, sizeof(grpc_arg)));
191 /* These are used to keep all strings until then end of the block, then
192 destroy them */
Craig Tillere8e304e2015-01-13 14:41:29 -0800193 std::vector<NanUtf8String *> key_strings(keys->Length());
194 std::vector<NanUtf8String *> value_strings(keys->Length());
murgatroid99e5061512015-01-12 18:14:35 -0800195 for (unsigned int i = 0; i < channel_args.num_args; i++) {
196 Handle<String> current_key(keys->Get(i)->ToString());
197 Handle<Value> current_value(args_hash->Get(current_key));
198 key_strings[i] = new NanUtf8String(current_key);
199 channel_args.args[i].key = **key_strings[i];
200 if (current_value->IsInt32()) {
201 channel_args.args[i].type = GRPC_ARG_INTEGER;
202 channel_args.args[i].value.integer = current_value->Int32Value();
203 } else if (current_value->IsString()) {
204 channel_args.args[i].type = GRPC_ARG_STRING;
205 value_strings[i] = new NanUtf8String(current_value);
206 channel_args.args[i].value.string = **value_strings[i];
207 } else {
208 free(channel_args.args);
209 return NanThrowTypeError("Arg values must be strings");
210 }
211 }
Craig Tillerf5081452015-05-06 12:42:47 -0700212 wrapped_server = grpc_server_create(&channel_args);
murgatroid99e5061512015-01-12 18:14:35 -0800213 free(channel_args.args);
214 } else {
215 return NanThrowTypeError("Server expects an object");
216 }
Craig Tillerf5081452015-05-06 12:42:47 -0700217 grpc_server_register_completion_queue(wrapped_server, queue);
murgatroid99e5061512015-01-12 18:14:35 -0800218 Server *server = new Server(wrapped_server);
219 server->Wrap(args.This());
220 NanReturnValue(args.This());
221}
222
223NAN_METHOD(Server::RequestCall) {
224 NanScope();
225 if (!HasInstance(args.This())) {
226 return NanThrowTypeError("requestCall can only be called on a Server");
227 }
228 Server *server = ObjectWrap::Unwrap<Server>(args.This());
murgatroid99cd35c4c2015-05-28 13:39:25 -0700229 if (server->wrapped_server == NULL) {
230 return NanThrowError("requestCall cannot be called on a shut down Server");
231 }
murgatroid99016bb502015-02-09 15:55:10 -0800232 NewCallOp *op = new NewCallOp();
murgatroid99d3f9f9f2015-02-13 12:21:59 -0800233 unique_ptr<OpVec> ops(new OpVec());
murgatroid99016bb502015-02-09 15:55:10 -0800234 ops->push_back(unique_ptr<Op>(op));
murgatroid99d4d67ad2015-02-09 10:43:21 -0800235 grpc_call_error error = grpc_server_request_call(
murgatroid99016bb502015-02-09 15:55:10 -0800236 server->wrapped_server, &op->call, &op->details, &op->request_metadata,
murgatroid99d4d67ad2015-02-09 10:43:21 -0800237 CompletionQueueAsyncWorker::GetQueue(),
Craig Tillerf5081452015-05-06 12:42:47 -0700238 CompletionQueueAsyncWorker::GetQueue(),
murgatroid99d3f9f9f2015-02-13 12:21:59 -0800239 new struct tag(new NanCallback(args[0].As<Function>()), ops.release(),
murgatroid9917be5892015-02-13 10:19:10 -0800240 shared_ptr<Resources>(nullptr)));
murgatroid99d4d67ad2015-02-09 10:43:21 -0800241 if (error != GRPC_CALL_OK) {
murgatroid99e5061512015-01-12 18:14:35 -0800242 return NanThrowError("requestCall failed", error);
243 }
murgatroid99d4d67ad2015-02-09 10:43:21 -0800244 CompletionQueueAsyncWorker::Next();
murgatroid99e5061512015-01-12 18:14:35 -0800245 NanReturnUndefined();
246}
247
248NAN_METHOD(Server::AddHttp2Port) {
249 NanScope();
250 if (!HasInstance(args.This())) {
251 return NanThrowTypeError("addHttp2Port can only be called on a Server");
252 }
253 if (!args[0]->IsString()) {
254 return NanThrowTypeError("addHttp2Port's argument must be a String");
255 }
256 Server *server = ObjectWrap::Unwrap<Server>(args.This());
murgatroid99cd35c4c2015-05-28 13:39:25 -0700257 if (server->wrapped_server == NULL) {
258 return NanThrowError("addHttp2Port cannot be called on a shut down Server");
259 }
murgatroid99d2f20b22015-01-21 11:55:39 -0800260 NanReturnValue(NanNew<Number>(grpc_server_add_http2_port(
Craig Tillere8e304e2015-01-13 14:41:29 -0800261 server->wrapped_server, *NanUtf8String(args[0]))));
murgatroid99e5061512015-01-12 18:14:35 -0800262}
263
264NAN_METHOD(Server::AddSecureHttp2Port) {
265 NanScope();
266 if (!HasInstance(args.This())) {
267 return NanThrowTypeError(
268 "addSecureHttp2Port can only be called on a Server");
269 }
270 if (!args[0]->IsString()) {
murgatroid99da02a672015-03-02 17:28:02 -0800271 return NanThrowTypeError(
272 "addSecureHttp2Port's first argument must be a String");
273 }
274 if (!ServerCredentials::HasInstance(args[1])) {
275 return NanThrowTypeError(
276 "addSecureHttp2Port's second argument must be ServerCredentials");
murgatroid99e5061512015-01-12 18:14:35 -0800277 }
278 Server *server = ObjectWrap::Unwrap<Server>(args.This());
murgatroid99cd35c4c2015-05-28 13:39:25 -0700279 if (server->wrapped_server == NULL) {
280 return NanThrowError(
281 "addSecureHttp2Port cannot be called on a shut down Server");
282 }
murgatroid99da02a672015-03-02 17:28:02 -0800283 ServerCredentials *creds = ObjectWrap::Unwrap<ServerCredentials>(
284 args[1]->ToObject());
murgatroid99d2f20b22015-01-21 11:55:39 -0800285 NanReturnValue(NanNew<Number>(grpc_server_add_secure_http2_port(
murgatroid99da02a672015-03-02 17:28:02 -0800286 server->wrapped_server, *NanUtf8String(args[0]),
287 creds->GetWrappedServerCredentials())));
murgatroid99e5061512015-01-12 18:14:35 -0800288}
289
290NAN_METHOD(Server::Start) {
291 NanScope();
292 if (!HasInstance(args.This())) {
293 return NanThrowTypeError("start can only be called on a Server");
294 }
295 Server *server = ObjectWrap::Unwrap<Server>(args.This());
murgatroid99cd35c4c2015-05-28 13:39:25 -0700296 if (server->wrapped_server == NULL) {
297 return NanThrowError("start cannot be called on a shut down Server");
298 }
murgatroid99e5061512015-01-12 18:14:35 -0800299 grpc_server_start(server->wrapped_server);
300 NanReturnUndefined();
301}
302
murgatroid99cd35c4c2015-05-28 13:39:25 -0700303NAN_METHOD(ShutdownCallback) {
304 NanReturnUndefined();
305}
306
murgatroid99e5061512015-01-12 18:14:35 -0800307NAN_METHOD(Server::Shutdown) {
308 NanScope();
309 if (!HasInstance(args.This())) {
310 return NanThrowTypeError("shutdown can only be called on a Server");
311 }
312 Server *server = ObjectWrap::Unwrap<Server>(args.This());
murgatroid99cd35c4c2015-05-28 13:39:25 -0700313 server->ShutdownServer();
murgatroid99e5061512015-01-12 18:14:35 -0800314 NanReturnUndefined();
315}
316
317} // namespace node
Craig Tiller190d3602015-02-18 09:23:38 -0800318} // namespace grpc