blob: e3a0a5ad80595bca51cff582a41cec2b2079ff2b [file] [log] [blame]
nnoble097ef9b2014-12-01 17:06:10 -08001/*
2 *
Craig Tiller06059952015-02-18 08:34:56 -08003 * Copyright 2015, Google Inc.
nnoble097ef9b2014-12-01 17:06:10 -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
34#include "rb_server.h"
35
Nicolas "Pixel" Noble357cb812015-05-14 05:33:43 +020036#include <ruby/ruby.h>
nnoble097ef9b2014-12-01 17:06:10 -080037
38#include <grpc/grpc.h>
nnoble0c475f02014-12-05 15:37:39 -080039#include <grpc/grpc_security.h>
nnoble097ef9b2014-12-01 17:06:10 -080040#include "rb_call.h"
41#include "rb_channel_args.h"
42#include "rb_completion_queue.h"
nnoble0c475f02014-12-05 15:37:39 -080043#include "rb_server_credentials.h"
nnoble097ef9b2014-12-01 17:06:10 -080044#include "rb_grpc.h"
45
Yuki Yugui Sonodaa7d369e2015-04-11 11:48:36 +090046/* grpc_rb_cServer is the ruby class that proxies grpc_server. */
Yuki Yugui Sonoda3c88e5d2015-04-16 20:09:00 +090047static VALUE grpc_rb_cServer = Qnil;
nnoble097ef9b2014-12-01 17:06:10 -080048
Tim Emiola48b36b52015-03-28 15:15:03 -070049/* id_at is the constructor method of the ruby standard Time class. */
50static ID id_at;
51
nnoble097ef9b2014-12-01 17:06:10 -080052/* grpc_rb_server wraps a grpc_server. It provides a peer ruby object,
nnoble0c475f02014-12-05 15:37:39 -080053 'mark' to minimize copying when a server is created from ruby. */
nnoble097ef9b2014-12-01 17:06:10 -080054typedef struct grpc_rb_server {
55 /* Holder of ruby objects involved in constructing the server */
56 VALUE mark;
57 /* The actual server */
58 grpc_server *wrapped;
59} grpc_rb_server;
60
61/* Destroys server instances. */
62static void grpc_rb_server_free(void *p) {
63 grpc_rb_server *svr = NULL;
64 if (p == NULL) {
65 return;
66 };
67 svr = (grpc_rb_server *)p;
68
69 /* Deletes the wrapped object if the mark object is Qnil, which indicates
nnoble0c475f02014-12-05 15:37:39 -080070 that no other object is the actual owner. */
murgatroid99fa0fa182015-07-07 18:02:00 -070071 /* grpc_server_shutdown does not exist. Change this to something that does
72 or delete it */
nnoble097ef9b2014-12-01 17:06:10 -080073 if (svr->wrapped != NULL && svr->mark == Qnil) {
murgatroid99fa0fa182015-07-07 18:02:00 -070074 // grpc_server_shutdown(svr->wrapped);
75 // Aborting to indicate a bug
76 abort();
nnoble097ef9b2014-12-01 17:06:10 -080077 grpc_server_destroy(svr->wrapped);
78 }
79
80 xfree(p);
81}
82
83/* Protects the mark object from GC */
84static void grpc_rb_server_mark(void *p) {
85 grpc_rb_server *server = NULL;
86 if (p == NULL) {
87 return;
88 }
89 server = (grpc_rb_server *)p;
90 if (server->mark != Qnil) {
91 rb_gc_mark(server->mark);
92 }
93}
94
Yuki Yugui Sonoda9232f122015-04-12 16:39:37 +090095static const rb_data_type_t grpc_rb_server_data_type = {
96 "grpc_server",
murgatroid9987afb5d2015-07-16 16:01:02 -070097 {grpc_rb_server_mark, grpc_rb_server_free, GRPC_RB_MEMSIZE_UNAVAILABLE,
98 {NULL, NULL}},
Yuki Yugui Sonoda9232f122015-04-12 16:39:37 +090099 NULL,
100 NULL,
101 /* It is unsafe to specify RUBY_TYPED_FREE_IMMEDIATELY because the free function would block
102 * and we might want to unlock GVL
103 * TODO(yugui) Unlock GVL?
104 */
105 0};
106
nnoble097ef9b2014-12-01 17:06:10 -0800107/* Allocates grpc_rb_server instances. */
108static VALUE grpc_rb_server_alloc(VALUE cls) {
109 grpc_rb_server *wrapper = ALLOC(grpc_rb_server);
110 wrapper->wrapped = NULL;
111 wrapper->mark = Qnil;
Yuki Yugui Sonoda9232f122015-04-12 16:39:37 +0900112 return TypedData_Wrap_Struct(cls, &grpc_rb_server_data_type, wrapper);
nnoble097ef9b2014-12-01 17:06:10 -0800113}
114
nnoble0c475f02014-12-05 15:37:39 -0800115/*
116 call-seq:
117 cq = CompletionQueue.new
Tim Emiola3a0d9762015-03-05 12:43:24 -0800118 server = Server.new(cq, {'arg1': 'value1'})
nnoble0c475f02014-12-05 15:37:39 -0800119
120 Initializes server instances. */
Tim Emiola3a0d9762015-03-05 12:43:24 -0800121static VALUE grpc_rb_server_init(VALUE self, VALUE cqueue, VALUE channel_args) {
nnoble0c475f02014-12-05 15:37:39 -0800122 grpc_completion_queue *cq = NULL;
nnoble097ef9b2014-12-01 17:06:10 -0800123 grpc_rb_server *wrapper = NULL;
124 grpc_server *srv = NULL;
125 grpc_channel_args args;
126 MEMZERO(&args, grpc_channel_args, 1);
nnoble0c475f02014-12-05 15:37:39 -0800127 cq = grpc_rb_get_wrapped_completion_queue(cqueue);
Yuki Yugui Sonoda9232f122015-04-12 16:39:37 +0900128 TypedData_Get_Struct(self, grpc_rb_server, &grpc_rb_server_data_type,
129 wrapper);
nnoble097ef9b2014-12-01 17:06:10 -0800130 grpc_rb_hash_convert_to_channel_args(channel_args, &args);
Craig Tiller997fab62015-05-08 07:39:04 -0700131 srv = grpc_server_create(&args);
nnoble0c475f02014-12-05 15:37:39 -0800132
nnoble097ef9b2014-12-01 17:06:10 -0800133 if (args.args != NULL) {
Craig Tillerb5dcec52015-01-13 11:13:42 -0800134 xfree(args.args); /* Allocated by grpc_rb_hash_convert_to_channel_args */
nnoble097ef9b2014-12-01 17:06:10 -0800135 }
136 if (srv == NULL) {
137 rb_raise(rb_eRuntimeError, "could not create a gRPC server, not sure why");
138 }
Craig Tiller997fab62015-05-08 07:39:04 -0700139 grpc_server_register_completion_queue(srv, cq);
nnoble097ef9b2014-12-01 17:06:10 -0800140 wrapper->wrapped = srv;
141
142 /* Add the cq as the server's mark object. This ensures the ruby cq can't be
nnoble0c475f02014-12-05 15:37:39 -0800143 GCed before the server */
nnoble097ef9b2014-12-01 17:06:10 -0800144 wrapper->mark = cqueue;
145 return self;
146}
147
148/* Clones Server instances.
149
150 Gives Server a consistent implementation of Ruby's object copy/dup
151 protocol. */
152static VALUE grpc_rb_server_init_copy(VALUE copy, VALUE orig) {
153 grpc_rb_server *orig_srv = NULL;
154 grpc_rb_server *copy_srv = NULL;
155
156 if (copy == orig) {
157 return copy;
158 }
159
160 /* Raise an error if orig is not a server object or a subclass. */
161 if (TYPE(orig) != T_DATA ||
162 RDATA(orig)->dfree != (RUBY_DATA_FUNC)grpc_rb_server_free) {
Yuki Yugui Sonodaa7d369e2015-04-11 11:48:36 +0900163 rb_raise(rb_eTypeError, "not a %s", rb_obj_classname(grpc_rb_cServer));
nnoble097ef9b2014-12-01 17:06:10 -0800164 }
165
Yuki Yugui Sonoda9232f122015-04-12 16:39:37 +0900166 TypedData_Get_Struct(orig, grpc_rb_server, &grpc_rb_server_data_type,
167 orig_srv);
168 TypedData_Get_Struct(copy, grpc_rb_server, &grpc_rb_server_data_type,
169 copy_srv);
nnoble097ef9b2014-12-01 17:06:10 -0800170
171 /* use ruby's MEMCPY to make a byte-for-byte copy of the server wrapper
nnoble0c475f02014-12-05 15:37:39 -0800172 object. */
nnoble097ef9b2014-12-01 17:06:10 -0800173 MEMCPY(copy_srv, orig_srv, grpc_rb_server, 1);
174 return copy;
175}
176
Tim Emiola48b36b52015-03-28 15:15:03 -0700177/* request_call_stack holds various values used by the
178 * grpc_rb_server_request_call function */
179typedef struct request_call_stack {
180 grpc_call_details details;
181 grpc_metadata_array md_ary;
182} request_call_stack;
183
184/* grpc_request_call_stack_init ensures the request_call_stack is properly
185 * initialized */
186static void grpc_request_call_stack_init(request_call_stack* st) {
187 MEMZERO(st, request_call_stack, 1);
188 grpc_metadata_array_init(&st->md_ary);
189 grpc_call_details_init(&st->details);
190 st->details.method = NULL;
191 st->details.host = NULL;
192}
193
194/* grpc_request_call_stack_cleanup ensures the request_call_stack is properly
195 * cleaned up */
196static void grpc_request_call_stack_cleanup(request_call_stack* st) {
197 grpc_metadata_array_destroy(&st->md_ary);
198 grpc_call_details_destroy(&st->details);
199}
200
201/* call-seq:
202 cq = CompletionQueue.new
203 tag = Object.new
204 timeout = 10
205 server.request_call(cqueue, tag, timeout)
206
207 Requests notification of a new call on a server. */
208static VALUE grpc_rb_server_request_call(VALUE self, VALUE cqueue,
209 VALUE tag_new, VALUE timeout) {
nnoble097ef9b2014-12-01 17:06:10 -0800210 grpc_rb_server *s = NULL;
Tim Emiola48b36b52015-03-28 15:15:03 -0700211 grpc_call *call = NULL;
Craig Tillerc4440d92015-05-08 16:52:51 -0700212 grpc_event ev;
Tim Emiola48b36b52015-03-28 15:15:03 -0700213 grpc_call_error err;
214 request_call_stack st;
215 VALUE result;
Yuki Yugui Sonoda9232f122015-04-12 16:39:37 +0900216 TypedData_Get_Struct(self, grpc_rb_server, &grpc_rb_server_data_type, s);
nnoble097ef9b2014-12-01 17:06:10 -0800217 if (s->wrapped == NULL) {
Tim Emiolab1fa5d42015-06-11 09:35:06 -0700218 rb_raise(rb_eRuntimeError, "destroyed!");
Tim Emiola48b36b52015-03-28 15:15:03 -0700219 return Qnil;
nnoble097ef9b2014-12-01 17:06:10 -0800220 } else {
Tim Emiola48b36b52015-03-28 15:15:03 -0700221 grpc_request_call_stack_init(&st);
222 /* call grpc_server_request_call, then wait for it to complete using
223 * pluck_event */
224 err = grpc_server_request_call(
225 s->wrapped, &call, &st.details, &st.md_ary,
226 grpc_rb_get_wrapped_completion_queue(cqueue),
Craig Tiller997fab62015-05-08 07:39:04 -0700227 grpc_rb_get_wrapped_completion_queue(cqueue),
Tim Emiola48b36b52015-03-28 15:15:03 -0700228 ROBJECT(tag_new));
nnoble097ef9b2014-12-01 17:06:10 -0800229 if (err != GRPC_CALL_OK) {
Tim Emiola48b36b52015-03-28 15:15:03 -0700230 grpc_request_call_stack_cleanup(&st);
Yuki Yugui Sonodaa7d369e2015-04-11 11:48:36 +0900231 rb_raise(grpc_rb_eCallError,
232 "grpc_server_request_call failed: %s (code=%d)",
nnoble097ef9b2014-12-01 17:06:10 -0800233 grpc_call_error_detail_of(err), err);
Tim Emiola48b36b52015-03-28 15:15:03 -0700234 return Qnil;
nnoble097ef9b2014-12-01 17:06:10 -0800235 }
Tim Emiola48b36b52015-03-28 15:15:03 -0700236 ev = grpc_rb_completion_queue_pluck_event(cqueue, tag_new, timeout);
Craig Tillerc4440d92015-05-08 16:52:51 -0700237 if (ev.type == GRPC_QUEUE_TIMEOUT) {
Tim Emiola48b36b52015-03-28 15:15:03 -0700238 grpc_request_call_stack_cleanup(&st);
239 return Qnil;
240 }
Craig Tillerc4440d92015-05-08 16:52:51 -0700241 if (!ev.success) {
Tim Emiola48b36b52015-03-28 15:15:03 -0700242 grpc_request_call_stack_cleanup(&st);
Craig Tillerc4440d92015-05-08 16:52:51 -0700243 rb_raise(grpc_rb_eCallError, "request_call completion failed");
Tim Emiola48b36b52015-03-28 15:15:03 -0700244 return Qnil;
245 }
246
247 /* build the NewServerRpc struct result */
248 result = rb_struct_new(
Yuki Yugui Sonodaa7d369e2015-04-11 11:48:36 +0900249 grpc_rb_sNewServerRpc,
Tim Emiola48b36b52015-03-28 15:15:03 -0700250 rb_str_new2(st.details.method),
251 rb_str_new2(st.details.host),
252 rb_funcall(rb_cTime, id_at, 2, INT2NUM(st.details.deadline.tv_sec),
253 INT2NUM(st.details.deadline.tv_nsec)),
254 grpc_rb_md_ary_to_h(&st.md_ary),
255 grpc_rb_wrap_call(call),
256 NULL);
Tim Emiola48b36b52015-03-28 15:15:03 -0700257 grpc_request_call_stack_cleanup(&st);
258 return result;
nnoble097ef9b2014-12-01 17:06:10 -0800259 }
260 return Qnil;
261}
262
263static VALUE grpc_rb_server_start(VALUE self) {
264 grpc_rb_server *s = NULL;
Yuki Yugui Sonoda9232f122015-04-12 16:39:37 +0900265 TypedData_Get_Struct(self, grpc_rb_server, &grpc_rb_server_data_type, s);
nnoble097ef9b2014-12-01 17:06:10 -0800266 if (s->wrapped == NULL) {
Tim Emiolab1fa5d42015-06-11 09:35:06 -0700267 rb_raise(rb_eRuntimeError, "destroyed!");
nnoble097ef9b2014-12-01 17:06:10 -0800268 } else {
269 grpc_server_start(s->wrapped);
270 }
271 return Qnil;
272}
273
Tim Emiolab1fa5d42015-06-11 09:35:06 -0700274/*
275 call-seq:
276 cq = CompletionQueue.new
277 server = Server.new(cq, {'arg1': 'value1'})
278 ... // do stuff with server
279 ...
280 ... // to shutdown the server
281 server.destroy(cq)
282
283 ... // to shutdown the server with a timeout
284 server.destroy(cq, timeout)
285
286 Destroys server instances. */
287static VALUE grpc_rb_server_destroy(int argc, VALUE *argv, VALUE self) {
288 VALUE cqueue = Qnil;
289 VALUE timeout = Qnil;
290 grpc_completion_queue *cq = NULL;
291 grpc_event ev;
nnoble097ef9b2014-12-01 17:06:10 -0800292 grpc_rb_server *s = NULL;
Tim Emiolab1fa5d42015-06-11 09:35:06 -0700293
294 /* "11" == 1 mandatory args, 1 (timeout) is optional */
295 rb_scan_args(argc, argv, "11", &cqueue, &timeout);
296 cq = grpc_rb_get_wrapped_completion_queue(cqueue);
Yuki Yugui Sonoda9232f122015-04-12 16:39:37 +0900297 TypedData_Get_Struct(self, grpc_rb_server, &grpc_rb_server_data_type, s);
Tim Emiolab1fa5d42015-06-11 09:35:06 -0700298
nnoble097ef9b2014-12-01 17:06:10 -0800299 if (s->wrapped != NULL) {
Tim Emiolab1fa5d42015-06-11 09:35:06 -0700300 grpc_server_shutdown_and_notify(s->wrapped, cq, NULL);
301 ev = grpc_rb_completion_queue_pluck_event(cqueue, Qnil, timeout);
302
303 if (!ev.success) {
304 rb_warn("server shutdown failed, there will be a LEAKED object warning");
305 return Qnil;
306 /*
307 TODO: renable the rb_raise below.
308
309 At the moment if the timeout is INFINITE_FUTURE as recommended, the
310 pluck blocks forever, even though
311
312 the outstanding server_request_calls correctly fail on the other
313 thread that they are running on.
314
315 it's almost as if calls that fail on the other thread do not get
316 cleaned up by shutdown request, even though it caused htem to
317 terminate.
318
319 rb_raise(rb_eRuntimeError, "grpc server shutdown did not succeed");
320 return Qnil;
321
322 The workaround is just to use a timeout and return without really
323 shutting down the server, and rely on the grpc core garbage collection
324 it down as a 'LEAKED OBJECT'.
325
326 */
327 }
nnoble097ef9b2014-12-01 17:06:10 -0800328 grpc_server_destroy(s->wrapped);
329 s->wrapped = NULL;
nnoble097ef9b2014-12-01 17:06:10 -0800330 }
331 return Qnil;
332}
333
nnoble0c475f02014-12-05 15:37:39 -0800334/*
335 call-seq:
336 // insecure port
337 insecure_server = Server.new(cq, {'arg1': 'value1'})
remi Taylor47b7bd92015-05-24 15:10:01 -0700338 insecure_server.add_http2_port('mydomain:50051')
nnoble0c475f02014-12-05 15:37:39 -0800339
340 // secure port
341 server_creds = ...
Tim Emiola3a0d9762015-03-05 12:43:24 -0800342 secure_server = Server.new(cq, {'arg1': 'value1'})
remi Taylor47b7bd92015-05-24 15:10:01 -0700343 secure_server.add_http_port('mydomain:50051', server_creds)
nnoble0c475f02014-12-05 15:37:39 -0800344
345 Adds a http2 port to server */
346static VALUE grpc_rb_server_add_http2_port(int argc, VALUE *argv, VALUE self) {
347 VALUE port = Qnil;
Tim Emiola3a0d9762015-03-05 12:43:24 -0800348 VALUE rb_creds = Qnil;
nnoble097ef9b2014-12-01 17:06:10 -0800349 grpc_rb_server *s = NULL;
Tim Emiola3a0d9762015-03-05 12:43:24 -0800350 grpc_server_credentials *creds = NULL;
Tim Emiola0a7d8582015-01-26 12:30:51 -0800351 int recvd_port = 0;
nnoble0c475f02014-12-05 15:37:39 -0800352
Tim Emiola3a0d9762015-03-05 12:43:24 -0800353 /* "11" == 1 mandatory args, 1 (rb_creds) is optional */
354 rb_scan_args(argc, argv, "11", &port, &rb_creds);
nnoble0c475f02014-12-05 15:37:39 -0800355
Yuki Yugui Sonoda9232f122015-04-12 16:39:37 +0900356 TypedData_Get_Struct(self, grpc_rb_server, &grpc_rb_server_data_type, s);
nnoble097ef9b2014-12-01 17:06:10 -0800357 if (s->wrapped == NULL) {
Tim Emiolab1fa5d42015-06-11 09:35:06 -0700358 rb_raise(rb_eRuntimeError, "destroyed!");
nnoble0c475f02014-12-05 15:37:39 -0800359 return Qnil;
Tim Emiola3a0d9762015-03-05 12:43:24 -0800360 } else if (rb_creds == Qnil) {
Tim Emiola0a7d8582015-01-26 12:30:51 -0800361 recvd_port = grpc_server_add_http2_port(s->wrapped, StringValueCStr(port));
362 if (recvd_port == 0) {
nnoble0c475f02014-12-05 15:37:39 -0800363 rb_raise(rb_eRuntimeError,
364 "could not add port %s to server, not sure why",
365 StringValueCStr(port));
366 }
Tim Emiola3a0d9762015-03-05 12:43:24 -0800367 } else {
368 creds = grpc_rb_get_wrapped_server_credentials(rb_creds);
Tim Emiola0a7d8582015-01-26 12:30:51 -0800369 recvd_port =
Tim Emiola3a0d9762015-03-05 12:43:24 -0800370 grpc_server_add_secure_http2_port(s->wrapped, StringValueCStr(port),
Tim Emiolab1fa5d42015-06-11 09:35:06 -0700371 creds);
Tim Emiola0a7d8582015-01-26 12:30:51 -0800372 if (recvd_port == 0) {
nnoble0c475f02014-12-05 15:37:39 -0800373 rb_raise(rb_eRuntimeError,
374 "could not add secure port %s to server, not sure why",
nnoble097ef9b2014-12-01 17:06:10 -0800375 StringValueCStr(port));
376 }
377 }
Tim Emiola0a7d8582015-01-26 12:30:51 -0800378 return INT2NUM(recvd_port);
nnoble097ef9b2014-12-01 17:06:10 -0800379}
380
Tim Emiola409e6c82015-02-17 17:46:35 -0800381void Init_grpc_server() {
Yuki Yugui Sonodaa7d369e2015-04-11 11:48:36 +0900382 grpc_rb_cServer =
383 rb_define_class_under(grpc_rb_mGrpcCore, "Server", rb_cObject);
nnoble097ef9b2014-12-01 17:06:10 -0800384
385 /* Allocates an object managed by the ruby runtime */
Yuki Yugui Sonodaa7d369e2015-04-11 11:48:36 +0900386 rb_define_alloc_func(grpc_rb_cServer, grpc_rb_server_alloc);
nnoble097ef9b2014-12-01 17:06:10 -0800387
388 /* Provides a ruby constructor and support for dup/clone. */
Yuki Yugui Sonodaa7d369e2015-04-11 11:48:36 +0900389 rb_define_method(grpc_rb_cServer, "initialize", grpc_rb_server_init, 2);
390 rb_define_method(grpc_rb_cServer, "initialize_copy",
391 grpc_rb_server_init_copy, 1);
nnoble097ef9b2014-12-01 17:06:10 -0800392
393 /* Add the server methods. */
Yuki Yugui Sonodaa7d369e2015-04-11 11:48:36 +0900394 rb_define_method(grpc_rb_cServer, "request_call",
395 grpc_rb_server_request_call, 3);
396 rb_define_method(grpc_rb_cServer, "start", grpc_rb_server_start, 0);
Tim Emiolab1fa5d42015-06-11 09:35:06 -0700397 rb_define_method(grpc_rb_cServer, "destroy", grpc_rb_server_destroy, -1);
Yuki Yugui Sonodaa7d369e2015-04-11 11:48:36 +0900398 rb_define_alias(grpc_rb_cServer, "close", "destroy");
399 rb_define_method(grpc_rb_cServer, "add_http2_port",
400 grpc_rb_server_add_http2_port,
nnoble0c475f02014-12-05 15:37:39 -0800401 -1);
Tim Emiola48b36b52015-03-28 15:15:03 -0700402 id_at = rb_intern("at");
nnoble097ef9b2014-12-01 17:06:10 -0800403}
404
405/* Gets the wrapped server from the ruby wrapper */
Craig Tillerb5dcec52015-01-13 11:13:42 -0800406grpc_server *grpc_rb_get_wrapped_server(VALUE v) {
nnoble097ef9b2014-12-01 17:06:10 -0800407 grpc_rb_server *wrapper = NULL;
Yuki Yugui Sonoda9232f122015-04-12 16:39:37 +0900408 TypedData_Get_Struct(v, grpc_rb_server, &grpc_rb_server_data_type, wrapper);
nnoble097ef9b2014-12-01 17:06:10 -0800409 return wrapper->wrapped;
410}