bossan 0.1.6 → 0.1.7

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,74 @@
1
+ #include "buffer.h"
2
+
3
+ #define LIMIT_MAX 1024 * 1024 * 1024
4
+
5
+ buffer *
6
+ new_buffer(size_t buf_size, size_t limit)
7
+ {
8
+ buffer *buf;
9
+ buf = ruby_xmalloc(sizeof(buffer));
10
+ memset(buf, 0, sizeof(buffer));
11
+ buf->buf = ruby_xmalloc(sizeof(char) * buf_size);
12
+ buf->buf_size = buf_size;
13
+ if(limit){
14
+ buf->limit = limit;
15
+ }else{
16
+ buf->limit = LIMIT_MAX;
17
+ }
18
+ return buf;
19
+ }
20
+
21
+
22
+ buffer_result
23
+ write2buf(buffer *buf, const char *c, size_t l)
24
+ {
25
+ size_t newl;
26
+ char *newbuf;
27
+ buffer_result ret = WRITE_OK;
28
+ newl = buf->len + l;
29
+
30
+ if (newl >= buf->buf_size) {
31
+ buf->buf_size *= 2;
32
+ if(buf->buf_size <= newl) {
33
+ buf->buf_size = (int)(newl + 1);
34
+ }
35
+ if(buf->buf_size > buf->limit){
36
+ buf->buf_size = buf->limit + 1;
37
+ }
38
+ newbuf = (char*)ruby_xrealloc(buf->buf, buf->buf_size);
39
+ buf->buf = newbuf;
40
+ }
41
+ if(newl >= buf->buf_size){
42
+ l = buf->buf_size - buf->len -1;
43
+ ret = LIMIT_OVER;
44
+ }
45
+ memcpy(buf->buf + buf->len, c , l);
46
+ buf->len += (int)l;
47
+ return ret;
48
+ }
49
+
50
+
51
+ void
52
+ free_buffer(buffer *buf)
53
+ {
54
+ ruby_xfree(buf->buf);
55
+ ruby_xfree(buf);
56
+ }
57
+
58
+
59
+ VALUE
60
+ getRbString(buffer *buf)
61
+ {
62
+ VALUE o;
63
+ o = rb_str_new(buf->buf, buf->len);
64
+ free_buffer(buf);
65
+ return o;
66
+ }
67
+
68
+
69
+ char *
70
+ getString(buffer *buf)
71
+ {
72
+ buf->buf[buf->len] = '\0';
73
+ return buf->buf;
74
+ }
@@ -0,0 +1,43 @@
1
+ #ifndef BUFFER_H
2
+ #define BUFFER_H
3
+
4
+ #include "ruby.h"
5
+ #include <stdio.h>
6
+ #include <stdlib.h>
7
+ #include <string.h>
8
+ #include <inttypes.h>
9
+
10
+ typedef enum {
11
+ WRITE_OK,
12
+ MEMORY_ERROR,
13
+ LIMIT_OVER,
14
+ } buffer_result;
15
+
16
+ typedef struct {
17
+ char *buf;
18
+ size_t buf_size;
19
+ size_t len;
20
+ size_t limit;
21
+ } buffer;
22
+
23
+ buffer *
24
+ new_buffer(size_t buf_size, size_t limit);
25
+
26
+ buffer_result
27
+ write2buf(buffer *buf, const char *c, size_t l);
28
+
29
+ void
30
+ free_buffer(buffer *buf);
31
+
32
+ VALUE
33
+ getRbString(buffer *buf);
34
+
35
+ char *
36
+ getString(buffer *buf);
37
+
38
+
39
+ #endif
40
+
41
+
42
+
43
+
@@ -0,0 +1,35 @@
1
+ #ifndef CLIENT_H
2
+ #define CLIENT_H
3
+
4
+ #include "request.h"
5
+
6
+ typedef struct _client {
7
+ int fd;
8
+ char *remote_addr;
9
+ uint32_t remote_port;
10
+ uint8_t keep_alive;
11
+ request *req;
12
+ uint32_t body_length;
13
+ int body_readed;
14
+ void *body;
15
+ int bad_request_code;
16
+ request_body_type body_type;
17
+ uint8_t complete;
18
+
19
+ http_parser *http; // http req parser
20
+ VALUE environ; // rack environ
21
+ int status_code; // response status code
22
+
23
+ VALUE http_status; // response status line
24
+ VALUE headers; // http response headers
25
+ uint8_t header_done; // header write status
26
+ VALUE response; // rack response object
27
+ VALUE response_iter; // rack response object
28
+ uint8_t content_length_set; // content_length_set flag
29
+ uint32_t content_length; // content_length
30
+ uint32_t write_bytes; // send body length
31
+ void *bucket; //write_data
32
+ uint8_t response_closed; //response closed flag
33
+ } client_t;
34
+
35
+ #endif
@@ -10,4 +10,15 @@ Dir.chdir bossan_dir
10
10
 
