xref: /aosp_15_r20/external/grpc-grpc/src/ruby/ext/grpc/rb_xds_channel_credentials.c (revision cc02d7e222339f7a4f6ba5f422e6413f4bd931f2)
1 /*
2  *
3  * Copyright 2021 gRPC authors.
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  *     http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  *
17  */
18 
19 #include <ruby/ruby.h>
20 
21 #include "rb_xds_channel_credentials.h"
22 
23 #include <string.h>
24 
25 #include "rb_call_credentials.h"
26 #include "rb_channel_credentials.h"
27 #include "rb_grpc.h"
28 #include "rb_grpc_imports.generated.h"
29 
30 #include <grpc/grpc.h>
31 #include <grpc/grpc_security.h>
32 #include <grpc/support/alloc.h>
33 #include <grpc/support/log.h>
34 
35 /* grpc_rb_cXdsChannelCredentials is the ruby class that proxies
36    grpc_channel_credentials. */
37 static VALUE grpc_rb_cXdsChannelCredentials = Qnil;
38 
39 /* grpc_rb_xds_channel_credentials wraps a grpc_channel_credentials.  It
40  * provides a mark object that is used to hold references to any objects used to
41  * create the credentials. */
42 typedef struct grpc_rb_xds_channel_credentials {
43   /* Holder of ruby objects involved in constructing the credentials */
44   VALUE mark;
45 
46   /* The actual credentials */
47   grpc_channel_credentials* wrapped;
48 } grpc_rb_xds_channel_credentials;
49 
grpc_rb_xds_channel_credentials_free_internal(void * p)50 static void grpc_rb_xds_channel_credentials_free_internal(void* p) {
51   grpc_rb_xds_channel_credentials* wrapper = NULL;
52   if (p == NULL) {
53     return;
54   };
55   wrapper = (grpc_rb_xds_channel_credentials*)p;
56   grpc_channel_credentials_release(wrapper->wrapped);
57   wrapper->wrapped = NULL;
58 
59   xfree(p);
60 }
61 
62 /* Destroys the credentials instances. */
grpc_rb_xds_channel_credentials_free(void * p)63 static void grpc_rb_xds_channel_credentials_free(void* p) {
64   grpc_rb_xds_channel_credentials_free_internal(p);
65 }
66 
67 /* Protects the mark object from GC */
grpc_rb_xds_channel_credentials_mark(void * p)68 static void grpc_rb_xds_channel_credentials_mark(void* p) {
69   grpc_rb_xds_channel_credentials* wrapper = NULL;
70   if (p == NULL) {
71     return;
72   }
73   wrapper = (grpc_rb_xds_channel_credentials*)p;
74 
75   if (wrapper->mark != Qnil) {
76     rb_gc_mark(wrapper->mark);
77   }
78 }
79 
80 static rb_data_type_t grpc_rb_xds_channel_credentials_data_type = {
81     "grpc_xds_channel_credentials",
82     {grpc_rb_xds_channel_credentials_mark, grpc_rb_xds_channel_credentials_free,
83      GRPC_RB_MEMSIZE_UNAVAILABLE, NULL},
84     NULL,
85     NULL,
86 #ifdef RUBY_TYPED_FREE_IMMEDIATELY
87     RUBY_TYPED_FREE_IMMEDIATELY
88 #endif
89 };
90 
91 /* Allocates ChannelCredential instances.
92    Provides safe initial defaults for the instance fields. */
grpc_rb_xds_channel_credentials_alloc(VALUE cls)93 static VALUE grpc_rb_xds_channel_credentials_alloc(VALUE cls) {
94   grpc_ruby_init();
95   grpc_rb_xds_channel_credentials* wrapper =
96       ALLOC(grpc_rb_xds_channel_credentials);
97   wrapper->wrapped = NULL;
98   wrapper->mark = Qnil;
99   return TypedData_Wrap_Struct(cls, &grpc_rb_xds_channel_credentials_data_type,
100                                wrapper);
101 }
102 
103 /* Creates a wrapping object for a given channel credentials. This should only
104  * be called with grpc_channel_credentials objects that are not already
105  * associated with any Ruby object. */
grpc_rb_xds_wrap_channel_credentials(grpc_channel_credentials * c,VALUE mark)106 VALUE grpc_rb_xds_wrap_channel_credentials(grpc_channel_credentials* c,
107                                            VALUE mark) {
108   grpc_rb_xds_channel_credentials* wrapper;
109   if (c == NULL) {
110     return Qnil;
111   }
112   VALUE rb_wrapper =
113       grpc_rb_xds_channel_credentials_alloc(grpc_rb_cXdsChannelCredentials);
114   TypedData_Get_Struct(rb_wrapper, grpc_rb_xds_channel_credentials,
115                        &grpc_rb_xds_channel_credentials_data_type, wrapper);
116   wrapper->wrapped = c;
117   wrapper->mark = mark;
118   return rb_wrapper;
119 }
120 
121 /* The attribute used on the mark object to hold the fallback creds. */
122 static ID id_fallback_creds;
123 
124 /*
125   call-seq:
126     fallback_creds: (ChannelCredentials) fallback credentials to create
127     XDS credentials
128     Initializes Credential instances. */
grpc_rb_xds_channel_credentials_init(VALUE self,VALUE fallback_creds)129 static VALUE grpc_rb_xds_channel_credentials_init(VALUE self,
130                                                   VALUE fallback_creds) {
131   grpc_rb_xds_channel_credentials* wrapper = NULL;
132   grpc_channel_credentials* grpc_fallback_creds =
133       grpc_rb_get_wrapped_channel_credentials(fallback_creds);
134   grpc_channel_credentials* creds =
135       grpc_xds_credentials_create(grpc_fallback_creds);
136   if (creds == NULL) {
137     rb_raise(rb_eRuntimeError,
138              "the call to grpc_xds_credentials_create() failed, could not "
139              "create a credentials, , see "
140              "https://github.com/grpc/grpc/blob/master/TROUBLESHOOTING.md for "
141              "debugging tips");
142     return Qnil;
143   }
144 
145   TypedData_Get_Struct(self, grpc_rb_xds_channel_credentials,
146                        &grpc_rb_xds_channel_credentials_data_type, wrapper);
147   wrapper->wrapped = creds;
148 
149   /* Add the input objects as hidden fields to preserve them. */
150   rb_ivar_set(self, id_fallback_creds, fallback_creds);
151 
152   return self;
153 }
154 
155 // TODO: de-duplicate this code with the similar method in
156 // rb_channel_credentials.c, after putting ChannelCredentials and
157 // XdsChannelCredentials under a common parent class
grpc_rb_xds_channel_credentials_compose(int argc,VALUE * argv,VALUE self)158 static VALUE grpc_rb_xds_channel_credentials_compose(int argc, VALUE* argv,
159                                                      VALUE self) {
160   grpc_channel_credentials* creds;
161   grpc_call_credentials* other;
162   grpc_channel_credentials* prev = NULL;
163   VALUE mark;
164   if (argc == 0) {
165     return self;
166   }
167   mark = rb_ary_new();
168   rb_ary_push(mark, self);
169   creds = grpc_rb_get_wrapped_xds_channel_credentials(self);
170   for (int i = 0; i < argc; i++) {
171     rb_ary_push(mark, argv[i]);
172     other = grpc_rb_get_wrapped_call_credentials(argv[i]);
173     creds = grpc_composite_channel_credentials_create(creds, other, NULL);
174     if (prev != NULL) {
175       grpc_channel_credentials_release(prev);
176     }
177     prev = creds;
178 
179     if (creds == NULL) {
180       rb_raise(rb_eRuntimeError,
181                "Failed to compose channel and call credentials");
182     }
183   }
184   return grpc_rb_xds_wrap_channel_credentials(creds, mark);
185 }
186 
Init_grpc_xds_channel_credentials()187 void Init_grpc_xds_channel_credentials() {
188   grpc_rb_cXdsChannelCredentials = rb_define_class_under(
189       grpc_rb_mGrpcCore, "XdsChannelCredentials", rb_cObject);
190 
191   /* Allocates an object managed by the ruby runtime */
192   rb_define_alloc_func(grpc_rb_cXdsChannelCredentials,
193                        grpc_rb_xds_channel_credentials_alloc);
194 
195   /* Provides a ruby constructor and support for dup/clone. */
196   rb_define_method(grpc_rb_cXdsChannelCredentials, "initialize",
197                    grpc_rb_xds_channel_credentials_init, 1);
198   rb_define_method(grpc_rb_cXdsChannelCredentials, "initialize_copy",
199                    grpc_rb_cannot_init_copy, 1);
200   rb_define_method(grpc_rb_cXdsChannelCredentials, "compose",
201                    grpc_rb_xds_channel_credentials_compose, -1);
202 
203   id_fallback_creds = rb_intern("__fallback_creds");
204 }
205 
206 /* Gets the wrapped grpc_channel_credentials from the ruby wrapper */
grpc_rb_get_wrapped_xds_channel_credentials(VALUE v)207 grpc_channel_credentials* grpc_rb_get_wrapped_xds_channel_credentials(VALUE v) {
208   grpc_rb_xds_channel_credentials* wrapper = NULL;
209   Check_TypedStruct(v, &grpc_rb_xds_channel_credentials_data_type);
210   TypedData_Get_Struct(v, grpc_rb_xds_channel_credentials,
211                        &grpc_rb_xds_channel_credentials_data_type, wrapper);
212   return wrapper->wrapped;
213 }
214 
grpc_rb_is_xds_channel_credentials(VALUE v)215 bool grpc_rb_is_xds_channel_credentials(VALUE v) {
216   return rb_typeddata_is_kind_of(v, &grpc_rb_xds_channel_credentials_data_type);
217 }
218