agoo 2.5.1 → 2.5.2
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of agoo might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CHANGELOG.md +9 -1
- data/README.md +12 -1
- data/ext/agoo/agoo.c +4 -3
- data/ext/agoo/bind.c +51 -11
- data/ext/agoo/bind.h +9 -0
- data/ext/agoo/con.c +127 -89
- data/ext/agoo/con.h +24 -8
- data/ext/agoo/debug.c +2 -0
- data/ext/agoo/debug.h +1 -0
- data/ext/agoo/err.c +1 -1
- data/ext/agoo/err.h +2 -5
- data/ext/agoo/foo/agoo.c +109 -0
- data/ext/agoo/foo/con.c +1220 -0
- data/ext/agoo/foo/con.h +65 -0
- data/ext/agoo/foo/page.c +699 -0
- data/ext/agoo/foo/pub.c +131 -0
- data/ext/agoo/foo/pub.h +40 -0
- data/ext/agoo/foo/rserver.c +1016 -0
- data/ext/agoo/foo/server.c +303 -0
- data/ext/agoo/foo/server.h +67 -0
- data/ext/agoo/foo/upgraded.c +182 -0
- data/ext/agoo/hook.c +31 -0
- data/ext/agoo/hook.h +9 -10
- data/ext/agoo/{types.h → kinds.h} +3 -3
- data/ext/agoo/log.c +168 -83
- data/ext/agoo/log.h +6 -2
- data/ext/agoo/page.c +38 -32
- data/ext/agoo/pub.c +16 -0
- data/ext/agoo/pub.h +1 -0
- data/ext/agoo/queue.h +1 -0
- data/ext/agoo/req.c +95 -0
- data/ext/agoo/req.h +48 -0
- data/ext/agoo/request.c +10 -38
- data/ext/agoo/request.h +1 -34
- data/ext/agoo/res.h +1 -3
- data/ext/agoo/response.c +6 -248
- data/ext/agoo/response.h +2 -6
- data/ext/agoo/rlog.c +2 -1
- data/ext/agoo/rresponse.c +252 -0
- data/ext/agoo/rresponse.h +14 -0
- data/ext/agoo/rserver.c +43 -45
- data/ext/agoo/rserver.h +3 -24
- data/ext/agoo/rupgraded.c +303 -0
- data/ext/agoo/rupgraded.h +17 -0
- data/ext/agoo/server.c +125 -8
- data/ext/agoo/server.h +26 -4
- data/ext/agoo/sse.c +3 -1
- data/ext/agoo/upgraded.c +42 -280
- data/ext/agoo/upgraded.h +16 -8
- data/ext/agoo/websocket.c +13 -9
- data/lib/agoo/base.rb +84 -0
- data/lib/agoo/client.rb +25 -0
- data/lib/agoo/version.rb +1 -1
- data/test/bind_test.rb +2 -2
- metadata +22 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 00756b3df4ad9bf284685f770eac1535e7ed1fd78c3c48b8bf71445d6af6f3ea
|
4
|
+
data.tar.gz: e055161332315715e295918121c0241fd517b31f730b2296b37f4f31b56e7df8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5cc15a45719ede4f3c6a2d2075a8c2d61eb3de1e89c1cbf726116bb70794c10820131912c646b392eb1829b4c7643bd952aeba3e296b1d55f61bbfb9b5c0072f
|
7
|
+
data.tar.gz: 99c9c21864789960c30de16dea4a08399dd8ef8fc958e1150a1c0232d116b6d182ac378b3a2676550baa7985abe29a5fc05587a4c5280b3dfc0b7f363e72fcb3
|
data/CHANGELOG.md
CHANGED
@@ -1,10 +1,18 @@
|
|
1
1
|
# CHANGELOG
|
2
2
|
|
3
|
+
### 2.5.2 - 2018-11-09
|
4
|
+
|
5
|
+
Latency improvements.
|
6
|
+
|
7
|
+
- Allow empty pages to be returned.
|
8
|
+
|
9
|
+
- Included multiple read/write threads.
|
10
|
+
|
3
11
|
### 2.5.1 - 2018-08-30
|
4
12
|
|
5
13
|
Bug fix.
|
6
14
|
|
7
|
-
- Sending a POST request that was not
|
15
|
+
- Sending a POST request that was not handled and caused a segfault. Fixed.
|
8
16
|
|
9
17
|
### 2.5.0 - 2018-08-10
|
10
18
|
|
data/README.md
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
[![Build Status](https://img.shields.io/travis/ohler55/agoo/master.svg)](http://travis-ci.org/ohler55/agoo?branch=master)
|
4
4
|
[![Gem Version](https://badge.fury.io/rb/agoo.svg)](https://badge.fury.io/rb/agoo)
|
5
|
-
![Gem](https://img.shields.io/gem/dt/agoo.svg)
|
5
|
+
![Gem](https://img.shields.io/gem/dt/agoo.svg) [![TideLift](https://tidelift.com/badges/github/ohler55/agoo)](https://tidelift.com/subscription/pkg/rubygems-agoo?utm_source=rubygems-agoo&utm_medium=referral&utm_campaign=readme)
|
6
6
|
|
7
7
|
A High Performance HTTP Server for Ruby
|
8
8
|
|
@@ -50,8 +50,15 @@ benchmarks driver could not push Agoo hard enough.
|
|
50
50
|
Agoo supports the [Ruby rack API](https://rack.github.io) which allows for the
|
51
51
|
use of rack compatible gems such as Hanami and Rails. Agoo also supports WebSockets and SSE.
|
52
52
|
|
53
|
+
Agoo is not available on Windows.
|
54
|
+
|
53
55
|
## News
|
54
56
|
|
57
|
+
- Agoo takes first place as the highest throughput on [web-frameworks
|
58
|
+
benchmarks](https://github.com/the-benchmarker/web-frameworks). Latency was
|
59
|
+
not at the top but release 2.5.2 improves that. Look for an Agoo-C benchmark
|
60
|
+
in the future.
|
61
|
+
|
55
62
|
- Clustered Agoo is ready. For slower application and a machine with multiple
|
56
63
|
cores a significant improvement is performance is realized. The application
|
57
64
|
must be stateless in that no data is shared between workers.
|
@@ -71,6 +78,10 @@ See [file:CHANGELOG.md](CHANGELOG.md)
|
|
71
78
|
Releases are made from the master branch. The default branch for checkout is
|
72
79
|
the develop branch. Pull requests should be made against the develop branch.
|
73
80
|
|
81
|
+
## Support
|
82
|
+
|
83
|
+
[Get supported Agoo with a Tidelift Subscription.](https://tidelift.com/subscription/pkg/rubygems-agoo?utm_source=rubygems-agoo&utm_medium=referral&utm_campaign=readme)
|
84
|
+
|
74
85
|
## Links
|
75
86
|
|
76
87
|
- *Documentation*: http://rubydoc.info/gems/agoo or http://www.ohler.com/agoo/doc/index.html
|
data/ext/agoo/agoo.c
CHANGED
@@ -10,9 +10,10 @@
|
|
10
10
|
#include "pub.h"
|
11
11
|
#include "rack_logger.h"
|
12
12
|
#include "request.h"
|
13
|
-
#include "
|
13
|
+
#include "rresponse.h"
|
14
14
|
#include "rlog.h"
|
15
15
|
#include "rserver.h"
|
16
|
+
#include "rupgraded.h"
|
16
17
|
#include "server.h"
|
17
18
|
#include "upgraded.h"
|
18
19
|
|
@@ -48,7 +49,7 @@ ragoo_publish(VALUE self, VALUE subject, VALUE message) {
|
|
48
49
|
const char *subj = extract_subject(subject, &slen);
|
49
50
|
|
50
51
|
rb_check_type(message, T_STRING);
|
51
|
-
|
52
|
+
server_publish(pub_publish(subj, slen, StringValuePtr(message), (int)RSTRING_LEN(message)));
|
52
53
|
|
53
54
|
return Qnil;
|
54
55
|
}
|
@@ -65,7 +66,7 @@ static VALUE
|
|
65
66
|
ragoo_unsubscribe(VALUE self, VALUE subject) {
|
66
67
|
rb_check_type(subject, T_STRING);
|
67
68
|
|
68
|
-
|
69
|
+
server_publish(pub_unsubscribe(NULL, StringValuePtr(subject), (int)RSTRING_LEN(subject)));
|
69
70
|
|
70
71
|
return Qnil;
|
71
72
|
}
|
data/ext/agoo/bind.c
CHANGED
@@ -25,13 +25,18 @@ bind_port(Err err, int port) {
|
|
25
25
|
b->port = port;
|
26
26
|
b->family = AF_INET;
|
27
27
|
snprintf(id, sizeof(id) - 1, "http://:%d", port);
|
28
|
+
strcpy(b->scheme, "http");
|
28
29
|
b->id = strdup(id);
|
30
|
+
b->kind = CON_HTTP;
|
31
|
+
b->read = NULL;
|
32
|
+
b->write = NULL;
|
33
|
+
b->events = NULL;
|
29
34
|
}
|
30
35
|
return b;
|
31
36
|
}
|
32
37
|
|
33
38
|
static Bind
|
34
|
-
url_tcp(Err err, const char *url) {
|
39
|
+
url_tcp(Err err, const char *url, const char *scheme) {
|
35
40
|
char *colon = index(url, ':');
|
36
41
|
struct in_addr addr = { .s_addr = 0 };
|
37
42
|
int port;
|
@@ -40,15 +45,17 @@ url_tcp(Err err, const char *url) {
|
|
40
45
|
if (NULL == colon) {
|
41
46
|
port = 80;
|
42
47
|
} else if (15 < colon - url) {
|
43
|
-
err_set(err, ERR_ARG, "
|
48
|
+
err_set(err, ERR_ARG, "%s bind address is not valid, too long. (%s)", scheme, url);
|
44
49
|
return NULL;
|
50
|
+
} else if (':' == *url) {
|
51
|
+
port = atoi(colon + 1);
|
45
52
|
} else {
|
46
53
|
char buf[32];
|
47
54
|
|
48
55
|
strncpy(buf, url, colon - url);
|
49
56
|
buf[colon - url] = '\0';
|
50
57
|
if (0 == inet_aton(buf, &addr)) {
|
51
|
-
err_set(err, ERR_ARG, "
|
58
|
+
err_set(err, ERR_ARG, "%s bind address is not valid. (%s)", scheme, url);
|
52
59
|
return NULL;
|
53
60
|
}
|
54
61
|
port = atoi(colon + 1);
|
@@ -62,8 +69,14 @@ url_tcp(Err err, const char *url) {
|
|
62
69
|
b->port = port;
|
63
70
|
b->addr4 = addr;
|
64
71
|
b->family = AF_INET;
|
65
|
-
snprintf(id, sizeof(id), "
|
72
|
+
snprintf(id, sizeof(id), "%s://%s:%d", scheme, inet_ntoa(addr), port);
|
66
73
|
b->id = strdup(id);
|
74
|
+
strncpy(b->scheme, scheme, sizeof(b->scheme));
|
75
|
+
b->scheme[sizeof(b->scheme) - 1] = '\0';
|
76
|
+
b->kind = CON_HTTP;
|
77
|
+
b->read = NULL;
|
78
|
+
b->write = NULL;
|
79
|
+
b->events = NULL;
|
67
80
|
|
68
81
|
return b;
|
69
82
|
}
|
@@ -73,7 +86,7 @@ url_tcp(Err err, const char *url) {
|
|
73
86
|
}
|
74
87
|
|
75
88
|
static Bind
|
76
|
-
url_tcp6(Err err, const char *url) {
|
89
|
+
url_tcp6(Err err, const char *url, const char *scheme) {
|
77
90
|
struct in6_addr addr;
|
78
91
|
char *end = index(url, ']');
|
79
92
|
int port = 80;
|
@@ -87,7 +100,7 @@ url_tcp6(Err err, const char *url) {
|
|
87
100
|
buf[end - url - 1] = '\0';
|
88
101
|
memset(&addr, 0, sizeof(addr));
|
89
102
|
if (0 == inet_pton(AF_INET6, buf, &addr)) {
|
90
|
-
err_set(err, ERR_ARG, "
|
103
|
+
err_set(err, ERR_ARG, "%s bind address is not valid. (%s)", scheme, url);
|
91
104
|
return NULL;
|
92
105
|
}
|
93
106
|
if (NULL != (b = (Bind)malloc(sizeof(struct _Bind)))) {
|
@@ -99,8 +112,14 @@ url_tcp6(Err err, const char *url) {
|
|
99
112
|
b->port = port;
|
100
113
|
b->addr6 = addr;
|
101
114
|
b->family = AF_INET6;
|
102
|
-
snprintf(buf, sizeof(buf), "
|
115
|
+
snprintf(buf, sizeof(buf), "%s://[%s]:%d", scheme, inet_ntop(AF_INET6, &addr, str, INET6_ADDRSTRLEN), port);
|
103
116
|
b->id = strdup(buf);
|
117
|
+
strncpy(b->scheme, scheme, sizeof(b->scheme));
|
118
|
+
b->scheme[sizeof(b->scheme) - 1] = '\0';
|
119
|
+
b->kind = CON_HTTP;
|
120
|
+
b->read = NULL;
|
121
|
+
b->write = NULL;
|
122
|
+
b->events = NULL;
|
104
123
|
|
105
124
|
return b;
|
106
125
|
}
|
@@ -126,6 +145,11 @@ url_named(Err err, const char *url) {
|
|
126
145
|
b->name = strdup(url);
|
127
146
|
snprintf(id, sizeof(id) - 1, fmt, url);
|
128
147
|
b->id = strdup(id);
|
148
|
+
strcpy(b->scheme, "unix");
|
149
|
+
b->kind = CON_HTTP;
|
150
|
+
b->read = NULL;
|
151
|
+
b->write = NULL;
|
152
|
+
b->events = NULL;
|
129
153
|
}
|
130
154
|
return b;
|
131
155
|
}
|
@@ -144,15 +168,15 @@ Bind
|
|
144
168
|
bind_url(Err err, const char *url) {
|
145
169
|
if (0 == strncmp("tcp://", url, 6)) {
|
146
170
|
if ('[' == url[6]) {
|
147
|
-
return url_tcp6(err, url + 6);
|
171
|
+
return url_tcp6(err, url + 6, "tcp");
|
148
172
|
}
|
149
|
-
return url_tcp(err, url + 6);
|
173
|
+
return url_tcp(err, url + 6, "tcp");
|
150
174
|
}
|
151
175
|
if (0 == strncmp("http://", url, 7)) {
|
152
176
|
if ('[' == url[7]) {
|
153
|
-
return url_tcp6(err, url + 7);
|
177
|
+
return url_tcp6(err, url + 7, "http");
|
154
178
|
}
|
155
|
-
return url_tcp(err, url + 7);
|
179
|
+
return url_tcp(err, url + 7, "http");
|
156
180
|
}
|
157
181
|
if (0 == strncmp("unix://", url, 7)) {
|
158
182
|
return url_named(err, url + 7);
|
@@ -163,6 +187,22 @@ bind_url(Err err, const char *url) {
|
|
163
187
|
if (0 == strncmp("ssl://", url, 6)) {
|
164
188
|
return url_ssl(err, url + 6);
|
165
189
|
}
|
190
|
+
// All others assume
|
191
|
+
{
|
192
|
+
char *colon = index(url, ':');
|
193
|
+
char scheme[8];
|
194
|
+
|
195
|
+
if (NULL != colon && colon - url < (int)sizeof(scheme)) {
|
196
|
+
int slen = colon - url;
|
197
|
+
|
198
|
+
memcpy(scheme, url, slen);
|
199
|
+
scheme[slen] = '\0';
|
200
|
+
if ('[' == url[slen + 3]) {
|
201
|
+
return url_tcp6(err, url + slen + 3, scheme);
|
202
|
+
}
|
203
|
+
return url_tcp(err, url + slen + 3, scheme);
|
204
|
+
}
|
205
|
+
}
|
166
206
|
return NULL;
|
167
207
|
}
|
168
208
|
|
data/ext/agoo/bind.h
CHANGED
@@ -3,11 +3,15 @@
|
|
3
3
|
#ifndef __AGOO_BIND_H__
|
4
4
|
#define __AGOO_BIND_H__
|
5
5
|
|
6
|
+
#include <stdbool.h>
|
6
7
|
#include <sys/socket.h>
|
7
8
|
#include <netinet/in.h>
|
8
9
|
#include <arpa/inet.h>
|
9
10
|
|
10
11
|
#include "err.h"
|
12
|
+
#include "kinds.h"
|
13
|
+
|
14
|
+
struct _Con;
|
11
15
|
|
12
16
|
typedef struct _Bind {
|
13
17
|
struct _Bind *next;
|
@@ -18,6 +22,11 @@ typedef struct _Bind {
|
|
18
22
|
struct in_addr addr4;
|
19
23
|
struct in6_addr addr6;
|
20
24
|
};
|
25
|
+
ConKind kind;
|
26
|
+
bool (*read)(struct _Con *c);
|
27
|
+
bool (*write)(struct _Con *c);
|
28
|
+
short (*events)(struct _Con *c);
|
29
|
+
char scheme[8];
|
21
30
|
char *name; // if set then Unix file
|
22
31
|
char *key; // if set then SSL
|
23
32
|
char *cert;
|
data/ext/agoo/con.c
CHANGED
@@ -4,17 +4,19 @@
|
|
4
4
|
#include <netdb.h>
|
5
5
|
#include <stdio.h>
|
6
6
|
#include <string.h>
|
7
|
+
#include <unistd.h>
|
7
8
|
|
9
|
+
#include "bind.h"
|
8
10
|
#include "con.h"
|
9
11
|
#include "debug.h"
|
10
12
|
#include "dtime.h"
|
11
13
|
#include "hook.h"
|
12
14
|
#include "http.h"
|
15
|
+
#include "log.h"
|
13
16
|
#include "page.h"
|
14
17
|
#include "pub.h"
|
15
18
|
#include "res.h"
|
16
19
|
#include "seg.h"
|
17
|
-
#include "rserver.h"
|
18
20
|
#include "server.h"
|
19
21
|
#include "sse.h"
|
20
22
|
#include "subject.h"
|
@@ -24,10 +26,28 @@
|
|
24
26
|
#define CON_TIMEOUT 5.0
|
25
27
|
#define INITIAL_POLL_SIZE 1024
|
26
28
|
|
27
|
-
|
29
|
+
static bool con_ws_read(Con c);
|
30
|
+
static bool con_ws_write(Con c);
|
31
|
+
static short con_ws_events(Con c);
|
32
|
+
static bool con_sse_write(Con c);
|
33
|
+
static short con_sse_events(Con c);
|
34
|
+
|
35
|
+
static struct _Bind ws_bind = {
|
36
|
+
.kind = CON_WS,
|
37
|
+
.read = con_ws_read,
|
38
|
+
.write = con_ws_write,
|
39
|
+
.events = con_ws_events,
|
40
|
+
};
|
41
|
+
|
42
|
+
static struct _Bind sse_bind = {
|
43
|
+
.kind = CON_SSE,
|
44
|
+
.read = NULL,
|
45
|
+
.write = con_sse_write,
|
46
|
+
.events = con_sse_events,
|
47
|
+
};
|
28
48
|
|
29
49
|
Con
|
30
|
-
con_create(Err err, int sock, uint64_t id) {
|
50
|
+
con_create(Err err, int sock, uint64_t id, Bind b) {
|
31
51
|
Con c;
|
32
52
|
|
33
53
|
if (NULL == (c = (Con)malloc(sizeof(struct _Con)))) {
|
@@ -37,15 +57,17 @@ con_create(Err err, int sock, uint64_t id) {
|
|
37
57
|
memset(c, 0, sizeof(struct _Con));
|
38
58
|
c->sock = sock;
|
39
59
|
c->id = id;
|
40
|
-
c->kind = CON_HTTP;
|
41
60
|
c->timeout = dtime() + CON_TIMEOUT;
|
61
|
+
c->bind = b;
|
42
62
|
}
|
43
63
|
return c;
|
44
64
|
}
|
45
65
|
|
46
66
|
void
|
47
67
|
con_destroy(Con c) {
|
48
|
-
|
68
|
+
atomic_fetch_sub(&the_server.con_cnt, 1);
|
69
|
+
|
70
|
+
if (CON_WS == c->bind->kind || CON_SSE == c->bind->kind) {
|
49
71
|
ws_req_close(c);
|
50
72
|
}
|
51
73
|
if (0 < c->sock) {
|
@@ -53,7 +75,7 @@ con_destroy(Con c) {
|
|
53
75
|
c->sock = 0;
|
54
76
|
}
|
55
77
|
if (NULL != c->req) {
|
56
|
-
|
78
|
+
req_destroy(c->req);
|
57
79
|
}
|
58
80
|
if (NULL != c->up) {
|
59
81
|
upgraded_release_con(c->up);
|
@@ -157,8 +179,8 @@ page_response(Con c, Page p, char *hend) {
|
|
157
179
|
// rserver
|
158
180
|
static void
|
159
181
|
push_error(Upgraded up, const char *msg, int mlen) {
|
160
|
-
if (NULL != up &&
|
161
|
-
Req req =
|
182
|
+
if (NULL != up && the_server.ctx_nil_value != up->ctx && up->on_error) {
|
183
|
+
Req req = req_create(mlen);
|
162
184
|
|
163
185
|
if (NULL == req) {
|
164
186
|
return;
|
@@ -167,9 +189,9 @@ push_error(Upgraded up, const char *msg, int mlen) {
|
|
167
189
|
req->msg[mlen] = '\0';
|
168
190
|
req->up = up;
|
169
191
|
req->method = ON_ERROR;
|
170
|
-
req->hook = hook_create(NONE, NULL,
|
192
|
+
req->hook = hook_create(NONE, NULL, up->ctx, PUSH_HOOK, &the_server.eval_queue);
|
171
193
|
upgraded_ref(up);
|
172
|
-
queue_push(&
|
194
|
+
queue_push(&the_server.eval_queue, (void*)req);
|
173
195
|
}
|
174
196
|
}
|
175
197
|
|
@@ -332,7 +354,7 @@ con_header_read(Con c) {
|
|
332
354
|
}
|
333
355
|
HOOKED:
|
334
356
|
// Create request and populate.
|
335
|
-
if (NULL == (c->req =
|
357
|
+
if (NULL == (c->req = req_create(mlen))) {
|
336
358
|
return bad_request(c, 413, __LINE__);
|
337
359
|
}
|
338
360
|
if ((long)c->bcnt <= mlen) {
|
@@ -351,6 +373,7 @@ HOOKED:
|
|
351
373
|
c->req->path.len = (int)(path.end - path.start);
|
352
374
|
c->req->query.start = c->req->msg + (query - c->buf);
|
353
375
|
c->req->query.len = (int)(qend - query);
|
376
|
+
c->req->query.start[c->req->query.len] = '\0';
|
354
377
|
c->req->body.start = c->req->msg + (hend - c->buf + 4);
|
355
378
|
c->req->body.len = (unsigned int)clen;
|
356
379
|
b = strstr(b, "\r\n");
|
@@ -390,7 +413,7 @@ check_upgrade(Con c) {
|
|
390
413
|
}
|
391
414
|
}
|
392
415
|
|
393
|
-
|
416
|
+
bool
|
394
417
|
con_http_read(Con c) {
|
395
418
|
ssize_t cnt;
|
396
419
|
|
@@ -570,7 +593,7 @@ con_ws_read(Con c) {
|
|
570
593
|
}
|
571
594
|
}
|
572
595
|
upgraded_ref(c->up);
|
573
|
-
queue_push(&
|
596
|
+
queue_push(&the_server.eval_queue, (void*)c->req);
|
574
597
|
if (mlen < (long)c->bcnt) {
|
575
598
|
memmove(c->buf, c->buf + mlen, c->bcnt - mlen);
|
576
599
|
c->bcnt -= mlen;
|
@@ -591,19 +614,14 @@ con_ws_read(Con c) {
|
|
591
614
|
// return true to remove/close connection
|
592
615
|
static bool
|
593
616
|
con_read(Con c) {
|
594
|
-
|
595
|
-
|
596
|
-
return con_http_read(c);
|
597
|
-
case CON_WS:
|
598
|
-
return con_ws_read(c);
|
599
|
-
default:
|
600
|
-
break;
|
617
|
+
if (NULL != c->bind->read) {
|
618
|
+
return c->bind->read(c);
|
601
619
|
}
|
602
620
|
return true;
|
603
621
|
}
|
604
622
|
|
605
623
|
// return true to remove/close connection
|
606
|
-
|
624
|
+
bool
|
607
625
|
con_http_write(Con c) {
|
608
626
|
Text message = res_message(c->res_head);
|
609
627
|
ssize_t cnt;
|
@@ -628,7 +646,7 @@ con_http_write(Con c) {
|
|
628
646
|
log_cat(&debug_cat, "response on %llu: %s", (unsigned long long)c->id, message->text);
|
629
647
|
}
|
630
648
|
}
|
631
|
-
if (0 > (cnt = send(c->sock, message->text + c->wcnt, message->len - c->wcnt,
|
649
|
+
if (0 > (cnt = send(c->sock, message->text + c->wcnt, message->len - c->wcnt, MSG_DONTWAIT))) {
|
632
650
|
if (EAGAIN == errno) {
|
633
651
|
return false;
|
634
652
|
}
|
@@ -650,6 +668,7 @@ con_http_write(Con c) {
|
|
650
668
|
|
651
669
|
return done;
|
652
670
|
}
|
671
|
+
|
653
672
|
return false;
|
654
673
|
}
|
655
674
|
|
@@ -819,27 +838,21 @@ con_write(Con c) {
|
|
819
838
|
bool remove = true;
|
820
839
|
ConKind kind = c->res_head->con_kind;
|
821
840
|
|
822
|
-
|
823
|
-
|
824
|
-
remove = con_http_write(c);
|
825
|
-
break;
|
826
|
-
case CON_WS:
|
827
|
-
remove = con_ws_write(c);
|
828
|
-
break;
|
829
|
-
case CON_SSE:
|
830
|
-
remove = con_sse_write(c);
|
831
|
-
break;
|
832
|
-
default:
|
833
|
-
break;
|
841
|
+
if (NULL != c->bind->write) {
|
842
|
+
remove = c->bind->write(c);
|
834
843
|
}
|
835
|
-
if (kind != c->kind && CON_ANY != kind) {
|
836
|
-
|
837
|
-
|
838
|
-
|
839
|
-
|
840
|
-
|
844
|
+
//if (kind != c->kind && CON_ANY != kind) {
|
845
|
+
if (CON_ANY != kind) {
|
846
|
+
switch (kind) {
|
847
|
+
case CON_WS:
|
848
|
+
c->bind = &ws_bind;
|
849
|
+
break;
|
850
|
+
case CON_SSE:
|
851
|
+
c->bind = &sse_bind;
|
852
|
+
break;
|
853
|
+
default:
|
854
|
+
break;
|
841
855
|
}
|
842
|
-
*/
|
843
856
|
}
|
844
857
|
return remove;
|
845
858
|
}
|
@@ -850,7 +863,7 @@ publish_pub(Pub pub) {
|
|
850
863
|
const char *sub = pub->subject->pattern;
|
851
864
|
int cnt = 0;
|
852
865
|
|
853
|
-
for (up =
|
866
|
+
for (up = the_server.up_list; NULL != up; up = up->next) {
|
854
867
|
if (NULL != up->con && upgraded_match(up, sub)) {
|
855
868
|
Res res = res_create(up->con);
|
856
869
|
|
@@ -874,7 +887,7 @@ unsubscribe_pub(Pub pub) {
|
|
874
887
|
if (NULL == pub->up) {
|
875
888
|
Upgraded up;
|
876
889
|
|
877
|
-
for (up =
|
890
|
+
for (up = the_server.up_list; NULL != up; up = up->next) {
|
878
891
|
upgraded_del_subject(up, pub->subject);
|
879
892
|
}
|
880
893
|
} else {
|
@@ -891,20 +904,20 @@ process_pub_con(Pub pub) {
|
|
891
904
|
|
892
905
|
// TBD Change pending to be based on length of con queue
|
893
906
|
if (1 == (pending = atomic_fetch_sub(&up->pending, 1))) {
|
894
|
-
if (NULL != up &&
|
895
|
-
Req req =
|
907
|
+
if (NULL != up && the_server.ctx_nil_value != up->ctx && up->on_empty) {
|
908
|
+
Req req = req_create(0);
|
896
909
|
|
897
910
|
req->up = up;
|
898
911
|
req->method = ON_EMPTY;
|
899
|
-
req->hook = hook_create(NONE, NULL,
|
912
|
+
req->hook = hook_create(NONE, NULL, up->ctx, PUSH_HOOK, &the_server.eval_queue);
|
900
913
|
upgraded_ref(up);
|
901
|
-
queue_push(&
|
914
|
+
queue_push(&the_server.eval_queue, (void*)req);
|
902
915
|
}
|
903
916
|
}
|
904
917
|
}
|
905
918
|
switch (pub->kind) {
|
906
919
|
case PUB_CLOSE:
|
907
|
-
//
|
920
|
+
// A close after already closed is used to decrement the reference
|
908
921
|
// count on the upgraded so it can be destroyed in the con loop
|
909
922
|
// threads.
|
910
923
|
if (NULL != up->con) {
|
@@ -917,7 +930,7 @@ process_pub_con(Pub pub) {
|
|
917
930
|
up->con->res_tail->next = res;
|
918
931
|
}
|
919
932
|
up->con->res_tail = res;
|
920
|
-
res->con_kind = up->con->kind;
|
933
|
+
res->con_kind = up->con->bind->kind;
|
921
934
|
res->close = true;
|
922
935
|
}
|
923
936
|
}
|
@@ -957,15 +970,47 @@ process_pub_con(Pub pub) {
|
|
957
970
|
pub_destroy(pub);
|
958
971
|
}
|
959
972
|
|
973
|
+
short
|
974
|
+
con_http_events(Con c) {
|
975
|
+
short events = 0;
|
976
|
+
|
977
|
+
if (!c->closing) {
|
978
|
+
events = POLLIN | POLLOUT;
|
979
|
+
}
|
980
|
+
return events;
|
981
|
+
}
|
982
|
+
|
983
|
+
static short
|
984
|
+
con_ws_events(Con c) {
|
985
|
+
short events = 0;
|
986
|
+
|
987
|
+
if (NULL != c->res_head && (c->res_head->close || c->res_head->ping || NULL != res_message(c->res_head))) {
|
988
|
+
events = POLLIN | POLLOUT;
|
989
|
+
} else if (!c->closing) {
|
990
|
+
events = POLLIN;
|
991
|
+
}
|
992
|
+
return events;
|
993
|
+
}
|
994
|
+
|
995
|
+
static short
|
996
|
+
con_sse_events(Con c) {
|
997
|
+
short events = 0;
|
998
|
+
|
999
|
+
if (NULL != c->res_head && NULL != res_message(c->res_head)) {
|
1000
|
+
events = POLLOUT;
|
1001
|
+
}
|
1002
|
+
return events;
|
1003
|
+
}
|
1004
|
+
|
960
1005
|
static struct pollfd*
|
961
|
-
poll_setup(Con c, struct pollfd *pp) {
|
1006
|
+
poll_setup(Con c, Queue q, struct pollfd *pp) {
|
962
1007
|
// The first two pollfd are for the con_queue and the pub_queue in that
|
963
1008
|
// order.
|
964
1009
|
pp->fd = queue_listen(&the_server.con_queue);
|
965
1010
|
pp->events = POLLIN;
|
966
1011
|
pp->revents = 0;
|
967
1012
|
pp++;
|
968
|
-
pp->fd = queue_listen(
|
1013
|
+
pp->fd = queue_listen(q);
|
969
1014
|
pp->events = POLLIN;
|
970
1015
|
pp->revents = 0;
|
971
1016
|
pp++;
|
@@ -979,31 +1024,7 @@ poll_setup(Con c, struct pollfd *pp) {
|
|
979
1024
|
}
|
980
1025
|
c->pp = pp;
|
981
1026
|
pp->fd = c->sock;
|
982
|
-
pp->events =
|
983
|
-
switch (c->kind) {
|
984
|
-
case CON_HTTP:
|
985
|
-
if (NULL != c->res_head && NULL != res_message(c->res_head)) {
|
986
|
-
pp->events = POLLIN | POLLOUT;
|
987
|
-
} else if (!c->closing) {
|
988
|
-
pp->events = POLLIN;
|
989
|
-
}
|
990
|
-
break;
|
991
|
-
case CON_WS:
|
992
|
-
if (NULL != c->res_head && (c->res_head->close || c->res_head->ping || NULL != res_message(c->res_head))) {
|
993
|
-
pp->events = POLLIN | POLLOUT;
|
994
|
-
} else if (!c->closing) {
|
995
|
-
pp->events = POLLIN;
|
996
|
-
}
|
997
|
-
break;
|
998
|
-
case CON_SSE:
|
999
|
-
if (NULL != c->res_head && NULL != res_message(c->res_head)) {
|
1000
|
-
pp->events = POLLOUT;
|
1001
|
-
}
|
1002
|
-
break;
|
1003
|
-
default:
|
1004
|
-
continue; // should never get here
|
1005
|
-
break;
|
1006
|
-
}
|
1027
|
+
pp->events = c->bind->events(c);
|
1007
1028
|
pp->revents = 0;
|
1008
1029
|
pp++;
|
1009
1030
|
}
|
@@ -1029,6 +1050,7 @@ remove_dead_res(Con c) {
|
|
1029
1050
|
|
1030
1051
|
void*
|
1031
1052
|
con_loop(void *x) {
|
1053
|
+
ConLoop loop = (ConLoop)x;
|
1032
1054
|
Con c;
|
1033
1055
|
Con prev;
|
1034
1056
|
Con next;
|
@@ -1041,7 +1063,7 @@ con_loop(void *x) {
|
|
1041
1063
|
int i;
|
1042
1064
|
double now;
|
1043
1065
|
Pub pub;
|
1044
|
-
|
1066
|
+
|
1045
1067
|
atomic_fetch_add(&the_server.running, 1);
|
1046
1068
|
memset(pa, 0, size);
|
1047
1069
|
while (the_server.active) {
|
@@ -1055,18 +1077,19 @@ con_loop(void *x) {
|
|
1055
1077
|
size = sizeof(struct pollfd) * cnt;
|
1056
1078
|
if (NULL == (pa = (struct pollfd*)malloc(size))) {
|
1057
1079
|
log_cat(&error_cat, "Out of memory.");
|
1058
|
-
|
1080
|
+
log_close();
|
1081
|
+
exit(EXIT_FAILURE);
|
1082
|
+
|
1059
1083
|
return NULL;
|
1060
1084
|
}
|
1061
1085
|
pend = pa + cnt;
|
1062
1086
|
}
|
1063
1087
|
}
|
1064
|
-
while (NULL != (pub = (Pub)queue_pop(&
|
1088
|
+
while (NULL != (pub = (Pub)queue_pop(&loop->pub_queue, 0.0))) {
|
1065
1089
|
process_pub_con(pub);
|
1066
1090
|
}
|
1067
|
-
|
1068
|
-
|
1069
|
-
if (0 > (i = poll(pa, (nfds_t)(pp - pa), 100))) {
|
1091
|
+
pp = poll_setup(cons, &loop->pub_queue, pa);
|
1092
|
+
if (0 > (i = poll(pa, (nfds_t)(pp - pa), 10))) {
|
1070
1093
|
if (EAGAIN == errno) {
|
1071
1094
|
continue;
|
1072
1095
|
}
|
@@ -1075,7 +1098,6 @@ con_loop(void *x) {
|
|
1075
1098
|
break;
|
1076
1099
|
}
|
1077
1100
|
now = dtime();
|
1078
|
-
|
1079
1101
|
if (0 < i) {
|
1080
1102
|
// Check con_queue if an event is waiting.
|
1081
1103
|
if (0 != (pa->revents & POLLIN)) {
|
@@ -1090,7 +1112,9 @@ con_loop(void *x) {
|
|
1090
1112
|
size = sizeof(struct pollfd) * cnt;
|
1091
1113
|
if (NULL == (pa = (struct pollfd*)malloc(size))) {
|
1092
1114
|
log_cat(&error_cat, "Out of memory.");
|
1093
|
-
|
1115
|
+
log_close();
|
1116
|
+
exit(EXIT_FAILURE);
|
1117
|
+
|
1094
1118
|
return NULL;
|
1095
1119
|
}
|
1096
1120
|
pend = pa + cnt;
|
@@ -1099,8 +1123,8 @@ con_loop(void *x) {
|
|
1099
1123
|
}
|
1100
1124
|
// Check pub_queue if an event is waiting.
|
1101
1125
|
if (0 != (pa[1].revents & POLLIN)) {
|
1102
|
-
queue_release(&
|
1103
|
-
while (NULL != (pub = (Pub)queue_pop(&
|
1126
|
+
queue_release(&loop->pub_queue);
|
1127
|
+
while (NULL != (pub = (Pub)queue_pop(&loop->pub_queue, 0.0))) {
|
1104
1128
|
process_pub_con(pub);
|
1105
1129
|
}
|
1106
1130
|
}
|
@@ -1118,7 +1142,7 @@ con_loop(void *x) {
|
|
1118
1142
|
goto CON_CHECK;
|
1119
1143
|
}
|
1120
1144
|
}
|
1121
|
-
if (0 != (pp->revents & POLLOUT)) {
|
1145
|
+
if (0 != (pp->revents & POLLOUT) && NULL != c->res_head && NULL != res_message(c->res_head)) {
|
1122
1146
|
if (con_write(c)) {
|
1123
1147
|
c->dead = true;
|
1124
1148
|
goto CON_CHECK;
|
@@ -1147,14 +1171,13 @@ con_loop(void *x) {
|
|
1147
1171
|
if (remove_dead_res(c)) {
|
1148
1172
|
goto CON_RM;
|
1149
1173
|
}
|
1150
|
-
} else if (CON_WS == c->kind || CON_SSE == c->kind) {
|
1174
|
+
} else if (CON_WS == c->bind->kind || CON_SSE == c->bind->kind) {
|
1151
1175
|
c->timeout = dtime() + CON_TIMEOUT;
|
1152
1176
|
ws_ping(c);
|
1153
1177
|
continue;
|
1154
1178
|
} else {
|
1155
1179
|
c->closing = true;
|
1156
1180
|
c->timeout = now + 0.5;
|
1157
|
-
//wush_text_set(&c->resp, (char*)close_resp, sizeof(close_resp) - 1, false);
|
1158
1181
|
prev = c;
|
1159
1182
|
continue;
|
1160
1183
|
}
|
@@ -1180,3 +1203,18 @@ con_loop(void *x) {
|
|
1180
1203
|
return NULL;
|
1181
1204
|
}
|
1182
1205
|
|
1206
|
+
ConLoop
|
1207
|
+
conloop_create(Err err, int id) {
|
1208
|
+
ConLoop loop;
|
1209
|
+
|
1210
|
+
if (NULL == (loop = (ConLoop)malloc(sizeof(struct _ConLoop)))) {
|
1211
|
+
err_set(err, ERR_MEMORY, "Failed to allocate memory for a connection thread.");
|
1212
|
+
} else {
|
1213
|
+
//DEBUG_ALLOC(mem_con, c);
|
1214
|
+
loop->next = NULL;
|
1215
|
+
queue_multi_init(&loop->pub_queue, 256, true, false);
|
1216
|
+
loop->id = id;
|
1217
|
+
pthread_create(&loop->thread, NULL, con_loop, loop);
|
1218
|
+
}
|
1219
|
+
return loop;
|
1220
|
+
}
|