nnoble | 097ef9b | 2014-12-01 17:06:10 -0800 | [diff] [blame] | 1 | /* |
| 2 | * |
| 3 | * Copyright 2014, Google Inc. |
| 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_grpc.h" |
| 35 | |
| 36 | #include <math.h> |
| 37 | #include <ruby.h> |
| 38 | #include <sys/time.h> |
| 39 | |
| 40 | #include <grpc/grpc.h> |
| 41 | #include <grpc/support/time.h> |
| 42 | #include "rb_byte_buffer.h" |
| 43 | #include "rb_call.h" |
| 44 | #include "rb_channel.h" |
| 45 | #include "rb_completion_queue.h" |
| 46 | #include "rb_event.h" |
| 47 | #include "rb_metadata.h" |
| 48 | #include "rb_server.h" |
nnoble | 0c475f0 | 2014-12-05 15:37:39 -0800 | [diff] [blame] | 49 | #include "rb_credentials.h" |
| 50 | #include "rb_server_credentials.h" |
nnoble | 097ef9b | 2014-12-01 17:06:10 -0800 | [diff] [blame] | 51 | |
| 52 | /* Define common vars and funcs declared in rb.h */ |
| 53 | const RUBY_DATA_FUNC GC_NOT_MARKED = NULL; |
| 54 | const RUBY_DATA_FUNC GC_DONT_FREE = NULL; |
| 55 | |
| 56 | VALUE rb_cTimeVal = Qnil; |
| 57 | |
| 58 | /* Alloc func that blocks allocation of a given object by raising an |
| 59 | * exception. */ |
| 60 | VALUE grpc_rb_cannot_alloc(VALUE cls) { |
| 61 | rb_raise(rb_eTypeError, |
| 62 | "allocation of %s only allowed from the gRPC native layer", |
| 63 | rb_class2name(cls)); |
| 64 | return Qnil; |
| 65 | } |
| 66 | |
| 67 | /* Init func that fails by raising an exception. */ |
| 68 | VALUE grpc_rb_cannot_init(VALUE self) { |
| 69 | rb_raise(rb_eTypeError, |
| 70 | "initialization of %s only allowed from the gRPC native layer", |
| 71 | rb_obj_classname(self)); |
| 72 | return Qnil; |
| 73 | } |
| 74 | |
| 75 | /* Init/Clone func that fails by raising an exception. */ |
| 76 | VALUE grpc_rb_cannot_init_copy(VALUE copy, VALUE self) { |
| 77 | rb_raise(rb_eTypeError, |
| 78 | "initialization of %s only allowed from the gRPC native layer", |
| 79 | rb_obj_classname(copy)); |
| 80 | return Qnil; |
| 81 | } |
| 82 | |
| 83 | /* id_tv_{,u}sec are accessor methods on Ruby Time instances. */ |
| 84 | static ID id_tv_sec; |
| 85 | static ID id_tv_nsec; |
| 86 | |
| 87 | /** |
| 88 | * grpc_rb_time_timeval creates a time_eval from a ruby time object. |
| 89 | * |
| 90 | * This func is copied from ruby source, MRI/source/time.c, which is published |
| 91 | * under the same license as the ruby.h, on which the entire extensions is |
| 92 | * based. |
| 93 | */ |
| 94 | gpr_timespec grpc_rb_time_timeval(VALUE time, int interval) { |
| 95 | gpr_timespec t; |
| 96 | gpr_timespec *time_const; |
| 97 | const char *tstr = interval ? "time interval" : "time"; |
| 98 | const char *want = " want <secs from epoch>|<Time>|<GRPC::TimeConst.*>"; |
| 99 | |
| 100 | switch (TYPE(time)) { |
| 101 | |
| 102 | case T_DATA: |
| 103 | if (CLASS_OF(time) == rb_cTimeVal) { |
| 104 | Data_Get_Struct(time, gpr_timespec, time_const); |
| 105 | t = *time_const; |
| 106 | } else if (CLASS_OF(time) == rb_cTime) { |
| 107 | t.tv_sec = NUM2INT(rb_funcall(time, id_tv_sec, 0)); |
| 108 | t.tv_nsec = NUM2INT(rb_funcall(time, id_tv_nsec, 0)); |
| 109 | } else { |
| 110 | rb_raise(rb_eTypeError, |
| 111 | "bad input: (%s)->c_timeval, got <%s>,%s", |
| 112 | tstr, rb_obj_classname(time), want); |
| 113 | } |
| 114 | break; |
| 115 | |
| 116 | case T_FIXNUM: |
| 117 | t.tv_sec = FIX2LONG(time); |
| 118 | if (interval && t.tv_sec < 0) |
| 119 | rb_raise(rb_eArgError, "%s must be positive", tstr); |
| 120 | t.tv_nsec = 0; |
| 121 | break; |
| 122 | |
| 123 | case T_FLOAT: |
| 124 | if (interval && RFLOAT(time)->float_value < 0.0) |
| 125 | rb_raise(rb_eArgError, "%s must be positive", tstr); |
| 126 | else { |
| 127 | double f, d; |
| 128 | |
| 129 | d = modf(RFLOAT(time)->float_value, &f); |
| 130 | if (d < 0) { |
| 131 | d += 1; |
| 132 | f -= 1; |
| 133 | } |
| 134 | t.tv_sec = (time_t)f; |
| 135 | if (f != t.tv_sec) { |
| 136 | rb_raise(rb_eRangeError, "%f out of Time range", |
| 137 | RFLOAT(time)->float_value); |
| 138 | } |
| 139 | t.tv_nsec = (time_t)(d*1e9+0.5); |
| 140 | } |
| 141 | break; |
| 142 | |
| 143 | case T_BIGNUM: |
| 144 | t.tv_sec = NUM2LONG(time); |
| 145 | if (interval && t.tv_sec < 0) |
| 146 | rb_raise(rb_eArgError, "%s must be positive", tstr); |
| 147 | t.tv_nsec = 0; |
| 148 | break; |
| 149 | |
| 150 | default: |
| 151 | rb_raise(rb_eTypeError, |
| 152 | "bad input: (%s)->c_timeval, got <%s>,%s", |
| 153 | tstr, rb_obj_classname(time), want); |
| 154 | break; |
| 155 | } |
| 156 | return t; |
| 157 | } |
| 158 | |
temiola | 5832791 | 2014-12-15 17:51:16 -0800 | [diff] [blame^] | 159 | void Init_google_status_codes() { |
| 160 | /* Constants representing the status codes or grpc_status_code in status.h */ |
| 161 | VALUE rb_mStatusCodes = rb_define_module_under(rb_mGoogleRpcCore, |
| 162 | "StatusCodes"); |
| 163 | rb_define_const(rb_mStatusCodes, "OK", INT2NUM(GRPC_STATUS_OK)); |
| 164 | rb_define_const(rb_mStatusCodes, "CANCELLED", INT2NUM(GRPC_STATUS_CANCELLED)); |
| 165 | rb_define_const(rb_mStatusCodes, "UNKNOWN", INT2NUM(GRPC_STATUS_UNKNOWN)); |
| 166 | rb_define_const(rb_mStatusCodes, "INVALID_ARGUMENT", |
| 167 | INT2NUM(GRPC_STATUS_INVALID_ARGUMENT)); |
| 168 | rb_define_const(rb_mStatusCodes, "DEADLINE_EXCEEDED", |
| 169 | INT2NUM(GRPC_STATUS_DEADLINE_EXCEEDED)); |
| 170 | rb_define_const(rb_mStatusCodes, "NOT_FOUND", INT2NUM(GRPC_STATUS_NOT_FOUND)); |
| 171 | rb_define_const(rb_mStatusCodes, "ALREADY_EXISTS", |
| 172 | INT2NUM(GRPC_STATUS_ALREADY_EXISTS)); |
| 173 | rb_define_const(rb_mStatusCodes, "PERMISSION_DENIED", |
| 174 | INT2NUM(GRPC_STATUS_PERMISSION_DENIED)); |
| 175 | rb_define_const(rb_mStatusCodes, "UNAUTHENTICATED", |
| 176 | INT2NUM(GRPC_STATUS_UNAUTHENTICATED)); |
| 177 | rb_define_const(rb_mStatusCodes, "RESOURCE_EXHAUSTED", |
| 178 | INT2NUM(GRPC_STATUS_RESOURCE_EXHAUSTED)); |
| 179 | rb_define_const(rb_mStatusCodes, "FAILED_PRECONDITION", |
| 180 | INT2NUM(GRPC_STATUS_FAILED_PRECONDITION)); |
| 181 | rb_define_const(rb_mStatusCodes, "ABORTED", INT2NUM(GRPC_STATUS_ABORTED)); |
| 182 | rb_define_const(rb_mStatusCodes, "OUT_OF_RANGE", |
| 183 | INT2NUM(GRPC_STATUS_OUT_OF_RANGE)); |
| 184 | rb_define_const(rb_mStatusCodes, "UNIMPLEMENTED", |
| 185 | INT2NUM(GRPC_STATUS_UNIMPLEMENTED)); |
| 186 | rb_define_const(rb_mStatusCodes, "INTERNAL", INT2NUM(GRPC_STATUS_INTERNAL)); |
| 187 | rb_define_const(rb_mStatusCodes, "UNAVAILABLE", |
| 188 | INT2NUM(GRPC_STATUS_UNAVAILABLE)); |
| 189 | rb_define_const(rb_mStatusCodes, "DATA_LOSS", INT2NUM(GRPC_STATUS_DATA_LOSS)); |
| 190 | } |
| 191 | |
nnoble | 097ef9b | 2014-12-01 17:06:10 -0800 | [diff] [blame] | 192 | /* id_at is the constructor method of the ruby standard Time class. */ |
| 193 | static ID id_at; |
| 194 | |
| 195 | /* id_inspect is the inspect method found on various ruby objects. */ |
| 196 | static ID id_inspect; |
| 197 | |
| 198 | /* id_to_s is the to_s method found on various ruby objects. */ |
| 199 | static ID id_to_s; |
| 200 | |
| 201 | /* Converts `a wrapped time constant to a standard time. */ |
| 202 | VALUE grpc_rb_time_val_to_time(VALUE self) { |
| 203 | gpr_timespec *time_const = NULL; |
| 204 | Data_Get_Struct(self, gpr_timespec, time_const); |
| 205 | return rb_funcall(rb_cTime, id_at, 2, INT2NUM(time_const->tv_sec), |
| 206 | INT2NUM(time_const->tv_nsec)); |
| 207 | } |
| 208 | |
| 209 | /* Invokes inspect on the ctime version of the time val. */ |
| 210 | VALUE grpc_rb_time_val_inspect(VALUE self) { |
| 211 | return rb_funcall(grpc_rb_time_val_to_time(self), id_inspect, 0); |
| 212 | } |
| 213 | |
| 214 | /* Invokes to_s on the ctime version of the time val. */ |
| 215 | VALUE grpc_rb_time_val_to_s(VALUE self) { |
| 216 | return rb_funcall(grpc_rb_time_val_to_time(self), id_to_s, 0); |
| 217 | } |
| 218 | |
| 219 | /* Adds a module with constants that map to gpr's static timeval structs. */ |
| 220 | void Init_google_time_consts() { |
nnoble | 0c475f0 | 2014-12-05 15:37:39 -0800 | [diff] [blame] | 221 | VALUE rb_mTimeConsts = rb_define_module_under(rb_mGoogleRpcCore, |
| 222 | "TimeConsts"); |
| 223 | rb_cTimeVal = rb_define_class_under(rb_mGoogleRpcCore, "TimeSpec", |
| 224 | rb_cObject); |
nnoble | 097ef9b | 2014-12-01 17:06:10 -0800 | [diff] [blame] | 225 | rb_define_const(rb_mTimeConsts, "ZERO", |
| 226 | Data_Wrap_Struct(rb_cTimeVal, GC_NOT_MARKED, |
| 227 | GC_DONT_FREE, (void *)&gpr_time_0)); |
| 228 | rb_define_const(rb_mTimeConsts, "INFINITE_FUTURE", |
| 229 | Data_Wrap_Struct(rb_cTimeVal, GC_NOT_MARKED, |
| 230 | GC_DONT_FREE, (void *)&gpr_inf_future)); |
| 231 | rb_define_const(rb_mTimeConsts, "INFINITE_PAST", |
| 232 | Data_Wrap_Struct(rb_cTimeVal, GC_NOT_MARKED, |
| 233 | GC_DONT_FREE, (void *)&gpr_inf_past)); |
| 234 | rb_define_method(rb_cTimeVal, "to_time", grpc_rb_time_val_to_time, 0); |
| 235 | rb_define_method(rb_cTimeVal, "inspect", grpc_rb_time_val_inspect, 0); |
| 236 | rb_define_method(rb_cTimeVal, "to_s", grpc_rb_time_val_to_s, 0); |
| 237 | id_at = rb_intern("at"); |
| 238 | id_inspect = rb_intern("inspect"); |
| 239 | id_to_s = rb_intern("to_s"); |
| 240 | id_tv_sec = rb_intern("tv_sec"); |
| 241 | id_tv_nsec = rb_intern("tv_nsec"); |
| 242 | } |
| 243 | |
| 244 | void grpc_rb_shutdown(void *vm) { |
| 245 | grpc_shutdown(); |
| 246 | } |
| 247 | |
| 248 | /* Initialize the Google RPC module. */ |
| 249 | VALUE rb_mGoogle = Qnil; |
| 250 | VALUE rb_mGoogleRPC = Qnil; |
nnoble | 0c475f0 | 2014-12-05 15:37:39 -0800 | [diff] [blame] | 251 | VALUE rb_mGoogleRpcCore = Qnil; |
nnoble | 097ef9b | 2014-12-01 17:06:10 -0800 | [diff] [blame] | 252 | void Init_grpc() { |
| 253 | grpc_init(); |
| 254 | ruby_vm_at_exit(grpc_rb_shutdown); |
| 255 | rb_mGoogle = rb_define_module("Google"); |
| 256 | rb_mGoogleRPC = rb_define_module_under(rb_mGoogle, "RPC"); |
nnoble | 0c475f0 | 2014-12-05 15:37:39 -0800 | [diff] [blame] | 257 | rb_mGoogleRpcCore = rb_define_module_under(rb_mGoogleRPC, "Core"); |
nnoble | 097ef9b | 2014-12-01 17:06:10 -0800 | [diff] [blame] | 258 | |
| 259 | Init_google_rpc_byte_buffer(); |
| 260 | Init_google_rpc_event(); |
| 261 | Init_google_rpc_channel(); |
| 262 | Init_google_rpc_completion_queue(); |
| 263 | Init_google_rpc_call(); |
nnoble | 0c475f0 | 2014-12-05 15:37:39 -0800 | [diff] [blame] | 264 | Init_google_rpc_credentials(); |
nnoble | 097ef9b | 2014-12-01 17:06:10 -0800 | [diff] [blame] | 265 | Init_google_rpc_metadata(); |
| 266 | Init_google_rpc_server(); |
nnoble | 0c475f0 | 2014-12-05 15:37:39 -0800 | [diff] [blame] | 267 | Init_google_rpc_server_credentials(); |
temiola | 5832791 | 2014-12-15 17:51:16 -0800 | [diff] [blame^] | 268 | Init_google_status_codes(); |
nnoble | 097ef9b | 2014-12-01 17:06:10 -0800 | [diff] [blame] | 269 | Init_google_time_consts(); |
| 270 | } |