frostbitten 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,4 @@
1
+ require 'mkmf'
2
+ extension_name = 'native'
3
+ dir_config(extension_name)
4
+ create_makefile("frostbitten/#{extension_name}")
@@ -0,0 +1,13 @@
1
+ #ifndef frostbitten_h
2
+ #define frostbitten_h
3
+ #include <ruby.h>
4
+ #include <ruby/io.h>
5
+ #include <stdint.h>
6
+ #include <stdbool.h>
7
+ #include <stdlib.h>
8
+ extern VALUE m_frostbitten;
9
+ void Init_frostbitten();
10
+ #define OVERRIDE_IF_SET(options,name) rb_funcall(options, rb_intern("has_key?"), 1, ID2SYM(rb_intern(#name))) == Qtrue ? \
11
+ rb_hash_aref(options, ID2SYM(rb_intern(#name))) : name
12
+ #endif
13
+
@@ -0,0 +1,194 @@
1
+ #include "frostbitten.h"
2
+ #include "header.h"
3
+ #include <ruby/io.h>
4
+ VALUE c_frostbitten_header;
5
+
6
+
7
+ VALUE frostbitten_header_parse_from_buffer(VALUE self, fb_packet_buffer *buffer) {
8
+ fb_header *header;
9
+ Data_Get_Struct(self, fb_header, header);
10
+ frostbitten_header_unpack(header, buffer->header);
11
+ return self;
12
+ }
13
+
14
+ VALUE frostbitten_header_get_sequence(VALUE self) {
15
+ fb_header *header;
16
+ Data_Get_Struct(self, fb_header, header);
17
+ return INT2NUM(header->sequence);
18
+ }
19
+
20
+ VALUE frostbitten_header_set_sequence(VALUE self, VALUE seq) {
21
+ fb_header *header;
22
+ Data_Get_Struct(self, fb_header, header);
23
+ header->sequence = NUM2INT(seq);
24
+ return frostbitten_header_get_sequence(self);
25
+ }
26
+
27
+ VALUE frostbitten_header_set_origin(VALUE self, VALUE origin) {
28
+ fb_header *header;
29
+ Data_Get_Struct(self, fb_header, header);
30
+ if ( ID2SYM(rb_intern("client")) == origin ) {
31
+ header->origin = 1;
32
+ } else if ID2SYM(rb_intern("server") == origin ) {
33
+ header->origin = 0;
34
+ } else {
35
+ rb_raise(rb_eTypeError, "must be either :client or :server");
36
+ }
37
+ return Qfalse;
38
+ }
39
+
40
+ VALUE frostbitten_header_get_origin(VALUE self) {
41
+ fb_header *header;
42
+ Data_Get_Struct(self, fb_header, header);
43
+ switch(header->origin) {
44
+ case 1:
45
+ return ID2SYM(rb_intern("client"));
46
+ break;
47
+
48
+ case 0:
49
+ return ID2SYM(rb_intern("server"));
50
+ break;
51
+ }
52
+ return Qnil;
53
+ }
54
+
55
+ VALUE frostbitten_header_get_response(VALUE self) {
56
+ fb_header *header;
57
+ Data_Get_Struct(self, fb_header, header);
58
+ if ( header->response == 0 ) {
59
+ return Qtrue;
60
+ } else {
61
+ return Qfalse;
62
+ }
63
+ }
64
+
65
+ VALUE frostbitten_header_set_response(VALUE self, VALUE response) {
66
+ if ( TYPE(response) != T_TRUE && TYPE(response) != T_FALSE) {
67
+ rb_raise(rb_eTypeError, "must be either true or false");
68
+ }
69
+
70
+ fb_header *header;
71
+ Data_Get_Struct(self, fb_header, header);
72
+ if ( response == Qtrue )
73
+ header->response = 1;
74
+ else {
75
+ header->response = 0;
76
+ }
77
+ return frostbitten_header_get_response(self);
78
+ }
79
+
80
+ uint32_t frostbitten_header_package(fb_header *header) {
81
+ uint32_t data = header->sequence;
82
+ if ( header->origin == 0 ) {
83
+ data |= 1 << 31;
84
+ } else {
85
+ data &= ~(1 << 31);
86
+ }
87
+
88
+ if ( header->response != (( 1 << 30 ) & data) ) {
89
+ data ^= 1 << 30;
90
+ }
91
+
92
+ return data;
93
+ }
94
+
95
+ void frostbitten_header_unpack(fb_header *header, uint32_t val) {
96
+ header->sequence = (uint32_t)val & 0x3fffffff;
97
+ header->origin = (val & (1 << 31));
98
+ header->response = (val & (1 << 30));
99
+ }
100
+
101
+ VALUE frostbitten_header_write_to_io(VALUE self, VALUE io) {
102
+ fb_header *header;
103
+ Data_Get_Struct(self, fb_header, header);
104
+
105
+ rb_io_t *fptr;
106
+ GetOpenFile(io, fptr);
107
+ rb_io_check_writable(fptr);
108
+
109
+ FILE *fp = rb_io_stdio_file(fptr);
110
+
111
+ uint32_t val = frostbitten_header_package(header);
112
+ fwrite((const void*)&val,sizeof(uint32_t),1,fp);
113
+ return self;
114
+ }
115
+
116
+ VALUE frostbitten_header_cls_read_from_io(VALUE self, VALUE io) {
117
+ VALUE header = rb_obj_alloc(c_frostbitten_header);
118
+ rb_obj_call_init(header, 0, 0);
119
+ return frostbitten_header_read_from_io(header, io);
120
+ }
121
+
122
+ VALUE frostbitten_header_read_from_io(VALUE self, VALUE io) {
123
+ fb_header *header;
124
+ Data_Get_Struct(self, fb_header, header);
125
+
126
+ uint32_t val = 0;
127
+
128
+ rb_io_t *fptr;
129
+ GetOpenFile(io, fptr);
130
+ rb_io_check_readable(fptr);
131
+
132
+ FILE *fp = rb_io_stdio_file(fptr);
133
+ fread((void*)&val, sizeof(uint32_t),1, fp);
134
+
135
+ frostbitten_header_unpack(header, val);
136
+ return self;
137
+ }
138
+
139
+ void frostbitten_header_deallocate(fb_header *header) {
140
+ header->sequence = 0;
141
+ header->origin = 0;
142
+ header->response = false;
143
+ ruby_xfree(header);
144
+ }
145
+
146
+ VALUE frostbitten_header_allocate (VALUE klass) {
147
+ fb_header *header = ruby_xmalloc(sizeof(fb_header));
148
+ return Data_Wrap_Struct(klass,NULL,frostbitten_header_deallocate, header);
149
+ }
150
+
151
+ VALUE frostbitten_header_init(int argc, VALUE *argv, VALUE self) {
152
+
153
+ fb_header *header;
154
+ Data_Get_Struct(self, fb_header, header);
155
+
156
+ VALUE options;
157
+ if (rb_scan_args(argc, argv, "01", &options) == 0)
158
+ options = Qnil;
159
+
160
+ VALUE sequence = INT2NUM(0);
161
+ VALUE origin = ID2SYM(rb_intern("client"));
162
+ VALUE response = Qfalse;
163
+
164
+ if (!NIL_P(options) && TYPE(options) == T_HASH) {
165
+ sequence = OVERRIDE_IF_SET(options,sequence);
166
+ origin = OVERRIDE_IF_SET(options,origin);
167
+ response = OVERRIDE_IF_SET(options,response);
168
+ }
169
+ frostbitten_header_set_sequence(self,sequence);
170
+ frostbitten_header_set_origin(self,origin);
171
+ frostbitten_header_set_response(self,response);
172
+
173
+ return self;
174
+ }
175
+
176
+ void header_init() {
177
+ c_frostbitten_header = rb_define_class_under(m_frostbitten, "Header", rb_cObject);
178
+ rb_define_alloc_func(c_frostbitten_header, frostbitten_header_allocate);
179
+ rb_define_method(c_frostbitten_header, "initialize", frostbitten_header_init, -1);
180
+
181
+ rb_define_method(c_frostbitten_header,"sequence=", frostbitten_header_set_sequence,1);
182
+ rb_define_method(c_frostbitten_header,"sequence", frostbitten_header_get_sequence,0);
183
+
184
+ rb_define_method(c_frostbitten_header, "origin", frostbitten_header_get_origin,0);
185
+ rb_define_method(c_frostbitten_header, "origin=", frostbitten_header_set_origin, 1);
186
+
187
+ rb_define_method(c_frostbitten_header,"response=", frostbitten_header_set_response, 1);
188
+ rb_define_method(c_frostbitten_header,"is_response?", frostbitten_header_get_response, 0);
189
+
190
+ rb_define_method(c_frostbitten_header, "read", frostbitten_header_read_from_io, 1);
191
+ rb_define_method(c_frostbitten_header, "write", frostbitten_header_write_to_io, 1);
192
+ rb_define_singleton_method(c_frostbitten_header, "read", frostbitten_header_cls_read_from_io, 1);
193
+
194
+ }
@@ -0,0 +1,30 @@
1
+ #include "frostbitten.h"
2
+ #include "packet.h"
3
+ #ifndef header_h
4
+ #define header_h
5
+
6
+ extern VALUE c_frostbitten_header;
7
+
8
+ typedef struct _fb_header {
9
+ uint32_t sequence;
10
+ uint32_t origin;
11
+ bool response;
12
+ } fb_header;
13
+
14
+ void header_init();
15
+ VALUE frostbitten_header_parse_from_buffer(VALUE self, fb_packet_buffer *buffer);
16
+ VALUE frostbitten_header_get_sequence(VALUE self);
17
+ VALUE frostbitten_header_set_sequence(VALUE self, VALUE seq);
18
+ uint32_t frostbitten_header_package(fb_header *header);
19
+ void frostbitten_header_unpack(fb_header *header, uint32_t val);
20
+
21
+ VALUE frostbitten_header_cls_read_from_io(VALUE self, VALUE io);
22
+ VALUE frostbitten_header_read_from_io(VALUE self, VALUE io);
23
+ VALUE frostbitten_header_write_to_io(VALUE self, VALUE io);
24
+ // VALUE frostbitten_header_test_write(VALUE self);
25
+ // VALUE frostbitten_header_test_read(VALUE self);
26
+ VALUE frostbitten_header_format(VALUE self);
27
+ void frostbitten_header_deallocate(fb_header *header);
28
+ VALUE frostbitten_header_allocate (VALUE klass);
29
+
30
+ #endif
@@ -0,0 +1,202 @@
1
+ #include "frostbitten.h"
2
+ #include "message.h"
3
+
4
+ VALUE c_frostbitten_message;
5
+
6
+ void frostbitten_read_words_from_file(fb_message *message, FILE *fp, fb_packet_buffer *buffer) {
7
+ for(uint32_t i=0; i < buffer->wordCount; i++) {
8
+ uint32_t wordByteLength = 0;
9
+ fread(&wordByteLength, sizeof(uint32_t), 1, fp);
10
+
11
+ char *word = malloc(wordByteLength+1);
12
+ fread(word, sizeof(char), wordByteLength+1, fp);
13
+ rb_ary_push(message->words, rb_str_new2(word));
14
+ }
15
+ }
16
+
17
+ VALUE frostbitten_message_read_from_io(VALUE self, VALUE io) {
18
+ fb_message *message;
19
+ Data_Get_Struct(self, fb_message, message);
20
+
21
+ rb_io_t *fptr;
22
+ GetOpenFile(io, fptr);
23
+ rb_io_check_readable(fptr);
24
+ FILE *fp = rb_io_stdio_file(fptr);
25
+ fb_packet_buffer *buffer = read_buffer_from_io(fp);
26
+
27
+ if ( !message->header ) {
28
+ message->header = rb_class_new_instance(0, NULL, c_frostbitten_header);
29
+ frostbitten_header_parse_from_buffer(message->header, buffer);
30
+ }
31
+
32
+ frostbitten_read_words_from_file(message, fp, buffer);
33
+ return self;
34
+ }
35
+
36
+ VALUE frostbitten_message_cls_read_from_io(VALUE self, VALUE io) {
37
+ VALUE msg = rb_obj_alloc(c_frostbitten_message);
38
+ rb_obj_call_init(msg, 0, 0);
39
+ return frostbitten_message_read_from_io(msg, io);
40
+ }
41
+
42
+ VALUE frostbitten_message_complete(VALUE self, VALUE io) {
43
+ rb_io_t *fptr;
44
+ GetOpenFile(io, fptr);
45
+ rb_io_check_readable(fptr);
46
+ FILE *fp = rb_io_stdio_file(fptr);
47
+
48
+ fb_packet_buffer *buffer = read_buffer_from_io(fp);
49
+ if (is_packet_valid(buffer)) {
50
+ VALUE msg = rb_obj_alloc(c_frostbitten_message);
51
+ rb_obj_call_init(msg, 0, 0);
52
+ fb_message *message;
53
+ Data_Get_Struct(msg, fb_message, message);
54
+ frostbitten_read_words_from_file(message, fp, buffer);
55
+
56
+ if (rb_block_given_p()) {
57
+ return rb_yield(msg);
58
+ } else {
59
+ return msg;
60
+ }
61
+ }
62
+ free(buffer);
63
+ return Qnil;
64
+ }
65
+
66
+
67
+
68
+
69
+ VALUE frostbitten_message_write_to_io(VALUE self, VALUE io) {
70
+ fb_message *message;
71
+ Data_Get_Struct(self, fb_message, message);
72
+
73
+ frostbitten_header_write_to_io(message->header, io);
74
+
75
+
76
+ uint32_t arrayLength = (uint32_t)RARRAY_LEN(message->words);
77
+ uint32_t packetSize = 0;
78
+
79
+ char** strings = frostbitten_message_generate(message, &packetSize);
80
+ packetSize += sizeof(uint32_t); // Header
81
+ packetSize += sizeof(uint32_t); // packetSize
82
+ packetSize += sizeof(uint32_t); // wordCount
83
+ rb_io_t *fptr;
84
+ GetOpenFile(io, fptr);
85
+ rb_io_check_readable(fptr);
86
+ FILE *fp = rb_io_stdio_file(fptr);
87
+
88
+ fwrite((const void*)&packetSize,sizeof(uint32_t),1,fp);
89
+ fwrite((const void*)&arrayLength,sizeof(uint32_t),1,fp);
90
+ for(uint32_t i=0; i < arrayLength; i++) {
91
+ char *str = strings[i];
92
+ uint32_t len = (uint32_t)strlen(str);
93
+ fwrite((const void*)&len, sizeof(uint32_t), 1, fp);
94
+ fwrite(str, sizeof(char), strlen(str)+1, fp);
95
+ }
96
+ fflush(fp);
97
+ return self;
98
+ }
99
+
100
+ char** frostbitten_message_generate(fb_message *message, uint32_t *message_size) {
101
+ uint32_t arrayLength = (uint32_t)RARRAY_LEN(message->words);
102
+ char **strings = (char **)calloc(arrayLength,sizeof(char *));
103
+
104
+ for(uint32_t i=0; i < arrayLength; i++) {
105
+ VALUE str = rb_ary_entry(message->words, i);
106
+ if ( !NIL_P(str) && TYPE(str) == T_STRING ) {
107
+ char *p = StringValueCStr(str);
108
+ char *p2 = malloc(strlen(p)*sizeof(char)+1);
109
+ memcpy(p2,p,strlen(p)*sizeof(char)+1);
110
+ strings[i] = p2;
111
+ *message_size += sizeof(char)*(strlen(p2)+1)+sizeof(uint32_t);
112
+ }
113
+ }
114
+ return strings;
115
+ }
116
+
117
+ VALUE frostbitten_message_get_words(VALUE self) {
118
+ fb_message *message;
119
+ Data_Get_Struct(self, fb_message, message);
120
+ return message->words;
121
+ }
122
+
123
+ VALUE frostbitten_message_set_words(VALUE self, VALUE words) {
124
+ Check_Type(words, T_ARRAY);
125
+
126
+ fb_message *message;
127
+ Data_Get_Struct(self, fb_message, message);
128
+ message->words = words;
129
+ return message->words;
130
+ }
131
+
132
+ VALUE frostbitten_message_get_header(VALUE self) {
133
+ fb_message *message;
134
+ Data_Get_Struct(self, fb_message, message);
135
+ return message->header;
136
+ }
137
+
138
+ VALUE frostbitten_message_set_header(VALUE self, VALUE header) {
139
+ if ( NIL_P(header) || CLASS_OF(header) != c_frostbitten_header ) {
140
+ rb_raise(rb_eTypeError, "Invalid argument header, not a Frostbitten::Header");
141
+ return Qnil;
142
+ }
143
+ fb_message *message;
144
+ Data_Get_Struct(self, fb_message, message);
145
+ message->header = header;
146
+ return message->header;
147
+ }
148
+
149
+ VALUE frostbitten_message_init(int argc, VALUE *argv, VALUE self) {
150
+
151
+ fb_message *message;
152
+ Data_Get_Struct(self, fb_message, message);
153
+
154
+ VALUE options;
155
+ if (rb_scan_args(argc, argv, "01", &options) == 0)
156
+ options = Qnil;
157
+ VALUE words = rb_ary_new();
158
+ VALUE header = rb_obj_alloc(c_frostbitten_header);
159
+
160
+ if (!NIL_P(options) && TYPE(options) == T_HASH) {
161
+ words = OVERRIDE_IF_SET(options,words);
162
+ header = OVERRIDE_IF_SET(options,header);
163
+ }
164
+
165
+ frostbitten_message_set_header(self,header);
166
+ frostbitten_message_set_words(self,words);
167
+
168
+ return self;
169
+ }
170
+
171
+ void frostbitten_message_deallocate(fb_message *message) {
172
+ // frostbitten_header_deallocate(message->header);
173
+ ruby_xfree(message);
174
+ }
175
+
176
+ void frostbitten_message_mark(fb_message *message) {
177
+ rb_gc_mark(message->header);
178
+ rb_gc_mark(message->words);
179
+ }
180
+
181
+
182
+ VALUE frostbitten_message_allocate (VALUE klass) {
183
+ fb_message *msg = ruby_xmalloc(sizeof(fb_message));
184
+ return Data_Wrap_Struct(klass, frostbitten_message_mark, frostbitten_message_deallocate, msg);
185
+ }
186
+
187
+ void message_init() {
188
+ c_frostbitten_message = rb_define_class_under(m_frostbitten, "Message", rb_cObject);
189
+ rb_define_alloc_func(c_frostbitten_message, frostbitten_message_allocate);
190
+ rb_define_method(c_frostbitten_message, "initialize", frostbitten_message_init, -1);
191
+
192
+ rb_define_method(c_frostbitten_message, "write", frostbitten_message_write_to_io, 1);
193
+ rb_define_method(c_frostbitten_message, "read", frostbitten_message_read_from_io, 1);
194
+
195
+ rb_define_method(c_frostbitten_message, "words", frostbitten_message_get_words, 0);
196
+ rb_define_method(c_frostbitten_message, "words=", frostbitten_message_set_words, 1);
197
+
198
+ rb_define_method(c_frostbitten_message, "header", frostbitten_message_get_header, 0);
199
+ rb_define_method(c_frostbitten_message, "header=", frostbitten_message_set_header, 1);
200
+ rb_define_singleton_method(c_frostbitten_message, "read", frostbitten_message_cls_read_from_io, 1);
201
+ rb_define_singleton_method(c_frostbitten_message, "locate_packet", frostbitten_message_complete, 1);
202
+ }