frida 0.1.0 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. checksums.yaml +4 -4
  2. data/CODE_OF_CONDUCT.md +84 -0
  3. data/Gemfile +12 -0
  4. data/Gemfile.lock +25 -0
  5. data/LICENSE.txt +21 -0
  6. data/README.md +64 -0
  7. data/Rakefile +20 -0
  8. data/exe/frida +3 -0
  9. data/ext/c_frida/Application.c +79 -0
  10. data/ext/c_frida/Bus.c +91 -0
  11. data/ext/c_frida/Child.c +134 -0
  12. data/ext/c_frida/Compiler.c +208 -0
  13. data/ext/c_frida/Crash.c +92 -0
  14. data/ext/c_frida/Device.c +955 -0
  15. data/ext/c_frida/DeviceManager.c +260 -0
  16. data/ext/c_frida/EndpointParameters.c +189 -0
  17. data/ext/c_frida/FileMonitor.c +67 -0
  18. data/ext/c_frida/GObject.c +138 -0
  19. data/ext/c_frida/IOStream.c +228 -0
  20. data/ext/c_frida/PortalMembership.c +43 -0
  21. data/ext/c_frida/PortalService.c +413 -0
  22. data/ext/c_frida/Process.c +67 -0
  23. data/ext/c_frida/Relay.c +121 -0
  24. data/ext/c_frida/Script.c +221 -0
  25. data/ext/c_frida/Session.c +626 -0
  26. data/ext/c_frida/Spawn.c +53 -0
  27. data/ext/c_frida/c_frida.c +68 -0
  28. data/ext/c_frida/extconf.rb +13 -12
  29. data/ext/c_frida/gutils.c +498 -0
  30. data/ext/c_frida/gvl_bridge.c +131 -0
  31. data/ext/c_frida/inc/Application.h +9 -0
  32. data/ext/c_frida/inc/Bus.h +15 -0
  33. data/ext/c_frida/inc/Child.h +9 -0
  34. data/ext/c_frida/inc/Compiler.h +21 -0
  35. data/ext/c_frida/inc/Crash.h +9 -0
  36. data/ext/c_frida/inc/Device.h +71 -0
  37. data/ext/c_frida/inc/DeviceManager.h +20 -0
  38. data/ext/c_frida/inc/EndpointParameters.h +15 -0
  39. data/ext/c_frida/inc/FileMonitor.h +9 -0
  40. data/ext/c_frida/inc/GObject.h +10 -0
  41. data/ext/c_frida/inc/IOStream.h +29 -0
  42. data/ext/c_frida/inc/PortalMembership.h +9 -0
  43. data/ext/c_frida/inc/PortalService.h +47 -0
  44. data/ext/c_frida/inc/Process.h +9 -0
  45. data/ext/c_frida/inc/Relay.h +9 -0
  46. data/ext/c_frida/inc/Script.h +21 -0
  47. data/ext/c_frida/inc/Session.h +40 -0
  48. data/ext/c_frida/inc/Spawn.h +9 -0
  49. data/ext/c_frida/inc/c_frida.h +129 -0
  50. data/ext/c_frida/inc/gutils.h +21 -0
  51. data/ext/c_frida/inc/gvl_bridge.h +42 -0
  52. data/lib/frida/version.rb +5 -0
  53. data/lib/frida.rb +8 -0
  54. metadata +54 -5
