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.

Files changed (56) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +9 -1
  3. data/README.md +12 -1
  4. data/ext/agoo/agoo.c +4 -3
  5. data/ext/agoo/bind.c +51 -11
  6. data/ext/agoo/bind.h +9 -0
  7. data/ext/agoo/con.c +127 -89
  8. data/ext/agoo/con.h +24 -8
  9. data/ext/agoo/debug.c +2 -0
  10. data/ext/agoo/debug.h +1 -0
  11. data/ext/agoo/err.c +1 -1
  12. data/ext/agoo/err.h +2 -5
  13. data/ext/agoo/foo/agoo.c +109 -0
  14. data/ext/agoo/foo/con.c +1220 -0
  15. data/ext/agoo/foo/con.h +65 -0
  16. data/ext/agoo/foo/page.c +699 -0
  17. data/ext/agoo/foo/pub.c +131 -0
  18. data/ext/agoo/foo/pub.h +40 -0
  19. data/ext/agoo/foo/rserver.c +1016 -0
  20. data/ext/agoo/foo/server.c +303 -0
  21. data/ext/agoo/foo/server.h +67 -0
  22. data/ext/agoo/foo/upgraded.c +182 -0
  23. data/ext/agoo/hook.c +31 -0
  24. data/ext/agoo/hook.h +9 -10
  25. data/ext/agoo/{types.h → kinds.h} +3 -3
  26. data/ext/agoo/log.c +168 -83
  27. data/ext/agoo/log.h +6 -2
  28. data/ext/agoo/page.c +38 -32
  29. data/ext/agoo/pub.c +16 -0
  30. data/ext/agoo/pub.h +1 -0
  31. data/ext/agoo/queue.h +1 -0
  32. data/ext/agoo/req.c +95 -0
  33. data/ext/agoo/req.h +48 -0
  34. data/ext/agoo/request.c +10 -38
  35. data/ext/agoo/request.h +1 -34
  36. data/ext/agoo/res.h +1 -3
  37. data/ext/agoo/response.c +6 -248
  38. data/ext/agoo/response.h +2 -6
  39. data/ext/agoo/rlog.c +2 -1
  40. data/ext/agoo/rresponse.c +252 -0
  41. data/ext/agoo/rresponse.h +14 -0
  42. data/ext/agoo/rserver.c +43 -45
  43. data/ext/agoo/rserver.h +3 -24
  44. data/ext/agoo/rupgraded.c +303 -0
  45. data/ext/agoo/rupgraded.h +17 -0
  46. data/ext/agoo/server.c +125 -8
  47. data/ext/agoo/server.h +26 -4
  48. data/ext/agoo/sse.c +3 -1
  49. data/ext/agoo/upgraded.c +42 -280
  50. data/ext/agoo/upgraded.h +16 -8
  51. data/ext/agoo/websocket.c +13 -9
  52. data/lib/agoo/base.rb +84 -0
  53. data/lib/agoo/client.rb +25 -0
  54. data/lib/agoo/version.rb +1 -1
  55. data/test/bind_test.rb +2 -2
  56. metadata +22 -4
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c72122c668962937fb515235a7e54ac99aac7d0b70b96d2536caf5b682832e8b
4
- data.tar.gz: be5095e0f7a8222d6860f67191cc989ad688a2c9c54c5a6e8b8b6b4e76b6af11
3
+ metadata.gz: 00756b3df4ad9bf284685f770eac1535e7ed1fd78c3c48b8bf71445d6af6f3ea
4
+ data.tar.gz: e055161332315715e295918121c0241fd517b31f730b2296b37f4f31b56e7df8
5
5
  SHA512:
6
- metadata.gz: 726616b8f62a4f2e116aff746aa517c1ad6f1176ae1a31a2790b8fd156c4d0c49eba7588d92be3600407f925c9d7158472e096f47c58cb4dc1c2109e446f2cc0
7
- data.tar.gz: 590334a3f012719cc51bcc554470cb7807b0363af51c20068b2461f5c1b9990658e0748cff4ff20f336295555a523902f3f756dae3982ef1a2c4ad347c944348
6
+ metadata.gz: 5cc15a45719ede4f3c6a2d2075a8c2d61eb3de1e89c1cbf726116bb70794c10820131912c646b392eb1829b4c7643bd952aeba3e296b1d55f61bbfb9b5c0072f
7
+ data.tar.gz: 99c9c21864789960c30de16dea4a08399dd8ef8fc958e1150a1c0232d116b6d182ac378b3a2676550baa7985abe29a5fc05587a4c5280b3dfc0b7f363e72fcb3
@@ -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 hanlded cause a segfault. Fixed.
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
@@ -10,9 +10,10 @@
10
10
  #include "pub.h"
11
11
  #include "rack_logger.h"
12
12
  #include "request.h"
13
- #include "response.h"
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
- queue_push(&the_rserver.pub_queue, pub_publish(subj, slen, StringValuePtr(message), (int)RSTRING_LEN(message)));
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
- queue_push(&the_rserver.pub_queue, pub_unsubscribe(NULL, StringValuePtr(subject), (int)RSTRING_LEN(subject)));
69
+ server_publish(pub_unsubscribe(NULL, StringValuePtr(subject), (int)RSTRING_LEN(subject)));
69
70
 
70
71
  return Qnil;
71
72
  }
@@ -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, "tcp/http bind address is not valid. (%s)", url);
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, "tcp/http bind address is not valid. (%s)", url);
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), "http://%s:%d", inet_ntoa(addr), port);
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, "tcp/http bind address is not valid. (%s)", url);
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), "http://[%s]:%d", inet_ntop(AF_INET6, &addr, str, INET6_ADDRSTRLEN), port);
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
 
@@ -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;
@@ -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
- extern void agoo_shutdown();
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
- if (CON_WS == c->kind || CON_SSE == c->kind) {
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
- request_destroy(c->req);
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 && Qnil != up->handler && up->on_error) {
161
- Req req = request_create(mlen);
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, (void*)up->handler, PUSH_HOOK, &the_rserver.eval_queue);
192
+ req->hook = hook_create(NONE, NULL, up->ctx, PUSH_HOOK, &the_server.eval_queue);
171
193
  upgraded_ref(up);
172
- queue_push(&the_rserver.eval_queue, (void*)req);
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 = request_create(mlen))) {
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
- static bool
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(&the_rserver.eval_queue, (void*)c->req);
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
- switch (c->kind) {
595
- case CON_HTTP:
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
- static bool
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, 0))) {
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
- switch (c->kind) {
823
- case CON_HTTP:
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
- c->kind = kind;
837
- /*
838
- if (CON_HTTP != kind && !remove) {
839
- // TBD add to up_list now or later?
840
- //c->slot = cc_set_con(&the_server.con_cache, c);
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 = the_rserver.up_list; NULL != up; up = up->next) {
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 = the_rserver.up_list; NULL != up; up = up->next) {
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 && Qnil != up->handler && up->on_empty) {
895
- Req req = request_create(0);
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, (void*)up->handler, PUSH_HOOK, &the_rserver.eval_queue);
912
+ req->hook = hook_create(NONE, NULL, up->ctx, PUSH_HOOK, &the_server.eval_queue);
900
913
  upgraded_ref(up);
901
- queue_push(&the_rserver.eval_queue, (void*)req);
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
- // An close after already closed is used to decrement the reference
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(&the_rserver.pub_queue);
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 = 0;
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
- agoo_shutdown();
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(&the_rserver.pub_queue, 0.0))) {
1088
+ while (NULL != (pub = (Pub)queue_pop(&loop->pub_queue, 0.0))) {
1065
1089
  process_pub_con(pub);
1066
1090
  }
1067
-
1068
- pp = poll_setup(cons, pa);
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
- agoo_shutdown();
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(&the_rserver.pub_queue);
1103
- while (NULL != (pub = (Pub)queue_pop(&the_rserver.pub_queue, 0.0))) {
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
+ }