11
11
  dir_config bossan_dir
12
12
 
13
+ srcs = Dir.glob("*.c")
14
+ if have_header("sys/epoll.h")
15
+ srcs.delete("picoev_kqueue.c")
16
+ elsif have_header("sys/event.h")
17
+ srcs.delete("picoev_epoll.c")
18
+ else
19
+ $stderr.puts "error: not found kqueue or epoll on your system."
20
+ exit 1
21
+ end
22
+ $srcs = srcs
23
+
13
24
  create_makefile "bossan/bossan_ext"
@@ -0,0 +1,209 @@
1
+ /*
2
+ * Copyright (c) 2009, Cybozu Labs, Inc.
3
+ * All rights reserved.
4
+ *
5
+ * Redistribution and use in source and binary forms, with or without
6
+ * modification, are permitted provided that the following conditions are met:
7
+ *
8
+ * * Redistributions of source code must retain the above copyright notice,
9
+ * this list of conditions and the following disclaimer.
10
+ * * Redistributions in binary form must reproduce the above copyright notice,
11
+ * this list of conditions and the following disclaimer in the documentation
12
+ * and/or other materials provided with the distribution.
13
+ * * Neither the name of the <ORGANIZATION> nor the names of its contributors
14
+ * may be used to endorse or promote products derived from this software
15
+ * without specific prior written permission.
16
+ *
17
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
21
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27
+ * POSSIBILITY OF SUCH DAMAGE.
28
+ */
29
+
30
+ #include <errno.h>
31
+ #include <sys/types.h>
32
+ #include <sys/event.h>
33
+ #include <sys/time.h>
34
+ #include <unistd.h>
35
+ #include "picoev.h"
36
+
37
+ #define EV_QUEUE_SZ 128
38
+
39
+ #define BACKEND_BUILD(next_fd, events) \
40
+ ((unsigned)((next_fd << 8) | (events & 0xff)))
41
+ #define BACKEND_GET_NEXT_FD(backend) ((int)(backend) >> 8)
42
+ #define BACKEND_GET_OLD_EVENTS(backend) ((int)(backend) & 0xff)
43
+
44
+ typedef struct picoev_loop_kqueue_st {
45
+ picoev_loop loop;
46
+ int kq;
47
+ int changed_fds; /* link list using picoev_fd::_backend, -1 if not changed */
48
+ struct kevent events[1024];
49
+ struct kevent changelist[256];
50
+ } picoev_loop_kqueue;
51
+
52
+ picoev_globals picoev;
53
+
54
+ static int apply_pending_changes(picoev_loop_kqueue* loop, int apply_all)
55
+ {
56
+ #define SET(op, events) \
57
+ EV_SET(loop->changelist + cl_off++, loop->changed_fds, \
58
+ (((events) & PICOEV_READ) != 0 ? EVFILT_READ : 0) \
59
+ | (((events) & PICOEV_WRITE) != 0 ? EVFILT_WRITE : 0), \
60
+ (op), 0, 0, NULL)
61
+
62
+ int cl_off = 0, nevents;
63
+
64
+ while (loop->changed_fds != -1) {
65
+ picoev_fd* changed = picoev.fds + loop->changed_fds;
66
+ int old_events = BACKEND_GET_OLD_EVENTS(changed->_backend);
67
+ if (changed->events != old_events) {
68
+ if (old_events != 0) {
69
+ SET(EV_DISABLE, old_events);
70
+ }
71
+ if (changed->events != 0) {
72
+ SET(EV_ADD | EV_ENABLE, changed->events);
73
+ }
74
+ if ((size_t)cl_off + 1
75
+ >= sizeof(loop->changelist) / sizeof(loop->changelist[0])) {
76
+ nevents = kevent(loop->kq, loop->changelist, cl_off, NULL, 0, NULL);
77
+ assert(nevents == 0);
78
+ cl_off = 0;
79
+ }
80
+ }
81
+ loop->changed_fds = BACKEND_GET_NEXT_FD(changed->_backend);
82
+ changed->_backend = -1;
83
+ }
84
+
85
+ if (apply_all && cl_off != 0) {
86
+ nevents = kevent(loop->kq, loop->changelist, cl_off, NULL, 0, NULL);
87
+ assert(nevents == 0);
88
+ cl_off = 0;
89
+ }
90
+
91
+ return cl_off;
92
+
93
+ #undef SET
94
+ }
95
+
96
+ picoev_loop* picoev_create_loop(int max_timeout)
97
+ {
98
+ picoev_loop_kqueue* loop;
99
+
100
+ /* init parent */
101
+ assert(PICOEV_IS_INITED);
102
+ if ((loop = (picoev_loop_kqueue*)malloc(sizeof(picoev_loop_kqueue)))
103
+ == NULL) {
104
+ return NULL;
105
+ }
106
+ if (picoev_init_loop_internal(&loop->loop, max_timeout) != 0) {
107
+ free(loop);
108
+ return NULL;
109
+ }
110
+
111
+ /* init kqueue */
112
+ if ((loop->kq = kqueue()) == -1) {
113
+ picoev_deinit_loop_internal(&loop->loop);
114
+ free(loop);
115
+ return NULL;
116
+ }
117
+ loop->changed_fds = -1;
118
+
119
+ loop->loop.now = time(NULL);
120
+ return &loop->loop;
121
+ }
122
+
123
+ int picoev_destroy_loop(picoev_loop* _loop)
124
+ {
125
+ picoev_loop_kqueue* loop = (picoev_loop_kqueue*)_loop;
126
+
127
+ if (close(loop->kq) != 0) {
128
+ return -1;
129
+ }
130
+ picoev_deinit_loop_internal(&loop->loop);
131
+ free(loop);
132
+ return 0;
133
+ }
134
+
135
+ int picoev_update_events_internal(picoev_loop* _loop, int fd, int events)
136
+ {
137
+ picoev_loop_kqueue* loop = (picoev_loop_kqueue*)_loop;
138
+ picoev_fd* target = picoev.fds + fd;
139
+
140
+ assert(PICOEV_FD_BELONGS_TO_LOOP(&loop->loop, fd));
141
+
142
+ /* initialize if adding the fd */
143
+ if ((events & PICOEV_ADD) != 0) {
144
+ target->_backend = -1;
145
+ }
146
+ /* return if nothing to do */
147
+ if (events == PICOEV_DEL
148
+ ? target->_backend == -1
149
+ : (events & PICOEV_READWRITE) == target->events) {
150
+ return 0;
151
+ }
152
+ /* add to changed list if not yet being done */
153
+ if (target->_backend == -1) {
154
+ target->_backend = BACKEND_BUILD(loop->changed_fds, target->events);
155
+ loop->changed_fds = fd;
156
+ }
157
+ /* update events */
158
+ target->events = events & PICOEV_READWRITE;
159
+ /* apply immediately if is a DELETE */
160
+ if ((events & PICOEV_DEL) != 0) {
161
+ apply_pending_changes(loop, 1);
162
+ }
163
+
164
+ return 0;
165
+ }
166
+
167
+ int picoev_poll_once_internal(picoev_loop* _loop, int max_wait)
168
+ {
169
+ picoev_loop_kqueue* loop = (picoev_loop_kqueue*)_loop;
170
+ struct timespec ts;
171
+ int cl_off = 0, nevents, i;
172
+
173
+ /* apply pending changes, with last changes stored to loop->changelist */
174
+ cl_off = apply_pending_changes(loop, 0);
175
+
176
+ ts.tv_sec = max_wait;
177
+ ts.tv_nsec = 0;
178
+ nevents = kevent(loop->kq, loop->changelist, cl_off, loop->events,
179
+ sizeof(loop->events) / sizeof(loop->events[0]), &ts);
180
+ if (nevents == -1) {
181
+ /* the errors we can only rescue */
182
+ assert(errno == EACCES || errno == EFAULT || errno == EINTR);
183
+ return -1;
184
+ }
185
+ for (i = 0; i < nevents; ++i) {
186
+ struct kevent* event = loop->events + i;
187
+ picoev_fd* target = picoev.fds + event->ident;
188
+ assert((event->flags & EV_ERROR) == 0); /* changelist errors are fatal */
189
+ if (loop->loop.loop_id == target->loop_id
190
+ && (event->filter & (EVFILT_READ | EVFILT_WRITE)) != 0) {
191
+ int revents;
192
+ switch (event->filter) {
193
+ case EVFILT_READ:
194
+ revents = PICOEV_READ;
195
+ break;
196
+ case EVFILT_WRITE:
197
+ revents = PICOEV_WRITE;
198
+ break;
199
+ default:
200
+ assert(0);
201
+ revents = 0; // suppress compiler warning
202
+ break;
203
+ }
204
+ (*target->callback)(&loop->loop, event->ident, revents, target->cb_arg);
205
+ }
206
+ }
207
+
208
+ return 0;
209
+ }
@@ -0,0 +1,62 @@
1
+ #include "request.h"
2
+
3
+
4
+ request *
5
+ new_request(void)
6
+ {
7
+ request *req = (request *)ruby_xmalloc(sizeof(request));
8
+ memset(req, 0, sizeof(request));
9
+ return req;
10
+ }
11
+
12
+
13
+ header *
14
+ new_header(size_t fsize, size_t flimit, size_t vsize, size_t vlimit)
15
+ {
16
+ header *h;
17
+ h = ruby_xmalloc(sizeof(header));
18
+ h->field = new_buffer(fsize, flimit);
19
+ h->value = new_buffer(vsize, vlimit);
20
+ return h;
21
+ }
22
+
23
+
24
+ void
25
+ free_header(header *h)
26
+ {
27
+ ruby_xfree(h);
28
+ }
29
+
30
+
31
+ void
32
+ free_request(request *req)
33
+ {
34
+ uint32_t i;
35
+ header *h;
36
+ if(req->path){
37
+ free_buffer(req->path);
38
+ req->path = NULL;
39
+ }
40
+ if(req->uri){
41
+ free_buffer(req->uri);
42
+ req->uri = NULL;
43
+ }
44
+ if(req->query_string){
45
+ free_buffer(req->query_string);
46
+ req->query_string = NULL;
47
+ }
48
+ if(req->fragment){
49
+ free_buffer(req->fragment);
50
+ req->fragment = NULL;
51
+ }
52
+ for(i = 0; i < req->num_headers+1; i++){
53
+ h = req->headers[i];
54
+ if(h){
55
+ free_buffer(h->field);
56
+ free_buffer(h->value);
57
+ free_header(h);
58
+ req->headers[i] = NULL;
59
+ }
60
+ }
61
+ ruby_xfree(req);
62
+ }
@@ -0,0 +1,54 @@
1
+ #ifndef REQUEST_H
2
+ #define REQUEST_H
3
+
4
+ #include <inttypes.h>
5
+ #include "buffer.h"
6
+
7
+ #define LIMIT_PATH 1024 * 4
8
+ #define LIMIT_FRAGMENT 1024
9
+ #define LIMIT_URI 1024 * 4
10
+ #define LIMIT_QUERY_STRING 1024 * 8
11
+
12
+ #define LIMIT_REQUEST_FIELDS 30
13
+ #define LIMIT_REQUEST_FIELD_SIZE 1024 * 8
14
+
15
+ typedef enum {
16
+ BODY_TYPE_NONE,
17
+ BODY_TYPE_TMPFILE,
18
+ BODY_TYPE_BUFFER
19
+ } request_body_type;
20
+
21
+ typedef enum {
22
+ FIELD,
23
+ VAL,
24
+ } field_type;
25
+
26
+ typedef struct {
27
+ buffer *field;
28
+ buffer *value;
29
+ } header;
30
+
31
+ typedef struct {
32
+ buffer *path;
33
+ buffer *uri;
34
+ buffer *query_string;
35
+ buffer *fragment;
36
+ header *headers[LIMIT_REQUEST_FIELDS];
37
+ uint32_t num_headers;
38
+ field_type last_header_element;
39
+ } request;
40
+
41
+
42
+ request *
43
+ new_request(void);
44
+
45
+ header *
46
+ new_header(size_t fsize, size_t flimit, size_t vsize, size_t vlimit);
47
+
48
+ void
49
+ free_header(header *h);
50
+
51
+ void
52
+ free_request(request *req);
53
+
54
+ #endif