frida 0.1.0 → 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (55) 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 +26 -25
  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/frida.gemspec +39 -0
  53. data/lib/frida/version.rb +5 -0
  54. data/lib/frida.rb +8 -0
  55. metadata +55 -3
@@ -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
+ }