nnoble | 097ef9b | 2014-12-01 17:06:10 -0800 | [diff] [blame] | 1 | /* |
| 2 | * |
Craig Tiller | 0605995 | 2015-02-18 08:34:56 -0800 | [diff] [blame] | 3 | * Copyright 2015, Google Inc. |
nnoble | 097ef9b | 2014-12-01 17:06:10 -0800 | [diff] [blame] | 4 | * 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" Noble | 357cb81 | 2015-05-14 05:33:43 +0200 | [diff] [blame] | 36 | #include <ruby/ruby.h> |
nnoble | 097ef9b | 2014-12-01 17:06:10 -0800 | [diff] [blame] | 37 | |
| 38 | #include <grpc/grpc.h> |
nnoble | 0c475f0 | 2014-12-05 15:37:39 -0800 | [diff] [blame] | 39 | #include <grpc/grpc_security.h> |
nnoble | 097ef9b | 2014-12-01 17:06:10 -0800 | [diff] [blame] | 40 | #include "rb_call.h" |
| 41 | #include "rb_channel_args.h" |
| 42 | #include "rb_completion_queue.h" |
nnoble | 0c475f0 | 2014-12-05 15:37:39 -0800 | [diff] [blame] | 43 | #include "rb_server_credentials.h" |
nnoble | 097ef9b | 2014-12-01 17:06:10 -0800 | [diff] [blame] | 44 | #include "rb_grpc.h" |
| 45 | |
Yuki Yugui Sonoda | a7d369e | 2015-04-11 11:48:36 +0900 | [diff] [blame] | 46 | /* grpc_rb_cServer is the ruby class that proxies grpc_server. */ |
Yuki Yugui Sonoda | 3c88e5d | 2015-04-16 20:09:00 +0900 | [diff] [blame] | 47 | static VALUE grpc_rb_cServer = Qnil; |
nnoble | 097ef9b | 2014-12-01 17:06:10 -0800 | [diff] [blame] | 48 | |
Tim Emiola | 48b36b5 | 2015-03-28 15:15:03 -0700 | [diff] [blame] | 49 | /* id_at is the constructor method of the ruby standard Time class. */ |
| 50 | static ID id_at; |
| 51 | |
nnoble | 097ef9b | 2014-12-01 17:06:10 -0800 | [diff] [blame] | 52 | /* grpc_rb_server wraps a grpc_server. It provides a peer ruby object, |
nnoble | 0c475f0 | 2014-12-05 15:37:39 -0800 | [diff] [blame] | 53 | 'mark' to minimize copying when a server is created from ruby. */ |
nnoble | 097ef9b | 2014-12-01 17:06:10 -0800 | [diff] [blame] | 54 | typedef 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. */ |
| 62 | static 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 |
nnoble | 0c475f0 | 2014-12-05 15:37:39 -0800 | [diff] [blame] | 70 | that no other object is the actual owner. */ |
murgatroid99 | fa0fa18 | 2015-07-07 18:02:00 -0700 | [diff] [blame] | 71 | /* grpc_server_shutdown does not exist. Change this to something that does |
| 72 | or delete it */ |
nnoble | 097ef9b | 2014-12-01 17:06:10 -0800 | [diff] [blame] | 73 | if (svr->wrapped != NULL && svr->mark == Qnil) { |
murgatroid99 | fa0fa18 | 2015-07-07 18:02:00 -0700 | [diff] [blame] | 74 | // grpc_server_shutdown(svr->wrapped); |
| 75 | // Aborting to indicate a bug |
| 76 | abort(); |
nnoble | 097ef9b | 2014-12-01 17:06:10 -0800 | [diff] [blame] | 77 | grpc_server_destroy(svr->wrapped); |
| 78 | } |
| 79 | |
| 80 | xfree(p); |
| 81 | } |
| 82 | |
| 83 | /* Protects the mark object from GC */ |
| 84 | static 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 Sonoda | 9232f12 | 2015-04-12 16:39:37 +0900 | [diff] [blame] | 95 | static const rb_data_type_t grpc_rb_server_data_type = { |
| 96 | "grpc_server", |
murgatroid99 | 87afb5d | 2015-07-16 16:01:02 -0700 | [diff] [blame] | 97 | {grpc_rb_server_mark, grpc_rb_server_free, GRPC_RB_MEMSIZE_UNAVAILABLE, |
| 98 | {NULL, NULL}}, |
Yuki Yugui Sonoda | 9232f12 | 2015-04-12 16:39:37 +0900 | [diff] [blame] | 99 | 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 | |
nnoble | 097ef9b | 2014-12-01 17:06:10 -0800 | [diff] [blame] | 107 | /* Allocates grpc_rb_server instances. */ |
| 108 | static 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 Sonoda | 9232f12 | 2015-04-12 16:39:37 +0900 | [diff] [blame] | 112 | return TypedData_Wrap_Struct(cls, &grpc_rb_server_data_type, wrapper); |
nnoble | 097ef9b | 2014-12-01 17:06:10 -0800 | [diff] [blame] | 113 | } |
| 114 | |
nnoble | 0c475f0 | 2014-12-05 15:37:39 -0800 | [diff] [blame] | 115 | /* |
| 116 | call-seq: |
| 117 | cq = CompletionQueue.new |
Tim Emiola | 3a0d976 | 2015-03-05 12:43:24 -0800 | [diff] [blame] | 118 | server = Server.new(cq, {'arg1': 'value1'}) |
nnoble | 0c475f0 | 2014-12-05 15:37:39 -0800 | [diff] [blame] | 119 | |
| 120 | Initializes server instances. */ |
Tim Emiola | 3a0d976 | 2015-03-05 12:43:24 -0800 | [diff] [blame] | 121 | static VALUE grpc_rb_server_init(VALUE self, VALUE cqueue, VALUE channel_args) { |
nnoble | 0c475f0 | 2014-12-05 15:37:39 -0800 | [diff] [blame] | 122 | grpc_completion_queue *cq = NULL; |
nnoble | 097ef9b | 2014-12-01 17:06:10 -0800 | [diff] [blame] | 123 | grpc_rb_server *wrapper = NULL; |
| 124 | grpc_server *srv = NULL; |
| 125 | grpc_channel_args args; |
| 126 | MEMZERO(&args, grpc_channel_args, 1); |
nnoble | 0c475f0 | 2014-12-05 15:37:39 -0800 | [diff] [blame] | 127 | cq = grpc_rb_get_wrapped_completion_queue(cqueue); |
Yuki Yugui Sonoda | 9232f12 | 2015-04-12 16:39:37 +0900 | [diff] [blame] | 128 | TypedData_Get_Struct(self, grpc_rb_server, &grpc_rb_server_data_type, |
| 129 | wrapper); |
nnoble | 097ef9b | 2014-12-01 17:06:10 -0800 | [diff] [blame] | 130 | grpc_rb_hash_convert_to_channel_args(channel_args, &args); |
Craig Tiller | 997fab6 | 2015-05-08 07:39:04 -0700 | [diff] [blame] | 131 | srv = grpc_server_create(&args); |
nnoble | 0c475f0 | 2014-12-05 15:37:39 -0800 | [diff] [blame] | 132 | |
nnoble | 097ef9b | 2014-12-01 17:06:10 -0800 | [diff] [blame] | 133 | if (args.args != NULL) { |
Craig Tiller | b5dcec5 | 2015-01-13 11:13:42 -0800 | [diff] [blame] | 134 | xfree(args.args); /* Allocated by grpc_rb_hash_convert_to_channel_args */ |
nnoble | 097ef9b | 2014-12-01 17:06:10 -0800 | [diff] [blame] | 135 | } |
| 136 | if (srv == NULL) { |
| 137 | rb_raise(rb_eRuntimeError, "could not create a gRPC server, not sure why"); |
| 138 | } |
Craig Tiller | 997fab6 | 2015-05-08 07:39:04 -0700 | [diff] [blame] | 139 | grpc_server_register_completion_queue(srv, cq); |
nnoble | 097ef9b | 2014-12-01 17:06:10 -0800 | [diff] [blame] | 140 | wrapper->wrapped = srv; |
| 141 | |
| 142 | /* Add the cq as the server's mark object. This ensures the ruby cq can't be |
nnoble | 0c475f0 | 2014-12-05 15:37:39 -0800 | [diff] [blame] | 143 | GCed before the server */ |
nnoble | 097ef9b | 2014-12-01 17:06:10 -0800 | [diff] [blame] | 144 | 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. */ |
| 152 | static 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 Sonoda | a7d369e | 2015-04-11 11:48:36 +0900 | [diff] [blame] | 163 | rb_raise(rb_eTypeError, "not a %s", rb_obj_classname(grpc_rb_cServer)); |
nnoble | 097ef9b | 2014-12-01 17:06:10 -0800 | [diff] [blame] | 164 | } |
| 165 | |
Yuki Yugui Sonoda | 9232f12 | 2015-04-12 16:39:37 +0900 | [diff] [blame] | 166 | 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); |
nnoble | 097ef9b | 2014-12-01 17:06:10 -0800 | [diff] [blame] | 170 | |
| 171 | /* use ruby's MEMCPY to make a byte-for-byte copy of the server wrapper |
nnoble | 0c475f0 | 2014-12-05 15:37:39 -0800 | [diff] [blame] | 172 | object. */ |
nnoble | 097ef9b | 2014-12-01 17:06:10 -0800 | [diff] [blame] | 173 | MEMCPY(copy_srv, orig_srv, grpc_rb_server, 1); |
| 174 | return copy; |
| 175 | } |
| 176 | |
Tim Emiola | 48b36b5 | 2015-03-28 15:15:03 -0700 | [diff] [blame] | 177 | /* request_call_stack holds various values used by the |
| 178 | * grpc_rb_server_request_call function */ |
| 179 | typedef 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 */ |
| 186 | static 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 */ |
| 196 | static 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. */ |
| 208 | static VALUE grpc_rb_server_request_call(VALUE self, VALUE cqueue, |
| 209 | VALUE tag_new, VALUE timeout) { |
nnoble | 097ef9b | 2014-12-01 17:06:10 -0800 | [diff] [blame] | 210 | grpc_rb_server *s = NULL; |
Tim Emiola | 48b36b5 | 2015-03-28 15:15:03 -0700 | [diff] [blame] | 211 | grpc_call *call = NULL; |
Craig Tiller | c4440d9 | 2015-05-08 16:52:51 -0700 | [diff] [blame] | 212 | grpc_event ev; |
Tim Emiola | 48b36b5 | 2015-03-28 15:15:03 -0700 | [diff] [blame] | 213 | grpc_call_error err; |
| 214 | request_call_stack st; |
| 215 | VALUE result; |
Yuki Yugui Sonoda | 9232f12 | 2015-04-12 16:39:37 +0900 | [diff] [blame] | 216 | TypedData_Get_Struct(self, grpc_rb_server, &grpc_rb_server_data_type, s); |
nnoble | 097ef9b | 2014-12-01 17:06:10 -0800 | [diff] [blame] | 217 | if (s->wrapped == NULL) { |
Tim Emiola | b1fa5d4 | 2015-06-11 09:35:06 -0700 | [diff] [blame] | 218 | rb_raise(rb_eRuntimeError, "destroyed!"); |
Tim Emiola | 48b36b5 | 2015-03-28 15:15:03 -0700 | [diff] [blame] | 219 | return Qnil; |
nnoble | 097ef9b | 2014-12-01 17:06:10 -0800 | [diff] [blame] | 220 | } else { |
Tim Emiola | 48b36b5 | 2015-03-28 15:15:03 -0700 | [diff] [blame] | 221 | 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 Tiller | 997fab6 | 2015-05-08 07:39:04 -0700 | [diff] [blame] | 227 | grpc_rb_get_wrapped_completion_queue(cqueue), |
Tim Emiola | 48b36b5 | 2015-03-28 15:15:03 -0700 | [diff] [blame] | 228 | ROBJECT(tag_new)); |
nnoble | 097ef9b | 2014-12-01 17:06:10 -0800 | [diff] [blame] | 229 | if (err != GRPC_CALL_OK) { |
Tim Emiola | 48b36b5 | 2015-03-28 15:15:03 -0700 | [diff] [blame] | 230 | grpc_request_call_stack_cleanup(&st); |
Yuki Yugui Sonoda | a7d369e | 2015-04-11 11:48:36 +0900 | [diff] [blame] | 231 | rb_raise(grpc_rb_eCallError, |
| 232 | "grpc_server_request_call failed: %s (code=%d)", |
nnoble | 097ef9b | 2014-12-01 17:06:10 -0800 | [diff] [blame] | 233 | grpc_call_error_detail_of(err), err); |
Tim Emiola | 48b36b5 | 2015-03-28 15:15:03 -0700 | [diff] [blame] | 234 | return Qnil; |
nnoble | 097ef9b | 2014-12-01 17:06:10 -0800 | [diff] [blame] | 235 | } |
Tim Emiola | 48b36b5 | 2015-03-28 15:15:03 -0700 | [diff] [blame] | 236 | ev = grpc_rb_completion_queue_pluck_event(cqueue, tag_new, timeout); |
Craig Tiller | c4440d9 | 2015-05-08 16:52:51 -0700 | [diff] [blame] | 237 | if (ev.type == GRPC_QUEUE_TIMEOUT) { |
Tim Emiola | 48b36b5 | 2015-03-28 15:15:03 -0700 | [diff] [blame] | 238 | grpc_request_call_stack_cleanup(&st); |
| 239 | return Qnil; |
| 240 | } |
Craig Tiller | c4440d9 | 2015-05-08 16:52:51 -0700 | [diff] [blame] | 241 | if (!ev.success) { |
Tim Emiola | 48b36b5 | 2015-03-28 15:15:03 -0700 | [diff] [blame] | 242 | grpc_request_call_stack_cleanup(&st); |
Craig Tiller | c4440d9 | 2015-05-08 16:52:51 -0700 | [diff] [blame] | 243 | rb_raise(grpc_rb_eCallError, "request_call completion failed"); |
Tim Emiola | 48b36b5 | 2015-03-28 15:15:03 -0700 | [diff] [blame] | 244 | return Qnil; |
| 245 | } |
| 246 | |
| 247 | /* build the NewServerRpc struct result */ |
| 248 | result = rb_struct_new( |
Yuki Yugui Sonoda | a7d369e | 2015-04-11 11:48:36 +0900 | [diff] [blame] | 249 | grpc_rb_sNewServerRpc, |
Tim Emiola | 48b36b5 | 2015-03-28 15:15:03 -0700 | [diff] [blame] | 250 | 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 Emiola | 48b36b5 | 2015-03-28 15:15:03 -0700 | [diff] [blame] | 257 | grpc_request_call_stack_cleanup(&st); |
| 258 | return result; |
nnoble | 097ef9b | 2014-12-01 17:06:10 -0800 | [diff] [blame] | 259 | } |
| 260 | return Qnil; |
| 261 | } |
| 262 | |
| 263 | static VALUE grpc_rb_server_start(VALUE self) { |
| 264 | grpc_rb_server *s = NULL; |
Yuki Yugui Sonoda | 9232f12 | 2015-04-12 16:39:37 +0900 | [diff] [blame] | 265 | TypedData_Get_Struct(self, grpc_rb_server, &grpc_rb_server_data_type, s); |
nnoble | 097ef9b | 2014-12-01 17:06:10 -0800 | [diff] [blame] | 266 | if (s->wrapped == NULL) { |
Tim Emiola | b1fa5d4 | 2015-06-11 09:35:06 -0700 | [diff] [blame] | 267 | rb_raise(rb_eRuntimeError, "destroyed!"); |
nnoble | 097ef9b | 2014-12-01 17:06:10 -0800 | [diff] [blame] | 268 | } else { |
| 269 | grpc_server_start(s->wrapped); |
| 270 | } |
| 271 | return Qnil; |
| 272 | } |
| 273 | |
Tim Emiola | b1fa5d4 | 2015-06-11 09:35:06 -0700 | [diff] [blame] | 274 | /* |
| 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. */ |
| 287 | static 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; |
nnoble | 097ef9b | 2014-12-01 17:06:10 -0800 | [diff] [blame] | 292 | grpc_rb_server *s = NULL; |
Tim Emiola | b1fa5d4 | 2015-06-11 09:35:06 -0700 | [diff] [blame] | 293 | |
| 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 Sonoda | 9232f12 | 2015-04-12 16:39:37 +0900 | [diff] [blame] | 297 | TypedData_Get_Struct(self, grpc_rb_server, &grpc_rb_server_data_type, s); |
Tim Emiola | b1fa5d4 | 2015-06-11 09:35:06 -0700 | [diff] [blame] | 298 | |
nnoble | 097ef9b | 2014-12-01 17:06:10 -0800 | [diff] [blame] | 299 | if (s->wrapped != NULL) { |
Tim Emiola | b1fa5d4 | 2015-06-11 09:35:06 -0700 | [diff] [blame] | 300 | 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 | } |
nnoble | 097ef9b | 2014-12-01 17:06:10 -0800 | [diff] [blame] | 328 | grpc_server_destroy(s->wrapped); |
| 329 | s->wrapped = NULL; |
nnoble | 097ef9b | 2014-12-01 17:06:10 -0800 | [diff] [blame] | 330 | } |
| 331 | return Qnil; |
| 332 | } |
| 333 | |
nnoble | 0c475f0 | 2014-12-05 15:37:39 -0800 | [diff] [blame] | 334 | /* |
| 335 | call-seq: |
| 336 | // insecure port |
| 337 | insecure_server = Server.new(cq, {'arg1': 'value1'}) |
remi Taylor | 47b7bd9 | 2015-05-24 15:10:01 -0700 | [diff] [blame] | 338 | insecure_server.add_http2_port('mydomain:50051') |
nnoble | 0c475f0 | 2014-12-05 15:37:39 -0800 | [diff] [blame] | 339 | |
| 340 | // secure port |
| 341 | server_creds = ... |
Tim Emiola | 3a0d976 | 2015-03-05 12:43:24 -0800 | [diff] [blame] | 342 | secure_server = Server.new(cq, {'arg1': 'value1'}) |
remi Taylor | 47b7bd9 | 2015-05-24 15:10:01 -0700 | [diff] [blame] | 343 | secure_server.add_http_port('mydomain:50051', server_creds) |
nnoble | 0c475f0 | 2014-12-05 15:37:39 -0800 | [diff] [blame] | 344 | |
| 345 | Adds a http2 port to server */ |
| 346 | static VALUE grpc_rb_server_add_http2_port(int argc, VALUE *argv, VALUE self) { |
| 347 | VALUE port = Qnil; |
Tim Emiola | 3a0d976 | 2015-03-05 12:43:24 -0800 | [diff] [blame] | 348 | VALUE rb_creds = Qnil; |
nnoble | 097ef9b | 2014-12-01 17:06:10 -0800 | [diff] [blame] | 349 | grpc_rb_server *s = NULL; |
Tim Emiola | 3a0d976 | 2015-03-05 12:43:24 -0800 | [diff] [blame] | 350 | grpc_server_credentials *creds = NULL; |
Tim Emiola | 0a7d858 | 2015-01-26 12:30:51 -0800 | [diff] [blame] | 351 | int recvd_port = 0; |
nnoble | 0c475f0 | 2014-12-05 15:37:39 -0800 | [diff] [blame] | 352 | |
Tim Emiola | 3a0d976 | 2015-03-05 12:43:24 -0800 | [diff] [blame] | 353 | /* "11" == 1 mandatory args, 1 (rb_creds) is optional */ |
| 354 | rb_scan_args(argc, argv, "11", &port, &rb_creds); |
nnoble | 0c475f0 | 2014-12-05 15:37:39 -0800 | [diff] [blame] | 355 | |
Yuki Yugui Sonoda | 9232f12 | 2015-04-12 16:39:37 +0900 | [diff] [blame] | 356 | TypedData_Get_Struct(self, grpc_rb_server, &grpc_rb_server_data_type, s); |
nnoble | 097ef9b | 2014-12-01 17:06:10 -0800 | [diff] [blame] | 357 | if (s->wrapped == NULL) { |
Tim Emiola | b1fa5d4 | 2015-06-11 09:35:06 -0700 | [diff] [blame] | 358 | rb_raise(rb_eRuntimeError, "destroyed!"); |
nnoble | 0c475f0 | 2014-12-05 15:37:39 -0800 | [diff] [blame] | 359 | return Qnil; |
Tim Emiola | 3a0d976 | 2015-03-05 12:43:24 -0800 | [diff] [blame] | 360 | } else if (rb_creds == Qnil) { |
Tim Emiola | 0a7d858 | 2015-01-26 12:30:51 -0800 | [diff] [blame] | 361 | recvd_port = grpc_server_add_http2_port(s->wrapped, StringValueCStr(port)); |
| 362 | if (recvd_port == 0) { |
nnoble | 0c475f0 | 2014-12-05 15:37:39 -0800 | [diff] [blame] | 363 | rb_raise(rb_eRuntimeError, |
| 364 | "could not add port %s to server, not sure why", |
| 365 | StringValueCStr(port)); |
| 366 | } |
Tim Emiola | 3a0d976 | 2015-03-05 12:43:24 -0800 | [diff] [blame] | 367 | } else { |
| 368 | creds = grpc_rb_get_wrapped_server_credentials(rb_creds); |
Tim Emiola | 0a7d858 | 2015-01-26 12:30:51 -0800 | [diff] [blame] | 369 | recvd_port = |
Tim Emiola | 3a0d976 | 2015-03-05 12:43:24 -0800 | [diff] [blame] | 370 | grpc_server_add_secure_http2_port(s->wrapped, StringValueCStr(port), |
Tim Emiola | b1fa5d4 | 2015-06-11 09:35:06 -0700 | [diff] [blame] | 371 | creds); |
Tim Emiola | 0a7d858 | 2015-01-26 12:30:51 -0800 | [diff] [blame] | 372 | if (recvd_port == 0) { |
nnoble | 0c475f0 | 2014-12-05 15:37:39 -0800 | [diff] [blame] | 373 | rb_raise(rb_eRuntimeError, |
| 374 | "could not add secure port %s to server, not sure why", |
nnoble | 097ef9b | 2014-12-01 17:06:10 -0800 | [diff] [blame] | 375 | StringValueCStr(port)); |
| 376 | } |
| 377 | } |
Tim Emiola | 0a7d858 | 2015-01-26 12:30:51 -0800 | [diff] [blame] | 378 | return INT2NUM(recvd_port); |
nnoble | 097ef9b | 2014-12-01 17:06:10 -0800 | [diff] [blame] | 379 | } |
| 380 | |
Tim Emiola | 409e6c8 | 2015-02-17 17:46:35 -0800 | [diff] [blame] | 381 | void Init_grpc_server() { |
Yuki Yugui Sonoda | a7d369e | 2015-04-11 11:48:36 +0900 | [diff] [blame] | 382 | grpc_rb_cServer = |
| 383 | rb_define_class_under(grpc_rb_mGrpcCore, "Server", rb_cObject); |
nnoble | 097ef9b | 2014-12-01 17:06:10 -0800 | [diff] [blame] | 384 | |
| 385 | /* Allocates an object managed by the ruby runtime */ |
Yuki Yugui Sonoda | a7d369e | 2015-04-11 11:48:36 +0900 | [diff] [blame] | 386 | rb_define_alloc_func(grpc_rb_cServer, grpc_rb_server_alloc); |
nnoble | 097ef9b | 2014-12-01 17:06:10 -0800 | [diff] [blame] | 387 | |
| 388 | /* Provides a ruby constructor and support for dup/clone. */ |
Yuki Yugui Sonoda | a7d369e | 2015-04-11 11:48:36 +0900 | [diff] [blame] | 389 | 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); |
nnoble | 097ef9b | 2014-12-01 17:06:10 -0800 | [diff] [blame] | 392 | |
| 393 | /* Add the server methods. */ |
Yuki Yugui Sonoda | a7d369e | 2015-04-11 11:48:36 +0900 | [diff] [blame] | 394 | 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 Emiola | b1fa5d4 | 2015-06-11 09:35:06 -0700 | [diff] [blame] | 397 | rb_define_method(grpc_rb_cServer, "destroy", grpc_rb_server_destroy, -1); |
Yuki Yugui Sonoda | a7d369e | 2015-04-11 11:48:36 +0900 | [diff] [blame] | 398 | 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, |
nnoble | 0c475f0 | 2014-12-05 15:37:39 -0800 | [diff] [blame] | 401 | -1); |
Tim Emiola | 48b36b5 | 2015-03-28 15:15:03 -0700 | [diff] [blame] | 402 | id_at = rb_intern("at"); |
nnoble | 097ef9b | 2014-12-01 17:06:10 -0800 | [diff] [blame] | 403 | } |
| 404 | |
| 405 | /* Gets the wrapped server from the ruby wrapper */ |
Craig Tiller | b5dcec5 | 2015-01-13 11:13:42 -0800 | [diff] [blame] | 406 | grpc_server *grpc_rb_get_wrapped_server(VALUE v) { |
nnoble | 097ef9b | 2014-12-01 17:06:10 -0800 | [diff] [blame] | 407 | grpc_rb_server *wrapper = NULL; |
Yuki Yugui Sonoda | 9232f12 | 2015-04-12 16:39:37 +0900 | [diff] [blame] | 408 | TypedData_Get_Struct(v, grpc_rb_server, &grpc_rb_server_data_type, wrapper); |
nnoble | 097ef9b | 2014-12-01 17:06:10 -0800 | [diff] [blame] | 409 | return wrapper->wrapped; |
| 410 | } |