ebb 0.2.1 → 0.3.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.
- data/README +10 -44
- data/Rakefile +123 -0
- data/ext/ebb.c +794 -0
- data/ext/ebb.h +130 -0
- data/ext/ebb_ffi.c +575 -0
- data/ext/ebb_request_parser.c +5339 -0
- data/ext/ebb_request_parser.h +97 -0
- data/ext/ebb_request_parser.rl +513 -0
- data/{src → ext}/extconf.rb +12 -8
- data/ext/rbtree.c +408 -0
- data/ext/rbtree.h +54 -0
- data/lib/ebb.rb +311 -0
- data/lib/ebb/version.rb +4 -0
- data/libev/ev++.h +803 -0
- data/libev/ev.c +24 -6
- data/libev/ev.h +4 -0
- data/libev/ev_select.c +50 -15
- data/libev/ev_vars.h +3 -0
- data/libev/ev_win32.c +3 -0
- data/libev/ev_wrap.h +2 -0
- data/libev/event.c +403 -0
- data/libev/event.h +152 -0
- metadata +26 -40
- data/benchmark/application.rb +0 -93
- data/benchmark/server_test.rb +0 -193
- data/bin/ebb_rails +0 -4
- data/ruby_lib/ebb.rb +0 -257
- data/ruby_lib/ebb/runner.rb +0 -134
- data/ruby_lib/ebb/runner/rails.rb +0 -31
- data/ruby_lib/rack/adapter/rails.rb +0 -159
- data/src/ebb.c +0 -627
- data/src/ebb.h +0 -102
- data/src/ebb_ruby.c +0 -306
- data/src/parser.c +0 -2860
- data/src/parser.h +0 -53
- data/test/basic_test.rb +0 -46
- data/test/ebb_rails_test.rb +0 -34
- data/test/env_test.rb +0 -110
- data/test/helper.rb +0 -138
data/src/ebb.c
DELETED
@@ -1,627 +0,0 @@
|
|
1
|
-
/* The Ebb Web Server
|
2
|
-
* Copyright (c) 2008 Ry Dahl. This software is released under the MIT
|
3
|
-
* License. See README file for details.
|
4
|
-
*/
|
5
|
-
#include <unistd.h>
|
6
|
-
#include <fcntl.h>
|
7
|
-
#include <sys/types.h>
|
8
|
-
#include <arpa/inet.h>
|
9
|
-
#include <netinet/tcp.h>
|
10
|
-
#include <sys/un.h>
|
11
|
-
#include <netdb.h>
|
12
|
-
|
13
|
-
#include <stdio.h>
|
14
|
-
#include <string.h>
|
15
|
-
#include <stdlib.h>
|
16
|
-
#include <errno.h>
|
17
|
-
#include <signal.h>
|
18
|
-
#include <assert.h>
|
19
|
-
|
20
|
-
#define EV_STANDALONE 1
|
21
|
-
#include <ev.c>
|
22
|
-
#include <glib.h>
|
23
|
-
|
24
|
-
#include "parser.h"
|
25
|
-
#include "ebb.h"
|
26
|
-
|
27
|
-
#define min(a,b) (a < b ? a : b)
|
28
|
-
#define ramp(a) (a > 0 ? a : 0)
|
29
|
-
|
30
|
-
static void client_init(ebb_client *client);
|
31
|
-
|
32
|
-
static void set_nonblock(int fd)
|
33
|
-
{
|
34
|
-
int flags = fcntl(fd, F_GETFL, 0);
|
35
|
-
assert(0 <= fcntl(fd, F_SETFL, flags | O_NONBLOCK) && "Setting socket non-block failed!");
|
36
|
-
}
|
37
|
-
|
38
|
-
|
39
|
-
void env_add(ebb_client *client, const char *field, int flen, const char *value, int vlen)
|
40
|
-
{
|
41
|
-
if(client->env_size >= EBB_MAX_ENV) {
|
42
|
-
client->parser.overflow_error = TRUE;
|
43
|
-
return;
|
44
|
-
}
|
45
|
-
struct ebb_env_item * const item = &client->env[client->env_size++];
|
46
|
-
item->type = -1;
|
47
|
-
item->field_length = flen;
|
48
|
-
item->value_length = vlen;
|
49
|
-
item->field = field;
|
50
|
-
item->value = value;
|
51
|
-
}
|
52
|
-
|
53
|
-
|
54
|
-
void env_add_const(ebb_client *client, int type, const char *value, int vlen)
|
55
|
-
{
|
56
|
-
if(client->env_size >= EBB_MAX_ENV) {
|
57
|
-
client->parser.overflow_error = TRUE;
|
58
|
-
return;
|
59
|
-
}
|
60
|
-
struct ebb_env_item * const item = &client->env[client->env_size++];
|
61
|
-
item->type = type;
|
62
|
-
item->field_length = -1;
|
63
|
-
item->value_length = vlen;
|
64
|
-
item->field = NULL;
|
65
|
-
item->value = value;
|
66
|
-
}
|
67
|
-
|
68
|
-
|
69
|
-
void http_field_cb(void *data, const char *field, size_t flen, const char *value, size_t vlen)
|
70
|
-
{
|
71
|
-
ebb_client *client = (ebb_client*)(data);
|
72
|
-
assert(field != NULL);
|
73
|
-
assert(value != NULL);
|
74
|
-
env_add(client, field, flen, value, vlen);
|
75
|
-
}
|
76
|
-
|
77
|
-
|
78
|
-
void on_element(void *data, int type, const char *at, size_t length)
|
79
|
-
{
|
80
|
-
ebb_client *client = (ebb_client*)(data);
|
81
|
-
env_add_const(client, type, at, length);
|
82
|
-
}
|
83
|
-
|
84
|
-
|
85
|
-
static void dispatch(ebb_client *client)
|
86
|
-
{
|
87
|
-
ebb_server *server = client->server;
|
88
|
-
if(client->open == FALSE)
|
89
|
-
return;
|
90
|
-
client->in_use = TRUE;
|
91
|
-
|
92
|
-
/* XXX decide if to use keep-alive or not? */
|
93
|
-
|
94
|
-
server->request_cb(client, server->request_cb_data);
|
95
|
-
}
|
96
|
-
|
97
|
-
|
98
|
-
static void on_timeout(struct ev_loop *loop, ev_timer *watcher, int revents)
|
99
|
-
{
|
100
|
-
ebb_client *client = (ebb_client*)(watcher->data);
|
101
|
-
|
102
|
-
assert(client->server->loop == loop);
|
103
|
-
assert(&(client->timeout_watcher) == watcher);
|
104
|
-
|
105
|
-
ebb_client_close(client);
|
106
|
-
#ifdef DEBUG
|
107
|
-
g_message("peer timed out");
|
108
|
-
#endif
|
109
|
-
}
|
110
|
-
|
111
|
-
#define client_finished_parsing http_parser_is_finished(&client->parser)
|
112
|
-
#define total_request_size (client->parser.content_length + client->parser.nread)
|
113
|
-
|
114
|
-
static void on_client_readable(struct ev_loop *loop, ev_io *watcher, int revents)
|
115
|
-
{
|
116
|
-
ebb_client *client = (ebb_client*)(watcher->data);
|
117
|
-
|
118
|
-
assert(client->in_use == FALSE);
|
119
|
-
assert(client->open);
|
120
|
-
assert(client->server->open);
|
121
|
-
assert(client->server->loop == loop);
|
122
|
-
assert(&client->read_watcher == watcher);
|
123
|
-
|
124
|
-
ssize_t read = recv( client->fd
|
125
|
-
, client->request_buffer + client->read
|
126
|
-
, EBB_BUFFERSIZE - client->read
|
127
|
-
, 0
|
128
|
-
);
|
129
|
-
if(read < 0) goto error;
|
130
|
-
if(read == 0) goto error; /* XXX is this the right action to take for read==0 ? */
|
131
|
-
client->read += read;
|
132
|
-
ev_timer_again(loop, &client->timeout_watcher);
|
133
|
-
|
134
|
-
// if(client->read == EBB_BUFFERSIZE) goto error;
|
135
|
-
|
136
|
-
if(FALSE == client_finished_parsing) {
|
137
|
-
http_parser_execute( &client->parser
|
138
|
-
, client->request_buffer
|
139
|
-
, client->read
|
140
|
-
, client->parser.nread
|
141
|
-
);
|
142
|
-
if(http_parser_has_error(&client->parser)) goto error;
|
143
|
-
}
|
144
|
-
|
145
|
-
if(client_finished_parsing) {
|
146
|
-
assert(client->read <= total_request_size);
|
147
|
-
if(total_request_size == client->read || total_request_size > EBB_BUFFERSIZE) {
|
148
|
-
client->body_head = client->request_buffer + client->parser.nread;
|
149
|
-
client->body_head_len = client->read - client->parser.nread;
|
150
|
-
ev_io_stop(loop, watcher);
|
151
|
-
dispatch(client);
|
152
|
-
return;
|
153
|
-
}
|
154
|
-
}
|
155
|
-
return;
|
156
|
-
error:
|
157
|
-
#ifdef DEBUG
|
158
|
-
if(read < 0) g_message("Error recving data: %s", strerror(errno));
|
159
|
-
#endif
|
160
|
-
ebb_client_close(client);
|
161
|
-
}
|
162
|
-
|
163
|
-
|
164
|
-
static void on_client_writable(struct ev_loop *loop, ev_io *watcher, int revents)
|
165
|
-
{
|
166
|
-
ebb_client *client = (ebb_client*)(watcher->data);
|
167
|
-
ssize_t sent;
|
168
|
-
|
169
|
-
if(client->status_written == FALSE || client->headers_written == FALSE) {
|
170
|
-
g_message("no status or headers - closing connection.");
|
171
|
-
goto error;
|
172
|
-
}
|
173
|
-
|
174
|
-
if(EV_ERROR & revents) {
|
175
|
-
g_message("on_client_writable() got error event, closing peer");
|
176
|
-
goto error;
|
177
|
-
}
|
178
|
-
|
179
|
-
//if(client->written != 0)
|
180
|
-
// g_debug("total written: %d", (int)(client->written));
|
181
|
-
|
182
|
-
sent = send( client->fd
|
183
|
-
, client->response_buffer->str + sizeof(gchar)*(client->written)
|
184
|
-
, client->response_buffer->len - client->written
|
185
|
-
, 0
|
186
|
-
);
|
187
|
-
if(sent < 0) {
|
188
|
-
#ifdef DEBUG
|
189
|
-
g_message("Error writing: %s", strerror(errno));
|
190
|
-
#endif
|
191
|
-
goto error;
|
192
|
-
} else if(sent == 0) {
|
193
|
-
/* is this the wrong thing to do? */
|
194
|
-
g_message("Sent zero bytes? Closing connection");
|
195
|
-
goto error;
|
196
|
-
}
|
197
|
-
client->written += sent;
|
198
|
-
|
199
|
-
assert(client->written <= client->response_buffer->len);
|
200
|
-
//g_message("wrote %d bytes. total: %d", (int)sent, (int)(client->written));
|
201
|
-
|
202
|
-
ev_timer_again(loop, &client->timeout_watcher);
|
203
|
-
|
204
|
-
if(client->written == client->response_buffer->len) {
|
205
|
-
/* stop the write watcher. to be restarted by the next call to ebb_client_write_body
|
206
|
-
* or if client->body_written is set (by using ebb_client_release) then
|
207
|
-
* we close the connection
|
208
|
-
*/
|
209
|
-
ev_io_stop(loop, watcher);
|
210
|
-
if(client->body_written) {
|
211
|
-
client->keep_alive ? client_init(client) : ebb_client_close(client);
|
212
|
-
}
|
213
|
-
}
|
214
|
-
return;
|
215
|
-
error:
|
216
|
-
ebb_client_close(client);
|
217
|
-
}
|
218
|
-
|
219
|
-
|
220
|
-
static void client_init(ebb_client *client)
|
221
|
-
{
|
222
|
-
assert(client->in_use == FALSE);
|
223
|
-
|
224
|
-
/* If the client is already open, reuse the fd, just reset all the parameters
|
225
|
-
* this would happen in the case of a keep_alive request
|
226
|
-
*/
|
227
|
-
if(!client->open) {
|
228
|
-
/* DO SOCKET STUFF */
|
229
|
-
socklen_t len = sizeof(struct sockaddr);
|
230
|
-
int fd = accept(client->server->fd, (struct sockaddr*)&(client->sockaddr), &len);
|
231
|
-
if(fd < 0) {
|
232
|
-
perror("accept()");
|
233
|
-
return;
|
234
|
-
}
|
235
|
-
client->open = TRUE;
|
236
|
-
client->fd = fd;
|
237
|
-
}
|
238
|
-
|
239
|
-
set_nonblock(client->fd);
|
240
|
-
|
241
|
-
/* IP Address */
|
242
|
-
if(client->server->port)
|
243
|
-
client->ip = inet_ntoa(client->sockaddr.sin_addr);
|
244
|
-
|
245
|
-
/* INITIALIZE http_parser */
|
246
|
-
http_parser_init(&client->parser);
|
247
|
-
client->parser.data = client;
|
248
|
-
client->parser.http_field = http_field_cb;
|
249
|
-
client->parser.on_element = on_element;
|
250
|
-
|
251
|
-
/* OTHER */
|
252
|
-
client->env_size = 0;
|
253
|
-
client->read = 0;
|
254
|
-
if(client->request_buffer == NULL) {
|
255
|
-
/* Only allocate the request_buffer once */
|
256
|
-
client->request_buffer = (char*)malloc(EBB_BUFFERSIZE);
|
257
|
-
}
|
258
|
-
client->keep_alive = FALSE;
|
259
|
-
client->status_written = client->headers_written = client->body_written = FALSE;
|
260
|
-
client->written = 0;
|
261
|
-
|
262
|
-
if(client->response_buffer != NULL)
|
263
|
-
g_string_free(client->response_buffer, TRUE);
|
264
|
-
client->response_buffer = g_string_new("");
|
265
|
-
|
266
|
-
/* SETUP READ AND TIMEOUT WATCHERS */
|
267
|
-
client->write_watcher.data = client;
|
268
|
-
ev_init (&client->write_watcher, on_client_writable);
|
269
|
-
ev_io_set (&client->write_watcher, client->fd, EV_WRITE | EV_ERROR);
|
270
|
-
/* Note, do not start write_watcher until there is something to be written.
|
271
|
-
* See ebb_client_write_body() */
|
272
|
-
|
273
|
-
client->read_watcher.data = client;
|
274
|
-
ev_init(&client->read_watcher, on_client_readable);
|
275
|
-
ev_io_set(&client->read_watcher, client->fd, EV_READ | EV_ERROR);
|
276
|
-
ev_io_start(client->server->loop, &client->read_watcher);
|
277
|
-
|
278
|
-
client->timeout_watcher.data = client;
|
279
|
-
ev_timer_init(&client->timeout_watcher, on_timeout, EBB_TIMEOUT, 0);
|
280
|
-
ev_timer_start(client->server->loop, &client->timeout_watcher);
|
281
|
-
}
|
282
|
-
|
283
|
-
|
284
|
-
static void on_request(struct ev_loop *loop, ev_io *watcher, int revents)
|
285
|
-
{
|
286
|
-
ebb_server *server = (ebb_server*)(watcher->data);
|
287
|
-
assert(server->open);
|
288
|
-
assert(server->loop == loop);
|
289
|
-
assert(&server->request_watcher == watcher);
|
290
|
-
|
291
|
-
if(EV_ERROR & revents) {
|
292
|
-
g_message("on_request() got error event, closing server.");
|
293
|
-
ebb_server_unlisten(server);
|
294
|
-
return;
|
295
|
-
}
|
296
|
-
/* Now we're going to initialize the client
|
297
|
-
* and set up her callbacks for read and write
|
298
|
-
* the client won't get passed back to the user, however,
|
299
|
-
* until the request is complete and parsed.
|
300
|
-
*/
|
301
|
-
int i;
|
302
|
-
ebb_client *client = NULL;
|
303
|
-
/* Get next availible peer */
|
304
|
-
for(i=0; i < EBB_MAX_CLIENTS; i++)
|
305
|
-
if(!server->clients[i].in_use && !server->clients[i].open) {
|
306
|
-
client = &(server->clients[i]);
|
307
|
-
break;
|
308
|
-
}
|
309
|
-
if(client == NULL) {
|
310
|
-
g_message("Too many peers. Refusing connections.");
|
311
|
-
return;
|
312
|
-
}
|
313
|
-
|
314
|
-
#ifdef DEBUG
|
315
|
-
int count = 0;
|
316
|
-
for(i = 0; i < EBB_MAX_CLIENTS; i++)
|
317
|
-
if(server->clients[i].open) count += 1;
|
318
|
-
g_debug("%d open connections", count);
|
319
|
-
#endif
|
320
|
-
|
321
|
-
client_init(client);
|
322
|
-
}
|
323
|
-
|
324
|
-
|
325
|
-
ebb_server* ebb_server_alloc()
|
326
|
-
{
|
327
|
-
ebb_server *server = g_new0(ebb_server, 1);
|
328
|
-
return server;
|
329
|
-
}
|
330
|
-
|
331
|
-
|
332
|
-
void ebb_server_init( ebb_server *server
|
333
|
-
, struct ev_loop *loop
|
334
|
-
, ebb_request_cb request_cb
|
335
|
-
, void *request_cb_data
|
336
|
-
)
|
337
|
-
{
|
338
|
-
int i;
|
339
|
-
for(i=0; i < EBB_MAX_CLIENTS; i++) {
|
340
|
-
server->clients[i].request_buffer = NULL;
|
341
|
-
server->clients[i].response_buffer = NULL;
|
342
|
-
server->clients[i].open = FALSE;
|
343
|
-
server->clients[i].in_use = FALSE;
|
344
|
-
server->clients[i].server = server;
|
345
|
-
}
|
346
|
-
|
347
|
-
server->request_cb = request_cb;
|
348
|
-
server->request_cb_data = request_cb_data;
|
349
|
-
server->loop = loop;
|
350
|
-
server->open = FALSE;
|
351
|
-
server->fd = -1;
|
352
|
-
return;
|
353
|
-
error:
|
354
|
-
ebb_server_free(server);
|
355
|
-
return;
|
356
|
-
}
|
357
|
-
|
358
|
-
|
359
|
-
void ebb_server_free(ebb_server *server)
|
360
|
-
{
|
361
|
-
ebb_server_unlisten(server);
|
362
|
-
|
363
|
-
if(server->port)
|
364
|
-
free(server->port);
|
365
|
-
if(server->socketpath)
|
366
|
-
free(server->socketpath);
|
367
|
-
free(server);
|
368
|
-
}
|
369
|
-
|
370
|
-
|
371
|
-
void ebb_server_unlisten(ebb_server *server)
|
372
|
-
{
|
373
|
-
if(server->open) {
|
374
|
-
int i;
|
375
|
-
ebb_client *client;
|
376
|
-
ev_io_stop(server->loop, &server->request_watcher);
|
377
|
-
close(server->fd);
|
378
|
-
if(server->socketpath) {
|
379
|
-
unlink(server->socketpath);
|
380
|
-
server->socketpath = NULL;
|
381
|
-
}
|
382
|
-
if(server->port) {
|
383
|
-
free(server->port);
|
384
|
-
server->port = NULL;
|
385
|
-
}
|
386
|
-
server->open = FALSE;
|
387
|
-
}
|
388
|
-
}
|
389
|
-
|
390
|
-
|
391
|
-
int ebb_server_listen_on_fd(ebb_server *server, const int sfd)
|
392
|
-
{
|
393
|
-
if (listen(sfd, EBB_MAX_CLIENTS) < 0) {
|
394
|
-
perror("listen()");
|
395
|
-
return -1;
|
396
|
-
}
|
397
|
-
|
398
|
-
set_nonblock(sfd); /* XXX: superfluous? */
|
399
|
-
|
400
|
-
server->fd = sfd;
|
401
|
-
assert(server->port == NULL);
|
402
|
-
assert(server->socketpath == NULL);
|
403
|
-
assert(server->open == FALSE);
|
404
|
-
server->open = TRUE;
|
405
|
-
|
406
|
-
server->request_watcher.data = server;
|
407
|
-
ev_init (&server->request_watcher, on_request);
|
408
|
-
ev_io_set (&server->request_watcher, server->fd, EV_READ | EV_ERROR);
|
409
|
-
ev_io_start (server->loop, &server->request_watcher);
|
410
|
-
|
411
|
-
return server->fd;
|
412
|
-
}
|
413
|
-
|
414
|
-
|
415
|
-
int ebb_server_listen_on_port(ebb_server *server, const int port)
|
416
|
-
{
|
417
|
-
int sfd = -1;
|
418
|
-
struct linger ling = {0, 0};
|
419
|
-
struct sockaddr_in addr;
|
420
|
-
int flags = 1;
|
421
|
-
|
422
|
-
if ((sfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
|
423
|
-
perror("socket()");
|
424
|
-
goto error;
|
425
|
-
}
|
426
|
-
|
427
|
-
flags = 1;
|
428
|
-
setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, (void *)&flags, sizeof(flags));
|
429
|
-
setsockopt(sfd, SOL_SOCKET, SO_KEEPALIVE, (void *)&flags, sizeof(flags));
|
430
|
-
setsockopt(sfd, SOL_SOCKET, SO_LINGER, (void *)&ling, sizeof(ling));
|
431
|
-
setsockopt(sfd, IPPROTO_TCP, TCP_NODELAY, (void *)&flags, sizeof(flags));
|
432
|
-
|
433
|
-
/*
|
434
|
-
* the memset call clears nonstandard fields in some impementations
|
435
|
-
* that otherwise mess things up.
|
436
|
-
*/
|
437
|
-
memset(&addr, 0, sizeof(addr));
|
438
|
-
|
439
|
-
addr.sin_family = AF_INET;
|
440
|
-
addr.sin_port = htons(port);
|
441
|
-
addr.sin_addr.s_addr = htonl(INADDR_ANY);
|
442
|
-
|
443
|
-
if (bind(sfd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
|
444
|
-
perror("bind()");
|
445
|
-
goto error;
|
446
|
-
}
|
447
|
-
|
448
|
-
int ret = ebb_server_listen_on_fd(server, sfd);
|
449
|
-
if (ret >= 0) {
|
450
|
-
assert(server->port == NULL);
|
451
|
-
server->port = malloc(sizeof(char)*8); /* for easy access to the port */
|
452
|
-
sprintf(server->port, "%d", port);
|
453
|
-
}
|
454
|
-
return ret;
|
455
|
-
error:
|
456
|
-
if(sfd > 0) close(sfd);
|
457
|
-
return -1;
|
458
|
-
}
|
459
|
-
|
460
|
-
|
461
|
-
int ebb_server_listen_on_unix_socket(ebb_server *server, const char *socketpath)
|
462
|
-
{
|
463
|
-
int sfd = -1;
|
464
|
-
struct linger ling = {0, 0};
|
465
|
-
struct sockaddr_un addr;
|
466
|
-
struct stat tstat;
|
467
|
-
int flags =1;
|
468
|
-
int old_umask = -1;
|
469
|
-
int access_mask = 0777;
|
470
|
-
|
471
|
-
if(( sfd = socket(AF_UNIX, SOCK_STREAM, 0) ) == -1) {
|
472
|
-
perror("socket()");
|
473
|
-
goto error;
|
474
|
-
}
|
475
|
-
|
476
|
-
/* Clean up a previous socket file if we left it around */
|
477
|
-
if(lstat(socketpath, &tstat) == 0 && S_ISSOCK(tstat.st_mode)) {
|
478
|
-
unlink(socketpath);
|
479
|
-
}
|
480
|
-
|
481
|
-
flags = 1;
|
482
|
-
setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, (void *)&flags, sizeof(flags));
|
483
|
-
setsockopt(sfd, SOL_SOCKET, SO_KEEPALIVE, (void *)&flags, sizeof(flags));
|
484
|
-
setsockopt(sfd, SOL_SOCKET, SO_LINGER, (void *)&ling, sizeof(ling));
|
485
|
-
|
486
|
-
/*
|
487
|
-
* the memset call clears nonstandard fields in some impementations
|
488
|
-
* that otherwise mess things up.
|
489
|
-
*/
|
490
|
-
memset(&addr, 0, sizeof(addr));
|
491
|
-
|
492
|
-
addr.sun_family = AF_UNIX;
|
493
|
-
strcpy(addr.sun_path, socketpath);
|
494
|
-
old_umask = umask( ~(access_mask & 0777) );
|
495
|
-
|
496
|
-
if(bind(sfd, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
|
497
|
-
perror("bind()");
|
498
|
-
goto error;
|
499
|
-
}
|
500
|
-
umask(old_umask);
|
501
|
-
|
502
|
-
int ret = ebb_server_listen_on_fd(server, sfd);
|
503
|
-
if (ret >= 0) {
|
504
|
-
assert(server->socketpath == NULL);
|
505
|
-
server->socketpath = strdup(socketpath);
|
506
|
-
}
|
507
|
-
return ret;
|
508
|
-
error:
|
509
|
-
if(sfd > 0) close(sfd);
|
510
|
-
return -1;
|
511
|
-
}
|
512
|
-
|
513
|
-
|
514
|
-
int ebb_server_clients_in_use_p(ebb_server *server)
|
515
|
-
{
|
516
|
-
int i;
|
517
|
-
for(i = 0; i < EBB_MAX_CLIENTS; i++)
|
518
|
-
if(server->clients[i].in_use) return TRUE;
|
519
|
-
return FALSE;
|
520
|
-
}
|
521
|
-
|
522
|
-
|
523
|
-
void ebb_client_release(ebb_client *client)
|
524
|
-
{
|
525
|
-
assert(client->in_use);
|
526
|
-
client->in_use = FALSE;
|
527
|
-
|
528
|
-
if(client->headers_written == FALSE) {
|
529
|
-
g_string_append(client->response_buffer, "\r\n");
|
530
|
-
client->headers_written = TRUE;
|
531
|
-
}
|
532
|
-
client->body_written = TRUE;
|
533
|
-
|
534
|
-
/* If the write_watcher isn't yet active, then start it. It could be that
|
535
|
-
* we're streaming and the watcher has been stopped. In that case we
|
536
|
-
* start it again since we have more to write. */
|
537
|
-
if(ev_is_active(&client->write_watcher) == FALSE) {
|
538
|
-
set_nonblock(client->fd);
|
539
|
-
ev_io_start(client->server->loop, &client->write_watcher);
|
540
|
-
}
|
541
|
-
|
542
|
-
if(client->written == client->response_buffer->len)
|
543
|
-
ebb_client_close(client);
|
544
|
-
}
|
545
|
-
|
546
|
-
|
547
|
-
void ebb_client_close(ebb_client *client)
|
548
|
-
{
|
549
|
-
if(client->open) {
|
550
|
-
ev_io_stop(client->server->loop, &client->read_watcher);
|
551
|
-
ev_io_stop(client->server->loop, &client->write_watcher);
|
552
|
-
ev_timer_stop(client->server->loop, &client->timeout_watcher);
|
553
|
-
|
554
|
-
client->ip = NULL;
|
555
|
-
|
556
|
-
g_string_free(client->response_buffer, TRUE);
|
557
|
-
client->response_buffer = NULL;
|
558
|
-
|
559
|
-
close(client->fd);
|
560
|
-
client->open = FALSE;
|
561
|
-
}
|
562
|
-
}
|
563
|
-
|
564
|
-
|
565
|
-
void ebb_client_write_status(ebb_client *client, int status, const char *reason_phrase)
|
566
|
-
{
|
567
|
-
assert(client->in_use);
|
568
|
-
if(!client->open) return;
|
569
|
-
assert(client->status_written == FALSE);
|
570
|
-
g_string_append_printf( client->response_buffer
|
571
|
-
, "HTTP/1.1 %d %s\r\n"
|
572
|
-
, status
|
573
|
-
, reason_phrase
|
574
|
-
);
|
575
|
-
client->status_written = TRUE;
|
576
|
-
}
|
577
|
-
|
578
|
-
|
579
|
-
void ebb_client_write_header(ebb_client *client, const char *field, const char *value)
|
580
|
-
{
|
581
|
-
assert(client->in_use);
|
582
|
-
if(!client->open) return;
|
583
|
-
assert(client->status_written == TRUE);
|
584
|
-
assert(client->headers_written == FALSE);
|
585
|
-
|
586
|
-
if(strcmp(field, "Connection") == 0 && strcmp(value, "Keep-Alive") == 0) {
|
587
|
-
client->keep_alive = TRUE;
|
588
|
-
}
|
589
|
-
g_string_append_printf( client->response_buffer
|
590
|
-
, "%s: %s\r\n"
|
591
|
-
, field
|
592
|
-
, value
|
593
|
-
);
|
594
|
-
}
|
595
|
-
|
596
|
-
|
597
|
-
void ebb_client_write_body(ebb_client *client, const char *data, int length)
|
598
|
-
{
|
599
|
-
assert(client->in_use);
|
600
|
-
if(!client->open) return;
|
601
|
-
|
602
|
-
if(client->headers_written == FALSE) {
|
603
|
-
g_string_append(client->response_buffer, "\r\n");
|
604
|
-
client->headers_written = TRUE;
|
605
|
-
}
|
606
|
-
|
607
|
-
g_string_append_len(client->response_buffer, data, length);
|
608
|
-
|
609
|
-
/* If the write_watcher isn't yet active, then start it. It could be that
|
610
|
-
* we're streaming and the watcher has been stopped. In that case we
|
611
|
-
* start it again since we have more to write. */
|
612
|
-
if(ev_is_active(&client->write_watcher) == FALSE) {
|
613
|
-
set_nonblock(client->fd);
|
614
|
-
ev_io_start(client->server->loop, &client->write_watcher);
|
615
|
-
}
|
616
|
-
}
|
617
|
-
|
618
|
-
// int ebb_client_should_keep_alive(ebb_client*)
|
619
|
-
// {
|
620
|
-
// /* TODO - return boolean */
|
621
|
-
// if env['HTTP_VERSION'] == 'HTTP/1.0'
|
622
|
-
// return true if env['HTTP_CONNECTION'] =~ /Keep-Alive/i
|
623
|
-
// else
|
624
|
-
// return true unless env['HTTP_CONNECTION'] =~ /close/i
|
625
|
-
// end
|
626
|
-
// false
|
627
|
-
// }
|