blob: 8318e127958289910db92d7db0567adb8860e25f [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_grpc.h"
35
36#include <math.h>
Yuki Yugui Sonoda22887912015-04-16 20:57:17 +090037#include <ruby/ruby.h>
38#include <ruby/vm.h>
nnoble097ef9b2014-12-01 17:06:10 -080039#include <sys/time.h>
40
41#include <grpc/grpc.h>
42#include <grpc/support/time.h>
nnoble097ef9b2014-12-01 17:06:10 -080043#include "rb_call.h"
44#include "rb_channel.h"
Tim Emiola9332ea62015-10-27 23:48:29 -070045#include "rb_channel_credentials.h"
nnoble097ef9b2014-12-01 17:06:10 -080046#include "rb_completion_queue.h"
nnoble097ef9b2014-12-01 17:06:10 -080047#include "rb_server.h"
nnoble0c475f02014-12-05 15:37:39 -080048#include "rb_server_credentials.h"
nnoble097ef9b2014-12-01 17:06:10 -080049
Yuki Yugui Sonoda3c88e5d2015-04-16 20:09:00 +090050static VALUE grpc_rb_cTimeVal = Qnil;
nnoble097ef9b2014-12-01 17:06:10 -080051
Yuki Yugui Sonodad441c2e2015-04-11 15:33:58 +090052static rb_data_type_t grpc_rb_timespec_data_type = {
53 "gpr_timespec",
murgatroid9987afb5d2015-07-16 16:01:02 -070054 {GRPC_RB_GC_NOT_MARKED, GRPC_RB_GC_DONT_FREE, GRPC_RB_MEMSIZE_UNAVAILABLE,
55 {NULL, NULL}},
Yuki Yugui Sonodad441c2e2015-04-11 15:33:58 +090056 NULL,
57 NULL,
Tim Emiola9161a822015-11-11 15:58:44 -080058#ifdef RUBY_TYPED_FREE_IMMEDIATELY
59 RUBY_TYPED_FREE_IMMEDIATELY
60#endif
61};
Yuki Yugui Sonodad441c2e2015-04-11 15:33:58 +090062
nnoble097ef9b2014-12-01 17:06:10 -080063/* Alloc func that blocks allocation of a given object by raising an
64 * exception. */
65VALUE grpc_rb_cannot_alloc(VALUE cls) {
66 rb_raise(rb_eTypeError,
67 "allocation of %s only allowed from the gRPC native layer",
68 rb_class2name(cls));
69 return Qnil;
70}
71
72/* Init func that fails by raising an exception. */
73VALUE grpc_rb_cannot_init(VALUE self) {
74 rb_raise(rb_eTypeError,
75 "initialization of %s only allowed from the gRPC native layer",
76 rb_obj_classname(self));
77 return Qnil;
78}
79
80/* Init/Clone func that fails by raising an exception. */
81VALUE grpc_rb_cannot_init_copy(VALUE copy, VALUE self) {
murgatroid9987afb5d2015-07-16 16:01:02 -070082 (void)self;
nnoble097ef9b2014-12-01 17:06:10 -080083 rb_raise(rb_eTypeError,
84 "initialization of %s only allowed from the gRPC native layer",
85 rb_obj_classname(copy));
86 return Qnil;
87}
88
89/* id_tv_{,u}sec are accessor methods on Ruby Time instances. */
90static ID id_tv_sec;
91static ID id_tv_nsec;
92
93/**
Jan Tattermusch88086372015-12-10 10:54:12 -080094 * grpc_rb_time_timeval creates a timeval from a ruby time object.
nnoble097ef9b2014-12-01 17:06:10 -080095 *
96 * This func is copied from ruby source, MRI/source/time.c, which is published
97 * under the same license as the ruby.h, on which the entire extensions is
98 * based.
99 */
100gpr_timespec grpc_rb_time_timeval(VALUE time, int interval) {
101 gpr_timespec t;
102 gpr_timespec *time_const;
103 const char *tstr = interval ? "time interval" : "time";
104 const char *want = " want <secs from epoch>|<Time>|<GRPC::TimeConst.*>";
105
Craig Tiller5a1e7fd2015-07-14 07:14:47 -0700106 t.clock_type = GPR_CLOCK_REALTIME;
nnoble097ef9b2014-12-01 17:06:10 -0800107 switch (TYPE(time)) {
nnoble097ef9b2014-12-01 17:06:10 -0800108 case T_DATA:
Yuki Yugui Sonodaa7d369e2015-04-11 11:48:36 +0900109 if (CLASS_OF(time) == grpc_rb_cTimeVal) {
Yuki Yugui Sonodad441c2e2015-04-11 15:33:58 +0900110 TypedData_Get_Struct(time, gpr_timespec, &grpc_rb_timespec_data_type,
111 time_const);
nnoble097ef9b2014-12-01 17:06:10 -0800112 t = *time_const;
113 } else if (CLASS_OF(time) == rb_cTime) {
Craig Tillerb5dcec52015-01-13 11:13:42 -0800114 t.tv_sec = NUM2INT(rb_funcall(time, id_tv_sec, 0));
nnoble097ef9b2014-12-01 17:06:10 -0800115 t.tv_nsec = NUM2INT(rb_funcall(time, id_tv_nsec, 0));
116 } else {
Craig Tillerb5dcec52015-01-13 11:13:42 -0800117 rb_raise(rb_eTypeError, "bad input: (%s)->c_timeval, got <%s>,%s", tstr,
118 rb_obj_classname(time), want);
nnoble097ef9b2014-12-01 17:06:10 -0800119 }
120 break;
121
122 case T_FIXNUM:
123 t.tv_sec = FIX2LONG(time);
124 if (interval && t.tv_sec < 0)
125 rb_raise(rb_eArgError, "%s must be positive", tstr);
126 t.tv_nsec = 0;
127 break;
128
129 case T_FLOAT:
mattnb9e15632015-02-28 23:45:58 +0900130 if (interval && RFLOAT_VALUE(time) < 0.0)
nnoble097ef9b2014-12-01 17:06:10 -0800131 rb_raise(rb_eArgError, "%s must be positive", tstr);
132 else {
133 double f, d;
134
mattnb9e15632015-02-28 23:45:58 +0900135 d = modf(RFLOAT_VALUE(time), &f);
nnoble097ef9b2014-12-01 17:06:10 -0800136 if (d < 0) {
137 d += 1;
138 f -= 1;
139 }
Jan Tattermusch88086372015-12-10 10:54:12 -0800140 t.tv_sec = (gpr_int64)f;
nnoble097ef9b2014-12-01 17:06:10 -0800141 if (f != t.tv_sec) {
142 rb_raise(rb_eRangeError, "%f out of Time range",
mattnb9e15632015-02-28 23:45:58 +0900143 RFLOAT_VALUE(time));
nnoble097ef9b2014-12-01 17:06:10 -0800144 }
Marcin Wyszynski1a2ac332015-07-23 20:12:33 +0200145 t.tv_nsec = (int)(d * 1e9 + 0.5);
nnoble097ef9b2014-12-01 17:06:10 -0800146 }
147 break;
148
149 case T_BIGNUM:
150 t.tv_sec = NUM2LONG(time);
151 if (interval && t.tv_sec < 0)
152 rb_raise(rb_eArgError, "%s must be positive", tstr);
153 t.tv_nsec = 0;
154 break;
155
156 default:
Craig Tillerb5dcec52015-01-13 11:13:42 -0800157 rb_raise(rb_eTypeError, "bad input: (%s)->c_timeval, got <%s>,%s", tstr,
158 rb_obj_classname(time), want);
nnoble097ef9b2014-12-01 17:06:10 -0800159 break;
160 }
161 return t;
162}
163
Yuki Yugui Sonodaf0eee5f2015-04-16 20:25:28 +0900164static void Init_grpc_status_codes() {
temiola58327912014-12-15 17:51:16 -0800165 /* Constants representing the status codes or grpc_status_code in status.h */
Yuki Yugui Sonodaa7d369e2015-04-11 11:48:36 +0900166 VALUE grpc_rb_mStatusCodes =
167 rb_define_module_under(grpc_rb_mGrpcCore, "StatusCodes");
168 rb_define_const(grpc_rb_mStatusCodes, "OK", INT2NUM(GRPC_STATUS_OK));
169 rb_define_const(grpc_rb_mStatusCodes, "CANCELLED",
170 INT2NUM(GRPC_STATUS_CANCELLED));
171 rb_define_const(grpc_rb_mStatusCodes, "UNKNOWN",
172 INT2NUM(GRPC_STATUS_UNKNOWN));
173 rb_define_const(grpc_rb_mStatusCodes, "INVALID_ARGUMENT",
temiola58327912014-12-15 17:51:16 -0800174 INT2NUM(GRPC_STATUS_INVALID_ARGUMENT));
Yuki Yugui Sonodaa7d369e2015-04-11 11:48:36 +0900175 rb_define_const(grpc_rb_mStatusCodes, "DEADLINE_EXCEEDED",
temiola58327912014-12-15 17:51:16 -0800176 INT2NUM(GRPC_STATUS_DEADLINE_EXCEEDED));
Yuki Yugui Sonodaa7d369e2015-04-11 11:48:36 +0900177 rb_define_const(grpc_rb_mStatusCodes, "NOT_FOUND",
178 INT2NUM(GRPC_STATUS_NOT_FOUND));
179 rb_define_const(grpc_rb_mStatusCodes, "ALREADY_EXISTS",
temiola58327912014-12-15 17:51:16 -0800180 INT2NUM(GRPC_STATUS_ALREADY_EXISTS));
Yuki Yugui Sonodaa7d369e2015-04-11 11:48:36 +0900181 rb_define_const(grpc_rb_mStatusCodes, "PERMISSION_DENIED",
temiola58327912014-12-15 17:51:16 -0800182 INT2NUM(GRPC_STATUS_PERMISSION_DENIED));
Yuki Yugui Sonodaa7d369e2015-04-11 11:48:36 +0900183 rb_define_const(grpc_rb_mStatusCodes, "UNAUTHENTICATED",
temiola58327912014-12-15 17:51:16 -0800184 INT2NUM(GRPC_STATUS_UNAUTHENTICATED));
Yuki Yugui Sonodaa7d369e2015-04-11 11:48:36 +0900185 rb_define_const(grpc_rb_mStatusCodes, "RESOURCE_EXHAUSTED",
temiola58327912014-12-15 17:51:16 -0800186 INT2NUM(GRPC_STATUS_RESOURCE_EXHAUSTED));
Yuki Yugui Sonodaa7d369e2015-04-11 11:48:36 +0900187 rb_define_const(grpc_rb_mStatusCodes, "FAILED_PRECONDITION",
temiola58327912014-12-15 17:51:16 -0800188 INT2NUM(GRPC_STATUS_FAILED_PRECONDITION));
Yuki Yugui Sonodaa7d369e2015-04-11 11:48:36 +0900189 rb_define_const(grpc_rb_mStatusCodes, "ABORTED",
190 INT2NUM(GRPC_STATUS_ABORTED));
191 rb_define_const(grpc_rb_mStatusCodes, "OUT_OF_RANGE",
temiola58327912014-12-15 17:51:16 -0800192 INT2NUM(GRPC_STATUS_OUT_OF_RANGE));
Yuki Yugui Sonodaa7d369e2015-04-11 11:48:36 +0900193 rb_define_const(grpc_rb_mStatusCodes, "UNIMPLEMENTED",
temiola58327912014-12-15 17:51:16 -0800194 INT2NUM(GRPC_STATUS_UNIMPLEMENTED));
Yuki Yugui Sonodaa7d369e2015-04-11 11:48:36 +0900195 rb_define_const(grpc_rb_mStatusCodes, "INTERNAL",
196 INT2NUM(GRPC_STATUS_INTERNAL));
197 rb_define_const(grpc_rb_mStatusCodes, "UNAVAILABLE",
temiola58327912014-12-15 17:51:16 -0800198 INT2NUM(GRPC_STATUS_UNAVAILABLE));
Yuki Yugui Sonodaa7d369e2015-04-11 11:48:36 +0900199 rb_define_const(grpc_rb_mStatusCodes, "DATA_LOSS",
200 INT2NUM(GRPC_STATUS_DATA_LOSS));
temiola58327912014-12-15 17:51:16 -0800201}
202
nnoble097ef9b2014-12-01 17:06:10 -0800203/* id_at is the constructor method of the ruby standard Time class. */
204static ID id_at;
205
206/* id_inspect is the inspect method found on various ruby objects. */
207static ID id_inspect;
208
209/* id_to_s is the to_s method found on various ruby objects. */
210static ID id_to_s;
211
Tim Emiola98a32d32015-03-28 01:48:44 -0700212/* Converts a wrapped time constant to a standard time. */
Yuki Yugui Sonodaf0eee5f2015-04-16 20:25:28 +0900213static VALUE grpc_rb_time_val_to_time(VALUE self) {
nnoble097ef9b2014-12-01 17:06:10 -0800214 gpr_timespec *time_const = NULL;
Craig Tiller94329d02015-07-23 09:52:11 -0700215 gpr_timespec real_time;
Yuki Yugui Sonodad441c2e2015-04-11 15:33:58 +0900216 TypedData_Get_Struct(self, gpr_timespec, &grpc_rb_timespec_data_type,
217 time_const);
Craig Tiller94329d02015-07-23 09:52:11 -0700218 real_time = gpr_convert_clock_type(*time_const, GPR_CLOCK_REALTIME);
219 return rb_funcall(rb_cTime, id_at, 2, INT2NUM(real_time.tv_sec),
220 INT2NUM(real_time.tv_nsec));
nnoble097ef9b2014-12-01 17:06:10 -0800221}
222
223/* Invokes inspect on the ctime version of the time val. */
Yuki Yugui Sonodaf0eee5f2015-04-16 20:25:28 +0900224static VALUE grpc_rb_time_val_inspect(VALUE self) {
nnoble097ef9b2014-12-01 17:06:10 -0800225 return rb_funcall(grpc_rb_time_val_to_time(self), id_inspect, 0);
226}
227
228/* Invokes to_s on the ctime version of the time val. */
Yuki Yugui Sonodaf0eee5f2015-04-16 20:25:28 +0900229static VALUE grpc_rb_time_val_to_s(VALUE self) {
nnoble097ef9b2014-12-01 17:06:10 -0800230 return rb_funcall(grpc_rb_time_val_to_time(self), id_to_s, 0);
231}
232
Craig Tiller354398f2015-07-13 09:16:03 -0700233static gpr_timespec zero_realtime;
234static gpr_timespec inf_future_realtime;
235static gpr_timespec inf_past_realtime;
236
nnoble097ef9b2014-12-01 17:06:10 -0800237/* Adds a module with constants that map to gpr's static timeval structs. */
Yuki Yugui Sonodaf0eee5f2015-04-16 20:25:28 +0900238static void Init_grpc_time_consts() {
Yuki Yugui Sonodaa7d369e2015-04-11 11:48:36 +0900239 VALUE grpc_rb_mTimeConsts =
240 rb_define_module_under(grpc_rb_mGrpcCore, "TimeConsts");
241 grpc_rb_cTimeVal =
242 rb_define_class_under(grpc_rb_mGrpcCore, "TimeSpec", rb_cObject);
Craig Tiller354398f2015-07-13 09:16:03 -0700243 zero_realtime = gpr_time_0(GPR_CLOCK_REALTIME);
244 inf_future_realtime = gpr_inf_future(GPR_CLOCK_REALTIME);
245 inf_past_realtime = gpr_inf_past(GPR_CLOCK_REALTIME);
Yuki Yugui Sonodad441c2e2015-04-11 15:33:58 +0900246 rb_define_const(
247 grpc_rb_mTimeConsts, "ZERO",
248 TypedData_Wrap_Struct(grpc_rb_cTimeVal, &grpc_rb_timespec_data_type,
Craig Tiller354398f2015-07-13 09:16:03 -0700249 (void *)&zero_realtime));
Yuki Yugui Sonodad441c2e2015-04-11 15:33:58 +0900250 rb_define_const(
251 grpc_rb_mTimeConsts, "INFINITE_FUTURE",
252 TypedData_Wrap_Struct(grpc_rb_cTimeVal, &grpc_rb_timespec_data_type,
Craig Tiller354398f2015-07-13 09:16:03 -0700253 (void *)&inf_future_realtime));
Yuki Yugui Sonodad441c2e2015-04-11 15:33:58 +0900254 rb_define_const(
255 grpc_rb_mTimeConsts, "INFINITE_PAST",
256 TypedData_Wrap_Struct(grpc_rb_cTimeVal, &grpc_rb_timespec_data_type,
Craig Tiller354398f2015-07-13 09:16:03 -0700257 (void *)&inf_past_realtime));
Yuki Yugui Sonodaa7d369e2015-04-11 11:48:36 +0900258 rb_define_method(grpc_rb_cTimeVal, "to_time", grpc_rb_time_val_to_time, 0);
259 rb_define_method(grpc_rb_cTimeVal, "inspect", grpc_rb_time_val_inspect, 0);
260 rb_define_method(grpc_rb_cTimeVal, "to_s", grpc_rb_time_val_to_s, 0);
nnoble097ef9b2014-12-01 17:06:10 -0800261 id_at = rb_intern("at");
262 id_inspect = rb_intern("inspect");
263 id_to_s = rb_intern("to_s");
264 id_tv_sec = rb_intern("tv_sec");
265 id_tv_nsec = rb_intern("tv_nsec");
266}
267
Tim Emiola9161a822015-11-11 15:58:44 -0800268/*
269 TODO: find an alternative to ruby_vm_at_exit that is ok in Ruby 2.0 where
270 RUBY_TYPED_FREE_IMMEDIATELY is not defined.
271
272 At the moment, registering a function using ruby_vm_at_exit segfaults in Ruby
273 2.0. This is not an issue with the gRPC handler. More likely, this was an
274 in issue with 2.0 that got resolved in 2.1 and has not been backported.
275*/
276#ifdef RUBY_TYPED_FREE_IMMEDIATELY
murgatroid9987afb5d2015-07-16 16:01:02 -0700277static void grpc_rb_shutdown(ruby_vm_t *vm) {
278 (void)vm;
279 grpc_shutdown();
280}
Tim Emiola9161a822015-11-11 15:58:44 -0800281#endif
nnoble097ef9b2014-12-01 17:06:10 -0800282
Tim Emiola409e6c82015-02-17 17:46:35 -0800283/* Initialize the GRPC module structs */
temiola21bb60c2014-12-18 10:58:22 -0800284
Yuki Yugui Sonodaa7d369e2015-04-11 11:48:36 +0900285/* grpc_rb_sNewServerRpc is the struct that holds new server rpc details. */
286VALUE grpc_rb_sNewServerRpc = Qnil;
287/* grpc_rb_sStatus is the struct that holds status details. */
288VALUE grpc_rb_sStatus = Qnil;
temiola21bb60c2014-12-18 10:58:22 -0800289
Tim Emiola409e6c82015-02-17 17:46:35 -0800290/* Initialize the GRPC module. */
Yuki Yugui Sonodaa7d369e2015-04-11 11:48:36 +0900291VALUE grpc_rb_mGRPC = Qnil;
292VALUE grpc_rb_mGrpcCore = Qnil;
temiola21bb60c2014-12-18 10:58:22 -0800293
Yuki Yugui Sonoda99eb9f92015-04-16 20:09:55 +0900294/* cached Symbols for members in Status struct */
295VALUE sym_code = Qundef;
296VALUE sym_details = Qundef;
297VALUE sym_metadata = Qundef;
298
nnoble097ef9b2014-12-01 17:06:10 -0800299void Init_grpc() {
300 grpc_init();
Tim Emiola9161a822015-11-11 15:58:44 -0800301
302/* TODO: find alternative to ruby_vm_at_exit that is ok in Ruby 2.0 */
303#ifdef RUBY_TYPED_FREE_IMMEDIATELY
nnoble097ef9b2014-12-01 17:06:10 -0800304 ruby_vm_at_exit(grpc_rb_shutdown);
Tim Emiola9161a822015-11-11 15:58:44 -0800305#endif
306
Yuki Yugui Sonodaa7d369e2015-04-11 11:48:36 +0900307 grpc_rb_mGRPC = rb_define_module("GRPC");
308 grpc_rb_mGrpcCore = rb_define_module_under(grpc_rb_mGRPC, "Core");
309 grpc_rb_sNewServerRpc =
310 rb_struct_define("NewServerRpc", "method", "host",
311 "deadline", "metadata", "call", NULL);
312 grpc_rb_sStatus =
313 rb_struct_define("Status", "code", "details", "metadata", NULL);
Tim Emiola98a32d32015-03-28 01:48:44 -0700314 sym_code = ID2SYM(rb_intern("code"));
315 sym_details = ID2SYM(rb_intern("details"));
316 sym_metadata = ID2SYM(rb_intern("metadata"));
nnoble097ef9b2014-12-01 17:06:10 -0800317
Tim Emiola409e6c82015-02-17 17:46:35 -0800318 Init_grpc_channel();
319 Init_grpc_completion_queue();
320 Init_grpc_call();
Tim Emiola9332ea62015-10-27 23:48:29 -0700321 Init_grpc_channel_credentials();
Tim Emiola409e6c82015-02-17 17:46:35 -0800322 Init_grpc_server();
323 Init_grpc_server_credentials();
324 Init_grpc_status_codes();
325 Init_grpc_time_consts();
nnoble097ef9b2014-12-01 17:06:10 -0800326}