bossan 0.1.6 → 0.1.7

Sign up to get free protection for your applications and to get access to all the features.
@@ -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