rb-wartslib 0.9.10
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/CHANGES +6 -0
- data/COPYING +340 -0
- data/README +79 -0
- data/bin/analyze-order +37 -0
- data/bin/scdump +101 -0
- data/bin/wdump +81 -0
- data/ext/extconf.rb +32 -0
- data/ext/scaddr.c +223 -0
- data/ext/scaddr.h +32 -0
- data/ext/scext.c +52 -0
- data/ext/scfile.c +688 -0
- data/ext/scfile.h +29 -0
- data/ext/sclist.c +632 -0
- data/ext/sclist.h +34 -0
- data/ext/sctrace.c +873 -0
- data/ext/sctrace.h +35 -0
- data/lib/wartslib.rb +27 -0
- data/lib/wartslib/wl-file.rb +85 -0
- data/lib/wartslib/wl-trace.rb +111 -0
- metadata +67 -0
data/ext/scext.c
ADDED
@@ -0,0 +1,52 @@
|
|
1
|
+
/*
|
2
|
+
** Ruby bindings to the functions in libscamperfile.a that are needed to
|
3
|
+
** sort scamper trace files (a la sc_sorter).
|
4
|
+
**
|
5
|
+
** --------------------------------------------------------------------------
|
6
|
+
** Copyright (C) 2007 The Regents of the University of California.
|
7
|
+
**
|
8
|
+
** This program is free software; you can redistribute it and/or modify
|
9
|
+
** it under the terms of the GNU General Public License as published by
|
10
|
+
** the Free Software Foundation; either version 2 of the License, or
|
11
|
+
** (at your option) any later version.
|
12
|
+
**
|
13
|
+
** This program is distributed in the hope that it will be useful,
|
14
|
+
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
15
|
+
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
16
|
+
** GNU General Public License for more details.
|
17
|
+
**
|
18
|
+
** You should have received a copy of the GNU General Public License
|
19
|
+
** along with this program; if not, write to the Free Software
|
20
|
+
** Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
21
|
+
**
|
22
|
+
** $Id: scext.c,v 1.18 2007/11/29 01:51:54 youngh Exp $
|
23
|
+
**/
|
24
|
+
|
25
|
+
#include "ruby.h"
|
26
|
+
|
27
|
+
#if defined(__HAVE_STDINT_H__)
|
28
|
+
#include <stdint.h>
|
29
|
+
#endif
|
30
|
+
|
31
|
+
#include "scamper.h"
|
32
|
+
|
33
|
+
#include "scaddr.h"
|
34
|
+
#include "sclist.h"
|
35
|
+
#include "sctrace.h"
|
36
|
+
#include "scfile.h"
|
37
|
+
|
38
|
+
VALUE mWarts;
|
39
|
+
|
40
|
+
void Init_wartslibext(void)
|
41
|
+
{
|
42
|
+
mWarts = rb_define_module("Warts");
|
43
|
+
|
44
|
+
rb_define_const(mWarts, "WARTS_LIB_VERSION", rb_str_new2("0.9.10"));
|
45
|
+
rb_define_const(mWarts, "SCAMPER_VERSION", rb_str_new2(SCAMPER_VERSION));
|
46
|
+
|
47
|
+
Init_scaddr();
|
48
|
+
Init_sclist();
|
49
|
+
Init_sccycle();
|
50
|
+
Init_sctrace();
|
51
|
+
Init_scfile();
|
52
|
+
}
|
data/ext/scfile.c
ADDED
@@ -0,0 +1,688 @@
|
|
1
|
+
/*
|
2
|
+
** Ruby bindings to scamper file operations in scamper_file.c.
|
3
|
+
**
|
4
|
+
** --------------------------------------------------------------------------
|
5
|
+
** Copyright (C) 2007 The Regents of the University of California.
|
6
|
+
**
|
7
|
+
** This program is free software; you can redistribute it and/or modify
|
8
|
+
** it under the terms of the GNU General Public License as published by
|
9
|
+
** the Free Software Foundation; either version 2 of the License, or
|
10
|
+
** (at your option) any later version.
|
11
|
+
**
|
12
|
+
** This program is distributed in the hope that it will be useful,
|
13
|
+
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
14
|
+
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
15
|
+
** GNU General Public License for more details.
|
16
|
+
**
|
17
|
+
** You should have received a copy of the GNU General Public License
|
18
|
+
** along with this program; if not, write to the Free Software
|
19
|
+
** Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
20
|
+
**
|
21
|
+
** $Id: scfile.c,v 1.30 2007/11/29 01:42:07 youngh Exp $
|
22
|
+
**/
|
23
|
+
|
24
|
+
#include <unistd.h>
|
25
|
+
#include <string.h>
|
26
|
+
#include <strings.h>
|
27
|
+
|
28
|
+
#include "ruby.h"
|
29
|
+
|
30
|
+
#include "scfile.h"
|
31
|
+
#include "scaddr.h"
|
32
|
+
|
33
|
+
#if defined(__HAVE_STDINT_H__)
|
34
|
+
#include <stdint.h>
|
35
|
+
#endif
|
36
|
+
|
37
|
+
#include "scamper_list.h"
|
38
|
+
#include "scamper_addr.h"
|
39
|
+
#include "scamper_trace.h"
|
40
|
+
#include "scamper_file.h"
|
41
|
+
|
42
|
+
extern VALUE mWarts;
|
43
|
+
extern VALUE cTrace;
|
44
|
+
extern VALUE cCycle;
|
45
|
+
|
46
|
+
static VALUE cFile;
|
47
|
+
static ID iv_readable, iv_filters, iv_filters_changed;
|
48
|
+
static ID meth_write_to;
|
49
|
+
static ID meth_kind_of;
|
50
|
+
static ID meth_fileno;
|
51
|
+
|
52
|
+
typedef struct {
|
53
|
+
scamper_file_t *file;
|
54
|
+
scamper_file_filter_t *filters;
|
55
|
+
} file_data_t;
|
56
|
+
|
57
|
+
typedef struct {
|
58
|
+
const char* name;
|
59
|
+
int value;
|
60
|
+
} sctype_info_t;
|
61
|
+
|
62
|
+
sctype_info_t all_sctypes[] = {
|
63
|
+
{ "LIST", SCAMPER_FILE_OBJ_LIST },
|
64
|
+
{ "CYCLE_START", SCAMPER_FILE_OBJ_CYCLE_START },
|
65
|
+
{ "CYCLE_DEF", SCAMPER_FILE_OBJ_CYCLE_DEF },
|
66
|
+
{ "CYCLE_STOP", SCAMPER_FILE_OBJ_CYCLE_STOP },
|
67
|
+
{ "ADDR", SCAMPER_FILE_OBJ_ADDR },
|
68
|
+
{ "TRACE", SCAMPER_FILE_OBJ_TRACE },
|
69
|
+
{ "PING", SCAMPER_FILE_OBJ_PING }
|
70
|
+
};
|
71
|
+
|
72
|
+
size_t num_sctypes = sizeof(all_sctypes) / sizeof(sctype_info_t);
|
73
|
+
|
74
|
+
#define MIN_SCTYPE_VALUE SCAMPER_FILE_OBJ_LIST
|
75
|
+
#define MAX_SCTYPE_VALUE SCAMPER_FILE_OBJ_PING
|
76
|
+
|
77
|
+
#define CHECK_WRITABLE(self) \
|
78
|
+
if (RTEST(rb_ivar_get(self, iv_readable))) { \
|
79
|
+
rb_fatal("attempt to write to a file opened for reading"); \
|
80
|
+
}
|
81
|
+
|
82
|
+
#define CHECK_READABLE(self) \
|
83
|
+
if (!RTEST(rb_ivar_get(self, iv_readable))) { \
|
84
|
+
rb_fatal("attempt to read from a file opened for writing"); \
|
85
|
+
}
|
86
|
+
|
87
|
+
|
88
|
+
/***************************************************************************/
|
89
|
+
|
90
|
+
static void sf_free(void *arg)
|
91
|
+
{
|
92
|
+
file_data_t *data = (file_data_t *)arg;
|
93
|
+
if (data) {
|
94
|
+
if (data->file) {
|
95
|
+
scamper_file_close(data->file);
|
96
|
+
data->file = NULL;
|
97
|
+
}
|
98
|
+
if (data->filters) {
|
99
|
+
scamper_file_filter_free(data->filters);
|
100
|
+
data->filters = NULL;
|
101
|
+
}
|
102
|
+
free(data);
|
103
|
+
}
|
104
|
+
}
|
105
|
+
|
106
|
+
static VALUE scfile_alloc(VALUE klass)
|
107
|
+
{
|
108
|
+
return Data_Wrap_Struct(klass, 0, (RUBY_DATA_FUNC)sf_free, 0);
|
109
|
+
}
|
110
|
+
|
111
|
+
|
112
|
+
/*
|
113
|
+
** Opens either a path or a fd, depending on the type of the first argument.
|
114
|
+
** A file descriptor can be given as either a FIXNUM or as an instance of
|
115
|
+
** IO.
|
116
|
+
**
|
117
|
+
** NOTE: It is the responsibility of the caller to (eventually) close any
|
118
|
+
** passed in file descriptor. See comments below for the reason.
|
119
|
+
*/
|
120
|
+
static VALUE scfile_init(int argc, VALUE *argv, VALUE self)
|
121
|
+
{
|
122
|
+
VALUE path_or_fd, mode, type;
|
123
|
+
VALUE path = Qnil;
|
124
|
+
int fd = -1, fd_dup = -1;
|
125
|
+
char mode_char = 'r';
|
126
|
+
char *type_str = NULL;
|
127
|
+
scamper_file_t *file = NULL;
|
128
|
+
file_data_t *data = NULL;
|
129
|
+
|
130
|
+
rb_scan_args(argc, argv, "12", &path_or_fd, &mode, &type);
|
131
|
+
if (NIL_P(path_or_fd)) {
|
132
|
+
rb_raise(rb_eArgError, "missing path or fd");
|
133
|
+
}
|
134
|
+
|
135
|
+
if (TYPE(path_or_fd) == T_FIXNUM || TYPE(path_or_fd) == T_BIGNUM) {
|
136
|
+
fd = NUM2INT(path_or_fd);
|
137
|
+
}
|
138
|
+
else if (RTEST(rb_funcall(path_or_fd, meth_kind_of, 1, rb_cIO))) {
|
139
|
+
VALUE fileno = rb_funcall(path_or_fd, meth_fileno, 0);
|
140
|
+
fd = FIX2INT(fileno);
|
141
|
+
}
|
142
|
+
else {
|
143
|
+
path = path_or_fd;
|
144
|
+
SafeStringValue(path);
|
145
|
+
}
|
146
|
+
|
147
|
+
if (NIL_P(mode)) {
|
148
|
+
mode_char = 'r';
|
149
|
+
}
|
150
|
+
else {
|
151
|
+
/* Since scamper_file_open() doesn't return any distinguishable error for
|
152
|
+
an invalid mode, we check for validity here. */
|
153
|
+
const char *mode_str;
|
154
|
+
|
155
|
+
StringValue(mode);
|
156
|
+
mode_str = RSTRING(mode)->ptr;
|
157
|
+
if (strlen(mode_str) != 1 || !index("rwa", mode_str[0])) {
|
158
|
+
rb_raise(rb_eArgError, "invalid open mode");
|
159
|
+
}
|
160
|
+
mode_char = mode_str[0];
|
161
|
+
}
|
162
|
+
|
163
|
+
rb_ivar_set(self, iv_readable, (mode_char == 'r' ? Qtrue : Qfalse));
|
164
|
+
|
165
|
+
if (NIL_P(type)) {
|
166
|
+
if (fd >= 0) {
|
167
|
+
type_str = "warts";
|
168
|
+
}
|
169
|
+
else {
|
170
|
+
if (mode_char == 'w' || mode_char == 'a') {
|
171
|
+
type_str = "warts";
|
172
|
+
}
|
173
|
+
/* else let scamper_file_open do file type detection */
|
174
|
+
}
|
175
|
+
}
|
176
|
+
else {
|
177
|
+
StringValue(type);
|
178
|
+
type_str = RSTRING(type)->ptr;
|
179
|
+
|
180
|
+
/* Since scamper_file_open() doesn't return any distinguishable error for
|
181
|
+
an invalid type, we check for validity here. */
|
182
|
+
if (strcmp(type_str, "warts") && strcmp(type_str, "arts")
|
183
|
+
&& strcmp(type_str, "traceroute")) {
|
184
|
+
rb_raise(rb_eArgError, "invalid file type");
|
185
|
+
}
|
186
|
+
}
|
187
|
+
|
188
|
+
if (type_str) {
|
189
|
+
if ((mode_char == 'w' || mode_char == 'a') && strcmp(type_str, "arts")==0){
|
190
|
+
rb_raise(rb_eArgError,"writing or appending to arts files not supported");
|
191
|
+
}
|
192
|
+
|
193
|
+
if (mode_char == 'r' && strcmp(type_str, "traceroute") == 0) {
|
194
|
+
rb_raise(rb_eArgError, "reading from traceroute files not supported");
|
195
|
+
}
|
196
|
+
}
|
197
|
+
|
198
|
+
data = ALLOC(file_data_t);
|
199
|
+
data->file = NULL;
|
200
|
+
data->filters = NULL;
|
201
|
+
DATA_PTR(self) = data;
|
202
|
+
|
203
|
+
/*
|
204
|
+
** NOTE: We must be careful when calling scamper_file_openfd(). We
|
205
|
+
** should NOT simply pass in the file descriptor supplied to
|
206
|
+
** scfile_init because the policy of scamper_file_openfd is to
|
207
|
+
** take ownership of the passed-in file descriptor. This means
|
208
|
+
** that, eventually, scamper_file_close closes the file
|
209
|
+
** descriptor. Normally, this "takes-ownership-of-argument"
|
210
|
+
** policy is what you want, but when interfacing the scamper warts
|
211
|
+
** library to Ruby, this policy can cause problems.
|
212
|
+
**
|
213
|
+
** An open file in Ruby is more than simply a file
|
214
|
+
** descriptor--there's an allocated object associated with the
|
215
|
+
** file descriptor. Hence, we need to free the object in addition
|
216
|
+
** to closing the file descriptor when closing an open file in
|
217
|
+
** Ruby. So it causes problems when scamper_file_close does half
|
218
|
+
** of this work (by closing the file descriptor) without getting
|
219
|
+
** the Ruby object involved. This results in close() being called
|
220
|
+
** twice on the file descriptor. The first time, the call closes
|
221
|
+
** the actual file; the second time, it closes any unreleated open
|
222
|
+
** file that happens to be re-using the same file descriptor
|
223
|
+
** number (which can be particularly insidious if the extra
|
224
|
+
** close() is delayed till the next garbage collection).
|
225
|
+
**
|
226
|
+
** When piping in the output of 'gzip -dc' (in order to
|
227
|
+
** transparently read a compressed warts file), simply closing the
|
228
|
+
** file descriptor isn't sufficient to free up the resource. At
|
229
|
+
** some point after closing the file descriptor, we have to call
|
230
|
+
** waitpid(). Thus, in this case, the takes-ownership policy of
|
231
|
+
** scamper_file_openfd is problematic--the Ruby object needs to
|
232
|
+
** do the resource deallocation itself.
|
233
|
+
**
|
234
|
+
** Fortunately, there's an easy solution to the mismatch. We
|
235
|
+
** simply dup the file descriptor and pass the dup to
|
236
|
+
** scamper_file_openfd (and let it take ownership and do what it
|
237
|
+
** will of it).
|
238
|
+
*/
|
239
|
+
if (NIL_P(path)) {
|
240
|
+
if ((fd_dup = dup(fd)) < 0) {
|
241
|
+
rb_raise(rb_eRuntimeError, "couldn't duplicate file descriptor");
|
242
|
+
}
|
243
|
+
file = scamper_file_openfd(fd_dup, NULL, mode_char, type_str);
|
244
|
+
}
|
245
|
+
else {
|
246
|
+
file = scamper_file_open(RSTRING(path)->ptr, mode_char, type_str);
|
247
|
+
}
|
248
|
+
|
249
|
+
if (file) {
|
250
|
+
data->file = file;
|
251
|
+
return self;
|
252
|
+
}
|
253
|
+
else {
|
254
|
+
if (fd_dup >= 0) {
|
255
|
+
close(fd_dup);
|
256
|
+
}
|
257
|
+
return Qnil;
|
258
|
+
}
|
259
|
+
}
|
260
|
+
|
261
|
+
|
262
|
+
static VALUE scfile_type(VALUE self)
|
263
|
+
{
|
264
|
+
file_data_t *data = NULL;
|
265
|
+
|
266
|
+
Data_Get_Struct(self, file_data_t, data);
|
267
|
+
if (data->file) {
|
268
|
+
char buf [128];
|
269
|
+
return rb_str_new2(scamper_file_type_tostr(data->file, buf, 128));
|
270
|
+
}
|
271
|
+
return Qnil;
|
272
|
+
}
|
273
|
+
|
274
|
+
|
275
|
+
static VALUE scfile_path(VALUE self)
|
276
|
+
{
|
277
|
+
file_data_t *data = NULL;
|
278
|
+
|
279
|
+
Data_Get_Struct(self, file_data_t, data);
|
280
|
+
if (data->file) {
|
281
|
+
return rb_str_new2(scamper_file_getfilename(data->file));
|
282
|
+
}
|
283
|
+
return Qnil;
|
284
|
+
}
|
285
|
+
|
286
|
+
|
287
|
+
static VALUE scfile_close(VALUE self)
|
288
|
+
{
|
289
|
+
file_data_t *data = NULL;
|
290
|
+
|
291
|
+
Data_Get_Struct(self, file_data_t, data);
|
292
|
+
|
293
|
+
if (data->file) {
|
294
|
+
scamper_file_close(data->file);
|
295
|
+
data->file = NULL;
|
296
|
+
}
|
297
|
+
|
298
|
+
return self;
|
299
|
+
}
|
300
|
+
|
301
|
+
|
302
|
+
static VALUE scfile_closed(VALUE self)
|
303
|
+
{
|
304
|
+
file_data_t *data = NULL;
|
305
|
+
|
306
|
+
Data_Get_Struct(self, file_data_t, data);
|
307
|
+
|
308
|
+
return (data->file ? Qfalse : Qtrue);
|
309
|
+
}
|
310
|
+
|
311
|
+
|
312
|
+
static VALUE scfile_s_open(int argc, VALUE *argv, VALUE klass)
|
313
|
+
{
|
314
|
+
VALUE obj = Data_Wrap_Struct(klass, 0, sf_free, 0);
|
315
|
+
|
316
|
+
if (NIL_P(scfile_init(argc, argv, obj))) {
|
317
|
+
return Qnil;
|
318
|
+
}
|
319
|
+
|
320
|
+
return (rb_block_given_p() ? rb_ensure(rb_yield, obj, scfile_close, obj)
|
321
|
+
: obj);
|
322
|
+
}
|
323
|
+
|
324
|
+
|
325
|
+
static void update_filters(VALUE self)
|
326
|
+
{
|
327
|
+
file_data_t *data = NULL;
|
328
|
+
VALUE filters;
|
329
|
+
int i;
|
330
|
+
|
331
|
+
if (RTEST(rb_ivar_get(self, iv_filters_changed))) {
|
332
|
+
uint16_t filter_values[MAX_SCTYPE_VALUE];
|
333
|
+
uint16_t num_values = 0;
|
334
|
+
|
335
|
+
rb_ivar_set(self, iv_filters_changed, Qnil);
|
336
|
+
|
337
|
+
Data_Get_Struct(self, file_data_t, data);
|
338
|
+
if (data->filters) {
|
339
|
+
scamper_file_filter_free(data->filters);
|
340
|
+
data->filters = NULL;
|
341
|
+
}
|
342
|
+
|
343
|
+
filters = rb_ivar_get(self, iv_filters);
|
344
|
+
if (!NIL_P(filters) && RARRAY(filters)->len > 0) {
|
345
|
+
for (i = 0; i < RARRAY(filters)->len; i++) {
|
346
|
+
if (RTEST(rb_ary_entry(filters, i))) {
|
347
|
+
filter_values[num_values++] = i;
|
348
|
+
}
|
349
|
+
}
|
350
|
+
|
351
|
+
if (num_values > 0) {
|
352
|
+
data->filters = scamper_file_filter_alloc(filter_values, num_values);
|
353
|
+
}
|
354
|
+
}
|
355
|
+
}
|
356
|
+
}
|
357
|
+
|
358
|
+
|
359
|
+
#define RETURN(value) \
|
360
|
+
if (rb_block_given_p()) { \
|
361
|
+
rb_yield(value); \
|
362
|
+
goto loop; \
|
363
|
+
} else return (value)
|
364
|
+
|
365
|
+
static VALUE scfile_read(VALUE self)
|
366
|
+
{
|
367
|
+
file_data_t *data = NULL;
|
368
|
+
uint16_t obj_type = 0;
|
369
|
+
void *obj_data = NULL;
|
370
|
+
VALUE obj;
|
371
|
+
int result;
|
372
|
+
|
373
|
+
Data_Get_Struct(self, file_data_t, data);
|
374
|
+
if (!data->file) {
|
375
|
+
return Qnil;
|
376
|
+
}
|
377
|
+
CHECK_READABLE(self)
|
378
|
+
|
379
|
+
update_filters(self);
|
380
|
+
|
381
|
+
loop:
|
382
|
+
result = scamper_file_read(data->file, data->filters, &obj_type, &obj_data);
|
383
|
+
if (result == -1) {
|
384
|
+
rb_raise(rb_eIOError, "couldn't read warts file data");
|
385
|
+
}
|
386
|
+
if (!obj_data) {
|
387
|
+
return Qnil; /* EOF */
|
388
|
+
}
|
389
|
+
|
390
|
+
switch (obj_type) {
|
391
|
+
case SCAMPER_FILE_OBJ_LIST:
|
392
|
+
RETURN(sclist_create((scamper_list_t *)obj_data));
|
393
|
+
|
394
|
+
case SCAMPER_FILE_OBJ_CYCLE_START:
|
395
|
+
case SCAMPER_FILE_OBJ_CYCLE_DEF:
|
396
|
+
case SCAMPER_FILE_OBJ_CYCLE_STOP:
|
397
|
+
RETURN(sccycle_create((scamper_cycle_t *)obj_data, obj_type));
|
398
|
+
|
399
|
+
case SCAMPER_FILE_OBJ_ADDR:
|
400
|
+
RETURN(scaddr_create((scamper_addr_t *)obj_data));
|
401
|
+
|
402
|
+
case SCAMPER_FILE_OBJ_TRACE:
|
403
|
+
RETURN(sctrace_create((scamper_trace_t *)obj_data));
|
404
|
+
|
405
|
+
default:
|
406
|
+
rb_notimplement();
|
407
|
+
}
|
408
|
+
}
|
409
|
+
|
410
|
+
#undef RETURN
|
411
|
+
|
412
|
+
|
413
|
+
/*
|
414
|
+
** This method initiates multiple dispatch with obj. Obj.write_to(file)
|
415
|
+
** should turn around and invoke a suitable write_xxx method; e.g., a trace
|
416
|
+
** object should call file.write_trace(self), and a ping object should call
|
417
|
+
** file.write_ping(self).
|
418
|
+
*/
|
419
|
+
static VALUE scfile_write(VALUE self, VALUE obj)
|
420
|
+
{
|
421
|
+
rb_funcall(obj, meth_write_to, 1, self);
|
422
|
+
}
|
423
|
+
|
424
|
+
|
425
|
+
/*
|
426
|
+
** There's a bug in scamper_file_warts.c:warts_list_write
|
427
|
+
** (scamper-cvs-20070523e & f):
|
428
|
+
**
|
429
|
+
** $ split-traces-by-type trmethod-20071106-list.one24.100000.warts
|
430
|
+
** scamper_file_warts.c:1523: failed assertion `off == len'
|
431
|
+
** Abort trap
|
432
|
+
**
|
433
|
+
** This bug is triggered when a list object is missing BOTH
|
434
|
+
** a description and a monitor name. As a workaround, we set the
|
435
|
+
** description and monitor name to empty strings if they aren't
|
436
|
+
** already set.
|
437
|
+
*/
|
438
|
+
static void warts_list_write_bug_workaround(scamper_list_t *list)
|
439
|
+
{
|
440
|
+
if (!list) return;
|
441
|
+
if (!list->descr) list->descr = strdup("");
|
442
|
+
if (!list->monitor) list->monitor = strdup("");
|
443
|
+
}
|
444
|
+
|
445
|
+
|
446
|
+
static VALUE scfile_write_trace(VALUE self, VALUE obj)
|
447
|
+
{
|
448
|
+
file_data_t *data = NULL;
|
449
|
+
scamper_trace_t *trace = NULL;
|
450
|
+
int result;
|
451
|
+
|
452
|
+
if (TYPE(obj) != T_DATA || !RTEST(rb_obj_is_instance_of(obj, cTrace))) {
|
453
|
+
rb_raise(rb_eArgError, "argument must be instance of Warts::Trace");
|
454
|
+
}
|
455
|
+
|
456
|
+
Data_Get_Struct(self, file_data_t, data);
|
457
|
+
if (!data->file) {
|
458
|
+
return Qnil;
|
459
|
+
}
|
460
|
+
CHECK_WRITABLE(self)
|
461
|
+
|
462
|
+
Data_Get_Struct(obj, scamper_trace_t, trace);
|
463
|
+
warts_list_write_bug_workaround(trace->list);
|
464
|
+
if (trace->cycle) {
|
465
|
+
warts_list_write_bug_workaround(trace->cycle->list);
|
466
|
+
}
|
467
|
+
|
468
|
+
result = scamper_file_write_trace(data->file, trace);
|
469
|
+
if (result == -1) {
|
470
|
+
rb_raise(rb_eIOError, "couldn't write warts file data");
|
471
|
+
}
|
472
|
+
return self;
|
473
|
+
}
|
474
|
+
|
475
|
+
|
476
|
+
/*
|
477
|
+
** NOTE: We could have gone with a single scfile_write_cycle() function
|
478
|
+
** that determines what scamper function to call based on the type
|
479
|
+
** of the cycle object. However, such a design might prove
|
480
|
+
** inconvenient for the user since cycle objects are immutable
|
481
|
+
** in this extension. If there were only a single function, then
|
482
|
+
** users would have to be careful to hang onto the START/STOP
|
483
|
+
** cycle objects when sorting traces into files.
|
484
|
+
*/
|
485
|
+
static VALUE scfile_write_cycle_start(VALUE self, VALUE obj)
|
486
|
+
{
|
487
|
+
file_data_t *data = NULL;
|
488
|
+
scamper_cycle_t *cycle = NULL;
|
489
|
+
int result;
|
490
|
+
|
491
|
+
if (TYPE(obj) != T_DATA || !RTEST(rb_obj_is_instance_of(obj, cCycle))) {
|
492
|
+
rb_raise(rb_eArgError, "argument must be instance of Warts::Cycle");
|
493
|
+
}
|
494
|
+
|
495
|
+
Data_Get_Struct(self, file_data_t, data);
|
496
|
+
if (!data->file) {
|
497
|
+
return Qnil;
|
498
|
+
}
|
499
|
+
CHECK_WRITABLE(self)
|
500
|
+
|
501
|
+
Data_Get_Struct(obj, scamper_cycle_t, cycle);
|
502
|
+
warts_list_write_bug_workaround(cycle->list);
|
503
|
+
|
504
|
+
result = scamper_file_write_cycle_start(data->file, cycle);
|
505
|
+
if (result == -1) {
|
506
|
+
rb_raise(rb_eIOError, "couldn't write warts file data");
|
507
|
+
}
|
508
|
+
return self;
|
509
|
+
}
|
510
|
+
|
511
|
+
|
512
|
+
static VALUE scfile_write_cycle_stop(VALUE self, VALUE obj)
|
513
|
+
{
|
514
|
+
file_data_t *data = NULL;
|
515
|
+
scamper_cycle_t *cycle = NULL;
|
516
|
+
int result;
|
517
|
+
|
518
|
+
if (TYPE(obj) != T_DATA || !RTEST(rb_obj_is_instance_of(obj, cCycle))) {
|
519
|
+
rb_raise(rb_eArgError, "argument must be instance of Warts::Cycle");
|
520
|
+
}
|
521
|
+
|
522
|
+
Data_Get_Struct(self, file_data_t, data);
|
523
|
+
if (!data->file) {
|
524
|
+
return Qnil;
|
525
|
+
}
|
526
|
+
CHECK_WRITABLE(self)
|
527
|
+
|
528
|
+
Data_Get_Struct(obj, scamper_cycle_t, cycle);
|
529
|
+
warts_list_write_bug_workaround(cycle->list);
|
530
|
+
|
531
|
+
result = scamper_file_write_cycle_stop(data->file, cycle);
|
532
|
+
if (result == -1) {
|
533
|
+
rb_raise(rb_eIOError, "couldn't write warts file data");
|
534
|
+
}
|
535
|
+
return self;
|
536
|
+
}
|
537
|
+
|
538
|
+
|
539
|
+
/*-------------------------------------------------------------------------*/
|
540
|
+
|
541
|
+
static VALUE get_iv_filters(VALUE self)
|
542
|
+
{
|
543
|
+
VALUE filters = rb_ivar_get(self, iv_filters);
|
544
|
+
if (NIL_P(filters)) {
|
545
|
+
filters = rb_ary_new();
|
546
|
+
rb_ivar_set(self, iv_filters, filters);
|
547
|
+
}
|
548
|
+
return filters;
|
549
|
+
}
|
550
|
+
|
551
|
+
|
552
|
+
/* NOTE: This is a helper function: don't directly invoke as a Ruby method. */
|
553
|
+
static VALUE scfile_set_filters(int argc, VALUE *argv, VALUE self, VALUE value)
|
554
|
+
{
|
555
|
+
VALUE filters, given_filters, filter;
|
556
|
+
int i, filter_value;
|
557
|
+
|
558
|
+
filters = get_iv_filters(self);
|
559
|
+
|
560
|
+
rb_scan_args(argc, argv, "*", &given_filters);
|
561
|
+
for (i = 0; i < RARRAY(given_filters)->len; i++) {
|
562
|
+
filter = rb_ary_entry(given_filters, i);
|
563
|
+
if (RTEST(filter)) {
|
564
|
+
filter_value = NUM2INT(filter);
|
565
|
+
if (filter_value < MIN_SCTYPE_VALUE || filter_value > MAX_SCTYPE_VALUE) {
|
566
|
+
rb_raise(rb_eArgError, "invalid filter value %d", filter_value);
|
567
|
+
}
|
568
|
+
|
569
|
+
rb_ary_store(filters, filter_value, value);
|
570
|
+
}
|
571
|
+
}
|
572
|
+
|
573
|
+
rb_ivar_set(self, iv_filters_changed, Qtrue);
|
574
|
+
return self;
|
575
|
+
}
|
576
|
+
|
577
|
+
|
578
|
+
static VALUE scfile_add_all_filters(VALUE self)
|
579
|
+
{
|
580
|
+
VALUE filters;
|
581
|
+
int i;
|
582
|
+
|
583
|
+
filters = get_iv_filters(self);
|
584
|
+
|
585
|
+
for (i = 0; i < num_sctypes; i++) {
|
586
|
+
rb_ary_store(filters, all_sctypes[i].value, Qtrue);
|
587
|
+
}
|
588
|
+
|
589
|
+
rb_ivar_set(self, iv_filters_changed, Qtrue);
|
590
|
+
return self;
|
591
|
+
}
|
592
|
+
|
593
|
+
|
594
|
+
static VALUE scfile_add_filters(int argc, VALUE *argv, VALUE self)
|
595
|
+
{
|
596
|
+
return scfile_set_filters(argc, argv, self, Qtrue);
|
597
|
+
}
|
598
|
+
|
599
|
+
|
600
|
+
static VALUE scfile_clear_all_filters(VALUE self)
|
601
|
+
{
|
602
|
+
rb_ivar_set(self, iv_filters, Qnil);
|
603
|
+
rb_ivar_set(self, iv_filters_changed, Qtrue);
|
604
|
+
return self;
|
605
|
+
}
|
606
|
+
|
607
|
+
|
608
|
+
static VALUE scfile_clear_filters(int argc, VALUE *argv, VALUE self)
|
609
|
+
{
|
610
|
+
return scfile_set_filters(argc, argv, self, Qnil);
|
611
|
+
}
|
612
|
+
|
613
|
+
|
614
|
+
static VALUE scfile_get_filters(VALUE self)
|
615
|
+
{
|
616
|
+
VALUE retval, filters;
|
617
|
+
int i;
|
618
|
+
|
619
|
+
retval = rb_ary_new();
|
620
|
+
|
621
|
+
filters = rb_ivar_get(self, iv_filters);
|
622
|
+
if (!NIL_P(filters)) {
|
623
|
+
for (i = 0; i < RARRAY(filters)->len; i++) {
|
624
|
+
if (RTEST(rb_ary_entry(filters, i))) {
|
625
|
+
rb_ary_push(retval, INT2FIX(i));
|
626
|
+
}
|
627
|
+
}
|
628
|
+
}
|
629
|
+
return retval;
|
630
|
+
}
|
631
|
+
|
632
|
+
|
633
|
+
/***************************************************************************/
|
634
|
+
/***************************************************************************/
|
635
|
+
|
636
|
+
void Init_scfile(void)
|
637
|
+
{
|
638
|
+
ID private_ID, dup_ID, clone_ID;
|
639
|
+
int i;
|
640
|
+
|
641
|
+
iv_readable = rb_intern("@readable");
|
642
|
+
iv_filters = rb_intern("@filters");
|
643
|
+
iv_filters_changed = rb_intern("@filters_changed");
|
644
|
+
meth_write_to = rb_intern("write_to");
|
645
|
+
meth_kind_of = rb_intern("kind_of?");
|
646
|
+
meth_fileno = rb_intern("fileno");
|
647
|
+
|
648
|
+
cFile = rb_define_class_under(mWarts, "File", rb_cObject);
|
649
|
+
|
650
|
+
for (i = 0; i < num_sctypes; i++) {
|
651
|
+
rb_define_const(cFile, all_sctypes[i].name,
|
652
|
+
INT2FIX(all_sctypes[i].value));
|
653
|
+
}
|
654
|
+
|
655
|
+
rb_define_const(cFile, "TRACEROUTE", rb_str_new2("traceroute"));
|
656
|
+
rb_define_const(cFile, "ARTS", rb_str_new2("arts"));
|
657
|
+
rb_define_const(cFile, "WARTS", rb_str_new2("warts"));
|
658
|
+
|
659
|
+
rb_define_singleton_method(cFile, "open", scfile_s_open, -1);
|
660
|
+
|
661
|
+
rb_define_alloc_func(cFile, scfile_alloc);
|
662
|
+
|
663
|
+
rb_define_method(cFile, "initialize", scfile_init, -1);
|
664
|
+
rb_define_method(cFile, "type", scfile_type, 0);
|
665
|
+
rb_define_method(cFile, "path", scfile_path, 0);
|
666
|
+
rb_define_method(cFile, "close", scfile_close, 0);
|
667
|
+
rb_define_method(cFile, "closed?", scfile_closed, 0);
|
668
|
+
rb_define_method(cFile, "read", scfile_read, 0);
|
669
|
+
rb_define_method(cFile, "write", scfile_write, 1);
|
670
|
+
rb_define_method(cFile, "write_trace", scfile_write_trace, 1);
|
671
|
+
rb_define_method(cFile, "write_cycle_start", scfile_write_cycle_start, 1);
|
672
|
+
rb_define_method(cFile, "write_cycle_stop", scfile_write_cycle_stop, 1);
|
673
|
+
|
674
|
+
rb_define_alias(cFile, "each", "read");
|
675
|
+
|
676
|
+
rb_define_method(cFile, "add_all_filters", scfile_add_all_filters, 0);
|
677
|
+
rb_define_method(cFile, "add_filters", scfile_add_filters, -1);
|
678
|
+
rb_define_method(cFile, "clear_all_filters", scfile_clear_all_filters, 0);
|
679
|
+
rb_define_method(cFile, "clear_filters", scfile_clear_filters, -1);
|
680
|
+
rb_define_method(cFile, "filters", scfile_get_filters, 0);
|
681
|
+
|
682
|
+
private_ID = rb_intern("private");
|
683
|
+
dup_ID = rb_intern("dup");
|
684
|
+
clone_ID = rb_intern("clone");
|
685
|
+
|
686
|
+
rb_funcall(cFile, private_ID, 1, ID2SYM(dup_ID));
|
687
|
+
rb_funcall(cFile, private_ID, 1, ID2SYM(clone_ID));
|
688
|
+
}
|