agoo 2.0.5 → 2.1.0
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 +8 -0
- data/README.md +5 -2
- data/ext/agoo/agoo.c +35 -2
- data/ext/agoo/con.c +184 -86
- data/ext/agoo/con.h +4 -2
- data/ext/agoo/debug.c +2 -0
- data/ext/agoo/debug.h +2 -0
- data/ext/agoo/page.c +1 -0
- data/ext/agoo/pub.c +31 -27
- data/ext/agoo/pub.h +10 -11
- data/ext/agoo/request.c +5 -4
- data/ext/agoo/request.h +2 -1
- data/ext/agoo/res.c +3 -1
- data/ext/agoo/res.h +4 -1
- data/ext/agoo/server.c +55 -26
- data/ext/agoo/server.h +5 -3
- data/ext/agoo/subject.c +51 -0
- data/ext/agoo/subject.h +17 -0
- data/ext/agoo/text.c +18 -1
- data/ext/agoo/text.h +1 -0
- data/ext/agoo/upgraded.c +264 -57
- data/ext/agoo/upgraded.h +27 -1
- data/ext/agoo/websocket.c +10 -9
- data/lib/agoo/version.rb +1 -1
- metadata +4 -6
- data/ext/agoo/ccache.c +0 -301
- data/ext/agoo/ccache.h +0 -53
- data/ext/agoo/subscription.c +0 -54
- data/ext/agoo/subscription.h +0 -18
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 729ca7dab10faf0c9196e1297f814dc06471f5de2948a04e4a3d074067f042d6
|
4
|
+
data.tar.gz: 65f231b27c3eb5db90db659e920090fc075ffece27f65753d9769c32157f540d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8135b9c196acc16c80a81aa532d55f8452c1008f4ab22cd285a3f327655cf66f2f4b4f6177c9e7d3781f05964dde9ffb2d238f0808acd5c0150f95bd58eeec24
|
7
|
+
data.tar.gz: 7943dc936c2cb113054f04f2780185bbe80d9c62ab94e7a601874219ece58ee2c2ba5f3e8f71e4b23bb8ba24f3a31526bd944ea3351fd62a452c45bf06c0f187
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,13 @@
|
|
1
1
|
# CHANGELOG
|
2
2
|
|
3
|
+
### 2.1.0 - 2018-05-10
|
4
|
+
|
5
|
+
- This is a minor release even though the API has changed. The changed API is the one for Rack based WebSocket and SSE connection upgrades. The PR for the spec addition is currently stalled but some suggestions for a stateless API are implemented in this release. The proposed Rack SPEC is [here](misc/SPEC). The PR is [here](https://github.com/rack/rack/pull/1272)
|
6
|
+
|
7
|
+
- Publish and subscribe to WebSocket and SSE connections now available. An example in the push subdirectory demonstrates how it works.
|
8
|
+
|
9
|
+
- Slight performance boost.
|
10
|
+
|
3
11
|
### 2.0.5 - 2018-05-06
|
4
12
|
|
5
13
|
- Changed to putting all the path on the `REQUEST_PATH` variable instead of the `SCRIPT_NAME` to accomodate Rails which only uses the `REQUEST_PATH`.
|
data/README.md
CHANGED
@@ -22,7 +22,10 @@ end
|
|
22
22
|
handler = MyHandler.new
|
23
23
|
Agoo::Server.handle(:GET, "/hello", handler)
|
24
24
|
Agoo::Server.start()
|
25
|
-
|
25
|
+
|
26
|
+
# To run this example type the following then go to a browser and enter a URL
|
27
|
+
# of localhost:6464/hello.
|
28
|
+
#
|
26
29
|
# ruby hello.rb
|
27
30
|
```
|
28
31
|
|
@@ -45,7 +48,7 @@ href="https://github.com/ohler55/perfer">Perfer</a> to hit the Agoo
|
|
45
48
|
limits. Ruby benchmarks driver could not push Agoo hard enough.
|
46
49
|
|
47
50
|
Agoo supports the [Ruby rack API](https://rack.github.io) which allows for the
|
48
|
-
use of rack compatible gems. Agoo also supports WebSockets and SSE.
|
51
|
+
use of rack compatible gems such as Hanami and Rails. Agoo also supports WebSockets and SSE.
|
49
52
|
|
50
53
|
## Releases
|
51
54
|
|
data/ext/agoo/agoo.c
CHANGED
@@ -8,11 +8,11 @@
|
|
8
8
|
#include "debug.h"
|
9
9
|
#include "error_stream.h"
|
10
10
|
#include "log.h"
|
11
|
+
#include "pub.h"
|
11
12
|
#include "rack_logger.h"
|
12
13
|
#include "request.h"
|
13
14
|
#include "response.h"
|
14
15
|
#include "server.h"
|
15
|
-
#include "subscription.h"
|
16
16
|
#include "upgraded.h"
|
17
17
|
|
18
18
|
void
|
@@ -34,6 +34,38 @@ ragoo_shutdown(VALUE self) {
|
|
34
34
|
return Qnil;
|
35
35
|
}
|
36
36
|
|
37
|
+
/* Document-method: publish
|
38
|
+
*
|
39
|
+
* call-seq: publish(subject, message)
|
40
|
+
*
|
41
|
+
* Publish a message on the given subject.
|
42
|
+
*/
|
43
|
+
VALUE
|
44
|
+
ragoo_publish(VALUE self, VALUE subject, VALUE message) {
|
45
|
+
rb_check_type(subject, T_STRING);
|
46
|
+
rb_check_type(message, T_STRING);
|
47
|
+
|
48
|
+
queue_push(&the_server.pub_queue, pub_publish(StringValuePtr(subject), (int)RSTRING_LEN(subject),
|
49
|
+
StringValuePtr(message), (int)RSTRING_LEN(message)));
|
50
|
+
|
51
|
+
return Qnil;
|
52
|
+
}
|
53
|
+
|
54
|
+
/* Document-method: unsubscribe
|
55
|
+
*
|
56
|
+
* call-seq: unsubscribe(subject)
|
57
|
+
*
|
58
|
+
* Unsubscribes on client listeners on the specified subject.
|
59
|
+
*/
|
60
|
+
static VALUE
|
61
|
+
ragoo_unsubscribe(VALUE self, VALUE subject) {
|
62
|
+
rb_check_type(subject, T_STRING);
|
63
|
+
|
64
|
+
queue_push(&the_server.pub_queue, pub_unsubscribe(NULL, StringValuePtr(subject), (int)RSTRING_LEN(subject)));
|
65
|
+
|
66
|
+
return Qnil;
|
67
|
+
}
|
68
|
+
|
37
69
|
static void
|
38
70
|
sig_handler(int sig) {
|
39
71
|
agoo_shutdown();
|
@@ -60,10 +92,11 @@ Init_agoo() {
|
|
60
92
|
request_init(mod);
|
61
93
|
response_init(mod);
|
62
94
|
server_init(mod);
|
63
|
-
subscription_init(mod);
|
64
95
|
upgraded_init(mod);
|
65
96
|
|
66
97
|
rb_define_module_function(mod, "shutdown", ragoo_shutdown, 0);
|
98
|
+
rb_define_module_function(mod, "publish", ragoo_publish, 2);
|
99
|
+
rb_define_module_function(mod, "unsubscribe", ragoo_unsubscribe, 1);
|
67
100
|
|
68
101
|
signal(SIGINT, sig_handler);
|
69
102
|
signal(SIGTERM, sig_handler);
|
data/ext/agoo/con.c
CHANGED
@@ -12,19 +12,19 @@
|
|
12
12
|
#include "res.h"
|
13
13
|
#include "server.h"
|
14
14
|
#include "sse.h"
|
15
|
+
#include "subject.h"
|
16
|
+
#include "upgraded.h"
|
15
17
|
#include "websocket.h"
|
16
18
|
|
17
|
-
#define
|
18
|
-
#define
|
19
|
+
#define CON_TIMEOUT 5.0
|
20
|
+
#define INITIAL_POLL_SIZE 1024
|
21
|
+
|
22
|
+
extern void agoo_shutdown();
|
19
23
|
|
20
24
|
Con
|
21
25
|
con_create(Err err, int sock, uint64_t id) {
|
22
26
|
Con c;
|
23
27
|
|
24
|
-
if (MAX_SOCK <= sock) {
|
25
|
-
err_set(err, ERR_TOO_MANY, "Too many connections.");
|
26
|
-
return NULL;
|
27
|
-
}
|
28
28
|
if (NULL == (c = (Con)malloc(sizeof(struct _Con)))) {
|
29
29
|
err_set(err, ERR_MEMORY, "Failed to allocate memory for a connection.");
|
30
30
|
} else {
|
@@ -50,9 +50,9 @@ con_destroy(Con c) {
|
|
50
50
|
if (NULL != c->req) {
|
51
51
|
request_destroy(c->req);
|
52
52
|
}
|
53
|
-
if (NULL != c->
|
54
|
-
|
55
|
-
c->
|
53
|
+
if (NULL != c->up) {
|
54
|
+
upgraded_release_con(c->up);
|
55
|
+
c->up = NULL;
|
56
56
|
}
|
57
57
|
DEBUG_FREE(mem_con, c)
|
58
58
|
free(c);
|
@@ -94,7 +94,7 @@ bad_request(Con c, int status, int line) {
|
|
94
94
|
Res res;
|
95
95
|
const char *msg = http_code_message(status);
|
96
96
|
|
97
|
-
if (NULL == (res = res_create())) {
|
97
|
+
if (NULL == (res = res_create(c))) {
|
98
98
|
log_cat(&error_cat, "memory allocation of response failed on connection %llu @ %d.", c->id, line);
|
99
99
|
} else {
|
100
100
|
char buf[256];
|
@@ -254,7 +254,7 @@ con_header_read(Con c) {
|
|
254
254
|
}
|
255
255
|
return bad_request(c, 404, __LINE__);
|
256
256
|
}
|
257
|
-
if (NULL == (res = res_create())) {
|
257
|
+
if (NULL == (res = res_create(c))) {
|
258
258
|
return bad_request(c, 500, __LINE__);
|
259
259
|
}
|
260
260
|
if (NULL == c->res_tail) {
|
@@ -266,6 +266,9 @@ con_header_read(Con c) {
|
|
266
266
|
|
267
267
|
b = strstr(c->buf, "\r\n");
|
268
268
|
res->close = should_close(b, (int)(hend - b));
|
269
|
+
if (res->close) {
|
270
|
+
c->closing = true;
|
271
|
+
}
|
269
272
|
res_set_message(res, p->resp);
|
270
273
|
|
271
274
|
return -mlen;
|
@@ -287,7 +290,7 @@ HOOKED:
|
|
287
290
|
c->req->msg[mlen] = '\0';
|
288
291
|
c->req->method = method;
|
289
292
|
c->req->upgrade = UP_NONE;
|
290
|
-
c->req->
|
293
|
+
c->req->up = NULL;
|
291
294
|
c->req->path.start = c->req->msg + (path - c->buf);
|
292
295
|
c->req->path.len = (int)(pend - path);
|
293
296
|
c->req->query.start = c->req->msg + (query - c->buf);
|
@@ -339,7 +342,10 @@ check_upgrade(Con c) {
|
|
339
342
|
static bool
|
340
343
|
con_http_read(Con c) {
|
341
344
|
ssize_t cnt;
|
342
|
-
|
345
|
+
|
346
|
+
if (c->dead || 0 == c->sock || c->closing) {
|
347
|
+
return true;
|
348
|
+
}
|
343
349
|
if (NULL != c->req) {
|
344
350
|
cnt = recv(c->sock, c->req->msg + c->bcnt, c->req->mlen - c->bcnt, 0);
|
345
351
|
} else {
|
@@ -390,7 +396,7 @@ con_http_read(Con c) {
|
|
390
396
|
if (debug_cat.on && NULL != c->req && NULL != c->req->body.start) {
|
391
397
|
log_cat(&debug_cat, "request on %llu: %s", c->id, c->req->body.start);
|
392
398
|
}
|
393
|
-
if (NULL == (res = res_create())) {
|
399
|
+
if (NULL == (res = res_create(c))) {
|
394
400
|
c->req = NULL;
|
395
401
|
log_cat(&error_cat, "memory allocation of response failed on connection %llu.", c->id);
|
396
402
|
return bad_request(c, 500, __LINE__);
|
@@ -402,6 +408,9 @@ con_http_read(Con c) {
|
|
402
408
|
}
|
403
409
|
c->res_tail = res;
|
404
410
|
res->close = should_close(c->req->header.start, c->req->header.len);
|
411
|
+
if (res->close) {
|
412
|
+
c->closing = true;
|
413
|
+
}
|
405
414
|
}
|
406
415
|
c->req->res = res;
|
407
416
|
mlen = c->req->mlen;
|
@@ -493,6 +502,7 @@ con_ws_read(Con c) {
|
|
493
502
|
}
|
494
503
|
}
|
495
504
|
}
|
505
|
+
upgraded_ref(c->up);
|
496
506
|
queue_push(&the_server.eval_queue, (void*)c->req);
|
497
507
|
if (mlen < (long)c->bcnt) {
|
498
508
|
memmove(c->buf, c->buf + mlen, c->bcnt - mlen);
|
@@ -657,14 +667,15 @@ con_ws_write(Con c) {
|
|
657
667
|
}
|
658
668
|
c->wcnt = 0;
|
659
669
|
res_destroy(res);
|
660
|
-
if (1 == (pending = atomic_fetch_sub(&c->
|
661
|
-
if (NULL != c->
|
670
|
+
if (1 == (pending = atomic_fetch_sub(&c->up->pending, 1))) {
|
671
|
+
if (NULL != c->up && Qnil != c->up->handler && c->up->on_empty) {
|
662
672
|
Req req = request_create(0);
|
663
673
|
|
664
|
-
req->
|
674
|
+
req->up = c->up;
|
665
675
|
req->method = ON_EMPTY;
|
666
676
|
req->handler_type = PUSH_HOOK;
|
667
|
-
req->handler = c->
|
677
|
+
req->handler = c->up->handler;
|
678
|
+
upgraded_ref(c->up);
|
668
679
|
queue_push(&the_server.eval_queue, (void*)req);
|
669
680
|
}
|
670
681
|
}
|
@@ -718,14 +729,15 @@ con_sse_write(Con c) {
|
|
718
729
|
}
|
719
730
|
c->wcnt = 0;
|
720
731
|
res_destroy(res);
|
721
|
-
if (1 == (pending = atomic_fetch_sub(&c->
|
722
|
-
if (NULL != c->
|
732
|
+
if (1 == (pending = atomic_fetch_sub(&c->up->pending, 1))) {
|
733
|
+
if (NULL != c->up && Qnil != c->up->handler && c->up->on_empty) {
|
723
734
|
Req req = request_create(0);
|
724
735
|
|
725
|
-
req->
|
736
|
+
req->up = c->up;
|
726
737
|
req->method = ON_EMPTY;
|
727
738
|
req->handler_type = PUSH_HOOK;
|
728
|
-
req->handler = c->
|
739
|
+
req->handler = c->up->handler;
|
740
|
+
upgraded_ref(c->up);
|
729
741
|
queue_push(&the_server.eval_queue, (void*)req);
|
730
742
|
}
|
731
743
|
}
|
@@ -754,66 +766,103 @@ con_write(Con c) {
|
|
754
766
|
}
|
755
767
|
if (kind != c->kind) {
|
756
768
|
c->kind = kind;
|
769
|
+
/*
|
757
770
|
if (CON_HTTP != kind && !remove) {
|
758
|
-
|
771
|
+
// TBD add to up_list now or later?
|
772
|
+
//c->slot = cc_set_con(&the_server.con_cache, c);
|
759
773
|
}
|
774
|
+
*/
|
760
775
|
}
|
761
776
|
return remove;
|
762
777
|
}
|
763
778
|
|
779
|
+
static void
|
780
|
+
publish_pub(Pub pub) {
|
781
|
+
Upgraded up;
|
782
|
+
const char *sub = pub->subject->pattern;
|
783
|
+
|
784
|
+
for (up = the_server.up_list; NULL != up; up = up->next) {
|
785
|
+
if (NULL != up->con && upgraded_match(up, sub)) {
|
786
|
+
Res res = res_create(up->con);
|
787
|
+
|
788
|
+
if (NULL != res) {
|
789
|
+
if (NULL == up->con->res_tail) {
|
790
|
+
up->con->res_head = res;
|
791
|
+
} else {
|
792
|
+
up->con->res_tail->next = res;
|
793
|
+
}
|
794
|
+
up->con->res_tail = res;
|
795
|
+
res->con_kind = up->con->kind;
|
796
|
+
res_set_message(res, text_dup(pub->msg));
|
797
|
+
}
|
798
|
+
}
|
799
|
+
}
|
800
|
+
}
|
801
|
+
|
802
|
+
static void
|
803
|
+
unsubscribe_pub(Pub pub) {
|
804
|
+
if (NULL == pub->up) {
|
805
|
+
Upgraded up;
|
806
|
+
|
807
|
+
for (up = the_server.up_list; NULL != up; up = up->next) {
|
808
|
+
upgraded_del_subject(up, pub->subject);
|
809
|
+
}
|
810
|
+
} else {
|
811
|
+
upgraded_del_subject(pub->up, pub->subject);
|
812
|
+
}
|
813
|
+
}
|
814
|
+
|
764
815
|
static void
|
765
816
|
process_pub_con(Pub pub) {
|
766
|
-
|
817
|
+
Upgraded up = pub->up;
|
767
818
|
|
768
819
|
switch (pub->kind) {
|
769
820
|
case PUB_CLOSE:
|
770
|
-
|
771
|
-
|
772
|
-
|
773
|
-
|
774
|
-
|
775
|
-
Res res = res_create();;
|
821
|
+
// An close after already closed is used to decrement the reference
|
822
|
+
// count on the upgraded so it can be destroyed in the con loop
|
823
|
+
// threads.
|
824
|
+
if (NULL != up->con) {
|
825
|
+
Res res = res_create(up->con);
|
776
826
|
|
777
827
|
if (NULL != res) {
|
778
|
-
if (NULL ==
|
779
|
-
|
828
|
+
if (NULL == up->con->res_tail) {
|
829
|
+
up->con->res_head = res;
|
780
830
|
} else {
|
781
|
-
|
831
|
+
up->con->res_tail->next = res;
|
782
832
|
}
|
783
|
-
|
784
|
-
res->con_kind =
|
833
|
+
up->con->res_tail = res;
|
834
|
+
res->con_kind = up->con->kind;
|
785
835
|
res->close = true;
|
786
836
|
}
|
787
837
|
}
|
788
838
|
break;
|
789
839
|
case PUB_WRITE: {
|
790
|
-
if (NULL ==
|
791
|
-
log_cat(&warn_cat, "
|
792
|
-
pub_destroy(pub);
|
793
|
-
return;
|
840
|
+
if (NULL == up->con) {
|
841
|
+
log_cat(&warn_cat, "Connection already closed. WebSocket write failed.");
|
794
842
|
} else {
|
795
|
-
Res res = res_create();
|
843
|
+
Res res = res_create(up->con);
|
796
844
|
|
797
845
|
if (NULL != res) {
|
798
|
-
if (NULL ==
|
799
|
-
|
846
|
+
if (NULL == up->con->res_tail) {
|
847
|
+
up->con->res_head = res;
|
800
848
|
} else {
|
801
|
-
|
849
|
+
up->con->res_tail->next = res;
|
802
850
|
}
|
803
|
-
|
804
|
-
res->con_kind =
|
851
|
+
up->con->res_tail = res;
|
852
|
+
res->con_kind = up->con->kind;
|
805
853
|
res_set_message(res, pub->msg);
|
806
854
|
}
|
807
855
|
}
|
808
856
|
break;
|
809
857
|
case PUB_SUB:
|
810
|
-
|
858
|
+
upgraded_add_subject(pub->up, pub->subject);
|
859
|
+
pub->subject = NULL;
|
811
860
|
break;
|
812
861
|
case PUB_UN:
|
813
|
-
|
862
|
+
unsubscribe_pub(pub);
|
814
863
|
break;
|
815
864
|
case PUB_MSG:
|
816
|
-
|
865
|
+
publish_pub(pub);
|
817
866
|
break;
|
818
867
|
}
|
819
868
|
default:
|
@@ -823,12 +872,7 @@ process_pub_con(Pub pub) {
|
|
823
872
|
}
|
824
873
|
|
825
874
|
static struct pollfd*
|
826
|
-
poll_setup(Con
|
827
|
-
Con *cp;
|
828
|
-
Con *end = ca + MAX_SOCK;
|
829
|
-
Con c;
|
830
|
-
int i;
|
831
|
-
|
875
|
+
poll_setup(Con c, struct pollfd *pp) {
|
832
876
|
// The first two pollfd are for the con_queue and the pub_queue in that
|
833
877
|
// order.
|
834
878
|
pp->fd = queue_listen(&the_server.con_queue);
|
@@ -839,11 +883,10 @@ poll_setup(Con *ca, int ccnt, struct pollfd *pp) {
|
|
839
883
|
pp->events = POLLIN;
|
840
884
|
pp->revents = 0;
|
841
885
|
pp++;
|
842
|
-
for (
|
843
|
-
if (
|
886
|
+
for (; NULL != c; c = c->next) {
|
887
|
+
if (c->dead) {
|
844
888
|
continue;
|
845
889
|
}
|
846
|
-
c = *cp;
|
847
890
|
c->pp = pp;
|
848
891
|
pp->fd = c->sock;
|
849
892
|
pp->events = 0;
|
@@ -851,14 +894,14 @@ poll_setup(Con *ca, int ccnt, struct pollfd *pp) {
|
|
851
894
|
case CON_HTTP:
|
852
895
|
if (NULL != c->res_head && NULL != res_message(c->res_head)) {
|
853
896
|
pp->events = POLLIN | POLLOUT;
|
854
|
-
} else {
|
897
|
+
} else if (!c->closing) {
|
855
898
|
pp->events = POLLIN;
|
856
899
|
}
|
857
900
|
break;
|
858
901
|
case CON_WS:
|
859
902
|
if (NULL != c->res_head && (c->res_head->close || c->res_head->ping || NULL != res_message(c->res_head))) {
|
860
903
|
pp->events = POLLIN | POLLOUT;
|
861
|
-
} else {
|
904
|
+
} else if (!c->closing) {
|
862
905
|
pp->events = POLLIN;
|
863
906
|
}
|
864
907
|
break;
|
@@ -872,39 +915,67 @@ poll_setup(Con *ca, int ccnt, struct pollfd *pp) {
|
|
872
915
|
break;
|
873
916
|
}
|
874
917
|
pp->revents = 0;
|
875
|
-
i--;
|
876
918
|
pp++;
|
877
919
|
}
|
878
920
|
return pp;
|
879
921
|
}
|
880
922
|
|
923
|
+
static bool
|
924
|
+
remove_dead_res(Con c) {
|
925
|
+
Res res;
|
926
|
+
|
927
|
+
while (NULL != (res = c->res_head)) {
|
928
|
+
if (NULL == res_message(c->res_head) && !c->res_head->close && !c->res_head->ping) {
|
929
|
+
break;
|
930
|
+
}
|
931
|
+
c->res_head = res->next;
|
932
|
+
if (res == c->res_tail) {
|
933
|
+
c->res_tail = NULL;
|
934
|
+
}
|
935
|
+
res_destroy(res);
|
936
|
+
}
|
937
|
+
return NULL == c->res_head;
|
938
|
+
}
|
939
|
+
|
881
940
|
void*
|
882
941
|
con_loop(void *x) {
|
883
942
|
Con c;
|
884
|
-
Con
|
885
|
-
|
943
|
+
Con prev;
|
944
|
+
Con next;
|
945
|
+
Con cons = NULL;
|
946
|
+
size_t size = sizeof(struct pollfd) * INITIAL_POLL_SIZE;
|
947
|
+
struct pollfd *pa = (struct pollfd*)malloc(size);
|
948
|
+
struct pollfd *pend = pa + INITIAL_POLL_SIZE;
|
886
949
|
struct pollfd *pp;
|
887
|
-
Con *end = ca + MAX_SOCK;
|
888
|
-
Con *cp;
|
889
950
|
int ccnt = 0;
|
890
951
|
int i;
|
891
|
-
long mcnt = 0;
|
892
952
|
double now;
|
893
953
|
Pub pub;
|
894
954
|
|
895
955
|
atomic_fetch_add(&the_server.running, 1);
|
896
|
-
memset(
|
897
|
-
memset(pa, 0, sizeof(pa));
|
956
|
+
memset(pa, 0, size);
|
898
957
|
while (the_server.active) {
|
899
958
|
while (NULL != (c = (Con)queue_pop(&the_server.con_queue, 0.0))) {
|
900
|
-
|
901
|
-
|
959
|
+
c->next = cons;
|
960
|
+
cons = c;
|
902
961
|
ccnt++;
|
962
|
+
if (pend - pa < ccnt + 2) {
|
963
|
+
size_t cnt = (pend - pa) * 2;
|
964
|
+
|
965
|
+
size = sizeof(struct pollfd) * cnt;
|
966
|
+
if (NULL == (pa = (struct pollfd*)malloc(size))) {
|
967
|
+
log_cat(&error_cat, "Out of memory.");
|
968
|
+
agoo_shutdown();
|
969
|
+
return NULL;
|
970
|
+
}
|
971
|
+
pend = pa + cnt;
|
972
|
+
}
|
903
973
|
}
|
904
974
|
while (NULL != (pub = (Pub)queue_pop(&the_server.pub_queue, 0.0))) {
|
905
975
|
process_pub_con(pub);
|
906
976
|
}
|
907
|
-
|
977
|
+
|
978
|
+
pp = poll_setup(cons, pa);
|
908
979
|
if (0 > (i = poll(pa, (nfds_t)(pp - pa), 100))) {
|
909
980
|
if (EAGAIN == errno) {
|
910
981
|
continue;
|
@@ -920,9 +991,20 @@ con_loop(void *x) {
|
|
920
991
|
if (0 != (pa->revents & POLLIN)) {
|
921
992
|
queue_release(&the_server.con_queue);
|
922
993
|
while (NULL != (c = (Con)queue_pop(&the_server.con_queue, 0.0))) {
|
923
|
-
|
924
|
-
|
994
|
+
c->next = cons;
|
995
|
+
cons = c;
|
925
996
|
ccnt++;
|
997
|
+
if (pend - pa < ccnt + 2) {
|
998
|
+
size_t cnt = (pend - pa) * 2;
|
999
|
+
|
1000
|
+
size = sizeof(struct pollfd) * cnt;
|
1001
|
+
if (NULL == (pa = (struct pollfd*)malloc(size))) {
|
1002
|
+
log_cat(&error_cat, "Out of memory.");
|
1003
|
+
agoo_shutdown();
|
1004
|
+
return NULL;
|
1005
|
+
}
|
1006
|
+
pend = pa + cnt;
|
1007
|
+
}
|
926
1008
|
}
|
927
1009
|
}
|
928
1010
|
// Check pub_queue if an event is waiting.
|
@@ -933,21 +1015,23 @@ con_loop(void *x) {
|
|
933
1015
|
}
|
934
1016
|
}
|
935
1017
|
}
|
936
|
-
|
937
|
-
|
1018
|
+
prev = NULL;
|
1019
|
+
for (c = cons; NULL != c; c = next) {
|
1020
|
+
next = c->next;
|
1021
|
+
if (0 == c->sock || NULL == c->pp) {
|
938
1022
|
continue;
|
939
1023
|
}
|
940
|
-
c = *cp;
|
941
|
-
i--;
|
942
1024
|
pp = c->pp;
|
943
1025
|
if (0 != (pp->revents & POLLIN)) {
|
944
1026
|
if (con_read(c)) {
|
945
|
-
|
1027
|
+
c->dead = true;
|
1028
|
+
goto CON_CHECK;
|
946
1029
|
}
|
947
1030
|
}
|
948
1031
|
if (0 != (pp->revents & POLLOUT)) {
|
949
1032
|
if (con_write(c)) {
|
950
|
-
|
1033
|
+
c->dead = true;
|
1034
|
+
goto CON_CHECK;
|
951
1035
|
}
|
952
1036
|
}
|
953
1037
|
if (0 != (pp->revents & (POLLERR | POLLHUP | POLLNVAL))) {
|
@@ -958,12 +1042,21 @@ con_loop(void *x) {
|
|
958
1042
|
log_cat(&error_cat, "Socket %llu error. %s", c->id, strerror(errno));
|
959
1043
|
}
|
960
1044
|
}
|
961
|
-
|
1045
|
+
c->dead = true;
|
1046
|
+
goto CON_CHECK;
|
962
1047
|
}
|
963
|
-
|
1048
|
+
CON_CHECK:
|
1049
|
+
if (c->dead) {
|
1050
|
+
if (remove_dead_res(c)) {
|
1051
|
+
goto CON_RM;
|
1052
|
+
}
|
1053
|
+
} else if (0.0 == c->timeout || now < c->timeout) {
|
1054
|
+
prev = c;
|
964
1055
|
continue;
|
965
1056
|
} else if (c->closing) {
|
966
|
-
|
1057
|
+
if (remove_dead_res(c)) {
|
1058
|
+
goto CON_RM;
|
1059
|
+
}
|
967
1060
|
} else if (CON_WS == c->kind || CON_SSE == c->kind) {
|
968
1061
|
c->timeout = dtime() + CON_TIMEOUT;
|
969
1062
|
ws_ping(c);
|
@@ -972,20 +1065,25 @@ con_loop(void *x) {
|
|
972
1065
|
c->closing = true;
|
973
1066
|
c->timeout = now + 0.5;
|
974
1067
|
//wush_text_set(&c->resp, (char*)close_resp, sizeof(close_resp) - 1, false);
|
1068
|
+
prev = c;
|
975
1069
|
continue;
|
976
1070
|
}
|
1071
|
+
prev = c;
|
977
1072
|
continue;
|
978
1073
|
CON_RM:
|
979
|
-
|
1074
|
+
if (NULL == prev) {
|
1075
|
+
cons = next;
|
1076
|
+
} else {
|
1077
|
+
prev->next = next;
|
1078
|
+
}
|
980
1079
|
ccnt--;
|
981
1080
|
log_cat(&con_cat, "Connection %llu closed.", c->id);
|
982
1081
|
con_destroy(c);
|
983
1082
|
}
|
984
1083
|
}
|
985
|
-
|
986
|
-
|
987
|
-
|
988
|
-
}
|
1084
|
+
while (NULL != (c = cons)) {
|
1085
|
+
cons = c->next;
|
1086
|
+
con_destroy(c);
|
989
1087
|
}
|
990
1088
|
atomic_fetch_sub(&the_server.running, 1);
|
991
1089
|
|