frostbitten 0.1.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.
@@ -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
+ }