@@ -0,0 +1,228 @@
1
+ #include "IOStream.h"
2
+
3
+ DEFINE_GOBJECT_CHILD_KLASS_DATA_TYPE(IOStream);
4
+
5
+ VALUE IOStream_from_GIOStream(GIOStream *stream)
6
+ {
7
+ VALUE self;
8
+
9
+ if (!stream) return (Qnil);
10
+ self = rb_class_new_instance(0, NULL, cIOStream);
11
+ GET_GOBJECT_DATA();
12
+ d->handle = stream;
13
+ GET_DATA_EX(IOStream, self, io_d);
14
+ io_d->input = g_io_stream_get_input_stream(d->handle);
15
+ io_d->output = g_io_stream_get_output_stream(d->handle);
16
+ return (self);
17
+ }
18
+
19
+ void IOStream_free(IOStream_d *d)
20
+ {
21
+ if (d->base.handle)
22
+ g_object_unref(d->base.handle);
23
+ xfree(d);
24
+ }
25
+
26
+ /*
27
+ call-seq:
28
+ #is_closed() -> [TrueClass, FalseClass]
29
+ */
30
+ static VALUE IOStream_is_closed(VALUE self)
31
+ {
32
+ GET_GOBJECT_DATA();
33
+ REQUIRE_GOBJECT_HANDLE();
34
+ return (g_io_stream_is_closed(d->handle) ? Qtrue : Qfalse);
35
+ }
36
+
37
+ static VALUE IOStream_inspect(VALUE self)
38
+ {
39
+ GET_GOBJECT_DATA();
40
+ VALUE s;
41
+
42
+ s = rb_sprintf("#<IOStream: handle=\"%p\", is_closed=%+"PRIsVALUE">", d->handle, rb_funcall(self, rb_intern("is_closed"), 0, NULL));
43
+ return (s);
44
+ }
45
+
46
+ GVL_FREE_PROXY_FUNC(write, write_proxy_args *args)
47
+ {
48
+ GError *gerr = NULL;
49
+ gsize written;
50
+
51
+ written = g_output_stream_write(args->output, args->data, args->size, NULL, &gerr);
52
+ RETURN_GVL_FREE_RESULT((void*)written);
53
+ }
54
+
55
+ /*
56
+ call-seq:
57
+ #write(data) -> Fixnum
58
+ */
59
+ static VALUE IOStream_write(VALUE self, VALUE data)
60
+ {
61
+ GET_GOBJECT_DATA();
62
+ REQUIRE_GOBJECT_HANDLE();
63
+ GET_DATA_EX(IOStream, self, io_d);
64
+
65
+ if (!RB_TYPE_P(data, T_STRING)) {
66
+ raise_argerror("data should be a string.");
67
+ return (Qnil);
68
+ }
69
+ write_proxy_args args = {
70
+ .output = io_d->output,
71
+ .data = RSTRING_PTR(data),
72
+ .size = RSTRING_LEN(data)
73
+ };
74
+ CALL_GVL_FREE_WITH_RET(void *written, write, &args);
75
+ return (ULONG2NUM((gsize)written));
76
+
77
+ GERROR_BLOCK
78
+ }
79
+
80
+ GVL_FREE_PROXY_FUNC(write_all, write_proxy_args *args)
81
+ {
82
+ GError *gerr = NULL;
83
+
84
+ g_output_stream_write_all(args->output, args->data, args->size, NULL, NULL, &gerr);
85
+ RETURN_GVL_FREE_RESULT(NULL);
86
+ }
87
+
88
+ /*
89
+ call-seq:
90
+ #write_all(data) -> nil
91
+ */
92
+ static VALUE IOStream_write_all(VALUE self, VALUE data)
93
+ {
94
+ GET_GOBJECT_DATA();
95
+ REQUIRE_GOBJECT_HANDLE();
96
+ GET_DATA_EX(IOStream, self, io_d);
97
+
98
+ if (!RB_TYPE_P(data, T_STRING)) {
99
+ raise_argerror("data should be a string.");
100
+ return (Qnil);
101
+ }
102
+ write_proxy_args args = {
103
+ .output = io_d->output,
104
+ .data = RSTRING_PTR(data),
105
+ .size = RSTRING_LEN(data)
106
+ };
107
+ CALL_GVL_FREE_WITH_RET(void *dummy, write_all, &args);
108
+ return (Qnil);
109
+
110
+ GERROR_BLOCK
111
+ }
112
+
113
+ GVL_FREE_PROXY_FUNC(read, read_proxy_args *args)
114
+ {
115
+ GError *gerr = NULL;
116
+ gsize read;
117
+
118
+ read = g_input_stream_read(args->input, args->buffer, args->count, NULL, &gerr);
119
+ RETURN_GVL_FREE_RESULT((void*)read);
120
+ }
121
+
122
+ /*
123
+ call-seq:
124
+ #read(count) -> String
125
+ */
126
+ static VALUE IOStream_read(VALUE self, VALUE count)
127
+ {
128
+ GET_GOBJECT_DATA();
129
+ REQUIRE_GOBJECT_HANDLE();
130
+ GET_DATA_EX(IOStream, self, io_d);
131
+
132
+ if (!FIXNUM_P(count)) {
133
+ raise_argerror("count should be a number.");
134
+ return (Qnil);
135
+ }
136
+ VALUE buffer = rb_str_new(NULL, NUM2ULONG(count));
137
+ read_proxy_args args = {
138
+ .input = io_d->input,
139
+ .buffer = RSTRING_PTR(buffer),
140
+ .count = NUM2ULONG(count)
141
+ };
142
+ CALL_GVL_FREE_WITH_RET(void *read, read, &args);
143
+ if ((gsize)read != NUM2ULONG(count))
144
+ buffer = rb_str_new(RSTRING_PTR(buffer), (gsize)read);
145
+ return (buffer);
146
+
147
+ GERROR_BLOCK
148
+ }
149
+
150
+ GVL_FREE_PROXY_FUNC(read_all, read_proxy_args *args)
151
+ {
152
+ GError *gerr = NULL;
153
+ gsize read;
154
+
155
+ g_input_stream_read_all(args->input, args->buffer, args->count, &read, NULL, &gerr);
156
+ RETURN_GVL_FREE_RESULT(NULL);
157
+ }
158
+
159
+ /*
160
+ call-seq:
161
+ #read_all(count) -> String
162
+ */
163
+ static VALUE IOStream_read_all(VALUE self, VALUE count)
164
+ {
165
+ GET_GOBJECT_DATA();
166
+ REQUIRE_GOBJECT_HANDLE();
167
+ GET_DATA_EX(IOStream, self, io_d);
168
+
169
+ if (!FIXNUM_P(count)) {
170
+ raise_argerror("count should be a number.");
171
+ return (Qnil);
172
+ }
173
+ VALUE buffer = rb_str_new(NULL, NUM2ULONG(count));
174
+ read_proxy_args args = {
175
+ .input = io_d->input,
176
+ .buffer = RSTRING_PTR(buffer),
177
+ .count = NUM2ULONG(count)
178
+ };
179
+ CALL_GVL_FREE_WITH_RET(void *dummy, read_all, &args);
180
+ return (buffer);
181
+
182
+ GERROR_BLOCK
183
+ }
184
+
185
+ GVL_FREE_PROXY_FUNC(close, GIOStream *handle)
186
+ {
187
+ GError *gerr = NULL;
188
+
189
+ g_io_stream_close(handle, NULL, &gerr);
190
+ RETURN_GVL_FREE_RESULT(NULL);
191
+ }
192
+
193
+ /*
194
+ call-seq:
195
+ #close() -> nil
196
+ */
197
+ static VALUE IOStream_close(VALUE self)
198
+ {
199
+ GET_GOBJECT_DATA();
200
+ REQUIRE_GOBJECT_HANDLE();
201
+
202
+ CALL_GVL_FREE_WITH_RET(void *dummy, close, d->handle);
203
+ return (Qnil);
204
+
205
+ GERROR_BLOCK
206
+ }
207
+
208
+ static VALUE IOStream_alloc(VALUE klass)
209
+ {
210
+ MAKE_DATA(IOStream);
211
+ memset(d, 0, sizeof(IOStream_d));
212
+ rb_ivar_set(obj, rb_intern("callbacks"), rb_hash_new());
213
+ return (obj);
214
+ }
215
+
216
+ void define_IOStream()
217
+ {
218
+ cIOStream = rb_define_class_under(mCFrida, "IOStream", cGObject);
219
+ rb_define_alloc_func(cIOStream, IOStream_alloc);
220
+ rb_define_method(cIOStream, "inspect", IOStream_inspect, 0);
221
+ rb_define_alias(cIOStream, "to_s", "inspect");
222
+ rb_define_method(cIOStream, "is_closed", IOStream_is_closed, 0);
223
+ rb_define_method(cIOStream, "read", IOStream_read, 1);
224
+ rb_define_method(cIOStream, "read_all", IOStream_read_all, 1);
225
+ rb_define_method(cIOStream, "write", IOStream_write, 1);
226
+ rb_define_method(cIOStream, "write_all", IOStream_write_all, 1);
227
+ rb_define_method(cIOStream, "close", IOStream_close, 0);
228
+ }
@@ -0,0 +1,43 @@
1
+ #include "PortalMembership.h"
2
+
3
+ VALUE PortalMembership_from_FridaPortalMembership(FridaPortalMembership *handle)
4
+ {
5
+ VALUE self;
6
+
7
+ if (!handle)
8
+ return (Qnil);
9
+ self = rb_class_new_instance(0, NULL, cPortalMembership);
10
+ GET_GOBJECT_DATA();
11
+ d->handle = handle;
12
+ d->destroy = frida_unref;
13
+ return (self);
14
+ }
15
+
16
+ GVL_FREE_PROXY_FUNC(terminate_sync, FridaPortalMembership *handle)
17
+ {
18
+ GError *gerr = NULL;
19
+
20
+ frida_portal_membership_terminate_sync(handle, NULL, &gerr);
21
+ RETURN_GVL_FREE_RESULT(NULL);
22
+ }
23
+
24
+ /*
25
+ call-seq:
26
+ #terminate() -> nil
27
+ */
28
+ static VALUE PortalMembership_terminate(VALUE self)
29
+ {
30
+ GET_GOBJECT_DATA();
31
+ REQUIRE_GOBJECT_HANDLE();
32
+ CALL_GVL_FREE_WITH_RET(void *dummy, terminate_sync, d->handle);
33
+ return (Qnil);
34
+
35
+ GERROR_BLOCK
36
+ }
37
+
38
+ void define_PortalMembership()
39
+ {
40
+ cPortalMembership = rb_define_class_under(mCFrida, "PortalMembership", cGObject);
41
+
42
+ rb_define_method(cPortalMembership, "terminate", PortalMembership_terminate, 0);
43
+ }
@@ -0,0 +1,413 @@
1
+ #include "PortalService.h"
2
+
3
+ GVL_FREE_PROXY_FUNC(stop_sync, FridaPortalService *handle)
4
+ {
5
+ GError *gerr = NULL;
6
+
7
+ frida_portal_service_stop_sync(handle, NULL, &gerr);
8
+ RETURN_GVL_FREE_RESULT(NULL);
9
+ }
10
+
11
+ static void PortalService_destroy(void *handle)
12
+ {
13
+ CALL_GVL_FREE_WITH_RET(void *dummy, stop_sync, handle);
14
+ frida_unref(handle);
15
+ return ;
16
+
17
+ gerror:
18
+ g_error_free(_gerr);
19
+ frida_unref(handle);
20
+ }
21
+
22
+ /*
23
+ call-seq:
24
+ #device() -> Device
25
+ */
26
+ static VALUE PortalService_device(VALUE self)
27
+ {
28
+ return (rb_ivar_get(self, rb_intern("device")));
29
+ }
30
+
31
+ /*
32
+ call-seq:
33
+ #stop() -> nil
34
+ */
35
+ static VALUE PortalService_stop(VALUE self)
36
+ {
37
+ GET_GOBJECT_DATA();
38
+ REQUIRE_GOBJECT_HANDLE();
39
+
40
+ CALL_GVL_FREE_WITH_RET(void *dummy, stop_sync, d->handle);
41
+ return (Qnil);
42
+
43
+ GERROR_BLOCK
44
+ }
45
+
46
+
47
+ GVL_FREE_PROXY_FUNC(start_sync, FridaPortalService *handle)
48
+ {
49
+ GError *gerr = NULL;
50
+
51
+ frida_portal_service_start_sync(handle, NULL, &gerr);
52
+ RETURN_GVL_FREE_RESULT(NULL);
53
+ }
54
+
55
+ /*
56
+ call-seq:
57
+ #start() -> nil
58
+ */
59
+ static VALUE PortalService_start(VALUE self)
60
+ {
61
+ GET_GOBJECT_DATA();
62
+ REQUIRE_GOBJECT_HANDLE();
63
+
64
+ CALL_GVL_FREE_WITH_RET(void *dummy, start_sync, d->handle);
65
+ return (Qnil);
66
+
67
+ GERROR_BLOCK
68
+ }
69
+
70
+ GVL_FREE_PROXY_FUNC(kick, kick_proxy_args *args)
71
+ {
72
+ GError *gerr = NULL;
73
+
74
+ frida_portal_service_kick(args->handle, args->connection_id);
75
+ RETURN_GVL_FREE_RESULT(NULL);
76
+ }
77
+
78
+ /*
79
+ call-seq:
80
+ #kick(connection_id) -> nil
81
+ */
82
+ static VALUE PortalService_kick(VALUE self, VALUE connection_id)
83
+ {
84
+ GET_GOBJECT_DATA();
85
+ REQUIRE_GOBJECT_HANDLE();
86
+
87
+ if (!RB_TYPE_P(connection_id, T_FIXNUM)) {
88
+ raise_argerror("connection_id must be an integer.");
89
+ return (Qnil);
90
+ }
91
+ kick_proxy_args args = {
92
+ .handle = d->handle,
93
+ .connection_id = NUM2UINT(connection_id)
94
+ };
95
+ CALL_GVL_FREE_WITH_RET(void *dummy, kick, &args);
96
+ return (Qnil);
97
+
98
+ UNREACHABLE_GERROR_BLOCK
99
+ }
100
+
101
+ GVL_FREE_PROXY_FUNC(post, _post_proxy_args *args)
102
+ {
103
+ GError *gerr = NULL;
104
+
105
+ frida_portal_service_post(args->handle, args->connection_id, args->message, args->data);
106
+ RETURN_GVL_FREE_RESULT(NULL);
107
+ }
108
+
109
+ /*
110
+ call-seq:
111
+ #post(connection_id, message, data:) -> nil
112
+ */
113
+ static VALUE PortalService_post(int argc, VALUE *argv, VALUE self)
114
+ {
115
+ GET_GOBJECT_DATA();
116
+ REQUIRE_GOBJECT_HANDLE();
117
+ VALUE connection_id, message, kws;
118
+ GBytes *gdata = NULL;
119
+
120
+ rb_scan_args(argc, argv, "2:", &connection_id, &message, &kws);
121
+ if (!RB_TYPE_P(connection_id, T_FIXNUM)) {
122
+ raise_argerror("tag must be a number.");
123
+ return (Qnil);
124
+ }
125
+ if (!RB_TYPE_P(message, T_STRING)) {
126
+ raise_argerror("message must be a String.");
127
+ return (Qnil);
128
+ }
129
+ if (!NIL_P(kws)) {
130
+ VALUE data = rb_hash_aref(kws, ID2SYM(rb_intern("data")));
131
+ if (!NIL_P(data)) {
132
+ if (!RB_TYPE_P(data, T_STRING)) {
133
+ raise_argerror("data must be a String.");
134
+ return (Qnil);
135
+ }
136
+ }
137
+ gdata = g_bytes_new(RSTRING_PTR(data), RSTRING_LEN(data));
138
+ }
139
+ _post_proxy_args args = {
140
+ .handle = d->handle,
141
+ .connection_id = NUM2UINT(connection_id),
142
+ .message = StringValueCStr(message),
143
+ .data = gdata
144
+ };
145
+ CALL_GVL_FREE_WITH_RET(void *dummy, post, &args);
146
+ g_bytes_unref(gdata);
147
+ return (Qnil);
148
+
149
+ UNREACHABLE_GERROR_BLOCK
150
+ }
151
+
152
+ GVL_FREE_PROXY_FUNC(narrowcast, narrowcast_proxy_args *args)
153
+ {
154
+ GError *gerr = NULL;
155
+
156
+ frida_portal_service_narrowcast(args->handle, args->tag, args->message, args->data);
157
+ RETURN_GVL_FREE_RESULT(NULL);
158
+ }
159
+
160
+ /*
161
+ call-seq:
162
+ #narrowcast(tag, message, data:) -> nil
163
+ */
164
+ static VALUE PortalService_narrowcast(int argc, VALUE *argv, VALUE self)
165
+ {
166
+ GET_GOBJECT_DATA();
167
+ REQUIRE_GOBJECT_HANDLE();
168
+ VALUE tag, message, kws;
169
+ GBytes *gdata = NULL;
170
+
171
+ rb_scan_args(argc, argv, "2:", &tag, &message, &kws);
172
+ if (!RB_TYPE_P(tag, T_STRING)) {
173
+ raise_argerror("tag must be a String.");
174
+ return (Qnil);
175
+ }
176
+ if (!RB_TYPE_P(message, T_STRING)) {
177
+ raise_argerror("message must be a String.");
178
+ return (Qnil);
179
+ }
180
+ if (!NIL_P(kws)) {
181
+ VALUE data = rb_hash_aref(kws, ID2SYM(rb_intern("data")));
182
+ if (!NIL_P(data)) {
183
+ if (!RB_TYPE_P(data, T_STRING)) {
184
+ raise_argerror("data must be a String.");
185
+ return (Qnil);
186
+ }
187
+ }
188
+ gdata = g_bytes_new(RSTRING_PTR(data), RSTRING_LEN(data));
189
+ }
190
+ narrowcast_proxy_args args = {
191
+ .handle = d->handle,
192
+ .tag = StringValueCStr(tag),
193
+ .message = StringValueCStr(message),
194
+ .data = gdata
195
+ };
196
+ CALL_GVL_FREE_WITH_RET(void *dummy, narrowcast, &args);
197
+ g_bytes_unref(gdata);
198
+ return (Qnil);
199
+
200
+ UNREACHABLE_GERROR_BLOCK
201
+ }
202
+
203
+ GVL_FREE_PROXY_FUNC(broadcast, broadcast_proxy_args *args)
204
+ {
205
+ GError *gerr = NULL;
206
+
207
+ frida_portal_service_broadcast(args->handle, args->message, args->data);
208
+ RETURN_GVL_FREE_RESULT(NULL);
209
+ }
210
+
211
+ /*
212
+ call-seq:
213
+ #broadcast(message, data:) -> nil
214
+ */
215
+ static VALUE PortalService_broadcast(int argc, VALUE *argv, VALUE self)
216
+ {
217
+ GET_GOBJECT_DATA();
218
+ REQUIRE_GOBJECT_HANDLE();
219
+ VALUE message, kws;
220
+ GBytes *gdata = NULL;
221
+
222
+ rb_scan_args(argc, argv, "1:", &message, &kws);
223
+ if (!RB_TYPE_P(message, T_STRING)) {
224
+ raise_argerror("message must be a String.");
225
+ return (Qnil);
226
+ }
227
+ if (!NIL_P(kws)) {
228
+ VALUE data = rb_hash_aref(kws, ID2SYM(rb_intern("data")));
229
+ if (!NIL_P(data)) {
230
+ if (!RB_TYPE_P(data, T_STRING)) {
231
+ raise_argerror("data must be a String.");
232
+ return (Qnil);
233
+ }
234
+ }
235
+ gdata = g_bytes_new(RSTRING_PTR(data), RSTRING_LEN(data));
236
+ }
237
+ broadcast_proxy_args args = {
238
+ .handle = d->handle,
239
+ .message = StringValueCStr(message),
240
+ .data = gdata
241
+ };
242
+ CALL_GVL_FREE_WITH_RET(void *dummy, broadcast, &args);
243
+ g_bytes_unref(gdata);
244
+ return (Qnil);
245
+
246
+ UNREACHABLE_GERROR_BLOCK
247
+ }
248
+
249
+ GVL_FREE_PROXY_FUNC(enumerate_tags, enumerate_tags_proxy_args *args)
250
+ {
251
+ GError *gerr = NULL;
252
+ gchar **tags;
253
+
254
+ tags = frida_portal_service_enumerate_tags(args->handle, args->connection_id, args->tags_count);
255
+ RETURN_GVL_FREE_RESULT(tags);
256
+ }
257
+
258
+ /*
259
+ call-seq:
260
+ #enumerate_tags(connection_id) -> Array
261
+ */
262
+ static VALUE PortalService_enumerate_tags(VALUE self, VALUE connection_id)
263
+ {
264
+ GET_GOBJECT_DATA();
265
+ REQUIRE_GOBJECT_HANDLE();
266
+ gint tags_count;
267
+
268
+ if (!RB_TYPE_P(connection_id, T_FIXNUM)) {
269
+ raise_argerror("connection_id must be an integer.");
270
+ return (Qnil);
271
+ }
272
+ enumerate_tags_proxy_args args = {
273
+ .handle = d->handle,
274
+ .connection_id = NUM2UINT(connection_id),
275
+ .tags_count = &tags_count
276
+ };
277
+ CALL_GVL_FREE_WITH_RET(gchar **tags, enumerate_tags, &args);
278
+ VALUE rtags = rbGObject_marshal_strv(tags, tags_count);
279
+ g_strfreev(tags);
280
+ return (rtags);
281
+
282
+ UNREACHABLE_GERROR_BLOCK
283
+ }
284
+
285
+ GVL_FREE_PROXY_FUNC(tag, tag_proxy_args *args)
286
+ {
287
+ GError *gerr = NULL;
288
+
289
+ frida_portal_service_tag(args->handle, args->connection_id, args->tag);
290
+ RETURN_GVL_FREE_RESULT(NULL);
291
+ }
292
+
293
+ /*
294
+ call-seq:
295
+ #tag(connection_id, tag) -> nil
296
+ */
297
+ static VALUE PortalService_tag(VALUE self, VALUE connection_id, VALUE tag)
298
+ {
299
+ GET_GOBJECT_DATA();
300
+ REQUIRE_GOBJECT_HANDLE();
301
+
302
+ if (!RB_TYPE_P(connection_id, T_FIXNUM)) {
303
+ raise_argerror("connection_id must be an integer.");
304
+ return (Qnil);
305
+ }
306
+ if (!RB_TYPE_P(tag, T_STRING)) {
307
+ raise_argerror("tag must be a String.");
308
+ return (Qnil);
309
+ }
310
+ tag_proxy_args args = {
311
+ .handle = d->handle,
312
+ .connection_id = NUM2UINT(connection_id),
313
+ .tag = StringValueCStr(tag)
314
+ };
315
+ CALL_GVL_FREE_WITH_RET(void *dummy, tag, &args);
316
+ return (Qnil);
317
+
318
+ UNREACHABLE_GERROR_BLOCK
319
+ }
320
+
321
+ GVL_FREE_PROXY_FUNC(untag, untag_proxy_args *args)
322
+ {
323
+ GError *gerr = NULL;
324
+
325
+ frida_portal_service_untag(args->handle, args->connection_id, args->tag);
326
+ RETURN_GVL_FREE_RESULT(NULL);
327
+ }
328
+
329
+ /*
330
+ call-seq:
331
+ #untag(connection_id, tag) -> nil
332
+ */
333
+ static VALUE PortalService_untag(VALUE self, VALUE connection_id, VALUE tag)
334
+ {
335
+ GET_GOBJECT_DATA();
336
+ REQUIRE_GOBJECT_HANDLE();
337
+
338
+ if (!RB_TYPE_P(connection_id, T_FIXNUM)) {
339
+ raise_argerror("connection_id must be an integer.");
340
+ return (Qnil);
341
+ }
342
+ if (!RB_TYPE_P(tag, T_STRING)) {
343
+ raise_argerror("tag must be a String.");
344
+ return (Qnil);
345
+ }
346
+ untag_proxy_args args = {
347
+ .handle = d->handle,
348
+ .connection_id = NUM2UINT(connection_id),
349
+ .tag = StringValueCStr(tag)
350
+ };
351
+ CALL_GVL_FREE_WITH_RET(void *dummy, untag, &args);
352
+ return (Qnil);
353
+
354
+ UNREACHABLE_GERROR_BLOCK
355
+ }
356
+
357
+ /*
358
+ call-seq:
359
+ #new(cluster_params, control_params:) -> PortalService
360
+ */
361
+ static VALUE PortalService_initialize(int argc, VALUE *argv, VALUE self)
362
+ {
363
+ GET_GOBJECT_DATA();
364
+ VALUE cluster_params, kws;
365
+ FridaEndpointParameters *c, *cc = NULL;
366
+
367
+ rb_scan_args(argc, argv, "1:", &cluster_params, &kws);
368
+ if (!rb_obj_is_instance_of(cluster_params, cEndpointParameters)) {
369
+ raise_argerror("cluster_params must be an instance of EndpointParameters.");
370
+ return (Qnil);
371
+ }
372
+ GET_DATA_EX(GObject, cluster_params, c_d);
373
+ c = c_d->handle;
374
+ // we support creating classes without a handle for marshaling purposes, but those instances should not work here.
375
+ if (!c) {
376
+ raise_argerror("cluster_params must be an instance of a valid EndpointParameters.");
377
+ return (Qnil);
378
+ }
379
+ if (!NIL_P(kws)) {
380
+ VALUE control_params = rb_hash_aref(kws, ID2SYM(rb_intern("control_params")));
381
+ if (!NIL_P(control_params)) {
382
+ if (!rb_obj_is_instance_of(control_params, cEndpointParameters)) {
383
+ raise_argerror("control_params must be an instance of EndpointParameters.");
384
+ return (Qnil);
385
+ }
386
+ GET_DATA_EX(GObject, control_params, cc_d);
387
+ cc = cc_d->handle;
388
+ }
389
+ }
390
+ FridaPortalService *handle = frida_portal_service_new(c, cc);
391
+ d->handle = handle;
392
+ d->destroy = PortalService_destroy;
393
+ rb_ivar_set(self, rb_intern("device"), Device_from_FridaDevice(g_object_ref(frida_portal_service_get_device(d->handle))));
394
+ return (self);
395
+ }
396
+
397
+ void define_PortalService()
398
+ {
399
+ cPortalService = rb_define_class_under(mCFrida, "PortalService", cGObject);
400
+
401
+ rb_define_method(cPortalService, "initialize", PortalService_initialize, -1);
402
+ rb_define_method(cPortalService, "device", PortalService_device, 0);
403
+
404
+ rb_define_method(cPortalService, "start", PortalService_start, 0);
405
+ rb_define_method(cPortalService, "stop", PortalService_stop, 0);
406
+ rb_define_method(cPortalService, "kick", PortalService_kick, 1);
407
+ rb_define_method(cPortalService, "post", PortalService_post, -1);
408
+ rb_define_method(cPortalService, "narrowcast", PortalService_narrowcast, -1);
409
+ rb_define_method(cPortalService, "broadcast", PortalService_broadcast, -1);
410
+ rb_define_method(cPortalService, "enumerate_tags", PortalService_enumerate_tags, 1);
411
+ rb_define_method(cPortalService, "tag", PortalService_tag, 2);
412
+ rb_define_method(cPortalService, "untag", PortalService_untag, 2);
413
+ }