blob: 0fae9502c3089fd462993a8d2f0adafc29b5d300 [file] [log] [blame]
nnoble097ef9b2014-12-01 17:06:10 -08001/*
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_event.h"
35
36#include <ruby.h>
37
38#include <grpc/grpc.h>
39#include "rb_grpc.h"
40#include "rb_byte_buffer.h"
41#include "rb_call.h"
42#include "rb_metadata.h"
nnoble097ef9b2014-12-01 17:06:10 -080043
temiola21bb60c2014-12-18 10:58:22 -080044/* grpc_rb_event wraps a grpc_event. It provides a peer ruby object,
45 * 'mark' to minimize copying when an event is created from ruby. */
46typedef struct grpc_rb_event {
47 /* Holder of ruby objects involved in constructing the channel */
48 VALUE mark;
49 /* The actual event */
50 grpc_event *wrapped;
51} grpc_rb_event;
52
nnoble097ef9b2014-12-01 17:06:10 -080053/* rb_mCompletionType is a ruby module that holds the completion type values */
54VALUE rb_mCompletionType = Qnil;
55
temiola21bb60c2014-12-18 10:58:22 -080056/* Destroys Event instances. */
57static void grpc_rb_event_free(void *p) {
58 grpc_rb_event *ev = NULL;
59 if (p == NULL) {
60 return;
61 };
62 ev = (grpc_rb_event *)p;
63
64 /* Deletes the wrapped object if the mark object is Qnil, which indicates
65 * that no other object is the actual owner. */
66 if (ev->wrapped != NULL && ev->mark == Qnil) {
67 grpc_event_finish(ev->wrapped);
68 rb_warning("event gc: destroyed the c event");
69 } else {
70 rb_warning("event gc: did not destroy the c event");
71 }
72
73 xfree(p);
74}
75
76/* Protects the mark object from GC */
77static void grpc_rb_event_mark(void *p) {
78 grpc_rb_event *event = NULL;
79 if (p == NULL) {
80 return;
81 }
82 event = (grpc_rb_event *)p;
83 if (event->mark != Qnil) {
84 rb_gc_mark(event->mark);
85 }
nnoble097ef9b2014-12-01 17:06:10 -080086}
87
88static VALUE grpc_rb_event_result(VALUE self);
89
90/* Obtains the type of an event. */
91static VALUE grpc_rb_event_type(VALUE self) {
92 grpc_event *event = NULL;
temiola21bb60c2014-12-18 10:58:22 -080093 grpc_rb_event *wrapper = NULL;
94 Data_Get_Struct(self, grpc_rb_event, wrapper);
95 if (wrapper->wrapped == NULL) {
96 rb_raise(rb_eRuntimeError, "finished!");
97 return Qnil;
98 }
99
100 event = wrapper->wrapped;
nnoble097ef9b2014-12-01 17:06:10 -0800101 switch (event->type) {
102 case GRPC_QUEUE_SHUTDOWN:
103 return rb_const_get(rb_mCompletionType, rb_intern("QUEUE_SHUTDOWN"));
104
105 case GRPC_READ:
106 return rb_const_get(rb_mCompletionType, rb_intern("READ"));
107
108 case GRPC_INVOKE_ACCEPTED:
Craig Tillerb5dcec52015-01-13 11:13:42 -0800109 grpc_rb_event_result(self); /* validates the result */
nnoble097ef9b2014-12-01 17:06:10 -0800110 return rb_const_get(rb_mCompletionType, rb_intern("INVOKE_ACCEPTED"));
111
112 case GRPC_WRITE_ACCEPTED:
Craig Tillerb5dcec52015-01-13 11:13:42 -0800113 grpc_rb_event_result(self); /* validates the result */
nnoble097ef9b2014-12-01 17:06:10 -0800114 return rb_const_get(rb_mCompletionType, rb_intern("WRITE_ACCEPTED"));
115
116 case GRPC_FINISH_ACCEPTED:
Craig Tillerb5dcec52015-01-13 11:13:42 -0800117 grpc_rb_event_result(self); /* validates the result */
nnoble097ef9b2014-12-01 17:06:10 -0800118 return rb_const_get(rb_mCompletionType, rb_intern("FINISH_ACCEPTED"));
119
120 case GRPC_CLIENT_METADATA_READ:
121 return rb_const_get(rb_mCompletionType,
122 rb_intern("CLIENT_METADATA_READ"));
123
124 case GRPC_FINISHED:
125 return rb_const_get(rb_mCompletionType, rb_intern("FINISHED"));
126
127 case GRPC_SERVER_RPC_NEW:
128 return rb_const_get(rb_mCompletionType, rb_intern("SERVER_RPC_NEW"));
129
130 default:
Craig Tillerb5dcec52015-01-13 11:13:42 -0800131 rb_raise(rb_eRuntimeError, "unrecognized event code for an rpc event:%d",
132 event->type);
nnoble097ef9b2014-12-01 17:06:10 -0800133 }
134 return Qnil; /* should not be reached */
135}
136
137/* Obtains the tag associated with an event. */
138static VALUE grpc_rb_event_tag(VALUE self) {
139 grpc_event *event = NULL;
temiola21bb60c2014-12-18 10:58:22 -0800140 grpc_rb_event *wrapper = NULL;
141 Data_Get_Struct(self, grpc_rb_event, wrapper);
142 if (wrapper->wrapped == NULL) {
143 rb_raise(rb_eRuntimeError, "finished!");
144 return Qnil;
145 }
146
147 event = wrapper->wrapped;
nnoble097ef9b2014-12-01 17:06:10 -0800148 if (event->tag == NULL) {
149 return Qnil;
150 }
151 return (VALUE)event->tag;
152}
153
154/* Obtains the call associated with an event. */
155static VALUE grpc_rb_event_call(VALUE self) {
temiola21bb60c2014-12-18 10:58:22 -0800156 grpc_event *event = NULL;
157 grpc_rb_event *wrapper = NULL;
158 Data_Get_Struct(self, grpc_rb_event, wrapper);
159 if (wrapper->wrapped == NULL) {
160 rb_raise(rb_eRuntimeError, "finished!");
161 return Qnil;
162 }
163
164 event = wrapper->wrapped;
165 if (event->call != NULL) {
166 return grpc_rb_wrap_call(event->call);
nnoble097ef9b2014-12-01 17:06:10 -0800167 }
168 return Qnil;
169}
170
171/* Obtains the metadata associated with an event. */
172static VALUE grpc_rb_event_metadata(VALUE self) {
173 grpc_event *event = NULL;
temiola21bb60c2014-12-18 10:58:22 -0800174 grpc_rb_event *wrapper = NULL;
nnoble097ef9b2014-12-01 17:06:10 -0800175 grpc_metadata *metadata = NULL;
176 VALUE key = Qnil;
177 VALUE new_ary = Qnil;
178 VALUE result = Qnil;
179 VALUE value = Qnil;
180 size_t count = 0;
181 size_t i = 0;
temiola21bb60c2014-12-18 10:58:22 -0800182 Data_Get_Struct(self, grpc_rb_event, wrapper);
183 if (wrapper->wrapped == NULL) {
184 rb_raise(rb_eRuntimeError, "finished!");
185 return Qnil;
186 }
nnoble097ef9b2014-12-01 17:06:10 -0800187
188 /* Figure out which metadata to read. */
temiola21bb60c2014-12-18 10:58:22 -0800189 event = wrapper->wrapped;
nnoble097ef9b2014-12-01 17:06:10 -0800190 switch (event->type) {
nnoble097ef9b2014-12-01 17:06:10 -0800191 case GRPC_CLIENT_METADATA_READ:
192 count = event->data.client_metadata_read.count;
193 metadata = event->data.client_metadata_read.elements;
194 break;
195
temiola58327912014-12-15 17:51:16 -0800196 case GRPC_FINISHED:
197 count = event->data.finished.metadata_count;
198 metadata = event->data.finished.metadata_elements;
199 break;
200
nnoble097ef9b2014-12-01 17:06:10 -0800201 case GRPC_SERVER_RPC_NEW:
202 count = event->data.server_rpc_new.metadata_count;
203 metadata = event->data.server_rpc_new.metadata_elements;
204 break;
205
206 default:
207 rb_raise(rb_eRuntimeError,
temiola58327912014-12-15 17:51:16 -0800208 "bug: bad event type metadata. got %d; want %d|%d:%d",
209 event->type, GRPC_CLIENT_METADATA_READ, GRPC_FINISHED,
210 GRPC_SERVER_RPC_NEW);
nnoble097ef9b2014-12-01 17:06:10 -0800211 return Qnil;
212 }
213
214 result = rb_hash_new();
215 for (i = 0; i < count; i++) {
216 key = rb_str_new2(metadata[i].key);
217 value = rb_hash_aref(result, key);
218 if (value == Qnil) {
Craig Tillerb5dcec52015-01-13 11:13:42 -0800219 value = rb_str_new(metadata[i].value, metadata[i].value_length);
nnoble097ef9b2014-12-01 17:06:10 -0800220 rb_hash_aset(result, key, value);
221 } else if (TYPE(value) == T_ARRAY) {
222 /* Add the string to the returned array */
Craig Tillerb5dcec52015-01-13 11:13:42 -0800223 rb_ary_push(value,
224 rb_str_new(metadata[i].value, metadata[i].value_length));
nnoble097ef9b2014-12-01 17:06:10 -0800225 } else {
226 /* Add the current value with this key and the new one to an array */
227 new_ary = rb_ary_new();
228 rb_ary_push(new_ary, value);
Craig Tillerb5dcec52015-01-13 11:13:42 -0800229 rb_ary_push(new_ary,
230 rb_str_new(metadata[i].value, metadata[i].value_length));
nnoble097ef9b2014-12-01 17:06:10 -0800231 rb_hash_aset(result, key, new_ary);
232 }
233 }
234 return result;
235}
236
237/* Obtains the data associated with an event. */
238static VALUE grpc_rb_event_result(VALUE self) {
239 grpc_event *event = NULL;
temiola21bb60c2014-12-18 10:58:22 -0800240 grpc_rb_event *wrapper = NULL;
241 Data_Get_Struct(self, grpc_rb_event, wrapper);
242 if (wrapper->wrapped == NULL) {
243 rb_raise(rb_eRuntimeError, "finished!");
244 return Qnil;
245 }
246 event = wrapper->wrapped;
nnoble097ef9b2014-12-01 17:06:10 -0800247
248 switch (event->type) {
nnoble097ef9b2014-12-01 17:06:10 -0800249 case GRPC_QUEUE_SHUTDOWN:
250 return Qnil;
251
252 case GRPC_READ:
253 return grpc_rb_byte_buffer_create_with_mark(self, event->data.read);
254
255 case GRPC_FINISH_ACCEPTED:
256 if (event->data.finish_accepted == GRPC_OP_OK) {
257 return Qnil;
258 }
259 rb_raise(rb_eEventError, "finish failed, not sure why (code=%d)",
260 event->data.finish_accepted);
261 break;
262
263 case GRPC_INVOKE_ACCEPTED:
264 if (event->data.invoke_accepted == GRPC_OP_OK) {
265 return Qnil;
266 }
267 rb_raise(rb_eEventError, "invoke failed, not sure why (code=%d)",
268 event->data.invoke_accepted);
269 break;
270
271 case GRPC_WRITE_ACCEPTED:
272 if (event->data.write_accepted == GRPC_OP_OK) {
273 return Qnil;
274 }
275 rb_raise(rb_eEventError, "write failed, not sure why (code=%d)",
temiola6919c752014-12-10 13:22:00 -0800276 event->data.write_accepted);
nnoble097ef9b2014-12-01 17:06:10 -0800277 break;
278
279 case GRPC_CLIENT_METADATA_READ:
280 return grpc_rb_event_metadata(self);
281
282 case GRPC_FINISHED:
Craig Tillerb5dcec52015-01-13 11:13:42 -0800283 return rb_struct_new(rb_sStatus, UINT2NUM(event->data.finished.status),
284 (event->data.finished.details == NULL
285 ? Qnil
286 : rb_str_new2(event->data.finished.details)),
287 grpc_rb_event_metadata(self), NULL);
nnoble097ef9b2014-12-01 17:06:10 -0800288 break;
289
290 case GRPC_SERVER_RPC_NEW:
291 return rb_struct_new(
Craig Tillerb5dcec52015-01-13 11:13:42 -0800292 rb_sNewServerRpc, rb_str_new2(event->data.server_rpc_new.method),
nnoble097ef9b2014-12-01 17:06:10 -0800293 rb_str_new2(event->data.server_rpc_new.host),
Craig Tillerb5dcec52015-01-13 11:13:42 -0800294 Data_Wrap_Struct(rb_cTimeVal, GC_NOT_MARKED, GC_DONT_FREE,
295 (void *)&event->data.server_rpc_new.deadline),
296 grpc_rb_event_metadata(self), NULL);
nnoble097ef9b2014-12-01 17:06:10 -0800297
298 default:
Craig Tillerb5dcec52015-01-13 11:13:42 -0800299 rb_raise(rb_eRuntimeError, "unrecognized event code for an rpc event:%d",
300 event->type);
nnoble097ef9b2014-12-01 17:06:10 -0800301 }
302
303 return Qfalse;
304}
305
temiola21bb60c2014-12-18 10:58:22 -0800306static VALUE grpc_rb_event_finish(VALUE self) {
307 grpc_event *event = NULL;
308 grpc_rb_event *wrapper = NULL;
309 Data_Get_Struct(self, grpc_rb_event, wrapper);
Craig Tillerb5dcec52015-01-13 11:13:42 -0800310 if (wrapper->wrapped == NULL) { /* already closed */
temiola21bb60c2014-12-18 10:58:22 -0800311 return Qnil;
312 }
313 event = wrapper->wrapped;
314 grpc_event_finish(event);
315 wrapper->wrapped = NULL;
316 wrapper->mark = Qnil;
317 return Qnil;
318}
temiola58327912014-12-15 17:51:16 -0800319
nnoble097ef9b2014-12-01 17:06:10 -0800320/* rb_cEvent is the Event class whose instances proxy grpc_event */
321VALUE rb_cEvent = Qnil;
322
323/* rb_eEventError is the ruby class of the exception thrown on failures during
324 rpc event processing. */
325VALUE rb_eEventError = Qnil;
326
327void Init_google_rpc_event() {
Craig Tillerb5dcec52015-01-13 11:13:42 -0800328 rb_eEventError =
329 rb_define_class_under(rb_mGoogleRpcCore, "EventError", rb_eStandardError);
nnoble0c475f02014-12-05 15:37:39 -0800330 rb_cEvent = rb_define_class_under(rb_mGoogleRpcCore, "Event", rb_cObject);
nnoble097ef9b2014-12-01 17:06:10 -0800331
332 /* Prevent allocation or inialization from ruby. */
333 rb_define_alloc_func(rb_cEvent, grpc_rb_cannot_alloc);
334 rb_define_method(rb_cEvent, "initialize", grpc_rb_cannot_init, 0);
335 rb_define_method(rb_cEvent, "initialize_copy", grpc_rb_cannot_init_copy, 1);
336
337 /* Accessors for the data available in an event. */
338 rb_define_method(rb_cEvent, "call", grpc_rb_event_call, 0);
339 rb_define_method(rb_cEvent, "result", grpc_rb_event_result, 0);
340 rb_define_method(rb_cEvent, "tag", grpc_rb_event_tag, 0);
341 rb_define_method(rb_cEvent, "type", grpc_rb_event_type, 0);
temiola21bb60c2014-12-18 10:58:22 -0800342 rb_define_method(rb_cEvent, "finish", grpc_rb_event_finish, 0);
343 rb_define_alias(rb_cEvent, "close", "finish");
nnoble097ef9b2014-12-01 17:06:10 -0800344
345 /* Constants representing the completion types */
Craig Tillerb5dcec52015-01-13 11:13:42 -0800346 rb_mCompletionType =
347 rb_define_module_under(rb_mGoogleRpcCore, "CompletionType");
nnoble097ef9b2014-12-01 17:06:10 -0800348 rb_define_const(rb_mCompletionType, "QUEUE_SHUTDOWN",
349 INT2NUM(GRPC_QUEUE_SHUTDOWN));
350 rb_define_const(rb_mCompletionType, "READ", INT2NUM(GRPC_READ));
351 rb_define_const(rb_mCompletionType, "INVOKE_ACCEPTED",
352 INT2NUM(GRPC_INVOKE_ACCEPTED));
353 rb_define_const(rb_mCompletionType, "WRITE_ACCEPTED",
354 INT2NUM(GRPC_WRITE_ACCEPTED));
355 rb_define_const(rb_mCompletionType, "FINISH_ACCEPTED",
356 INT2NUM(GRPC_FINISH_ACCEPTED));
357 rb_define_const(rb_mCompletionType, "CLIENT_METADATA_READ",
358 INT2NUM(GRPC_CLIENT_METADATA_READ));
Craig Tillerb5dcec52015-01-13 11:13:42 -0800359 rb_define_const(rb_mCompletionType, "FINISHED", INT2NUM(GRPC_FINISHED));
nnoble097ef9b2014-12-01 17:06:10 -0800360 rb_define_const(rb_mCompletionType, "SERVER_RPC_NEW",
361 INT2NUM(GRPC_SERVER_RPC_NEW));
362 rb_define_const(rb_mCompletionType, "RESERVED",
363 INT2NUM(GRPC_COMPLETION_DO_NOT_USE));
364}
temiola21bb60c2014-12-18 10:58:22 -0800365
366VALUE grpc_rb_new_event(grpc_event *ev) {
367 grpc_rb_event *wrapper = ALLOC(grpc_rb_event);
368 wrapper->wrapped = ev;
369 wrapper->mark = Qnil;
370 return Data_Wrap_Struct(rb_cEvent, grpc_rb_event_mark, grpc_rb_event_free,
371 wrapper);
372}