arunthampi-evented_net 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,48 @@
1
+ /**
2
+ * Copyright (c) 2005 Zed A. Shaw
3
+ * You can redistribute it and/or modify it under the same terms as Ruby.
4
+ */
5
+
6
+ #ifndef http11_parser_h
7
+ #define http11_parser_h
8
+
9
+ #include <sys/types.h>
10
+
11
+ #if defined(_WIN32)
12
+ #include <stddef.h>
13
+ #endif
14
+
15
+ typedef void (*element_cb)(void *data, const char *at, size_t length);
16
+ typedef void (*field_cb)(void *data, const char *field, size_t flen, const char *value, size_t vlen);
17
+
18
+ typedef struct httpclient_parser {
19
+ int cs;
20
+ size_t body_start;
21
+ int content_len;
22
+ size_t nread;
23
+ size_t mark;
24
+ size_t field_start;
25
+ size_t field_len;
26
+
27
+ void *data;
28
+
29
+ field_cb http_field;
30
+ element_cb reason_phrase;
31
+ element_cb status_code;
32
+ element_cb chunk_size;
33
+ element_cb http_version;
34
+ element_cb header_done;
35
+ element_cb last_chunk;
36
+
37
+
38
+ } httpclient_parser;
39
+
40
+ int httpclient_parser_init(httpclient_parser *parser);
41
+ int httpclient_parser_finish(httpclient_parser *parser);
42
+ size_t httpclient_parser_execute(httpclient_parser *parser, const char *data, size_t len, size_t off);
43
+ int httpclient_parser_has_error(httpclient_parser *parser);
44
+ int httpclient_parser_is_finished(httpclient_parser *parser);
45
+
46
+ #define httpclient_parser_nread(parser) (parser)->nread
47
+
48
+ #endif
@@ -0,0 +1,173 @@
1
+ /**
2
+ * Copyright (c) 2005 Zed A. Shaw
3
+ * You can redistribute it and/or modify it under the same terms as Ruby.
4
+ */
5
+
6
+ #include "http11_parser.h"
7
+ #include <stdio.h>
8
+ #include <assert.h>
9
+ #include <stdlib.h>
10
+ #include <ctype.h>
11
+ #include <string.h>
12
+
13
+ #define LEN(AT, FPC) (FPC - buffer - parser->AT)
14
+ #define MARK(M,FPC) (parser->M = (FPC) - buffer)
15
+ #define PTR_TO(F) (buffer + parser->F)
16
+ #define L(M) fprintf(stderr, "" # M "\n");
17
+
18
+
19
+ /** machine **/
20
+ %%{
21
+ machine httpclient_parser;
22
+
23
+ action mark {MARK(mark, fpc); }
24
+
25
+ action start_field { MARK(field_start, fpc); }
26
+
27
+ action write_field {
28
+ parser->field_len = LEN(field_start, fpc);
29
+ }
30
+
31
+ action start_value { MARK(mark, fpc); }
32
+
33
+ action write_value {
34
+ parser->http_field(parser->data, PTR_TO(field_start), parser->field_len, PTR_TO(mark), LEN(mark, fpc));
35
+ }
36
+
37
+ action reason_phrase {
38
+ parser->reason_phrase(parser->data, PTR_TO(mark), LEN(mark, fpc));
39
+ }
40
+
41
+ action status_code {
42
+ parser->status_code(parser->data, PTR_TO(mark), LEN(mark, fpc));
43
+ }
44
+
45
+ action http_version {
46
+ parser->http_version(parser->data, PTR_TO(mark), LEN(mark, fpc));
47
+ }
48
+
49
+ action chunk_size {
50
+ parser->chunk_size(parser->data, PTR_TO(mark), LEN(mark, fpc));
51
+ }
52
+
53
+ action last_chunk {
54
+ parser->last_chunk(parser->data, NULL, 0);
55
+ }
56
+
57
+ action done {
58
+ parser->body_start = fpc - buffer + 1;
59
+ if(parser->header_done != NULL)
60
+ parser->header_done(parser->data, fpc + 1, pe - fpc - 1);
61
+ fbreak;
62
+ }
63
+
64
+ # line endings
65
+ CRLF = "\r\n";
66
+
67
+ # character types
68
+ CTL = (cntrl | 127);
69
+ tspecials = ("(" | ")" | "<" | ">" | "@" | "," | ";" | ":" | "\\" | "\"" | "/" | "[" | "]" | "?" | "=" | "{" | "}" | " " | "\t");
70
+
71
+ # elements
72
+ token = (ascii -- (CTL | tspecials));
73
+
74
+ Reason_Phrase = (any -- CRLF)* >mark %reason_phrase;
75
+ Status_Code = digit{3} >mark %status_code;
76
+ http_number = (digit+ "." digit+) ;
77
+ HTTP_Version = ("HTTP/" http_number) >mark %http_version ;
78
+ Status_Line = HTTP_Version " " Status_Code " "? Reason_Phrase :> CRLF;
79
+
80
+ field_name = token+ >start_field %write_field;
81
+ field_value = any* >start_value %write_value;
82
+ message_header = field_name ":" " "* field_value :> CRLF;
83
+
84
+ Response = Status_Line (message_header)* (CRLF @done);
85
+
86
+ chunk_ext_val = token+;
87
+ chunk_ext_name = token+;
88
+ chunk_extension = (";" chunk_ext_name >start_field %write_field %start_value ("=" chunk_ext_val >start_value)? %write_value )*;
89
+ last_chunk = "0"? chunk_extension :> (CRLF @last_chunk @done);
90
+ chunk_size = xdigit+;
91
+ chunk = chunk_size >mark %chunk_size chunk_extension space* :> (CRLF @done);
92
+ Chunked_Header = (chunk | last_chunk);
93
+
94
+ main := Response | Chunked_Header;
95
+ }%%
96
+
97
+ /** Data **/
98
+ %% write data;
99
+
100
+ int httpclient_parser_init(httpclient_parser *parser) {
101
+ int cs = 0;
102
+ %% write init;
103
+ parser->cs = cs;
104
+ parser->body_start = 0;
105
+ parser->content_len = 0;
106
+ parser->mark = 0;
107
+ parser->nread = 0;
108
+ parser->field_len = 0;
109
+ parser->field_start = 0;
110
+
111
+ return(1);
112
+ }
113
+
114
+
115
+ /** exec **/
116
+ size_t httpclient_parser_execute(httpclient_parser *parser, const char *buffer, size_t len, size_t off) {
117
+ const char *p, *pe;
118
+ int cs = parser->cs;
119
+
120
+ assert(off <= len && "offset past end of buffer");
121
+
122
+ p = buffer+off;
123
+ pe = buffer+len;
124
+
125
+ assert(*pe == '\0' && "pointer does not end on NUL");
126
+ assert(pe - p == len - off && "pointers aren't same distance");
127
+
128
+
129
+ %% write exec;
130
+
131
+ parser->cs = cs;
132
+ parser->nread += p - (buffer + off);
133
+
134
+ assert(p <= pe && "buffer overflow after parsing execute");
135
+ assert(parser->nread <= len && "nread longer than length");
136
+ assert(parser->body_start <= len && "body starts after buffer end");
137
+ assert(parser->mark < len && "mark is after buffer end");
138
+ assert(parser->field_len <= len && "field has length longer than whole buffer");
139
+ assert(parser->field_start < len && "field starts after buffer end");
140
+
141
+ if(parser->body_start) {
142
+ /* final \r\n combo encountered so stop right here */
143
+ %%write eof;
144
+ parser->nread++;
145
+ }
146
+
147
+ return(parser->nread);
148
+ }
149
+
150
+ int httpclient_parser_finish(httpclient_parser *parser)
151
+ {
152
+ int cs = parser->cs;
153
+
154
+ %%write eof;
155
+
156
+ parser->cs = cs;
157
+
158
+ if (httpclient_parser_has_error(parser) ) {
159
+ return -1;
160
+ } else if (httpclient_parser_is_finished(parser) ) {
161
+ return 1;
162
+ } else {
163
+ return 0;
164
+ }
165
+ }
166
+
167
+ int httpclient_parser_has_error(httpclient_parser *parser) {
168
+ return parser->cs == httpclient_parser_error;
169
+ }
170
+
171
+ int httpclient_parser_is_finished(httpclient_parser *parser) {
172
+ return parser->cs == httpclient_parser_first_final;
173
+ }
@@ -0,0 +1,6 @@
1
+ require 'mkmf'
2
+
3
+ dir_config("rev_buffer")
4
+ have_library("c", "main")
5
+
6
+ create_makefile("rev_buffer")
@@ -0,0 +1,631 @@
1
+ /*
2
+ * Copyright (C) 2007 Tony Arcieri
3
+ * You may redistribute this under the terms of the Ruby license.
4
+ * See LICENSE for details
5
+ */
6
+
7
+ #include "ruby.h"
8
+ #include "rubyio.h"
9
+
10
+ /*
11
+ #define EV_STANDALONE 1
12
+ #include "../libev/ev.h"
13
+ #include "rev.h"
14
+ */
15
+
16
+ #include <assert.h>
17
+
18
+ #include <string.h>
19
+ #include <time.h>
20
+ #include <unistd.h>
21
+ #include <errno.h>
22
+
23
+ /* Default number of bytes in each node's buffer */
24
+ #define DEFAULT_NODE_SIZE 16384
25
+
26
+ /* Maximum age of a buffer node in a memory pool, in seconds */
27
+ #define MAX_AGE 60
28
+
29
+ /* How often to scan the pool for old nodes */
30
+ #define PURGE_INTERVAL 10
31
+
32
+ struct buffer {
33
+ time_t last_purged_at;
34
+ unsigned size, node_size;
35
+ struct buffer_node *head, *tail;
36
+ struct buffer_node *pool_head, *pool_tail;
37
+
38
+ };
39
+
40
+ struct buffer_node {
41
+ time_t last_used_at;
42
+ unsigned start, end;
43
+ struct buffer_node *next;
44
+ unsigned char data[0];
45
+ };
46
+
47
+ static VALUE mRev = Qnil;
48
+ static VALUE cRev_Buffer = Qnil;
49
+
50
+ static VALUE Rev_Buffer_allocate(VALUE klass);
51
+ static void Rev_Buffer_mark(struct buffer *);
52
+ static void Rev_Buffer_free(struct buffer *);
53
+
54
+ static VALUE Rev_Buffer_initialize(int argc, VALUE *argv, VALUE self);
55
+ static VALUE Rev_Buffer_clear(VALUE self);
56
+ static VALUE Rev_Buffer_size(VALUE self);
57
+ static VALUE Rev_Buffer_empty(VALUE self);
58
+ static VALUE Rev_Buffer_append(VALUE self, VALUE data);
59
+ static VALUE Rev_Buffer_prepend(VALUE self, VALUE data);
60
+ static VALUE Rev_Buffer_read(int argc, VALUE *argv, VALUE self);
61
+ static VALUE Rev_Buffer_to_str(VALUE self);
62
+ static VALUE Rev_Buffer_read_from(VALUE self, VALUE io);
63
+ static VALUE Rev_Buffer_write_to(VALUE self, VALUE io);
64
+
65
+ static struct buffer *buffer_new(void);
66
+ static void buffer_clear(struct buffer *buf);
67
+ static void buffer_free(struct buffer *buf);
68
+ static void buffer_gc(struct buffer *buf);
69
+ static void buffer_prepend(struct buffer *buf, char *str, unsigned len);
70
+ static void buffer_append(struct buffer *buf, char *str, unsigned len);
71
+ static void buffer_read(struct buffer *buf, char *str, unsigned len);
72
+ static void buffer_copy(struct buffer *buf, char *str, unsigned len);
73
+ static int buffer_read_from(struct buffer *buf, int fd);
74
+ static int buffer_write_to(struct buffer *buf, int fd);
75
+
76
+ /*
77
+ * High speed buffering geared towards non-blocking I/O.
78
+ *
79
+ * Data is stored in a byte queue implemented as a linked list of equal size
80
+ * chunks. Since every node in the list is the same size they are easily
81
+ * memory pooled. Routines are provided for high speed non-blocking reads
82
+ * and writes from Ruby IO objects.
83
+ */
84
+ void Init_rev_buffer()
85
+ {
86
+ mRev = rb_define_module("Rev");
87
+ cRev_Buffer = rb_define_class_under(mRev, "Buffer", rb_cObject);
88
+ rb_define_alloc_func(cRev_Buffer, Rev_Buffer_allocate);
89
+
90
+ rb_define_method(cRev_Buffer, "initialize", Rev_Buffer_initialize, -1);
91
+ rb_define_method(cRev_Buffer, "clear", Rev_Buffer_clear, 0);
92
+ rb_define_method(cRev_Buffer, "size", Rev_Buffer_size, 0);
93
+ rb_define_method(cRev_Buffer, "empty?", Rev_Buffer_empty, 0);
94
+ rb_define_method(cRev_Buffer, "<<", Rev_Buffer_append, 1);
95
+ rb_define_method(cRev_Buffer, "append", Rev_Buffer_append, 1);
96
+ rb_define_method(cRev_Buffer, "prepend", Rev_Buffer_prepend, 1);
97
+ rb_define_method(cRev_Buffer, "read", Rev_Buffer_read, -1);
98
+ rb_define_method(cRev_Buffer, "to_str", Rev_Buffer_to_str, 0);
99
+ rb_define_method(cRev_Buffer, "read_from", Rev_Buffer_read_from, 1);
100
+ rb_define_method(cRev_Buffer, "write_to", Rev_Buffer_write_to, 1);
101
+ }
102
+
103
+ static VALUE Rev_Buffer_allocate(VALUE klass)
104
+ {
105
+ return Data_Wrap_Struct(klass, Rev_Buffer_mark, Rev_Buffer_free, buffer_new());
106
+ }
107
+
108
+ static void Rev_Buffer_mark(struct buffer *buf)
109
+ {
110
+ /* Walks the pool of unused chunks and frees any that are beyond a certain age */
111
+ buffer_gc(buf);
112
+ }
113
+
114
+ static void Rev_Buffer_free(struct buffer *buf)
115
+ {
116
+ buffer_free(buf);
117
+ }
118
+
119
+ /**
120
+ * call-seq:
121
+ * Rev::Buffer.new(size = DEFAULT_NODE_SIZE) -> Rev::Buffer
122
+ *
123
+ * Create a new Rev::Buffer with linked segments of the given size
124
+ */
125
+ static VALUE Rev_Buffer_initialize(int argc, VALUE *argv, VALUE self)
126
+ {
127
+ VALUE node_size_obj;
128
+ int node_size;
129
+ struct buffer *buf;
130
+
131
+ if(rb_scan_args(argc, argv, "01", &node_size_obj) == 1) {
132
+ node_size = NUM2INT(node_size_obj);
133
+
134
+ if(node_size < 1) rb_raise(rb_eArgError, "invalid buffer size");
135
+
136
+ Data_Get_Struct(self, struct buffer, buf);
137
+
138
+ /* Make sure we're not changing the buffer size after data has been allocated */
139
+ assert(!buf->head);
140
+ assert(!buf->pool_head);
141
+
142
+ buf->node_size = node_size;
143
+ }
144
+
145
+ return Qnil;
146
+ }
147
+
148
+ /**
149
+ * call-seq:
150
+ * Rev::Buffer#clear -> nil
151
+ *
152
+ * Clear all data from the Rev::Buffer
153
+ */
154
+ static VALUE Rev_Buffer_clear(VALUE self)
155
+ {
156
+ struct buffer *buf;
157
+ Data_Get_Struct(self, struct buffer, buf);
158
+
159
+ buffer_clear(buf);
160
+
161
+ return Qnil;
162
+ }
163
+
164
+ /**
165
+ * call-seq:
166
+ * Rev::Buffer#size -> Integer
167
+ *
168
+ * Return the size of the buffer in bytes
169
+ */
170
+ static VALUE Rev_Buffer_size(VALUE self)
171
+ {
172
+ struct buffer *buf;
173
+ Data_Get_Struct(self, struct buffer, buf);
174
+
175
+ return INT2NUM(buf->size);
176
+ }
177
+
178
+ /**
179
+ * call-seq:
180
+ * Rev::Buffer#empty? -> Boolean
181
+ *
182
+ * Is the buffer empty?
183
+ */
184
+ static VALUE Rev_Buffer_empty(VALUE self)
185
+ {
186
+ struct buffer *buf;
187
+ Data_Get_Struct(self, struct buffer, buf);
188
+
189
+ return buf->size > 0 ? Qfalse : Qtrue;
190
+ }
191
+
192
+ /**
193
+ * call-seq:
194
+ * Rev::Buffer#append(data) -> String
195
+ *
196
+ * Append the given data to the end of the buffer
197
+ */
198
+ static VALUE Rev_Buffer_append(VALUE self, VALUE data)
199
+ {
200
+ struct buffer *buf;
201
+ Data_Get_Struct(self, struct buffer, buf);
202
+
203
+ /* Is this needed? Never seen anyone else do it... */
204
+ data = rb_convert_type(data, T_STRING, "String", "to_str");
205
+ buffer_append(buf, RSTRING_PTR(data), RSTRING_LEN(data));
206
+
207
+ return data;
208
+ }
209
+
210
+ /**
211
+ * call-seq:
212
+ * Rev::Buffer#prepend(data) -> String
213
+ *
214
+ * Prepend the given data to the beginning of the buffer
215
+ */
216
+ static VALUE Rev_Buffer_prepend(VALUE self, VALUE data)
217
+ {
218
+ struct buffer *buf;
219
+ Data_Get_Struct(self, struct buffer, buf);
220
+
221
+ data = rb_convert_type(data, T_STRING, "String", "to_str");
222
+ buffer_prepend(buf, RSTRING_PTR(data), RSTRING_LEN(data));
223
+
224
+ return data;
225
+ }
226
+
227
+ /**
228
+ * call-seq:
229
+ * Rev::Buffer#read(length = nil) -> String
230
+ *
231
+ * Read the specified abount of data from the buffer. If no value
232
+ * is given the entire contents of the buffer are returned. Any data
233
+ * read from the buffer is cleared.
234
+ */
235
+ static VALUE Rev_Buffer_read(int argc, VALUE *argv, VALUE self)
236
+ {
237
+ VALUE length_obj, str;
238
+ int length;
239
+ struct buffer *buf;
240
+
241
+ Data_Get_Struct(self, struct buffer, buf);
242
+
243
+ if(rb_scan_args(argc, argv, "01", &length_obj) == 1) {
244
+ length = NUM2INT(length_obj);
245
+ } else {
246
+ if(buf->size == 0)
247
+ return rb_str_new2("");
248
+
249
+ length = buf->size;
250
+ }
251
+
252
+ if(length > buf->size)
253
+ length = buf->size;
254
+
255
+ if(length < 1)
256
+ rb_raise(rb_eArgError, "length must be greater than zero");
257
+
258
+ str = rb_str_new(0, length);
259
+ buffer_read(buf, RSTRING_PTR(str), length);
260
+
261
+ return str;
262
+ }
263
+
264
+ /**
265
+ * call-seq:
266
+ * Rev::Buffer#to_str -> String
267
+ *
268
+ * Convert the Buffer to a String. The original buffer is unmodified.
269
+ */
270
+ static VALUE Rev_Buffer_to_str(VALUE self) {
271
+ VALUE str;
272
+ struct buffer *buf;
273
+
274
+ Data_Get_Struct(self, struct buffer, buf);
275
+
276
+ str = rb_str_new(0, buf->size);
277
+ buffer_copy(buf, RSTRING_PTR(str), buf->size);
278
+
279
+ return str;
280
+ }
281
+
282
+ /**
283
+ * call-seq:
284
+ * Rev::Buffer#read_from(io) -> Integer
285
+ *
286
+ * Perform a nonblocking read of the the given IO object and fill
287
+ * the buffer with any data received. The call will read as much
288
+ * data as it can until the read would block.
289
+ */
290
+ static VALUE Rev_Buffer_read_from(VALUE self, VALUE io) {
291
+ struct buffer *buf;
292
+ #if HAVE_RB_IO_T
293
+ rb_io_t *fptr;
294
+ #else
295
+ OpenFile *fptr;
296
+ #endif
297
+
298
+ Data_Get_Struct(self, struct buffer, buf);
299
+ GetOpenFile(rb_convert_type(io, T_FILE, "IO", "to_io"), fptr);
300
+ rb_io_set_nonblock(fptr);
301
+
302
+ return INT2NUM(buffer_read_from(buf, FPTR_TO_FD(fptr)));
303
+ }
304
+
305
+ /**
306
+ * call-seq:
307
+ * Rev::Buffer#write_to(io) -> Integer
308
+ *
309
+ * Perform a nonblocking write of the buffer to the given IO object.
310
+ * As much data as possible is written until the call would block.
311
+ * Any data which is written is removed from the buffer.
312
+ */
313
+ static VALUE Rev_Buffer_write_to(VALUE self, VALUE io) {
314
+ struct buffer *buf;
315
+ #if HAVE_RB_IO_T
316
+ rb_io_t *fptr;
317
+ #else
318
+ OpenFile *fptr;
319
+ #endif
320
+
321
+ Data_Get_Struct(self, struct buffer, buf);
322
+ GetOpenFile(rb_convert_type(io, T_FILE, "IO", "to_io"), fptr);
323
+ rb_io_set_nonblock(fptr);
324
+
325
+ return INT2NUM(buffer_write_to(buf, FPTR_TO_FD(fptr)));
326
+ }
327
+
328
+ /*
329
+ * Ruby bindings end here. Below is the actual implementation of
330
+ * the underlying data structures.
331
+ */
332
+
333
+ /* Create a new buffer */
334
+ static struct buffer *buffer_new(void)
335
+ {
336
+ struct buffer *buf;
337
+
338
+ buf = (struct buffer *)xmalloc(sizeof(struct buffer));
339
+ buf->head = buf->tail = buf->pool_head = buf->pool_tail = 0;
340
+ buf->size = 0;
341
+ buf->node_size = DEFAULT_NODE_SIZE;
342
+ time(&buf->last_purged_at);
343
+
344
+ return buf;
345
+ }
346
+
347
+ /* Clear all data from a buffer */
348
+ static void buffer_clear(struct buffer *buf)
349
+ {
350
+ struct buffer_node *tmp;
351
+
352
+ /* Move everything into the buffer pool */
353
+ if(!buf->pool_tail)
354
+ buf->pool_head = buf->pool_tail = buf->head;
355
+ else
356
+ buf->pool_tail->next = buf->head;
357
+
358
+ buf->head = buf->tail = 0;
359
+ buf->size = 0;
360
+ }
361
+
362
+ /* Free a buffer */
363
+ static void buffer_free(struct buffer *buf)
364
+ {
365
+ struct buffer_node *tmp;
366
+
367
+ buffer_clear(buf);
368
+
369
+ while(buf->pool_head) {
370
+ tmp = buf->pool_head;
371
+ buf->pool_head = tmp->next;
372
+ free(tmp);
373
+ }
374
+
375
+ free(buf);
376
+ }
377
+
378
+ /* Run through the pool and find elements that haven't been used for awhile */
379
+ static void buffer_gc(struct buffer *buf)
380
+ {
381
+ struct buffer_node *cur, *tmp;
382
+ time_t now;
383
+ time(&now);
384
+
385
+ /* Only purge if we've passed the purge interval */
386
+ if(now - buf->last_purged_at < PURGE_INTERVAL)
387
+ return;
388
+
389
+ buf->last_purged_at = now;
390
+
391
+ while(buf->pool_head && now - buf->pool_head->last_used_at >= MAX_AGE) {
392
+ tmp = buf->pool_head;
393
+ buf->pool_head = buf->pool_head->next;
394
+ free(tmp);
395
+ }
396
+
397
+ if(!buf->pool_head)
398
+ buf->pool_tail = 0;
399
+ }
400
+
401
+ /* Create a new buffer_node (or pull one from the memory pool) */
402
+ static struct buffer_node *buffer_node_new(struct buffer *buf)
403
+ {
404
+ struct buffer_node *node;
405
+
406
+ /* Pull from the memory pool if available */
407
+ if(buf->pool_head) {
408
+ node = buf->pool_head;
409
+ buf->pool_head = node->next;
410
+
411
+ if(node->next)
412
+ node->next = 0;
413
+ else
414
+ buf->pool_tail = 0;
415
+ } else {
416
+ node = (struct buffer_node *)xmalloc(sizeof(struct buffer_node) + buf->node_size);
417
+ node->next = 0;
418
+ }
419
+
420
+ node->start = node->end = 0;
421
+ return node;
422
+ }
423
+
424
+ /* Free a buffer node (i.e. return it to the memory pool) */
425
+ static void buffer_node_free(struct buffer *buf, struct buffer_node *node)
426
+ {
427
+ /* Store when the node was freed */
428
+ time(&node->last_used_at);
429
+
430
+ node->next = buf->pool_head;
431
+ buf->pool_head = node;
432
+
433
+ if(!buf->pool_tail)
434
+ buf->pool_tail = node;
435
+ }
436
+
437
+ /* Prepend data to the front of the buffer */
438
+ static void buffer_prepend(struct buffer *buf, char *str, unsigned len)
439
+ {
440
+ struct buffer_node *node, *tmp;
441
+ buf->size += len;
442
+
443
+ /* If it fits in the beginning of the head */
444
+ if(buf->head && buf->head->start >= len) {
445
+ buf->head->start -= len;
446
+ memcpy(buf->head->data + buf->head->start, str, len);
447
+ } else {
448
+ node = buffer_node_new(buf);
449
+ node->next = buf->head;
450
+ buf->head = node;
451
+ if(!buf->tail) buf->tail = node;
452
+
453
+ while(len > buf->node_size) {
454
+ memcpy(node->data, str, buf->node_size);
455
+ node->end = buf->node_size;
456
+
457
+ tmp = buffer_node_new(buf);
458
+ tmp->next = node->next;
459
+ node->next = tmp;
460
+
461
+ if(buf->tail == node) buf->tail = tmp;
462
+ node = tmp;
463
+
464
+ str += buf->node_size;
465
+ len -= buf->node_size;
466
+ }
467
+
468
+ if(len > 0) {
469
+ memcpy(node->data, str, len);
470
+ node->end = len;
471
+ }
472
+ }
473
+ }
474
+
475
+ /* Append data to the front of the buffer */
476
+ static void buffer_append(struct buffer *buf, char *str, unsigned len)
477
+ {
478
+ unsigned nbytes;
479
+ buf->size += len;
480
+
481
+ /* If it fits in the remaining space in the tail */
482
+ if(buf->tail && len <= buf->node_size - buf->tail->end) {
483
+ memcpy(buf->tail->data + buf->tail->end, str, len);
484
+ buf->tail->end += len;
485
+ return;
486
+ }
487
+
488
+ /* Empty list needs initialized */
489
+ if(!buf->head) {
490
+ buf->head = buffer_node_new(buf);
491
+ buf->tail = buf->head;
492
+ }
493
+
494
+ /* Build links out of the data */
495
+ while(len > 0) {
496
+ nbytes = buf->node_size - buf->tail->end;
497
+ if(len < nbytes) nbytes = len;
498
+
499
+ memcpy(buf->tail->data + buf->tail->end, str, nbytes);
500
+ str += nbytes;
501
+ len -= nbytes;
502
+
503
+ buf->tail->end += nbytes;
504
+
505
+ if(len > 0) {
506
+ buf->tail->next = buffer_node_new(buf);
507
+ buf->tail = buf->tail->next;
508
+ }
509
+ }
510
+ }
511
+
512
+ /* Read data from the buffer (and clear what we've read) */
513
+ static void buffer_read(struct buffer *buf, char *str, unsigned len)
514
+ {
515
+ unsigned nbytes;
516
+ struct buffer_node *tmp;
517
+
518
+ while(buf->size > 0 && len > 0) {
519
+ nbytes = buf->head->end - buf->head->start;
520
+ if(len < nbytes) nbytes = len;
521
+
522
+ memcpy(str, buf->head->data + buf->head->start, nbytes);
523
+ str += nbytes;
524
+ len -= nbytes;
525
+
526
+ buf->head->start += nbytes;
527
+ buf->size -= nbytes;
528
+
529
+ if(buf->head->start == buf->head->end) {
530
+ tmp = buf->head;
531
+ buf->head = tmp->next;
532
+ buffer_node_free(buf, tmp);
533
+
534
+ if(!buf->head) buf->tail = 0;
535
+ }
536
+ }
537
+ }
538
+
539
+ /* Copy data from the buffer without clearing it */
540
+ static void buffer_copy(struct buffer *buf, char *str, unsigned len)
541
+ {
542
+ unsigned nbytes;
543
+ struct buffer_node *node;
544
+
545
+ node = buf->head;
546
+ while(node && len > 0) {
547
+ nbytes = node->end - node->start;
548
+ if(len < nbytes) nbytes = len;
549
+
550
+ memcpy(str, node->data + node->start, nbytes);
551
+ str += nbytes;
552
+ len -= nbytes;
553
+
554
+ if(node->start + nbytes == node->end)
555
+ node = node->next;
556
+ }
557
+ }
558
+
559
+ /* Write data from the buffer to a file descriptor */
560
+ static int buffer_write_to(struct buffer *buf, int fd)
561
+ {
562
+ int bytes_written, total_bytes_written = 0;
563
+ struct buffer_node *tmp;
564
+
565
+ while(buf->head) {
566
+ bytes_written = write(fd, buf->head->data + buf->head->start, buf->head->end - buf->head->start);
567
+
568
+ /* If the write failed... */
569
+ if(bytes_written < 0) {
570
+ if(errno != EAGAIN)
571
+ rb_sys_fail("write");
572
+
573
+ return total_bytes_written;
574
+ }
575
+
576
+ total_bytes_written += bytes_written;
577
+ buf->size -= bytes_written;
578
+
579
+ /* If the write blocked... */
580
+ if(bytes_written < buf->head->end - buf->head->start) {
581
+ buf->head->start += bytes_written;
582
+ return total_bytes_written;
583
+ }
584
+
585
+ /* Otherwise we wrote the whole buffer */
586
+ tmp = buf->head;
587
+ buf->head = tmp->next;
588
+ buffer_node_free(buf, tmp);
589
+
590
+ if(!buf->head) buf->tail = 0;
591
+ }
592
+
593
+ return total_bytes_written;
594
+ }
595
+
596
+ /* Read data from a file descriptor to a buffer */
597
+ /* Append data to the front of the buffer */
598
+ static int buffer_read_from(struct buffer *buf, int fd)
599
+ {
600
+ int bytes_read, total_bytes_read = 0;
601
+ unsigned nbytes;
602
+
603
+ /* Empty list needs initialized */
604
+ if(!buf->head) {
605
+ buf->head = buffer_node_new(buf);
606
+ buf->tail = buf->head;
607
+ }
608
+
609
+ do {
610
+ nbytes = buf->node_size - buf->tail->end;
611
+ bytes_read = read(fd, buf->tail->data + buf->tail->end, nbytes);
612
+
613
+ if(bytes_read < 1) {
614
+ if(errno != EAGAIN)
615
+ rb_sys_fail("read");
616
+
617
+ return total_bytes_read;
618
+ }
619
+
620
+ total_bytes_read += bytes_read;
621
+ buf->tail->end += nbytes;
622
+ buf->size += nbytes;
623
+
624
+ if(buf->tail->end == buf->node_size) {
625
+ buf->tail->next = buffer_node_new(buf);
626
+ buf->tail = buf->tail->next;
627
+ }
628
+ } while(bytes_read == nbytes);
629
+
630
+ return total_bytes_read;
631
+ }