intruder 0.1.0 → 0.2.0
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.
- data/README.md +25 -7
- data/extconf.rb +21 -0
- data/findei.erl +6 -0
- data/lib/intruder.rb +20 -0
- data/src/atom.c +7 -0
- data/src/atom.h +12 -0
- data/src/binary.c +20 -0
- data/src/binary.h +13 -0
- data/src/erlix_helper.c +165 -0
- data/src/erlix_helper.h +13 -0
- data/src/intruder_ext.c +48 -0
- data/src/intruder_ext.h +28 -0
- data/src/list.c +70 -0
- data/src/list.h +19 -0
- data/src/mod.c +74 -0
- data/src/mod.h +25 -0
- data/src/node.c +217 -0
- data/src/node.h +49 -0
- data/src/term.c +168 -0
- data/src/term.h +58 -0
- data/src/tuple.c +55 -0
- data/src/tuple.h +17 -0
- metadata +43 -10
data/README.md
CHANGED
@@ -12,27 +12,45 @@ Want to try?
|
|
12
12
|
the test script makes an rpc call to a rabbitmq server and queries for its status.
|
13
13
|
|
14
14
|
* checkout the source
|
15
|
-
*
|
15
|
+
* `ruby extconf.rb`
|
16
16
|
* start your rabbitmq server `sudo rabbitmq-server`
|
17
|
-
* `ruby
|
17
|
+
* `ruby examples/rabbitmq_status_rpc.rb`
|
18
18
|
|
19
19
|
the script should print something similar to this:
|
20
|
-
rabbit call
|
20
|
+
--- rabbit call ---
|
21
21
|
sending params: []
|
22
22
|
rpc call to rabbit:status
|
23
|
-
|
23
|
+
[{running_applications, [{rabbit, "RabbitMQ", "1.7.2"}, {mnesia, "MNESIA CXC 138 12", "4.4.13"}, {os_mon, "CPO CXC 138 46", "2.2.5"}, {sasl, "SASL CXC 138 11", "2.1.9"}, {stdlib, "ERTS CXC 138 10", "1.16.5"}, {kernel, "ERTS CXC 138 10", "2.13.5"}]}, {nodes, ['rabbit@codeslave']}, {running_nodes, ['rabbit@codeslave']}]
|
24
|
+
Intruder::List
|
25
|
+
|
26
|
+
--- length of the response ---
|
27
|
+
Members: 3
|
28
|
+
|
29
|
+
--- print every member with its class ---
|
30
|
+
{running_applications, [{rabbit, "RabbitMQ", "1.7.2"}, {mnesia, "MNESIA CXC 138 12", "4.4.13"}, {os_mon, "CPO CXC 138 46", "2.2.5"}, {sasl, "SASL CXC 138 11", "2.1.9"}, {stdlib, "ERTS CXC 138 10", "1.16.5"}, {kernel, "ERTS CXC 138 10", "2.13.5"}]} class: Intruder::Tuple
|
31
|
+
{nodes, ['rabbit@codeslave']} class: Intruder::Tuple
|
32
|
+
{running_nodes, ['rabbit@codeslave']} class: Intruder::Tuple
|
33
|
+
|
34
|
+
--- access the second element and print its size ---
|
35
|
+
{running_nodes, ['rabbit@codeslave']} has size 2
|
36
|
+
|
37
|
+
--- access the first element of the second member ---
|
38
|
+
nodes
|
39
|
+
|
40
|
+
--- which is a ---
|
41
|
+
Intruder::Atom
|
24
42
|
|
25
43
|
Why that?
|
26
44
|
=========
|
27
45
|
|
28
|
-
because thats a fun project to learn c :)
|
46
|
+
because thats a fun project to learn c and I need it for another project of mine (namely: paukul/humpty)
|
29
47
|
|
30
48
|
What works already?
|
31
49
|
===================
|
32
50
|
|
33
|
-
|
51
|
+
description missing... yet :)
|
34
52
|
|
35
53
|
Erlix?
|
36
54
|
======
|
37
55
|
|
38
|
-
is great, took some stuff from
|
56
|
+
is great, I also took some stuff from them. Afaik, Erlix uses erl_interface for most of its operations. erl_interface is limited to one connection only, I needed something to open multiple connections to multiple queues. Erlix is able to do a LOT more than Intruder at the moment, make sure to check it out as well!
|
data/extconf.rb
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'mkmf'
|
2
|
+
|
3
|
+
extension_name = 'intruder_ext'
|
4
|
+
src_dir = File.expand_path('../src', __FILE__)
|
5
|
+
findei = File.expand_path("../findei.erl", __FILE__)
|
6
|
+
|
7
|
+
dir_config(extension_name)
|
8
|
+
File.chmod(0755, findei)
|
9
|
+
|
10
|
+
ei_dir = `#{findei}`.chomp
|
11
|
+
include_dir = ei_dir + '/include/'
|
12
|
+
lib_dir = ei_dir + '/lib/'
|
13
|
+
|
14
|
+
$LDFLAGS << " -L#{lib_dir} -lei -lerl_interface"
|
15
|
+
$CPPFLAGS << ' -D_REENTRANT -g -g3 -gdwarf-2'
|
16
|
+
|
17
|
+
if find_header('ei.h', include_dir)
|
18
|
+
create_makefile(extension_name, src_dir)
|
19
|
+
else
|
20
|
+
puts "error: erl_interface not found!"
|
21
|
+
end
|
data/findei.erl
ADDED
data/lib/intruder.rb
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
require File.expand_path('../../intruder_ext', __FILE__)
|
2
|
+
|
3
|
+
module Intruder
|
4
|
+
|
5
|
+
class Node
|
6
|
+
def mod(mod_name)
|
7
|
+
Mod.new(mod_name, self)
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
class Mod
|
12
|
+
|
13
|
+
private
|
14
|
+
|
15
|
+
def method_missing(method, *args)
|
16
|
+
rpc(method.to_s, *args)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
data/src/atom.c
ADDED
data/src/atom.h
ADDED
data/src/binary.c
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
#include "binary.h"
|
2
|
+
|
3
|
+
VALUE IntruderBinary = Qnil;
|
4
|
+
|
5
|
+
void Init_intruder_binary() {
|
6
|
+
IntruderBinary = rb_define_class_under(IntruderModule, "Binary", IntruderTerm);
|
7
|
+
|
8
|
+
/* class methods */
|
9
|
+
rb_define_method(IntruderBinary, "initialize", intruder_binary_init, 1);
|
10
|
+
}
|
11
|
+
|
12
|
+
VALUE intruder_binary_init(VALUE self, VALUE str) {
|
13
|
+
ETERM *eterm;
|
14
|
+
INTRUDER_TERM *iterm;
|
15
|
+
Data_Get_Struct(self, INTRUDER_TERM, iterm);
|
16
|
+
|
17
|
+
eterm = erl_mk_binary(RSTRING_PTR(str), RSTRING_LEN(str));
|
18
|
+
iterm->eterm = eterm;
|
19
|
+
return self;
|
20
|
+
}
|
data/src/binary.h
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
#ifndef INTRUDER_BINARY_H
|
2
|
+
#define INTRUDER_BINARY_H
|
3
|
+
|
4
|
+
#include "ruby.h"
|
5
|
+
#include "term.h"
|
6
|
+
|
7
|
+
extern VALUE IntruderModule;
|
8
|
+
extern VALUE IntruderTerm;
|
9
|
+
|
10
|
+
void Init_intruder_binary();
|
11
|
+
VALUE intruder_binary_init(VALUE self, VALUE str);
|
12
|
+
|
13
|
+
#endif /* INTRUDER_BINARY_H */
|
data/src/erlix_helper.c
ADDED
@@ -0,0 +1,165 @@
|
|
1
|
+
/*
|
2
|
+
* taken from erlix erlix
|
3
|
+
* http://github.com/KDr2/erlix
|
4
|
+
*/
|
5
|
+
|
6
|
+
#include "erlix_helper.h"
|
7
|
+
|
8
|
+
static int is_printable_list(const ETERM* term);
|
9
|
+
static void fill_printable_list(VALUE *str, const ETERM* ep);
|
10
|
+
|
11
|
+
static int is_printable_list(const ETERM* term)
|
12
|
+
{
|
13
|
+
while (ERL_TYPE(term) == ERL_LIST) {
|
14
|
+
ETERM* head = (ETERM*)(ERL_CONS_HEAD(term));
|
15
|
+
if (ERL_INT_VALUE(head) < 0 || ERL_INT_VALUE(head) > 255) {
|
16
|
+
return 0;
|
17
|
+
}
|
18
|
+
if (ERL_INT_VALUE(head) < ' ') {
|
19
|
+
switch (ERL_INT_VALUE(head)) {
|
20
|
+
case '\n':
|
21
|
+
case '\r':
|
22
|
+
case '\t':
|
23
|
+
case '\v':
|
24
|
+
case '\b':
|
25
|
+
case '\f':
|
26
|
+
break;
|
27
|
+
default:
|
28
|
+
return 0;
|
29
|
+
}
|
30
|
+
}
|
31
|
+
term = (ETERM*)(ERL_CONS_TAIL(term));
|
32
|
+
}
|
33
|
+
return ERL_IS_EMPTY_LIST(term);
|
34
|
+
}
|
35
|
+
|
36
|
+
static void fill_printable_list(VALUE *str, const ETERM* ep){
|
37
|
+
ID concat=rb_intern("concat");
|
38
|
+
/* rb_funcall(*str,concat,1,rb_str_new2("\"")); */
|
39
|
+
|
40
|
+
while (ERL_IS_CONS(ep)) {
|
41
|
+
int c = ERL_INT_VALUE((ETERM*)ERL_CONS_HEAD(ep));
|
42
|
+
if (c >= ' ') {
|
43
|
+
char tmp_buf[2];
|
44
|
+
tmp_buf[0]=c;
|
45
|
+
tmp_buf[1]=0;
|
46
|
+
rb_funcall(*str,concat,1,rb_str_new2(tmp_buf));
|
47
|
+
}
|
48
|
+
else {
|
49
|
+
if(c=='\n'){
|
50
|
+
rb_funcall(*str,concat,1,rb_str_new2("\\n"));
|
51
|
+
}else if(c=='\r'){
|
52
|
+
rb_funcall(*str,concat,1,rb_str_new2("\\r"));
|
53
|
+
}else if(c=='\t'){
|
54
|
+
rb_funcall(*str,concat,1,rb_str_new2("\\t"));
|
55
|
+
}else if(c=='\v'){
|
56
|
+
rb_funcall(*str,concat,1,rb_str_new2("\\v"));
|
57
|
+
}else if(c=='\b'){
|
58
|
+
rb_funcall(*str,concat,1,rb_str_new2("\\b"));
|
59
|
+
}else if(c=='\f'){
|
60
|
+
rb_funcall(*str,concat,1,rb_str_new2("\\f"));
|
61
|
+
}else{
|
62
|
+
char tmp_buf[8];
|
63
|
+
memset(tmp_buf,0,8);
|
64
|
+
sprintf(tmp_buf,"\\%o",c);
|
65
|
+
rb_funcall(*str,concat,1,rb_str_new2(tmp_buf));
|
66
|
+
}
|
67
|
+
}
|
68
|
+
ep = (ETERM*)ERL_CONS_TAIL(ep);
|
69
|
+
}
|
70
|
+
/* rb_funcall(*str,concat,1,rb_str_new2("\"")); */
|
71
|
+
}
|
72
|
+
|
73
|
+
void fill_string(VALUE *str,ETERM *ep){
|
74
|
+
ID concat=rb_intern("concat");
|
75
|
+
|
76
|
+
int j,i,doquote;
|
77
|
+
if (!ep) return;
|
78
|
+
|
79
|
+
j = i = doquote = 0;
|
80
|
+
|
81
|
+
if(ERL_IS_ATOM(ep)){
|
82
|
+
/* FIXME: what if some weird locale is in use? */
|
83
|
+
if (!islower((int)ERL_ATOM_PTR(ep)[0]))
|
84
|
+
doquote = 1;
|
85
|
+
for (i = 0; !doquote && i < ERL_ATOM_SIZE(ep); i++){
|
86
|
+
doquote = !(isalnum((int)ERL_ATOM_PTR(ep)[i])
|
87
|
+
|| (ERL_ATOM_PTR(ep)[i] == '_'));
|
88
|
+
}
|
89
|
+
if (doquote) {
|
90
|
+
rb_funcall(*str,concat,1,rb_str_new2("\'"));
|
91
|
+
}
|
92
|
+
rb_funcall(*str,concat,1,rb_str_new2(ERL_ATOM_PTR(ep)));
|
93
|
+
if(doquote){
|
94
|
+
rb_funcall(*str,concat,1,rb_str_new2("\'"));
|
95
|
+
}
|
96
|
+
}else if(ERL_IS_PID(ep)){
|
97
|
+
int buffsize = 9 + strlen(ERL_PID_NODE(ep));
|
98
|
+
char tmp_buf_pid[buffsize];
|
99
|
+
memset(tmp_buf_pid,0,buffsize);
|
100
|
+
sprintf(tmp_buf_pid,"<%s.%d.%d>",ERL_PID_NODE(ep),ERL_PID_NUMBER(ep), ERL_PID_SERIAL(ep));
|
101
|
+
rb_funcall(*str,concat,1,rb_str_new2(tmp_buf_pid));
|
102
|
+
}else if(ERL_IS_PORT(ep)){
|
103
|
+
rb_funcall(*str,concat,1,rb_str_new2("#Port"));
|
104
|
+
}else if(ERL_IS_REF(ep)){
|
105
|
+
rb_funcall(*str,concat,1,rb_str_new2("#Ref"));
|
106
|
+
}else if(ERL_IS_EMPTY_LIST(ep)){
|
107
|
+
rb_funcall(*str,concat,1,rb_str_new2("[]"));
|
108
|
+
}else if(ERL_IS_LIST(ep)){
|
109
|
+
if (is_printable_list(ep)) {
|
110
|
+
fill_printable_list(str,ep);
|
111
|
+
} else {
|
112
|
+
rb_funcall(*str,concat,1,rb_str_new2("["));
|
113
|
+
ETERM *tl=ep,*hd,*tmp;
|
114
|
+
while (ERL_IS_CONS(tl)){
|
115
|
+
hd=erl_hd(tl);
|
116
|
+
fill_string(str,hd);
|
117
|
+
//erl_free_term(hd);
|
118
|
+
tmp = erl_tl(tl);
|
119
|
+
//if(tl!=ep)erl_free_term(tl);
|
120
|
+
tl=tmp;
|
121
|
+
if (ERL_IS_CONS(tl)) {
|
122
|
+
rb_funcall(*str,concat,1,rb_str_new2(", "));
|
123
|
+
}
|
124
|
+
}
|
125
|
+
if (!ERL_IS_EMPTY_LIST(tl)) {
|
126
|
+
rb_funcall(*str,concat,1,rb_str_new2("|"));
|
127
|
+
fill_string(str, tl);
|
128
|
+
}else{
|
129
|
+
//erl_free_term(tl);
|
130
|
+
}
|
131
|
+
rb_funcall(*str,concat,1,rb_str_new2("]"));
|
132
|
+
}
|
133
|
+
}else if(ERL_IS_TUPLE(ep)){
|
134
|
+
rb_funcall(*str,concat,1,rb_str_new2("{"));
|
135
|
+
for (i=0; i < ERL_TUPLE_SIZE(ep); i++) {
|
136
|
+
ETERM *e=erl_element(i+1,ep);
|
137
|
+
fill_string(str,e);
|
138
|
+
//erl_free_term(e);
|
139
|
+
if (i != ERL_TUPLE_SIZE(ep)-1) {
|
140
|
+
rb_funcall(*str,concat,1,rb_str_new2(", "));
|
141
|
+
}
|
142
|
+
}
|
143
|
+
rb_funcall(*str,concat,1,rb_str_new2("}"));
|
144
|
+
}else if(ERL_IS_BINARY(ep)){
|
145
|
+
rb_funcall(*str,concat,1,rb_str_new2(ERL_BIN_PTR(ep)));
|
146
|
+
}else if(ERL_IS_INTEGER(ep)){
|
147
|
+
char tmp_buf_num[24];
|
148
|
+
memset(tmp_buf_num,0,24);
|
149
|
+
sprintf(tmp_buf_num,"%d", ERL_INT_VALUE(ep));
|
150
|
+
rb_funcall(*str,concat,1,rb_str_new2(tmp_buf_num));
|
151
|
+
}else if(ERL_IS_UNSIGNED_INTEGER(ep)){
|
152
|
+
char tmp_buf_unum[24];
|
153
|
+
memset(tmp_buf_unum, 0, 24);
|
154
|
+
sprintf(tmp_buf_unum, "%u", ERL_INT_UVALUE(ep));
|
155
|
+
rb_funcall(*str,concat, 1, rb_str_new2(tmp_buf_unum));
|
156
|
+
}else if(ERL_IS_FLOAT(ep)){
|
157
|
+
char tmp_buf_float[24];
|
158
|
+
memset(tmp_buf_float, 0, 24);
|
159
|
+
sprintf(tmp_buf_float, "%f", ERL_FLOAT_VALUE(ep));
|
160
|
+
rb_funcall(*str,concat, 1, rb_str_new2(tmp_buf_float));
|
161
|
+
}else{
|
162
|
+
rb_funcall(*str,concat, 1, rb_str_new2("*Unknow*"));
|
163
|
+
//rb_raise(rb_eException,"ErlixTerm.to_s: Bad type of term !");
|
164
|
+
}
|
165
|
+
}
|
data/src/erlix_helper.h
ADDED
data/src/intruder_ext.c
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
#include "intruder_ext.h"
|
2
|
+
|
3
|
+
/* common imports */
|
4
|
+
#include <stdlib.h>
|
5
|
+
#include <string.h>
|
6
|
+
#include <errno.h>
|
7
|
+
|
8
|
+
/* TODO in den header*/
|
9
|
+
VALUE IntruderModule = Qnil;
|
10
|
+
VALUE IntruderException = Qnil;
|
11
|
+
extern VALUE IntruderNodeException;
|
12
|
+
|
13
|
+
void Init_intruder_ext(){
|
14
|
+
erl_init(NULL, 0);
|
15
|
+
IntruderModule = rb_define_module("Intruder");
|
16
|
+
IntruderException = rb_define_class_under(IntruderModule, "Error", rb_eRuntimeError);
|
17
|
+
|
18
|
+
Init_intruder_term();
|
19
|
+
Init_intruder_list();
|
20
|
+
Init_intruder_tuple();
|
21
|
+
Init_intruder_atom();
|
22
|
+
Init_intruder_binary();
|
23
|
+
Init_intruder_node();
|
24
|
+
Init_intruder_mod();
|
25
|
+
}
|
26
|
+
|
27
|
+
void raise_rException_for_erl_errno(){
|
28
|
+
/* DEBUG("Result: %d\n", erl_errno); */
|
29
|
+
/* DEBUG("ERHOSTUNREACH: %d\n", EHOSTUNREACH); */
|
30
|
+
/* DEBUG("ENOMEM: %d\n", ENOMEM); */
|
31
|
+
/* DEBUG("EIO: %d\n", EIO); */
|
32
|
+
|
33
|
+
switch( erl_errno )
|
34
|
+
{
|
35
|
+
case EHOSTUNREACH :
|
36
|
+
rb_raise(IntruderNodeException, "Host unreachable");
|
37
|
+
break;
|
38
|
+
case ENOMEM :
|
39
|
+
rb_raise(IntruderNodeException, "Memory Error");
|
40
|
+
break;
|
41
|
+
case EIO :
|
42
|
+
rb_raise(IntruderNodeException, "IO error");
|
43
|
+
break;
|
44
|
+
default :
|
45
|
+
rb_raise(IntruderNodeException, strerror(erl_errno));
|
46
|
+
break;
|
47
|
+
}
|
48
|
+
}
|
data/src/intruder_ext.h
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
#ifndef INTRUDER_EXT_H_
|
2
|
+
#define INTRUDER_EXT_H_
|
3
|
+
|
4
|
+
#include "ruby.h"
|
5
|
+
#include "node.h"
|
6
|
+
#include "mod.h"
|
7
|
+
#include "term.h"
|
8
|
+
#include "list.h"
|
9
|
+
#include "atom.h"
|
10
|
+
#include "binary.h"
|
11
|
+
|
12
|
+
#ifndef RSTRING_PTR
|
13
|
+
#define RSTRING_PTR(s) (RSTRING(s)->ptr)
|
14
|
+
#define RSTRING_LEN(s) (RSTRING(s)->len)
|
15
|
+
#define RARRAY_LEN(a) (RARRAY(a)->len)
|
16
|
+
#endif
|
17
|
+
|
18
|
+
extern void raise_rException_for_erl_errno();
|
19
|
+
#endif /* #ifndef INTRUDER_EXT_H */
|
20
|
+
|
21
|
+
/*
|
22
|
+
* TODO: Add Check_Type checks for every method that needs a specific argument type
|
23
|
+
* TODO: macros for retrival of the class structs like:
|
24
|
+
* #define GetDBM(obj, dbmp) {\
|
25
|
+
* Data_Get_Struct(obj, struct dbmdata, dbmp);\
|
26
|
+
* if (dbmp->di_dbm == 0) closed_dbm();\
|
27
|
+
* }
|
28
|
+
*/
|
data/src/list.c
ADDED
@@ -0,0 +1,70 @@
|
|
1
|
+
#include "list.h"
|
2
|
+
|
3
|
+
VALUE IntruderList = Qnil;
|
4
|
+
|
5
|
+
void Init_intruder_list()
|
6
|
+
{
|
7
|
+
IntruderList = rb_define_class_under(IntruderModule, "List", IntruderTerm);
|
8
|
+
|
9
|
+
rb_include_module(IntruderList, rb_mEnumerable);
|
10
|
+
rb_define_method(IntruderList, "each", intruder_list_each, 0);
|
11
|
+
rb_define_method(IntruderList, "[]", intruder_list_member_at, 1);
|
12
|
+
rb_define_method(IntruderList, "length", intruder_list_length, 0);
|
13
|
+
rb_define_alias(IntruderList, "size", "length");
|
14
|
+
}
|
15
|
+
|
16
|
+
/* lenght and size */
|
17
|
+
VALUE intruder_list_length(VALUE self){
|
18
|
+
INTRUDER_TERM *term;
|
19
|
+
Data_Get_Struct(self, INTRUDER_TERM, term);
|
20
|
+
|
21
|
+
return INT2FIX(erl_length(term->eterm));
|
22
|
+
}
|
23
|
+
|
24
|
+
/* [] */
|
25
|
+
VALUE intruder_list_member_at(VALUE self, VALUE pos)
|
26
|
+
{
|
27
|
+
int position = NUM2INT(pos) + 1;
|
28
|
+
if (position <= 0 || NUM2INT(intruder_list_length(self)) < position)
|
29
|
+
return Qnil;
|
30
|
+
|
31
|
+
INTRUDER_TERM *term;
|
32
|
+
Data_Get_Struct(self, INTRUDER_TERM, term);
|
33
|
+
|
34
|
+
int i;
|
35
|
+
ETERM *member, *list;
|
36
|
+
list = erl_copy_term(term->eterm);
|
37
|
+
|
38
|
+
for(i = 1; i <= position; i++)
|
39
|
+
{
|
40
|
+
member = erl_hd(list);
|
41
|
+
list = erl_tl(list);
|
42
|
+
}
|
43
|
+
|
44
|
+
erl_free_compound(list);
|
45
|
+
return rb_value_from_eterm(member);
|
46
|
+
}
|
47
|
+
|
48
|
+
/* Enumerable */
|
49
|
+
VALUE intruder_list_each(VALUE self)
|
50
|
+
{
|
51
|
+
INTRUDER_TERM *term;
|
52
|
+
ETERM *member, *list;
|
53
|
+
VALUE rMember;
|
54
|
+
int i;
|
55
|
+
|
56
|
+
Data_Get_Struct(self, INTRUDER_TERM, term);
|
57
|
+
list = erl_copy_term(term->eterm);
|
58
|
+
int length = erl_length(list);
|
59
|
+
|
60
|
+
for(i = 1; i <= length; i++)
|
61
|
+
{
|
62
|
+
member = erl_hd(list);
|
63
|
+
list = erl_tl(list);
|
64
|
+
rMember = rb_value_from_eterm(member);
|
65
|
+
rb_yield(rMember);
|
66
|
+
}
|
67
|
+
|
68
|
+
erl_free_compound(list);
|
69
|
+
return Qnil;
|
70
|
+
}
|
data/src/list.h
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
#ifndef INTRUDER_LIST_H
|
2
|
+
#define INTRUDER_LIST_H
|
3
|
+
|
4
|
+
#include "ruby.h"
|
5
|
+
|
6
|
+
#include "term.h"
|
7
|
+
|
8
|
+
extern VALUE IntruderModule;
|
9
|
+
extern VALUE IntruderTerm;
|
10
|
+
|
11
|
+
void Init_intruder_list();
|
12
|
+
|
13
|
+
/* Enumerable */
|
14
|
+
VALUE intruder_list_each(VALUE self);
|
15
|
+
|
16
|
+
VALUE intruder_list_member_at(VALUE self, VALUE position);
|
17
|
+
VALUE intruder_list_length(VALUE self);
|
18
|
+
|
19
|
+
#endif /* ifndef INTRUDER_LIST_H */
|
data/src/mod.c
ADDED
@@ -0,0 +1,74 @@
|
|
1
|
+
#include "mod.h"
|
2
|
+
|
3
|
+
VALUE IntruderMod = Qnil;
|
4
|
+
extern VALUE IntruderModule;
|
5
|
+
extern VALUE IntruderTerm;
|
6
|
+
|
7
|
+
VALUE intruder_mod_init(VALUE self, VALUE modname, VALUE node) {
|
8
|
+
rb_iv_set(self, "@node", node);
|
9
|
+
rb_iv_set(self, "@modname", modname);
|
10
|
+
return self;
|
11
|
+
}
|
12
|
+
|
13
|
+
VALUE intruder_mod_alloc(VALUE class) {
|
14
|
+
INTRUDER_MOD *im = (INTRUDER_MOD*)malloc(sizeof(INTRUDER_MOD));
|
15
|
+
VALUE obj;
|
16
|
+
obj = Data_Wrap_Struct(class, 0, free, im);
|
17
|
+
return obj;
|
18
|
+
}
|
19
|
+
|
20
|
+
VALUE intruder_mod_rpc(VALUE self, VALUE args) {
|
21
|
+
/* get the data struct of the Intruder::Node in the Intruder::Mod */
|
22
|
+
INTRUDER_NODE *inode;
|
23
|
+
Data_Get_Struct(rb_iv_get(self, "@node"), INTRUDER_NODE, inode);
|
24
|
+
if (inode->status == INTRUDER_DISCONNECTED) {
|
25
|
+
rb_raise(IntruderException, "node not connected");
|
26
|
+
}
|
27
|
+
|
28
|
+
VALUE fun = rb_ary_shift(args);
|
29
|
+
VALUE params = rb_ary_shift(args);
|
30
|
+
|
31
|
+
/* get the intruder term struct from the args array */
|
32
|
+
INTRUDER_TERM *iterm;
|
33
|
+
Data_Get_Struct(params, INTRUDER_TERM, iterm);
|
34
|
+
|
35
|
+
/* name of the module to call is set in a ruby ivar */
|
36
|
+
char *mod = RSTRING_PTR(rb_iv_get(self, "@modname"));
|
37
|
+
int ret;
|
38
|
+
|
39
|
+
/* prepare the erlang stuff */
|
40
|
+
int index = 0;
|
41
|
+
ei_x_buff rpcargs, result;
|
42
|
+
ei_x_new(&result);
|
43
|
+
ei_x_new(&rpcargs);
|
44
|
+
ei_x_encode_term(&rpcargs, iterm->eterm);
|
45
|
+
|
46
|
+
/* ei_print_term(stdout, rpcargs.buff, &index); */
|
47
|
+
/* fflush(stdout); */
|
48
|
+
|
49
|
+
/* RPC call */
|
50
|
+
pthread_mutex_lock(inode->mutex);
|
51
|
+
ret = ei_rpc(inode->cnode, inode->fd, mod, RSTRING_PTR(fun), rpcargs.buff, rpcargs.index, &result);
|
52
|
+
if (ret < 0) {
|
53
|
+
raise_rException_for_erl_errno();
|
54
|
+
return Qnil;
|
55
|
+
} else {
|
56
|
+
ETERM *tuplep;
|
57
|
+
tuplep = erl_decode(result.buff);
|
58
|
+
ei_x_free(&rpcargs);
|
59
|
+
ei_x_free(&result);
|
60
|
+
pthread_mutex_unlock(inode->mutex);
|
61
|
+
return rb_value_from_eterm(tuplep);
|
62
|
+
}
|
63
|
+
}
|
64
|
+
|
65
|
+
void Init_intruder_mod() {
|
66
|
+
IntruderMod = rb_define_class_under(IntruderModule, "Mod", rb_cObject);
|
67
|
+
|
68
|
+
/* class methods */
|
69
|
+
rb_define_alloc_func(IntruderMod, intruder_mod_alloc);
|
70
|
+
|
71
|
+
/* instance methods */
|
72
|
+
rb_define_method(IntruderMod, "initialize", intruder_mod_init, 2);
|
73
|
+
rb_define_method(IntruderMod, "rpc", intruder_mod_rpc, -2);
|
74
|
+
}
|
data/src/mod.h
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
#ifndef INTRUDER_MOD_H_
|
2
|
+
#define INTRUDER_MOD_H_
|
3
|
+
|
4
|
+
#include "ruby.h"
|
5
|
+
#include "ei.h"
|
6
|
+
#include "erl_interface.h"
|
7
|
+
#include <stdio.h>
|
8
|
+
#include <pthread.h>
|
9
|
+
|
10
|
+
#include "intruder_ext.h"
|
11
|
+
#include "node.h"
|
12
|
+
#include "term.h"
|
13
|
+
|
14
|
+
typedef struct intruder_mod
|
15
|
+
{
|
16
|
+
ei_cnode *node;
|
17
|
+
} INTRUDER_MOD;
|
18
|
+
|
19
|
+
void Init_intruder_mod();
|
20
|
+
|
21
|
+
VALUE intruder_mod_init(VALUE self, VALUE modname, VALUE node);
|
22
|
+
VALUE intruder_mod_alloc(VALUE self);
|
23
|
+
VALUE private_intruder_mod_rpc(VALUE self, VALUE args);
|
24
|
+
|
25
|
+
#endif
|
data/src/node.c
ADDED
@@ -0,0 +1,217 @@
|
|
1
|
+
/*
|
2
|
+
* Helpfull stuff:
|
3
|
+
* Erl_interface doku: http://erlang.mirror.su.se/doc/man/ei_connect.html
|
4
|
+
* http://erlang.org/pipermail/erlang-questions/2003-August/009536.html
|
5
|
+
* Erlix discussion: http://www.mentby.com/Group/ruby-talk/ruby-interface-of-erlang.html
|
6
|
+
* Extending ruby (german): http://home.vrweb.de/~juergen.katins/ruby/buch/ext_ruby.html
|
7
|
+
* http://www.eqqon.com/index.php/Ruby_C_Extension#debug
|
8
|
+
*/
|
9
|
+
#include "node.h"
|
10
|
+
|
11
|
+
#define STOSYM(string) ID2SYM(rb_intern(string))
|
12
|
+
|
13
|
+
VALUE IntruderNode = Qnil;
|
14
|
+
VALUE IntruderNodeException = Qnil;
|
15
|
+
int node_count = 0;
|
16
|
+
pthread_t alive_thread;
|
17
|
+
pthread_mutex_t **mutexes_locked_for_keep_alive;
|
18
|
+
INTRUDER_NODE **connectlist;
|
19
|
+
fd_set socks;
|
20
|
+
int highsock;
|
21
|
+
int readsocks;
|
22
|
+
int connectlist_inited = 0;
|
23
|
+
unsigned int tmo = 1;
|
24
|
+
|
25
|
+
/* internal methods */
|
26
|
+
static void declare_attr_accessors();
|
27
|
+
static void free_class_struct(void *class_struct);
|
28
|
+
static void release_locks();
|
29
|
+
|
30
|
+
void lock_node(INTRUDER_NODE *node);
|
31
|
+
void unlock_node(INTRUDER_NODE *node);
|
32
|
+
void read_socks();
|
33
|
+
void *aliveloop();
|
34
|
+
void build_select_list();
|
35
|
+
|
36
|
+
/* implementation */
|
37
|
+
VALUE intruder_node_alloc(VALUE class){
|
38
|
+
INTRUDER_NODE *class_struct = malloc(sizeof(INTRUDER_NODE));
|
39
|
+
class_struct->cnode = malloc(sizeof(ei_cnode));
|
40
|
+
class_struct->status = INTRUDER_DISCONNECTED;
|
41
|
+
class_struct->mutex = malloc(sizeof(pthread_mutex_t));
|
42
|
+
pthread_mutex_init(class_struct->mutex, NULL);
|
43
|
+
|
44
|
+
VALUE obj = Data_Wrap_Struct(class, 0, free_class_struct, class_struct);
|
45
|
+
return obj;
|
46
|
+
}
|
47
|
+
|
48
|
+
static void free_class_struct(void *class_struct)
|
49
|
+
{
|
50
|
+
pthread_mutex_destroy(((INTRUDER_NODE *)class_struct)->mutex);
|
51
|
+
free(((INTRUDER_NODE *)class_struct)->cnode);
|
52
|
+
free(class_struct);
|
53
|
+
}
|
54
|
+
|
55
|
+
VALUE intruder_node_init(VALUE self, VALUE sname, VALUE cookie){
|
56
|
+
CLASS_STRUCT;
|
57
|
+
|
58
|
+
rb_iv_set(self, "@sname", sname);
|
59
|
+
rb_iv_set(self, "@cookie", cookie);
|
60
|
+
|
61
|
+
if (!connectlist_inited) {
|
62
|
+
connectlist = (INTRUDER_NODE **)calloc(CONBUFFSIZE, sizeof(INTRUDER_NODE*));
|
63
|
+
mutexes_locked_for_keep_alive = (pthread_mutex_t **)calloc(CONBUFFSIZE, sizeof(pthread_mutex_t *));
|
64
|
+
connectlist_inited = 1;
|
65
|
+
}
|
66
|
+
|
67
|
+
/* initialize the node */
|
68
|
+
if(ei_connect_init(class_struct->cnode, RSTRING_PTR(sname), RSTRING_PTR(cookie), node_count) < 0){
|
69
|
+
free(class_struct->cnode);
|
70
|
+
rb_raise(rb_eRuntimeError, "Error initializing the node");
|
71
|
+
}
|
72
|
+
|
73
|
+
return self;
|
74
|
+
}
|
75
|
+
|
76
|
+
VALUE intruder_node_status(VALUE self){
|
77
|
+
CLASS_STRUCT;
|
78
|
+
if (class_struct->status == INTRUDER_CONNECTED)
|
79
|
+
return STOSYM("connected");
|
80
|
+
else
|
81
|
+
return STOSYM("disconnected");
|
82
|
+
}
|
83
|
+
|
84
|
+
VALUE intruder_node_pid(VALUE self){
|
85
|
+
CLASS_STRUCT;
|
86
|
+
erlang_pid *pid = ei_self(class_struct->cnode);
|
87
|
+
return INT2FIX(pid->num);
|
88
|
+
}
|
89
|
+
|
90
|
+
VALUE intruder_node_connect(VALUE self, VALUE remote_node){
|
91
|
+
INTRUDER_NODE *class_struct;
|
92
|
+
Data_Get_Struct(self, INTRUDER_NODE, class_struct);
|
93
|
+
|
94
|
+
if((class_struct->fd = ei_connect_tmo(class_struct->cnode, RSTRING_PTR(remote_node), tmo)) < 0)
|
95
|
+
raise_rException_for_erl_errno();
|
96
|
+
|
97
|
+
class_struct->status = INTRUDER_CONNECTED;
|
98
|
+
connectlist[node_count] = class_struct;
|
99
|
+
node_count++;
|
100
|
+
|
101
|
+
if (alive_thread == NULL) {
|
102
|
+
pthread_create(&alive_thread, NULL, aliveloop, NULL);
|
103
|
+
}
|
104
|
+
return Qtrue;
|
105
|
+
}
|
106
|
+
|
107
|
+
void Init_intruder_node(){
|
108
|
+
IntruderNode = rb_define_class_under(IntruderModule, "Node", rb_cObject);
|
109
|
+
declare_attr_accessors();
|
110
|
+
|
111
|
+
/* class methods */
|
112
|
+
rb_define_alloc_func(IntruderNode, intruder_node_alloc);
|
113
|
+
|
114
|
+
/* instance methods */
|
115
|
+
rb_define_method(IntruderNode, "initialize", intruder_node_init, 2);
|
116
|
+
rb_define_method(IntruderNode, "connect", intruder_node_connect, 1);
|
117
|
+
rb_define_method(IntruderNode, "pid", intruder_node_pid, 0);
|
118
|
+
rb_define_method(IntruderNode, "status", intruder_node_status, 0);
|
119
|
+
|
120
|
+
/* exceptions */
|
121
|
+
IntruderNodeException = rb_define_class_under(IntruderModule, "NodeError", IntruderException);
|
122
|
+
}
|
123
|
+
|
124
|
+
static void declare_attr_accessors(){
|
125
|
+
ID attr_accessor = rb_intern("attr_reader");
|
126
|
+
|
127
|
+
char *i_vars[2] = {"cookie", "sname"};
|
128
|
+
VALUE params[2];
|
129
|
+
|
130
|
+
int i = 0;
|
131
|
+
for(; i <= 1; i++){
|
132
|
+
params[i] = STOSYM(i_vars[i]);
|
133
|
+
}
|
134
|
+
rb_funcall2(IntruderNode, attr_accessor, 2, params);
|
135
|
+
}
|
136
|
+
|
137
|
+
void build_select_list() {
|
138
|
+
int listnum, locks = 0;
|
139
|
+
FD_ZERO(&socks);
|
140
|
+
|
141
|
+
for (listnum = 0; listnum < node_count; listnum++) {
|
142
|
+
if (connectlist[listnum] != NULL) {
|
143
|
+
if (!pthread_mutex_trylock(connectlist[listnum]->mutex)) {
|
144
|
+
mutexes_locked_for_keep_alive[locks++] = connectlist[listnum]->mutex;
|
145
|
+
FD_SET(connectlist[listnum]->fd, &socks);
|
146
|
+
if (connectlist[listnum]->fd > highsock)
|
147
|
+
highsock = connectlist[listnum]->fd;
|
148
|
+
}
|
149
|
+
else {
|
150
|
+
/* printf("fd %d is already locked, skipping\n", connectlist[listnum]->fd); */
|
151
|
+
}
|
152
|
+
}
|
153
|
+
}
|
154
|
+
}
|
155
|
+
|
156
|
+
void read_socks() {
|
157
|
+
int listnum;
|
158
|
+
int got;
|
159
|
+
char buf[400];
|
160
|
+
|
161
|
+
for (listnum = 0; listnum < node_count; listnum++) {
|
162
|
+
/* printf("checking socket %d (%d)\n", connectlist[listnum]->fd, listnum); */
|
163
|
+
if (connectlist[listnum] != 0 && FD_ISSET(connectlist[listnum]->fd, &socks)) {
|
164
|
+
got = erl_receive(connectlist[listnum]->fd, buf, 400);
|
165
|
+
if (got == ERL_TICK) { /* keeping the node alive */
|
166
|
+
continue;
|
167
|
+
} else {
|
168
|
+
rb_raise(rb_eRuntimeError, "Keep Alive thread cought a message other than ERL_TICK");
|
169
|
+
}
|
170
|
+
}
|
171
|
+
}
|
172
|
+
}
|
173
|
+
|
174
|
+
void *aliveloop() {
|
175
|
+
struct timeval timeout;
|
176
|
+
|
177
|
+
while(1) {
|
178
|
+
timeout.tv_sec = 1;
|
179
|
+
timeout.tv_usec = 0;
|
180
|
+
|
181
|
+
build_select_list();
|
182
|
+
/* printf("waiting for sockets\n"); */
|
183
|
+
readsocks = select(highsock+1, &socks, (fd_set *) 0, (fd_set *) 0, &timeout);
|
184
|
+
|
185
|
+
if (readsocks < 0) {
|
186
|
+
perror("select");
|
187
|
+
exit(EXIT_FAILURE);
|
188
|
+
}
|
189
|
+
if (readsocks != 0)
|
190
|
+
read_socks();
|
191
|
+
release_locks(); /* TODO: maybe return the locklist from build_select_list and pass in as an argument here */
|
192
|
+
}
|
193
|
+
}
|
194
|
+
|
195
|
+
static void release_locks() {
|
196
|
+
int i;
|
197
|
+
pthread_mutex_t *mutex;
|
198
|
+
/* printf("cleaning up locks"); */
|
199
|
+
for (i = 0; i < CONBUFFSIZE; i++) {
|
200
|
+
if ((mutex = mutexes_locked_for_keep_alive[i]) != NULL) {
|
201
|
+
/* printf(" %d", i); */
|
202
|
+
pthread_mutex_unlock(mutex);
|
203
|
+
mutexes_locked_for_keep_alive[i] = NULL;
|
204
|
+
} else {
|
205
|
+
/* printf("\n"); */
|
206
|
+
break;
|
207
|
+
}
|
208
|
+
}
|
209
|
+
}
|
210
|
+
|
211
|
+
void lock_node(INTRUDER_NODE *node) {
|
212
|
+
pthread_mutex_lock(node->mutex);
|
213
|
+
}
|
214
|
+
|
215
|
+
void unlock_node(INTRUDER_NODE *node) {
|
216
|
+
pthread_mutex_unlock(node->mutex);
|
217
|
+
}
|
data/src/node.h
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
/* FIXME node.h =schlechte idee, umbenennen */
|
2
|
+
#ifndef INTRUDER_NODE_H
|
3
|
+
#define INTRUDER_NODE_H
|
4
|
+
|
5
|
+
#include "ruby.h"
|
6
|
+
#include "erl_interface.h"
|
7
|
+
#include "ei.h"
|
8
|
+
|
9
|
+
#include "intruder_ext.h"
|
10
|
+
|
11
|
+
#include <stdio.h>
|
12
|
+
|
13
|
+
#define INTRUDER_DEBUG
|
14
|
+
|
15
|
+
#ifdef INTRUDER_DEBUG
|
16
|
+
#define DEBUG(fmt, args...) printf(fmt, ##args)
|
17
|
+
#else
|
18
|
+
#define DEBUG(fmt, args...)
|
19
|
+
#endif
|
20
|
+
|
21
|
+
#define INTRUDER_CONNECTED 0
|
22
|
+
#define INTRUDER_DISCONNECTED 1
|
23
|
+
|
24
|
+
#define CONBUFFSIZE 20
|
25
|
+
|
26
|
+
#define CLASS_STRUCT struct intruder_node *class_struct; Data_Get_Struct(self, struct intruder_node, class_struct)
|
27
|
+
|
28
|
+
typedef struct intruder_node
|
29
|
+
{
|
30
|
+
ei_cnode *cnode;
|
31
|
+
int fd; /* file descriptor for the communication with the epmd */
|
32
|
+
int status;
|
33
|
+
pthread_mutex_t *mutex; /* mutex on the fd */
|
34
|
+
} INTRUDER_NODE;
|
35
|
+
|
36
|
+
extern VALUE IntruderModule;
|
37
|
+
extern VALUE IntruderException;
|
38
|
+
|
39
|
+
/* prototypes */
|
40
|
+
void Init_intruder_node();
|
41
|
+
|
42
|
+
/* ruby instance methods */
|
43
|
+
VALUE intruder_node_init(VALUE self, VALUE sname, VALUE cookie);
|
44
|
+
VALUE intruder_node_connect(VALUE self, VALUE remote_node);
|
45
|
+
/* VALUE intruder_node_mod(VALUE self, VALUE mod_name); */
|
46
|
+
|
47
|
+
/* ruby class methods */
|
48
|
+
VALUE intruder_node_new(VALUE class, VALUE host, VALUE sname, VALUE cookie);
|
49
|
+
#endif
|
data/src/term.c
ADDED
@@ -0,0 +1,168 @@
|
|
1
|
+
#include "term.h"
|
2
|
+
|
3
|
+
VALUE IntruderTerm = Qnil;
|
4
|
+
|
5
|
+
/* internal methods */
|
6
|
+
void free_intruder_term(void *term) {
|
7
|
+
INTRUDER_TERM *iterm = term;
|
8
|
+
erl_free_compound(iterm->eterm);
|
9
|
+
free(term);
|
10
|
+
}
|
11
|
+
|
12
|
+
INTRUDER_TERM * new_intruder_term() {
|
13
|
+
INTRUDER_TERM *iterm = malloc(sizeof(INTRUDER_TERM));
|
14
|
+
return iterm;
|
15
|
+
}
|
16
|
+
|
17
|
+
/* instance methods */
|
18
|
+
|
19
|
+
VALUE intruder_term_to_s(VALUE self) {
|
20
|
+
INTRUDER_TERM *iterm;
|
21
|
+
Data_Get_Struct(self, INTRUDER_TERM, iterm);
|
22
|
+
ETERM *eterm = iterm->eterm;
|
23
|
+
VALUE ret = rb_str_new2("");
|
24
|
+
/* int ei_s_print_term(char** s, const char* buf, int* index) */
|
25
|
+
/* int index = 0; */
|
26
|
+
/* char *buff; */
|
27
|
+
/* int ei_s_print_term(&buff, , int* index); */
|
28
|
+
fill_string(&ret, eterm);
|
29
|
+
return ret;
|
30
|
+
}
|
31
|
+
|
32
|
+
VALUE rb_value_from_eterm(ETERM *eterm)
|
33
|
+
{
|
34
|
+
VALUE rubyObject;
|
35
|
+
INTRUDER_TERM *iterm = new_intruder_term();
|
36
|
+
iterm->eterm = eterm;
|
37
|
+
if (ERL_IS_LIST(eterm))
|
38
|
+
rubyObject = rb_value_from_list(iterm);
|
39
|
+
else if (ERL_IS_TUPLE(eterm))
|
40
|
+
rubyObject = rb_value_from_tuple(iterm);
|
41
|
+
else if (ERL_IS_ATOM(eterm))
|
42
|
+
rubyObject = rb_value_from_atom(iterm);
|
43
|
+
else if (ERL_IS_BINARY(eterm))
|
44
|
+
rubyObject = rb_value_from_binary(iterm);
|
45
|
+
else
|
46
|
+
rubyObject = Data_Wrap_Struct(IntruderTerm, 0, free_intruder_term, iterm);
|
47
|
+
|
48
|
+
return rubyObject;
|
49
|
+
|
50
|
+
/* figure out the type of the eterm (more to come) */
|
51
|
+
/* erl_free_compound(eterm); */
|
52
|
+
/* return Qnil; */
|
53
|
+
}
|
54
|
+
|
55
|
+
VALUE rb_value_from_list(INTRUDER_TERM *iterm) {
|
56
|
+
VALUE rValue;
|
57
|
+
iterm->type = INTRUDER_TYPE_LIST;
|
58
|
+
rValue = Data_Wrap_Struct(IntruderList, 0, free_intruder_term, iterm);
|
59
|
+
return rValue;
|
60
|
+
}
|
61
|
+
|
62
|
+
VALUE rb_value_from_tuple(INTRUDER_TERM *iterm) {
|
63
|
+
VALUE rValue;
|
64
|
+
iterm->type = INTRUDER_TYPE_TUPLE;
|
65
|
+
rValue = Data_Wrap_Struct(IntruderTuple, 0, free_intruder_term, iterm);
|
66
|
+
return rValue;
|
67
|
+
}
|
68
|
+
|
69
|
+
VALUE rb_value_from_atom(INTRUDER_TERM *iterm) {
|
70
|
+
VALUE rValue;
|
71
|
+
iterm->type = INTRUDER_TYPE_ATOM;
|
72
|
+
rValue = Data_Wrap_Struct(IntruderAtom, 0, free_intruder_term, iterm);
|
73
|
+
return rValue;
|
74
|
+
}
|
75
|
+
|
76
|
+
VALUE rb_value_from_binary(INTRUDER_TERM *iterm) {
|
77
|
+
VALUE rValue;
|
78
|
+
iterm->type = INTRUDER_TYPE_BINARY;
|
79
|
+
rValue = Data_Wrap_Struct(IntruderBinary, 0, free_intruder_term, iterm);
|
80
|
+
return Qnil;
|
81
|
+
}
|
82
|
+
|
83
|
+
static ETERM *intruder_eterm_from_array(VALUE obj);
|
84
|
+
VALUE intruder_term_encode(VALUE self, VALUE obj) {
|
85
|
+
VALUE ret = Qnil;
|
86
|
+
|
87
|
+
ETERM *eterm = intruder_eterm_from_value(obj);
|
88
|
+
if (eterm == NULL) {
|
89
|
+
erl_free(eterm);
|
90
|
+
rb_raise(IntruderException, "unable to convert that ruby object to an erlang term");
|
91
|
+
return Qnil;
|
92
|
+
}
|
93
|
+
|
94
|
+
ret = rb_value_from_eterm(eterm);
|
95
|
+
return ret;
|
96
|
+
}
|
97
|
+
|
98
|
+
/* Create an ETERM from a Ruby VALUE
|
99
|
+
* currently it knows how to handle Strings, Symbols and Arrays (of strings, symbols or arrays)
|
100
|
+
*/
|
101
|
+
ETERM *intruder_eterm_from_value(VALUE obj) {
|
102
|
+
ETERM *eterm;
|
103
|
+
if (rb_obj_is_kind_of(obj, IntruderTerm)) {
|
104
|
+
INTRUDER_TERM *iterm;
|
105
|
+
Data_Get_Struct(obj, INTRUDER_TERM, iterm);
|
106
|
+
eterm = iterm->eterm;
|
107
|
+
} else {
|
108
|
+
switch(TYPE(obj)) {
|
109
|
+
case T_SYMBOL :
|
110
|
+
eterm = erl_mk_atom(rb_id2name(SYM2ID(obj)));
|
111
|
+
break;
|
112
|
+
case T_ARRAY :
|
113
|
+
eterm = intruder_eterm_from_array(obj);
|
114
|
+
break;
|
115
|
+
case T_STRING :
|
116
|
+
eterm = erl_mk_estring(RSTRING_PTR(obj), RSTRING_LEN(obj));
|
117
|
+
break;
|
118
|
+
default :
|
119
|
+
eterm = NULL;
|
120
|
+
}
|
121
|
+
}
|
122
|
+
return eterm;
|
123
|
+
}
|
124
|
+
|
125
|
+
/* creates an ETERM from a ruby array of symbols, strings or arrays again */
|
126
|
+
static ETERM *intruder_eterm_from_array(VALUE obj) {
|
127
|
+
int size = RARRAY_LEN(obj);
|
128
|
+
|
129
|
+
if (size == 0)
|
130
|
+
return erl_format("[]");
|
131
|
+
|
132
|
+
ETERM **list = (ETERM **)malloc(sizeof(ETERM*) * size);
|
133
|
+
ETERM *element, *eterm;
|
134
|
+
INTRUDER_TERM *iterm;
|
135
|
+
VALUE rElement;
|
136
|
+
int i;
|
137
|
+
|
138
|
+
for (i = 0; i < size; i++) {
|
139
|
+
rElement = rb_ary_shift(obj);
|
140
|
+
element = intruder_eterm_from_value(rElement);
|
141
|
+
if (element == NULL) { /* it could not be decoded */
|
142
|
+
free(list);
|
143
|
+
return NULL;
|
144
|
+
}
|
145
|
+
*(list+i) = element;
|
146
|
+
}
|
147
|
+
|
148
|
+
eterm = erl_mk_list(list, size);
|
149
|
+
free(list);
|
150
|
+
return eterm;
|
151
|
+
}
|
152
|
+
|
153
|
+
VALUE intruder_term_alloc(VALUE class) {
|
154
|
+
INTRUDER_TERM *iterm = new_intruder_term();
|
155
|
+
VALUE obj = Data_Wrap_Struct(class, 0, free_intruder_term, iterm);
|
156
|
+
return obj;
|
157
|
+
}
|
158
|
+
|
159
|
+
void Init_intruder_term(){
|
160
|
+
IntruderTerm = rb_define_class_under(IntruderModule, "Term", rb_cObject);
|
161
|
+
|
162
|
+
/* instance methods */
|
163
|
+
rb_define_method(IntruderTerm, "to_s", intruder_term_to_s, 0);
|
164
|
+
rb_define_singleton_method(IntruderTerm, "encode", intruder_term_encode, 1);
|
165
|
+
|
166
|
+
/* allocation */
|
167
|
+
rb_define_alloc_func(IntruderTerm, intruder_term_alloc);
|
168
|
+
}
|
data/src/term.h
ADDED
@@ -0,0 +1,58 @@
|
|
1
|
+
#ifndef INTRUDER_TERM_H
|
2
|
+
#define INTRUDER_TERM_H
|
3
|
+
|
4
|
+
#include "ruby.h"
|
5
|
+
#include "ei.h"
|
6
|
+
#include "erl_interface.h"
|
7
|
+
|
8
|
+
#include "intruder_ext.h"
|
9
|
+
#include "list.h"
|
10
|
+
#include "erlix_helper.h"
|
11
|
+
|
12
|
+
#define INTRUDER_TYPE_ATOM 0
|
13
|
+
#define INTRUDER_TYPE_LIST 1
|
14
|
+
#define INTRUDER_TYPE_TUPLE 2
|
15
|
+
#define INTRUDER_TYPE_INT 3
|
16
|
+
#define INTRUDER_TYPE_UINT 4
|
17
|
+
#define INTRUDER_TYPE_FLOAT 5
|
18
|
+
#define INTRUDER_TYPE_PID 6
|
19
|
+
#define INTRUDER_TYPE_PORT 7
|
20
|
+
#define INTRUDER_TYPE_REF 8
|
21
|
+
#define INTRUDER_TYPE_BIN 9
|
22
|
+
#define INTRUDER_TYPE_CON 10
|
23
|
+
#define INTRUDER_TYPE_STRING 11
|
24
|
+
#define INTRUDER_TYPE_BINARY 12
|
25
|
+
|
26
|
+
extern VALUE IntruderModule;
|
27
|
+
extern VALUE IntruderList;
|
28
|
+
extern VALUE IntruderTuple;
|
29
|
+
extern VALUE IntruderAtom;
|
30
|
+
extern VALUE IntruderException;
|
31
|
+
extern VALUE IntruderBinary;
|
32
|
+
|
33
|
+
typedef struct intruder_term
|
34
|
+
{
|
35
|
+
ETERM *eterm;
|
36
|
+
int type;
|
37
|
+
} INTRUDER_TERM;
|
38
|
+
|
39
|
+
void Init_intruder_term();
|
40
|
+
|
41
|
+
/* instance methods */
|
42
|
+
VALUE intruder_term_to_s(VALUE self);
|
43
|
+
VALUE intruder_term_encode(VALUE self, VALUE ruby_object);
|
44
|
+
|
45
|
+
/* allocation */
|
46
|
+
VALUE intruder_term_alloc(VALUE class);
|
47
|
+
void free_intruder_term(void *term);
|
48
|
+
INTRUDER_TERM *new_intruder_term();
|
49
|
+
|
50
|
+
/* C Methods */
|
51
|
+
VALUE rb_value_from_eterm(ETERM *eterm);
|
52
|
+
VALUE rb_value_from_list(INTRUDER_TERM *iterm);
|
53
|
+
VALUE rb_value_from_tuple(INTRUDER_TERM *iterm);
|
54
|
+
VALUE rb_value_from_atom(INTRUDER_TERM *iterm);
|
55
|
+
VALUE rb_value_from_binary(INTRUDER_TERM *iterm);
|
56
|
+
ETERM *intruder_eterm_from_value(VALUE obj);
|
57
|
+
|
58
|
+
#endif /* ifndef INTRUDER_TERM_H */
|
data/src/tuple.c
ADDED
@@ -0,0 +1,55 @@
|
|
1
|
+
#include "tuple.h"
|
2
|
+
|
3
|
+
VALUE IntruderTuple = Qnil;
|
4
|
+
|
5
|
+
void Init_intruder_tuple() {
|
6
|
+
IntruderTuple = rb_define_class_under(IntruderModule, "Tuple", IntruderTerm);
|
7
|
+
|
8
|
+
rb_include_module(IntruderTuple, rb_mEnumerable);
|
9
|
+
rb_define_method(IntruderTuple, "initialize", intruder_tuple_init, 1);
|
10
|
+
rb_define_method(IntruderTuple, "each", intruder_tuple_each, 0);
|
11
|
+
rb_define_method(IntruderTuple, "[]", intruder_tuple_member_at, 1);
|
12
|
+
rb_define_method(IntruderTuple, "length", intruder_tuple_length, 0);
|
13
|
+
rb_define_alias(IntruderTuple, "size", "length");
|
14
|
+
}
|
15
|
+
|
16
|
+
VALUE intruder_tuple_each(VALUE self) {
|
17
|
+
INTRUDER_TERM *iterm;
|
18
|
+
Data_Get_Struct(self, INTRUDER_TERM, iterm);
|
19
|
+
int i;
|
20
|
+
for (i = 1; i <= erl_size(iterm->eterm); i++) {
|
21
|
+
rb_yield(rb_value_from_eterm(erl_element(i, iterm-> eterm)));
|
22
|
+
}
|
23
|
+
return Qnil;
|
24
|
+
}
|
25
|
+
|
26
|
+
VALUE intruder_tuple_init(VALUE self, VALUE arr) {
|
27
|
+
int i, arrsize = RARRAY_LEN(arr);
|
28
|
+
INTRUDER_TERM *iterm;
|
29
|
+
ETERM **members = (ETERM**)malloc(sizeof(ETERM*) * arrsize);
|
30
|
+
|
31
|
+
for (i = 0; i < arrsize; i++) {
|
32
|
+
members[i] = intruder_eterm_from_value(rb_ary_shift(arr));
|
33
|
+
}
|
34
|
+
|
35
|
+
Data_Get_Struct(self, INTRUDER_TERM, iterm);
|
36
|
+
iterm->eterm = erl_mk_tuple(members, arrsize);
|
37
|
+
return self;
|
38
|
+
}
|
39
|
+
|
40
|
+
VALUE intruder_tuple_member_at(VALUE self, VALUE position) {
|
41
|
+
INTRUDER_TERM *iterm;
|
42
|
+
ETERM *member;
|
43
|
+
int iPosition = NUM2INT(position);
|
44
|
+
Data_Get_Struct(self, INTRUDER_TERM, iterm);
|
45
|
+
member = erl_element(iPosition+1, iterm->eterm);
|
46
|
+
return rb_value_from_eterm(member);
|
47
|
+
}
|
48
|
+
|
49
|
+
VALUE intruder_tuple_length(VALUE self) {
|
50
|
+
INTRUDER_TERM *iterm;
|
51
|
+
Data_Get_Struct(self, INTRUDER_TERM, iterm);
|
52
|
+
int iLength;
|
53
|
+
iLength = erl_size(iterm->eterm);
|
54
|
+
return INT2NUM(iLength);
|
55
|
+
}
|
data/src/tuple.h
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
#ifndef INTRUDER_TUPLE_H
|
2
|
+
#define INTRUDER_TUPLE_H
|
3
|
+
|
4
|
+
#include "ruby.h"
|
5
|
+
#include "term.h"
|
6
|
+
|
7
|
+
extern VALUE IntruderModule;
|
8
|
+
extern VALUE IntruderTerm;
|
9
|
+
|
10
|
+
void Init_intruder_tuple();
|
11
|
+
|
12
|
+
VALUE intruder_tuple_each(VALUE self);
|
13
|
+
VALUE intruder_tuple_init(VALUE self, VALUE arr);
|
14
|
+
VALUE intruder_tuple_member_at(VALUE self, VALUE position);
|
15
|
+
VALUE intruder_tuple_length(VALUE self);
|
16
|
+
|
17
|
+
#endif /* ifndef INTRUDER_TUPLE_H */
|
metadata
CHANGED
@@ -4,9 +4,9 @@ version: !ruby/object:Gem::Version
|
|
4
4
|
prerelease: false
|
5
5
|
segments:
|
6
6
|
- 0
|
7
|
-
-
|
7
|
+
- 2
|
8
8
|
- 0
|
9
|
-
version: 0.
|
9
|
+
version: 0.2.0
|
10
10
|
platform: ruby
|
11
11
|
authors:
|
12
12
|
- Pascal Friederich
|
@@ -14,20 +14,53 @@ autorequire:
|
|
14
14
|
bindir: bin
|
15
15
|
cert_chain: []
|
16
16
|
|
17
|
-
date: 2010-03-11 00:00:00 +
|
17
|
+
date: 2010-03-11 00:00:00 +00:00
|
18
18
|
default_executable:
|
19
|
-
dependencies:
|
20
|
-
|
21
|
-
|
19
|
+
dependencies:
|
20
|
+
- !ruby/object:Gem::Dependency
|
21
|
+
name: minitest
|
22
|
+
prerelease: false
|
23
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
24
|
+
requirements:
|
25
|
+
- - ">="
|
26
|
+
- !ruby/object:Gem::Version
|
27
|
+
segments:
|
28
|
+
- 1
|
29
|
+
- 5
|
30
|
+
- 0
|
31
|
+
version: 1.5.0
|
32
|
+
type: :development
|
33
|
+
version_requirements: *id001
|
34
|
+
description: Communicate with erlang from within ruby natively
|
22
35
|
email: paukul@gmail.com
|
23
36
|
executables: []
|
24
37
|
|
25
|
-
extensions:
|
26
|
-
|
38
|
+
extensions:
|
39
|
+
- extconf.rb
|
27
40
|
extra_rdoc_files:
|
28
41
|
- README.md
|
29
|
-
files:
|
30
|
-
|
42
|
+
files:
|
43
|
+
- README.md
|
44
|
+
- findei.erl
|
45
|
+
- src/atom.c
|
46
|
+
- src/atom.h
|
47
|
+
- src/binary.c
|
48
|
+
- src/binary.h
|
49
|
+
- src/erlix_helper.c
|
50
|
+
- src/erlix_helper.h
|
51
|
+
- src/intruder_ext.c
|
52
|
+
- src/intruder_ext.h
|
53
|
+
- src/list.c
|
54
|
+
- src/list.h
|
55
|
+
- src/mod.c
|
56
|
+
- src/mod.h
|
57
|
+
- src/node.c
|
58
|
+
- src/node.h
|
59
|
+
- src/term.c
|
60
|
+
- src/term.h
|
61
|
+
- src/tuple.c
|
62
|
+
- src/tuple.h
|
63
|
+
- lib/intruder.rb
|
31
64
|
has_rdoc: true
|
32
65
|
homepage: http://github.com/paukul/intruder
|
33
66
|
licenses: []
|