agoo 2.5.5 → 2.5.6

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.

Potentially problematic release.


This version of agoo might be problematic. Click here for more details.

Files changed (79) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +10 -0
  3. data/README.md +1 -1
  4. data/ext/agoo/agoo.c +4 -3
  5. data/ext/agoo/atomic.h +120 -0
  6. data/ext/agoo/bind.c +52 -52
  7. data/ext/agoo/bind.h +13 -13
  8. data/ext/agoo/con.c +499 -481
  9. data/ext/agoo/con.h +47 -39
  10. data/ext/agoo/debug.c +42 -42
  11. data/ext/agoo/debug.h +1 -1
  12. data/ext/agoo/doc.c +17 -17
  13. data/ext/agoo/doc.h +12 -12
  14. data/ext/agoo/err.c +18 -18
  15. data/ext/agoo/err.h +27 -27
  16. data/ext/agoo/error_stream.c +9 -9
  17. data/ext/agoo/extconf.rb +3 -0
  18. data/ext/agoo/gqlintro.c +43 -43
  19. data/ext/agoo/gqlintro.h +1 -1
  20. data/ext/agoo/gqlvalue.c +131 -131
  21. data/ext/agoo/gqlvalue.h +32 -32
  22. data/ext/agoo/graphql.c +158 -158
  23. data/ext/agoo/graphql.h +34 -33
  24. data/ext/agoo/hook.c +15 -14
  25. data/ext/agoo/hook.h +18 -14
  26. data/ext/agoo/http.c +14 -14
  27. data/ext/agoo/http.h +4 -4
  28. data/ext/agoo/kinds.h +5 -5
  29. data/ext/agoo/log.c +232 -224
  30. data/ext/agoo/log.h +93 -93
  31. data/ext/agoo/method.h +17 -17
  32. data/ext/agoo/page.c +88 -86
  33. data/ext/agoo/page.h +21 -21
  34. data/ext/agoo/pub.c +36 -36
  35. data/ext/agoo/pub.h +23 -23
  36. data/ext/agoo/queue.c +37 -38
  37. data/ext/agoo/queue.h +20 -19
  38. data/ext/agoo/rack_logger.c +13 -13
  39. data/ext/agoo/ready.c +357 -0
  40. data/ext/agoo/ready.h +41 -0
  41. data/ext/agoo/req.c +11 -11
  42. data/ext/agoo/req.h +30 -31
  43. data/ext/agoo/request.c +46 -46
  44. data/ext/agoo/request.h +2 -2
  45. data/ext/agoo/res.c +40 -18
  46. data/ext/agoo/res.h +14 -14
  47. data/ext/agoo/response.c +6 -6
  48. data/ext/agoo/response.h +9 -9
  49. data/ext/agoo/rhook.c +3 -3
  50. data/ext/agoo/rhook.h +1 -1
  51. data/ext/agoo/rlog.c +47 -42
  52. data/ext/agoo/rlog.h +0 -1
  53. data/ext/agoo/rresponse.c +33 -33
  54. data/ext/agoo/rresponse.h +1 -1
  55. data/ext/agoo/rserver.c +184 -175
  56. data/ext/agoo/rserver.h +2 -2
  57. data/ext/agoo/rupgraded.c +41 -41
  58. data/ext/agoo/rupgraded.h +3 -3
  59. data/ext/agoo/sdl.c +80 -80
  60. data/ext/agoo/sdl.h +1 -1
  61. data/ext/agoo/seg.h +2 -2
  62. data/ext/agoo/server.c +143 -117
  63. data/ext/agoo/server.h +43 -42
  64. data/ext/agoo/sse.c +7 -7
  65. data/ext/agoo/sse.h +4 -4
  66. data/ext/agoo/subject.c +5 -5
  67. data/ext/agoo/subject.h +6 -6
  68. data/ext/agoo/text.c +21 -21
  69. data/ext/agoo/text.h +14 -13
  70. data/ext/agoo/upgraded.c +41 -40
  71. data/ext/agoo/upgraded.h +41 -40
  72. data/ext/agoo/websocket.c +42 -42
  73. data/ext/agoo/websocket.h +16 -16
  74. data/lib/agoo/version.rb +1 -1
  75. data/test/static_test.rb +2 -0
  76. metadata +5 -5
  77. data/ext/agoo/log_queue.h +0 -30
  78. data/ext/agoo/sub.c +0 -111
  79. data/ext/agoo/sub.h +0 -36
@@ -11,10 +11,10 @@
11
11
  #include "err.h"
12
12
  #include "kinds.h"
13
13
 
14
- struct _Con;
14
+ struct _agooCon;
15
15
 
16
- typedef struct _Bind {
17
- struct _Bind *next;
16
+ typedef struct _agooBind {
17
+ struct _agooBind *next;
18
18
  int fd;
19
19
  int port;
20
20
  sa_family_t family;
@@ -22,23 +22,23 @@ typedef struct _Bind {
22
22
  struct in_addr addr4;
23
23
  struct in6_addr addr6;
24
24
  };
25
- ConKind kind;
26
- bool (*read)(struct _Con *c);
27
- bool (*write)(struct _Con *c);
28
- short (*events)(struct _Con *c);
25
+ agooConKind kind;
26
+ bool (*read)(struct _agooCon *c);
27
+ bool (*write)(struct _agooCon *c);
28
+ short (*events)(struct _agooCon *c);
29
29
  char scheme[8];
30
30
  char *name; // if set then Unix file
31
31
  char *key; // if set then SSL
32
32
  char *cert;
33
33
  char *ca;
34
34
  char *id;
35
- } *Bind;
35
+ } *agooBind;
36
36
 
37
- extern Bind bind_url(Err err, const char *url);
38
- extern Bind bind_port(Err err, int port);
39
- extern void bind_destroy(Bind b);
37
+ extern agooBind agoo_bind_url(agooErr err, const char *url);
38
+ extern agooBind agoo_bind_port(agooErr err, int port);
39
+ extern void agoo_bind_destroy(agooBind b);
40
40
 
41
- extern int bind_listen(Err err, Bind b);
42
- extern void bind_close(Bind b);
41
+ extern int agoo_bind_listen(agooErr err, agooBind b);
42
+ extern void agoo_bind_close(agooBind b);
43
43
 
44
44
  #endif // AGOO_BIND_H
@@ -15,6 +15,7 @@
15
15
  #include "log.h"
16
16
  #include "page.h"
17
17
  #include "pub.h"
18
+ #include "ready.h"
18
19
  #include "res.h"
19
20
  #include "seg.h"
20
21
  #include "server.h"
@@ -26,67 +27,76 @@
26
27
  #define CON_TIMEOUT 5.0
27
28
  #define INITIAL_POLL_SIZE 1024
28
29
 
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,
30
+ typedef enum {
31
+ HEAD_AGAIN = 'A',
32
+ HEAD_ERR = 'E',
33
+ HEAD_OK = 'O',
34
+ HEAD_HANDLED = 'H',
35
+ } HeadReturn;
36
+
37
+ static bool con_ws_read(agooCon c);
38
+ static bool con_ws_write(agooCon c);
39
+ static short con_ws_events(agooCon c);
40
+ static bool con_sse_write(agooCon c);
41
+ static short con_sse_events(agooCon c);
42
+
43
+ static struct _agooBind ws_bind = {
44
+ .kind = AGOO_CON_WS,
37
45
  .read = con_ws_read,
38
46
  .write = con_ws_write,
39
47
  .events = con_ws_events,
40
48
  };
41
49
 
42
- static struct _Bind sse_bind = {
43
- .kind = CON_SSE,
50
+ static struct _agooBind sse_bind = {
51
+ .kind = AGOO_CON_SSE,
44
52
  .read = NULL,
45
53
  .write = con_sse_write,
46
54
  .events = con_sse_events,
47
55
  };
48
56
 
49
- Con
50
- con_create(Err err, int sock, uint64_t id, Bind b) {
51
- Con c;
57
+ agooCon
58
+ agoo_con_create(agooErr err, int sock, uint64_t id, agooBind b) {
59
+ agooCon c;
52
60
 
53
- if (NULL == (c = (Con)malloc(sizeof(struct _Con)))) {
54
- err_set(err, ERR_MEMORY, "Failed to allocate memory for a connection.");
61
+ if (NULL == (c = (agooCon)malloc(sizeof(struct _agooCon)))) {
62
+ agoo_err_set(err, AGOO_ERR_MEMORY, "Failed to allocate memory for a connection.");
55
63
  } else {
56
64
  DEBUG_ALLOC(mem_con, c)
57
- memset(c, 0, sizeof(struct _Con));
65
+ memset(c, 0, sizeof(struct _agooCon));
58
66
  c->sock = sock;
59
67
  c->id = id;
60
68
  c->timeout = dtime() + CON_TIMEOUT;
61
69
  c->bind = b;
70
+ c->loop = NULL;
62
71
  }
63
72
  return c;
64
73
  }
65
74
 
66
75
  void
67
- con_destroy(Con c) {
68
- atomic_fetch_sub(&the_server.con_cnt, 1);
76
+ agoo_con_destroy(agooCon c) {
77
+ atomic_fetch_sub(&agoo_server.con_cnt, 1);
69
78
 
70
- if (CON_WS == c->bind->kind || CON_SSE == c->bind->kind) {
71
- ws_req_close(c);
79
+ if (AGOO_CON_WS == c->bind->kind || AGOO_CON_SSE == c->bind->kind) {
80
+ agoo_ws_req_close(c);
72
81
  }
73
82
  if (0 < c->sock) {
74
83
  close(c->sock);
75
84
  c->sock = 0;
76
85
  }
77
86
  if (NULL != c->req) {
78
- req_destroy(c->req);
87
+ agoo_req_destroy(c->req);
79
88
  }
80
89
  if (NULL != c->up) {
81
- upgraded_release_con(c->up);
90
+ agoo_upgraded_release_con(c->up);
82
91
  c->up = NULL;
83
92
  }
93
+ agoo_log_cat(&agoo_con_cat, "Connection %llu closed.", (unsigned long long)c->id);
84
94
  DEBUG_FREE(mem_con, c)
85
95
  free(c);
86
96
  }
87
97
 
88
98
  const char*
89
- con_header_value(const char *header, int hlen, const char *key, int *vlen) {
99
+ agoo_con_header_value(const char *header, int hlen, const char *key, int *vlen) {
90
100
  // Search for \r then check for \n and then the key followed by a :. Keep
91
101
  // trying until the end of the header.
92
102
  const char *h = header;
@@ -116,17 +126,19 @@ con_header_value(const char *header, int hlen, const char *key, int *vlen) {
116
126
  return NULL;
117
127
  }
118
128
 
119
- static long
120
- bad_request(Con c, int status, int line) {
121
- Res res;
122
- const char *msg = http_code_message(status);
129
+ static HeadReturn
130
+ bad_request(agooCon c, int status, int line) {
131
+ agooRes res;
132
+ const char *msg = agoo_http_code_message(status);
123
133
 
124
- if (NULL == (res = res_create(c))) {
125
- log_cat(&error_cat, "memory allocation of response failed on connection %llu @ %d.", (unsigned long long)c->id, line);
134
+ if (NULL == (res = agoo_res_create(c))) {
135
+ agoo_log_cat(&agoo_error_cat, "memory allocation of response failed on connection %llu @ %d.",
136
+ (unsigned long long)c->id, line);
126
137
  } else {
127
- char buf[256];
128
- int cnt = snprintf(buf, sizeof(buf), "HTTP/1.1 %d %s\r\nConnection: Close\r\nContent-Length: 0\r\n\r\n", status, msg);
129
- Text message = text_create(buf, cnt);
138
+ char buf[256];
139
+ int cnt = snprintf(buf, sizeof(buf),
140
+ "HTTP/1.1 %d %s\r\nConnection: Close\r\nContent-Length: 0\r\n\r\n", status, msg);
141
+ agooText message = agoo_text_create(buf, cnt);
130
142
 
131
143
  if (NULL == c->res_tail) {
132
144
  c->res_head = res;
@@ -135,9 +147,9 @@ bad_request(Con c, int status, int line) {
135
147
  }
136
148
  c->res_tail = res;
137
149
  res->close = true;
138
- res_set_message(res, message);
150
+ agoo_res_set_message(res, message);
139
151
  }
140
- return -1;
152
+ return HEAD_ERR;
141
153
  }
142
154
 
143
155
  static bool
@@ -145,18 +157,18 @@ should_close(const char *header, int hlen) {
145
157
  const char *v;
146
158
  int vlen = 0;
147
159
 
148
- if (NULL != (v = con_header_value(header, hlen, "Connection", &vlen))) {
160
+ if (NULL != (v = agoo_con_header_value(header, hlen, "Connection", &vlen))) {
149
161
  return (5 == vlen && 0 == strncasecmp("Close", v, 5));
150
162
  }
151
163
  return false;
152
164
  }
153
165
 
154
166
  static bool
155
- page_response(Con c, Page p, char *hend) {
156
- Res res;
167
+ page_response(agooCon c, agooPage p, char *hend) {
168
+ agooRes res;
157
169
  char *b;
158
170
 
159
- if (NULL == (res = res_create(c))) {
171
+ if (NULL == (res = agoo_res_create(c))) {
160
172
  return true;
161
173
  }
162
174
  if (NULL == c->res_tail) {
@@ -171,16 +183,16 @@ page_response(Con c, Page p, char *hend) {
171
183
  if (res->close) {
172
184
  c->closing = true;
173
185
  }
174
- res_set_message(res, p->resp);
186
+ agoo_res_set_message(res, p->resp);
175
187
 
176
188
  return false;
177
189
  }
178
190
 
179
191
  // rserver
180
192
  static void
181
- push_error(Upgraded up, const char *msg, int mlen) {
182
- if (NULL != up && the_server.ctx_nil_value != up->ctx && up->on_error) {
183
- Req req = req_create(mlen);
193
+ push_error(agooUpgraded up, const char *msg, int mlen) {
194
+ if (NULL != up && agoo_server.ctx_nil_value != up->ctx && up->on_error) {
195
+ agooReq req = agoo_req_create(mlen);
184
196
 
185
197
  if (NULL == req) {
186
198
  return;
@@ -188,41 +200,36 @@ push_error(Upgraded up, const char *msg, int mlen) {
188
200
  memcpy(req->msg, msg, mlen);
189
201
  req->msg[mlen] = '\0';
190
202
  req->up = up;
191
- req->method = ON_ERROR;
192
- req->hook = hook_create(NONE, NULL, up->ctx, PUSH_HOOK, &the_server.eval_queue);
193
- upgraded_ref(up);
194
- queue_push(&the_server.eval_queue, (void*)req);
203
+ req->method = AGOO_ON_ERROR;
204
+ req->hook = agoo_hook_create(AGOO_NONE, NULL, up->ctx, PUSH_HOOK, &agoo_server.eval_queue);
205
+ agoo_upgraded_ref(up);
206
+ agoo_queue_push(&agoo_server.eval_queue, (void*)req);
195
207
  }
196
208
  }
197
209
 
198
- // Returns:
199
- // 0 - when header has not been read
200
- // message length - when length can be determined
201
- // -1 on a bad request
202
- // negative of message length - when message is handled here.
203
- static long
204
- con_header_read(Con c) {
205
- char *hend = strstr(c->buf, "\r\n\r\n");
206
- Method method;
207
- struct _Seg path;
208
- char *query = NULL;
209
- char *qend;
210
- char *b;
211
- size_t clen = 0;
212
- long mlen;
213
- Hook hook = NULL;
214
- Page p;
215
- struct _Err err = ERR_INIT;
216
-
210
+ static HeadReturn
211
+ agoo_con_header_read(agooCon c, size_t *mlenp) {
212
+ char *hend = strstr(c->buf, "\r\n\r\n");
213
+ agooMethod method;
214
+ struct _agooSeg path;
215
+ char *query = NULL;
216
+ char *qend;
217
+ char *b;
218
+ size_t clen = 0;
219
+ long mlen;
220
+ agooHook hook = NULL;
221
+ agooPage p;
222
+ struct _agooErr err = AGOO_ERR_INIT;
223
+
217
224
  if (NULL == hend) {
218
225
  if (sizeof(c->buf) - 1 <= c->bcnt) {
219
226
  return bad_request(c, 431, __LINE__);
220
227
  }
221
- return 0;
228
+ return HEAD_AGAIN;
222
229
  }
223
- if (req_cat.on) {
230
+ if (agoo_req_cat.on) {
224
231
  *hend = '\0';
225
- log_cat(&req_cat, "%llu: %s", (unsigned long long)c->id, c->buf);
232
+ agoo_log_cat(&agoo_req_cat, "%llu: %s", (unsigned long long)c->id, c->buf);
226
233
  *hend = '\r';
227
234
  }
228
235
  for (b = c->buf; ' ' != *b; b++) {
@@ -235,7 +242,7 @@ con_header_read(Con c) {
235
242
  if (3 != b - c->buf || 0 != strncmp("GET", c->buf, 3)) {
236
243
  return bad_request(c, 400, __LINE__);
237
244
  }
238
- method = GET;
245
+ method = AGOO_GET;
239
246
  break;
240
247
  case 'P': {
241
248
  const char *v;
@@ -243,13 +250,13 @@ con_header_read(Con c) {
243
250
  char *vend;
244
251
 
245
252
  if (3 == b - c->buf && 0 == strncmp("PUT", c->buf, 3)) {
246
- method = PUT;
253
+ method = AGOO_PUT;
247
254
  } else if (4 == b - c->buf && 0 == strncmp("POST", c->buf, 4)) {
248
- method = POST;
255
+ method = AGOO_POST;
249
256
  } else {
250
257
  return bad_request(c, 400, __LINE__);
251
258
  }
252
- if (NULL == (v = con_header_value(c->buf, (int)(hend - c->buf), "Content-Length", &vlen))) {
259
+ if (NULL == (v = agoo_con_header_value(c->buf, (int)(hend - c->buf), "Content-Length", &vlen))) {
253
260
  return bad_request(c, 411, __LINE__);
254
261
  }
255
262
  clen = (size_t)strtoul(v, &vend, 10);
@@ -262,25 +269,25 @@ con_header_read(Con c) {
262
269
  if (6 != b - c->buf || 0 != strncmp("DELETE", c->buf, 6)) {
263
270
  return bad_request(c, 400, __LINE__);
264
271
  }
265
- method = DELETE;
272
+ method = AGOO_DELETE;
266
273
  break;
267
274
  case 'H':
268
275
  if (4 != b - c->buf || 0 != strncmp("HEAD", c->buf, 4)) {
269
276
  return bad_request(c, 400, __LINE__);
270
277
  }
271
- method = HEAD;
278
+ method = AGOO_HEAD;
272
279
  break;
273
280
  case 'O':
274
281
  if (7 != b - c->buf || 0 != strncmp("OPTIONS", c->buf, 7)) {
275
282
  return bad_request(c, 400, __LINE__);
276
283
  }
277
- method = OPTIONS;
284
+ method = AGOO_OPTIONS;
278
285
  break;
279
286
  case 'C':
280
287
  if (7 != b - c->buf || 0 != strncmp("CONNECT", c->buf, 7)) {
281
288
  return bad_request(c, 400, __LINE__);
282
289
  }
283
- method = CONNECT;
290
+ method = AGOO_CONNECT;
284
291
  break;
285
292
  default:
286
293
  return bad_request(c, 400, __LINE__);
@@ -311,50 +318,39 @@ con_header_read(Con c) {
311
318
  qend = b;
312
319
  }
313
320
  mlen = hend - c->buf + 4 + clen;
314
- if (GET == method &&
315
- NULL != (p = group_get(&err, path.start, (int)(path.end - path.start)))) {
316
- if (page_response(c, p, hend)) {
317
- return bad_request(c, 500, __LINE__);
318
- }
319
- return -mlen;
320
- }
321
- if (GET == method && the_server.root_first &&
322
- NULL != (p = page_get(&err, path.start, (int)(path.end - path.start)))) {
323
- if (page_response(c, p, hend)) {
324
- return bad_request(c, 500, __LINE__);
321
+ *mlenp = mlen;
322
+
323
+ if (AGOO_GET == method) {
324
+ if (NULL != (p = group_get(&err, path.start, (int)(path.end - path.start)))) {
325
+ if (page_response(c, p, hend)) {
326
+ return bad_request(c, 500, __LINE__);
327
+ }
328
+ return HEAD_HANDLED;
325
329
  }
326
- return -mlen;
327
- }
328
- if (NULL == (hook = hook_find(the_server.hooks, method, &path))) {
329
- if (GET == method) {
330
- if (the_server.root_first) { // already checked
331
- if (NULL != the_server.hook404) {
332
- // There would be too many parameters to pass to a
333
- // separate function so just goto the hook processing.
334
- hook = the_server.hook404;
335
- goto HOOKED;
336
- }
337
- return bad_request(c, 404, __LINE__);
330
+ if (agoo_server.root_first &&
331
+ NULL != (p = agoo_page_get(&err, path.start, (int)(path.end - path.start)))) {
332
+ if (page_response(c, p, hend)) {
333
+ return bad_request(c, 500, __LINE__);
338
334
  }
339
- if (NULL == (p = page_get(&err, path.start, (int)(path.end - path.start)))) {
340
- if (NULL != the_server.hook404) {
341
- // There would be too many parameters to pass to a
342
- // separate function so just goto the hook processing.
343
- hook = the_server.hook404;
344
- goto HOOKED;
335
+ return HEAD_HANDLED;
336
+ }
337
+ if (NULL == (hook = agoo_hook_find(agoo_server.hooks, method, &path))) {
338
+ if (NULL != (p = agoo_page_get(&err, path.start, (int)(path.end - path.start)))) {
339
+ if (page_response(c, p, hend)) {
340
+ return bad_request(c, 500, __LINE__);
345
341
  }
342
+ return HEAD_HANDLED;
343
+ }
344
+ if (NULL == agoo_server.hook404) {
346
345
  return bad_request(c, 404, __LINE__);
347
346
  }
348
- if (page_response(c, p, hend)) {
349
- return bad_request(c, 500, __LINE__);
350
- }
351
- return -mlen;
347
+ hook = agoo_server.hook404;
352
348
  }
349
+ } else if (NULL == (hook = agoo_hook_find(agoo_server.hooks, method, &path))) {
353
350
  return bad_request(c, 404, __LINE__);
354
- }
355
- HOOKED:
351
+ }
356
352
  // Create request and populate.
357
- if (NULL == (c->req = req_create(mlen))) {
353
+ if (NULL == (c->req = agoo_req_create(mlen))) {
358
354
  return bad_request(c, 413, __LINE__);
359
355
  }
360
356
  if ((long)c->bcnt <= mlen) {
@@ -367,7 +363,7 @@ HOOKED:
367
363
  }
368
364
  c->req->msg[mlen] = '\0';
369
365
  c->req->method = method;
370
- c->req->upgrade = UP_NONE;
366
+ c->req->upgrade = AGOO_UP_NONE;
371
367
  c->req->up = NULL;
372
368
  c->req->path.start = c->req->msg + (path.start - c->buf);
373
369
  c->req->path.len = (int)(path.end - path.start);
@@ -382,39 +378,39 @@ HOOKED:
382
378
  c->req->res = NULL;
383
379
  c->req->hook = hook;
384
380
 
385
- return mlen;
381
+ return HEAD_OK;
386
382
  }
387
383
 
388
384
  static void
389
- check_upgrade(Con c) {
385
+ check_upgrade(agooCon c) {
390
386
  const char *v;
391
387
  int vlen = 0;
392
388
 
393
389
  if (NULL == c->req) {
394
390
  return;
395
391
  }
396
- if (NULL != (v = con_header_value(c->req->header.start, c->req->header.len, "Connection", &vlen))) {
392
+ if (NULL != (v = agoo_con_header_value(c->req->header.start, c->req->header.len, "Connection", &vlen))) {
397
393
  if (NULL != strstr(v, "Upgrade")) {
398
- if (NULL != (v = con_header_value(c->req->header.start, c->req->header.len, "Upgrade", &vlen))) {
394
+ if (NULL != (v = agoo_con_header_value(c->req->header.start, c->req->header.len, "Upgrade", &vlen))) {
399
395
  if (0 == strncasecmp("WebSocket", v, vlen)) {
400
396
  c->res_tail->close = false;
401
- c->res_tail->con_kind = CON_WS;
397
+ c->res_tail->con_kind = AGOO_CON_WS;
402
398
  return;
403
399
  }
404
400
  }
405
401
  }
406
402
  }
407
- if (NULL != (v = con_header_value(c->req->header.start, c->req->header.len, "Accept", &vlen))) {
403
+ if (NULL != (v = agoo_con_header_value(c->req->header.start, c->req->header.len, "Accept", &vlen))) {
408
404
  if (0 == strncasecmp("text/event-stream", v, vlen)) {
409
405
  c->res_tail->close = false;
410
- c->res_tail->con_kind = CON_SSE;
406
+ c->res_tail->con_kind = AGOO_CON_SSE;
411
407
  return;
412
408
  }
413
409
  }
414
410
  }
415
411
 
416
412
  bool
417
- con_http_read(Con c) {
413
+ agoo_con_http_read(agooCon c) {
418
414
  ssize_t cnt;
419
415
 
420
416
  if (c->dead || 0 == c->sock || c->closing) {
@@ -430,9 +426,9 @@ con_http_read(Con c) {
430
426
  // If nothing read then no need to complain. Just close.
431
427
  if (0 < c->bcnt) {
432
428
  if (0 == cnt) {
433
- log_cat(&warn_cat, "Nothing to read. Client closed socket on connection %llu.", (unsigned long long)c->id);
429
+ agoo_log_cat(&agoo_warn_cat, "Nothing to read. Client closed socket on connection %llu.", (unsigned long long)c->id);
434
430
  } else {
435
- log_cat(&warn_cat, "Failed to read request. %s.", strerror(errno));
431
+ agoo_log_cat(&agoo_warn_cat, "Failed to read request. %s.", strerror(errno));
436
432
  }
437
433
  }
438
434
  return true;
@@ -440,39 +436,48 @@ con_http_read(Con c) {
440
436
  c->bcnt += cnt;
441
437
  while (true) {
442
438
  if (NULL == c->req) {
443
- long mlen;
444
-
445
- // Terminate with \0 for debug and strstr() check
446
- c->buf[c->bcnt] = '\0';
447
- if (0 > (mlen = con_header_read(c))) {
448
- if (-1 == mlen) {
449
- c->bcnt = 0;
450
- *c->buf = '\0';
451
- return false;
452
- } else if (-mlen < (long)c->bcnt) {
453
- mlen = -mlen;
439
+ size_t mlen;
440
+
441
+ switch (agoo_con_header_read(c, &mlen)) {
442
+ case HEAD_AGAIN:
443
+ // Try again the next time. Didn't read enough..
444
+ return false;
445
+ case HEAD_OK:
446
+ // req was created
447
+ break;
448
+ case HEAD_HANDLED:
449
+ if (mlen < c->bcnt) {
454
450
  memmove(c->buf, c->buf + mlen, c->bcnt - mlen);
455
451
  c->bcnt -= mlen;
452
+ // req is NULL so try to ready the header on the next request.
453
+ continue;
456
454
  } else {
457
455
  c->bcnt = 0;
458
456
  *c->buf = '\0';
457
+
459
458
  return false;
460
459
  }
461
- continue;
460
+ break;
461
+ case HEAD_ERR:
462
+ default:
463
+ c->bcnt = 0;
464
+ *c->buf = '\0';
465
+
466
+ return false;
462
467
  }
463
468
  }
464
469
  if (NULL != c->req) {
465
470
  if (c->req->mlen <= c->bcnt) {
466
- Req req;
467
- Res res;
471
+ agooReq req;
472
+ agooRes res;
468
473
  long mlen;
469
474
 
470
- if (debug_cat.on && NULL != c->req && NULL != c->req->body.start) {
471
- log_cat(&debug_cat, "request on %llu: %s", (unsigned long long)c->id, c->req->body.start);
475
+ if (agoo_debug_cat.on && NULL != c->req && NULL != c->req->body.start) {
476
+ agoo_log_cat(&agoo_debug_cat, "request on %llu: %s", (unsigned long long)c->id, c->req->body.start);
472
477
  }
473
- if (NULL == (res = res_create(c))) {
478
+ if (NULL == (res = agoo_res_create(c))) {
474
479
  c->req = NULL;
475
- log_cat(&error_cat, "memory allocation of response failed on connection %llu.", (unsigned long long)c->id);
480
+ agoo_log_cat(&agoo_error_cat, "memory allocation of response failed on connection %llu.", (unsigned long long)c->id);
476
481
  return bad_request(c, 500, __LINE__);
477
482
  } else {
478
483
  if (NULL == c->res_tail) {
@@ -491,7 +496,12 @@ con_http_read(Con c) {
491
496
  check_upgrade(c);
492
497
  req = c->req;
493
498
  c->req = NULL;
494
- queue_push(req->hook->queue, (void*)req);
499
+ if (req->hook->no_queue && FUNC_HOOK == req->hook->type) {
500
+ req->hook->func(req);
501
+ agoo_req_destroy(req);
502
+ } else {
503
+ agoo_queue_push(req->hook->queue, (void*)req);
504
+ }
495
505
  if (mlen < (long)c->bcnt) {
496
506
  memmove(c->buf, c->buf + mlen, c->bcnt - mlen);
497
507
  c->bcnt -= mlen;
@@ -509,7 +519,7 @@ con_http_read(Con c) {
509
519
  }
510
520
 
511
521
  static bool
512
- con_ws_read(Con c) {
522
+ con_ws_read(agooCon c) {
513
523
  ssize_t cnt;
514
524
  uint8_t *b;
515
525
  uint8_t op;
@@ -525,13 +535,13 @@ con_ws_read(Con c) {
525
535
  // If nothing read then no need to complain. Just close.
526
536
  if (0 < c->bcnt) {
527
537
  if (0 == cnt) {
528
- log_cat(&warn_cat, "Nothing to read. Client closed socket on connection %llu.", (unsigned long long)c->id);
538
+ agoo_log_cat(&agoo_warn_cat, "Nothing to read. Client closed socket on connection %llu.", (unsigned long long)c->id);
529
539
  } else {
530
540
  char msg[1024];
531
541
  int len = snprintf(msg, sizeof(msg) - 1, "Failed to read WebSocket message. %s.", strerror(errno));
532
542
 
533
543
  push_error(c->up, msg, len);
534
- log_cat(&warn_cat, "Failed to read WebSocket message. %s.", strerror(errno));
544
+ agoo_log_cat(&agoo_warn_cat, "Failed to read WebSocket message. %s.", strerror(errno));
535
545
  }
536
546
  }
537
547
  return true;
@@ -543,57 +553,57 @@ con_ws_read(Con c) {
543
553
  return false; // Try again.
544
554
  }
545
555
  b = (uint8_t*)c->buf;
546
- if (0 >= (mlen = ws_calc_len(c, b, c->bcnt))) {
556
+ if (0 >= (mlen = agoo_ws_calc_len(c, b, c->bcnt))) {
547
557
  return (mlen < 0);
548
558
  }
549
559
  op = 0x0F & *b;
550
560
  switch (op) {
551
- case WS_OP_TEXT:
552
- case WS_OP_BIN:
553
- if (ws_create_req(c, mlen)) {
561
+ case AGOO_WS_OP_TEXT:
562
+ case AGOO_WS_OP_BIN:
563
+ if (agoo_ws_create_req(c, mlen)) {
554
564
  return true;
555
565
  }
556
566
  break;
557
- case WS_OP_CLOSE:
567
+ case AGOO_WS_OP_CLOSE:
558
568
  return true;
559
- case WS_OP_PING:
569
+ case AGOO_WS_OP_PING:
560
570
  if (mlen == (long)c->bcnt) {
561
- ws_pong(c);
571
+ agoo_ws_pong(c);
562
572
  c->bcnt = 0;
563
573
  }
564
574
  break;
565
- case WS_OP_PONG:
575
+ case AGOO_WS_OP_PONG:
566
576
  // ignore
567
577
  if (mlen == (long)c->bcnt) {
568
578
  c->bcnt = 0;
569
579
  }
570
580
  break;
571
- case WS_OP_CONT:
581
+ case AGOO_WS_OP_CONT:
572
582
  default: {
573
583
  char msg[1024];
574
584
  int len = snprintf(msg, sizeof(msg) - 1, "WebSocket op 0x%02x not supported on %llu.",
575
585
  op, (unsigned long long)c->id);
576
586
 
577
587
  push_error(c->up, msg, len);
578
- log_cat(&error_cat, "WebSocket op 0x%02x not supported on %llu.", op, (unsigned long long)c->id);
588
+ agoo_log_cat(&agoo_error_cat, "WebSocket op 0x%02x not supported on %llu.", op, (unsigned long long)c->id);
579
589
  return true;
580
590
  }
581
591
  }
582
592
  }
583
593
  if (NULL != c->req) {
584
594
  mlen = c->req->mlen;
585
- c->req->mlen = ws_decode(c->req->msg, c->req->mlen);
595
+ c->req->mlen = agoo_ws_decode(c->req->msg, c->req->mlen);
586
596
  if (mlen <= (long)c->bcnt) {
587
- if (debug_cat.on) {
588
- if (ON_MSG == c->req->method) {
589
- log_cat(&debug_cat, "WebSocket message on %llu: %s", (unsigned long long)c->id, c->req->msg);
597
+ if (agoo_debug_cat.on) {
598
+ if (AGOO_ON_MSG == c->req->method) {
599
+ agoo_log_cat(&agoo_debug_cat, "WebSocket message on %llu: %s", (unsigned long long)c->id, c->req->msg);
590
600
  } else {
591
- log_cat(&debug_cat, "WebSocket binary message on %llu", (unsigned long long)c->id);
601
+ agoo_log_cat(&agoo_debug_cat, "WebSocket binary message on %llu", (unsigned long long)c->id);
592
602
  }
593
603
  }
594
604
  }
595
- upgraded_ref(c->up);
596
- queue_push(&the_server.eval_queue, (void*)c->req);
605
+ agoo_upgraded_ref(c->up);
606
+ agoo_queue_push(&agoo_server.eval_queue, (void*)c->req);
597
607
  if (mlen < (long)c->bcnt) {
598
608
  memmove(c->buf, c->buf + mlen, c->bcnt - mlen);
599
609
  c->bcnt -= mlen;
@@ -611,24 +621,18 @@ con_ws_read(Con c) {
611
621
  return false;
612
622
  }
613
623
 
614
- // return true to remove/close connection
615
- static bool
616
- con_read(Con c) {
617
- if (NULL != c->bind->read) {
618
- return c->bind->read(c);
619
- }
620
- return true;
621
- }
622
-
623
- // return true to remove/close connection
624
+ // return false to remove/close connection
624
625
  bool
625
- con_http_write(Con c) {
626
- Text message = res_message(c->res_head);
626
+ agoo_con_http_write(agooCon c) {
627
+ agooText message = agoo_res_message(c->res_head);
627
628
  ssize_t cnt;
628
629
 
630
+ if (NULL == message) {
631
+ return true;
632
+ }
629
633
  c->timeout = dtime() + CON_TIMEOUT;
630
634
  if (0 == c->wcnt) {
631
- if (resp_cat.on) {
635
+ if (agoo_resp_cat.on) {
632
636
  char buf[4096];
633
637
  char *hend = strstr(message->text, "\r\n\r\n");
634
638
 
@@ -640,23 +644,23 @@ con_http_write(Con c) {
640
644
  }
641
645
  memcpy(buf, message->text, hend - message->text);
642
646
  buf[hend - message->text] = '\0';
643
- log_cat(&resp_cat, "%llu: %s", (unsigned long long)c->id, buf);
647
+ agoo_log_cat(&agoo_resp_cat, "%llu: %s", (unsigned long long)c->id, buf);
644
648
  }
645
- if (debug_cat.on) {
646
- log_cat(&debug_cat, "response on %llu: %s", (unsigned long long)c->id, message->text);
649
+ if (agoo_debug_cat.on) {
650
+ agoo_log_cat(&agoo_debug_cat, "response on %llu: %s", (unsigned long long)c->id, message->text);
647
651
  }
648
652
  }
649
653
  if (0 > (cnt = send(c->sock, message->text + c->wcnt, message->len - c->wcnt, MSG_DONTWAIT))) {
650
654
  if (EAGAIN == errno) {
651
- return false;
655
+ return true;
652
656
  }
653
- log_cat(&error_cat, "Socket error @ %llu.", (unsigned long long)c->id);
657
+ agoo_log_cat(&agoo_error_cat, "Socket error @ %llu.", (unsigned long long)c->id);
654
658
 
655
- return true;
659
+ return false;
656
660
  }
657
661
  c->wcnt += cnt;
658
662
  if (c->wcnt == message->len) { // finished
659
- Res res = c->res_head;
663
+ agooRes res = c->res_head;
660
664
  bool done = res->close;
661
665
 
662
666
  c->res_head = res->next;
@@ -664,21 +668,20 @@ con_http_write(Con c) {
664
668
  c->res_tail = NULL;
665
669
  }
666
670
  c->wcnt = 0;
667
- res_destroy(res);
671
+ agoo_res_destroy(res);
668
672
 
669
- return done;
673
+ return !done;
670
674
  }
671
-
672
- return false;
675
+ return true;
673
676
  }
674
677
 
675
678
  static const char ping_msg[] = "\x89\x00";
676
679
  static const char pong_msg[] = "\x8a\x00";
677
680
 
678
681
  static bool
679
- con_ws_write(Con c) {
680
- Res res = c->res_head;
681
- Text message = res_message(res);
682
+ con_ws_write(agooCon c) {
683
+ agooRes res = c->res_head;
684
+ agooText message = agoo_res_message(res);
682
685
  ssize_t cnt;
683
686
 
684
687
  if (NULL == message) {
@@ -688,16 +691,16 @@ con_ws_write(Con c) {
688
691
  int len;
689
692
 
690
693
  if (EAGAIN == errno) {
691
- return false;
694
+ return true;
692
695
  }
693
696
  len = snprintf(msg, sizeof(msg) - 1, "Socket error @ %llu.", (unsigned long long)c->id);
694
697
  push_error(c->up, msg, len);
695
698
 
696
- log_cat(&error_cat, "Socket error @ %llu.", (unsigned long long)c->id);
697
- ws_req_close(c);
698
- res_destroy(res);
699
+ agoo_log_cat(&agoo_error_cat, "Socket error @ %llu.", (unsigned long long)c->id);
700
+ agoo_ws_req_close(c);
701
+ agoo_res_destroy(res);
699
702
 
700
- return true;
703
+ return false;
701
704
  }
702
705
  } else if (res->pong) {
703
706
  if (0 > (cnt = send(c->sock, pong_msg, sizeof(pong_msg) - 1, 0))) {
@@ -705,45 +708,46 @@ con_ws_write(Con c) {
705
708
  int len;
706
709
 
707
710
  if (EAGAIN == errno) {
708
- return false;
711
+ return true;
709
712
  }
710
713
  len = snprintf(msg, sizeof(msg) - 1, "Socket error @ %llu.", (unsigned long long)c->id);
711
714
  push_error(c->up, msg, len);
712
- log_cat(&error_cat, "Socket error @ %llu.", (unsigned long long)c->id);
713
- ws_req_close(c);
714
- res_destroy(res);
715
+ agoo_log_cat(&agoo_error_cat, "Socket error @ %llu.", (unsigned long long)c->id);
716
+ agoo_ws_req_close(c);
717
+ agoo_res_destroy(res);
715
718
 
716
- return true;
719
+ return false;
717
720
  }
718
721
  } else {
719
- ws_req_close(c);
722
+ agoo_ws_req_close(c);
720
723
  c->res_head = res->next;
721
724
  if (res == c->res_tail) {
722
725
  c->res_tail = NULL;
723
726
  }
724
- res_destroy(res);
725
- return true;
727
+ agoo_res_destroy(res);
728
+
729
+ return false;
726
730
  }
727
731
  c->res_head = res->next;
728
732
  if (res == c->res_tail) {
729
733
  c->res_tail = NULL;
730
734
  }
731
- return false;
735
+ return true;
732
736
  }
733
737
  c->timeout = dtime() + CON_TIMEOUT;
734
738
  if (0 == c->wcnt) {
735
- Text t;
739
+ agooText t;
736
740
 
737
- if (push_cat.on) {
741
+ if (agoo_push_cat.on) {
738
742
  if (message->bin) {
739
- log_cat(&push_cat, "%llu binary", (unsigned long long)c->id);
743
+ agoo_log_cat(&agoo_push_cat, "%llu binary", (unsigned long long)c->id);
740
744
  } else {
741
- log_cat(&push_cat, "%llu: %s", (unsigned long long)c->id, message->text);
745
+ agoo_log_cat(&agoo_push_cat, "%llu: %s", (unsigned long long)c->id, message->text);
742
746
  }
743
747
  }
744
- t = ws_expand(message);
748
+ t = agoo_ws_expand(message);
745
749
  if (t != message) {
746
- res_set_message(res, t);
750
+ agoo_res_set_message(res, t);
747
751
  message = t;
748
752
  }
749
753
  }
@@ -752,18 +756,18 @@ con_ws_write(Con c) {
752
756
  int len;
753
757
 
754
758
  if (EAGAIN == errno) {
755
- return false;
759
+ return true;
756
760
  }
757
761
  len = snprintf(msg, sizeof(msg) - 1, "Socket error @ %llu.", (unsigned long long)c->id);
758
762
  push_error(c->up, msg, len);
759
- log_cat(&error_cat, "Socket error @ %llu.", (unsigned long long)c->id);
760
- ws_req_close(c);
763
+ agoo_log_cat(&agoo_error_cat, "Socket error @ %llu.", (unsigned long long)c->id);
764
+ agoo_ws_req_close(c);
761
765
 
762
- return true;
766
+ return false;
763
767
  }
764
768
  c->wcnt += cnt;
765
769
  if (c->wcnt == message->len) { // finished
766
- Res res = c->res_head;
770
+ agooRes res = c->res_head;
767
771
  bool done = res->close;
768
772
 
769
773
  c->res_head = res->next;
@@ -771,34 +775,35 @@ con_ws_write(Con c) {
771
775
  c->res_tail = NULL;
772
776
  }
773
777
  c->wcnt = 0;
774
- res_destroy(res);
778
+ agoo_res_destroy(res);
775
779
 
776
- return done;
780
+ return !done;
777
781
  }
778
- return false;
782
+ return true;
779
783
  }
780
784
 
781
785
  static bool
782
- con_sse_write(Con c) {
783
- Res res = c->res_head;
784
- Text message = res_message(res);
786
+ con_sse_write(agooCon c) {
787
+ agooRes res = c->res_head;
788
+ agooText message = agoo_res_message(res);
785
789
  ssize_t cnt;
786
790
 
787
791
  if (NULL == message) {
788
- ws_req_close(c);
789
- res_destroy(res);
790
- return true;
792
+ agoo_ws_req_close(c);
793
+ agoo_res_destroy(res);
794
+
795
+ return false;
791
796
  }
792
797
  c->timeout = dtime() + CON_TIMEOUT *2;
793
798
  if (0 == c->wcnt) {
794
- Text t;
799
+ agooText t;
795
800
 
796
- if (push_cat.on) {
797
- log_cat(&push_cat, "%llu: %s", (unsigned long long)c->id, message->text);
801
+ if (agoo_push_cat.on) {
802
+ agoo_log_cat(&agoo_push_cat, "%llu: %s", (unsigned long long)c->id, message->text);
798
803
  }
799
- t = sse_expand(message);
804
+ t = agoo_sse_expand(message);
800
805
  if (t != message) {
801
- res_set_message(res, t);
806
+ agoo_res_set_message(res, t);
802
807
  message = t;
803
808
  }
804
809
  }
@@ -807,18 +812,18 @@ con_sse_write(Con c) {
807
812
  int len;
808
813
 
809
814
  if (EAGAIN == errno) {
810
- return false;
815
+ return true;
811
816
  }
812
817
  len = snprintf(msg, sizeof(msg) - 1, "Socket error @ %llu.", (unsigned long long)c->id);
813
818
  push_error(c->up, msg, len);
814
- log_cat(&error_cat, "Socket error @ %llu.", (unsigned long long)c->id);
815
- ws_req_close(c);
819
+ agoo_log_cat(&agoo_error_cat, "Socket error @ %llu.", (unsigned long long)c->id);
820
+ agoo_ws_req_close(c);
816
821
 
817
- return true;
822
+ return false;
818
823
  }
819
824
  c->wcnt += cnt;
820
825
  if (c->wcnt == message->len) { // finished
821
- Res res = c->res_head;
826
+ agooRes res = c->res_head;
822
827
  bool done = res->close;
823
828
 
824
829
  c->res_head = res->next;
@@ -826,46 +831,22 @@ con_sse_write(Con c) {
826
831
  c->res_tail = NULL;
827
832
  }
828
833
  c->wcnt = 0;
829
- res_destroy(res);
834
+ agoo_res_destroy(res);
830
835
 
831
- return done;
836
+ return !done;
832
837
  }
833
- return false;
834
- }
835
-
836
- static bool
837
- con_write(Con c) {
838
- bool remove = true;
839
- ConKind kind = c->res_head->con_kind;
840
-
841
- if (NULL != c->bind->write) {
842
- remove = c->bind->write(c);
843
- }
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;
855
- }
856
- }
857
- return remove;
838
+ return true;
858
839
  }
859
840
 
860
841
  static void
861
- publish_pub(Pub pub) {
862
- Upgraded up;
863
- const char *sub = pub->subject->pattern;
864
- int cnt = 0;
842
+ publish_pub(agooPub pub) {
843
+ agooUpgraded up;
844
+ const char *sub = pub->subject->pattern;
845
+ int cnt = 0;
865
846
 
866
- for (up = the_server.up_list; NULL != up; up = up->next) {
867
- if (NULL != up->con && upgraded_match(up, sub)) {
868
- Res res = res_create(up->con);
847
+ for (up = agoo_server.up_list; NULL != up; up = up->next) {
848
+ if (NULL != up->con && agoo_upgraded_match(up, sub)) {
849
+ agooRes res = agoo_res_create(up->con);
869
850
 
870
851
  if (NULL != res) {
871
852
  if (NULL == up->con->res_tail) {
@@ -874,8 +855,8 @@ publish_pub(Pub pub) {
874
855
  up->con->res_tail->next = res;
875
856
  }
876
857
  up->con->res_tail = res;
877
- res->con_kind = CON_ANY;
878
- res_set_message(res, text_dup(pub->msg));
858
+ res->con_kind = AGOO_CON_ANY;
859
+ agoo_res_set_message(res, agoo_text_dup(pub->msg));
879
860
  cnt++;
880
861
  }
881
862
  }
@@ -883,45 +864,45 @@ publish_pub(Pub pub) {
883
864
  }
884
865
 
885
866
  static void
886
- unsubscribe_pub(Pub pub) {
867
+ unsubscribe_pub(agooPub pub) {
887
868
  if (NULL == pub->up) {
888
- Upgraded up;
869
+ agooUpgraded up;
889
870
 
890
- for (up = the_server.up_list; NULL != up; up = up->next) {
891
- upgraded_del_subject(up, pub->subject);
871
+ for (up = agoo_server.up_list; NULL != up; up = up->next) {
872
+ agoo_upgraded_del_subject(up, pub->subject);
892
873
  }
893
874
  } else {
894
- upgraded_del_subject(pub->up, pub->subject);
875
+ agoo_upgraded_del_subject(pub->up, pub->subject);
895
876
  }
896
877
  }
897
878
 
898
879
  static void
899
- process_pub_con(Pub pub) {
900
- Upgraded up = pub->up;
880
+ process_pub_con(agooPub pub) {
881
+ agooUpgraded up = pub->up;
901
882
 
902
883
  if (NULL != up) {
903
884
  int pending;
904
885
 
905
886
  // TBD Change pending to be based on length of con queue
906
887
  if (1 == (pending = atomic_fetch_sub(&up->pending, 1))) {
907
- if (NULL != up && the_server.ctx_nil_value != up->ctx && up->on_empty) {
908
- Req req = req_create(0);
888
+ if (NULL != up && agoo_server.ctx_nil_value != up->ctx && up->on_empty) {
889
+ agooReq req = agoo_req_create(0);
909
890
 
910
891
  req->up = up;
911
- req->method = ON_EMPTY;
912
- req->hook = hook_create(NONE, NULL, up->ctx, PUSH_HOOK, &the_server.eval_queue);
913
- upgraded_ref(up);
914
- queue_push(&the_server.eval_queue, (void*)req);
892
+ req->method = AGOO_ON_EMPTY;
893
+ req->hook = agoo_hook_create(AGOO_NONE, NULL, up->ctx, PUSH_HOOK, &agoo_server.eval_queue);
894
+ agoo_upgraded_ref(up);
895
+ agoo_queue_push(&agoo_server.eval_queue, (void*)req);
915
896
  }
916
897
  }
917
898
  }
918
899
  switch (pub->kind) {
919
- case PUB_CLOSE:
900
+ case AGOO_PUB_CLOSE:
920
901
  // A close after already closed is used to decrement the reference
921
902
  // count on the upgraded so it can be destroyed in the con loop
922
903
  // threads.
923
904
  if (NULL != up->con) {
924
- Res res = res_create(up->con);
905
+ agooRes res = agoo_res_create(up->con);
925
906
 
926
907
  if (NULL != res) {
927
908
  if (NULL == up->con->res_tail) {
@@ -935,11 +916,11 @@ process_pub_con(Pub pub) {
935
916
  }
936
917
  }
937
918
  break;
938
- case PUB_WRITE: {
919
+ case AGOO_PUB_WRITE: {
939
920
  if (NULL == up->con) {
940
- log_cat(&warn_cat, "Connection already closed. WebSocket write failed.");
921
+ agoo_log_cat(&agoo_warn_cat, "Connection already closed. WebSocket write failed.");
941
922
  } else {
942
- Res res = res_create(up->con);
923
+ agooRes res = agoo_res_create(up->con);
943
924
 
944
925
  if (NULL != res) {
945
926
  if (NULL == up->con->res_tail) {
@@ -948,33 +929,33 @@ process_pub_con(Pub pub) {
948
929
  up->con->res_tail->next = res;
949
930
  }
950
931
  up->con->res_tail = res;
951
- res->con_kind = CON_ANY;
952
- res_set_message(res, pub->msg);
932
+ res->con_kind = AGOO_CON_ANY;
933
+ agoo_res_set_message(res, pub->msg);
953
934
  }
954
935
  }
955
936
  break;
956
- case PUB_SUB:
957
- upgraded_add_subject(pub->up, pub->subject);
937
+ case AGOO_PUB_SUB:
938
+ agoo_upgraded_add_subject(pub->up, pub->subject);
958
939
  pub->subject = NULL;
959
940
  break;
960
- case PUB_UN:
941
+ case AGOO_PUB_UN:
961
942
  unsubscribe_pub(pub);
962
943
  break;
963
- case PUB_MSG:
944
+ case AGOO_PUB_MSG:
964
945
  publish_pub(pub);
965
946
  break;
966
947
  }
967
948
  default:
968
949
  break;
969
950
  }
970
- pub_destroy(pub);
951
+ agoo_pub_destroy(pub);
971
952
  }
972
953
 
973
954
  short
974
- con_http_events(Con c) {
955
+ agoo_con_http_events(agooCon c) {
975
956
  short events = 0;
976
957
 
977
- if (NULL != c->res_head && NULL != res_message(c->res_head)) {
958
+ if (NULL != c->res_head && NULL != agoo_res_message(c->res_head)) {
978
959
  events = POLLIN | POLLOUT;
979
960
  } else if (!c->closing) {
980
961
  events = POLLIN;
@@ -983,10 +964,10 @@ con_http_events(Con c) {
983
964
  }
984
965
 
985
966
  static short
986
- con_ws_events(Con c) {
967
+ con_ws_events(agooCon c) {
987
968
  short events = 0;
988
969
 
989
- if (NULL != c->res_head && (c->res_head->close || c->res_head->ping || NULL != res_message(c->res_head))) {
970
+ if (NULL != c->res_head && (c->res_head->close || c->res_head->ping || NULL != agoo_res_message(c->res_head))) {
990
971
  events = POLLIN | POLLOUT;
991
972
  } else if (!c->closing) {
992
973
  events = POLLIN;
@@ -995,228 +976,265 @@ con_ws_events(Con c) {
995
976
  }
996
977
 
997
978
  static short
998
- con_sse_events(Con c) {
979
+ con_sse_events(agooCon c) {
999
980
  short events = 0;
1000
981
 
1001
- if (NULL != c->res_head && NULL != res_message(c->res_head)) {
982
+ if (NULL != c->res_head && NULL != agoo_res_message(c->res_head)) {
1002
983
  events = POLLOUT;
1003
984
  }
1004
985
  return events;
1005
986
  }
1006
987
 
1007
- static struct pollfd*
1008
- poll_setup(Con c, Queue q, struct pollfd *pp) {
1009
- // The first two pollfd are for the con_queue and the pub_queue in that
1010
- // order.
1011
- pp->fd = queue_listen(&the_server.con_queue);
1012
- pp->events = POLLIN;
1013
- pp->revents = 0;
1014
- pp++;
1015
- pp->fd = queue_listen(q);
1016
- pp->events = POLLIN;
1017
- pp->revents = 0;
1018
- pp++;
1019
- for (; NULL != c; c = c->next) {
1020
- if (c->dead || 0 == c->sock) {
1021
- continue;
1022
- }
1023
- if (c->hijacked) {
1024
- c->sock = 0;
1025
- continue;
1026
- }
1027
- c->pp = pp;
1028
- pp->fd = c->sock;
1029
- pp->events = c->bind->events(c);
1030
- pp->revents = 0;
1031
- pp++;
1032
- }
1033
- return pp;
1034
- }
1035
-
1036
988
  static bool
1037
- remove_dead_res(Con c) {
1038
- Res res;
989
+ remove_dead_res(agooCon c) {
990
+ agooRes res;
1039
991
 
1040
992
  while (NULL != (res = c->res_head)) {
1041
- if (NULL == res_message(c->res_head) && !c->res_head->close && !c->res_head->ping) {
993
+ if (NULL == agoo_res_message(c->res_head) && !c->res_head->close && !c->res_head->ping) {
1042
994
  break;
1043
995
  }
1044
996
  c->res_head = res->next;
1045
997
  if (res == c->res_tail) {
1046
998
  c->res_tail = NULL;
1047
999
  }
1048
- res_destroy(res);
1000
+ agoo_res_destroy(res);
1049
1001
  }
1050
1002
  return NULL == c->res_head;
1051
1003
  }
1052
1004
 
1053
- void*
1054
- con_loop(void *x) {
1055
- ConLoop loop = (ConLoop)x;
1056
- Con c;
1057
- Con prev;
1058
- Con next;
1059
- Con cons = NULL;
1060
- size_t size = sizeof(struct pollfd) * INITIAL_POLL_SIZE;
1061
- struct pollfd *pa = (struct pollfd*)malloc(size);
1062
- struct pollfd *pend = pa + INITIAL_POLL_SIZE;
1063
- struct pollfd *pp;
1064
- int ccnt = 0;
1065
- int i;
1066
- double now;
1067
- Pub pub;
1068
-
1069
- atomic_fetch_add(&the_server.running, 1);
1070
- memset(pa, 0, size);
1071
- while (the_server.active) {
1072
- while (NULL != (c = (Con)queue_pop(&the_server.con_queue, 0.0))) {
1073
- c->next = cons;
1074
- cons = c;
1075
- ccnt++;
1076
- if (pend - pa < ccnt + 2) {
1077
- size_t cnt = (pend - pa) * 2;
1078
-
1079
- size = sizeof(struct pollfd) * cnt;
1080
- if (NULL == (pa = (struct pollfd*)malloc(size))) {
1081
- log_cat(&error_cat, "Out of memory.");
1082
- log_close();
1083
- exit(EXIT_FAILURE);
1084
-
1085
- return NULL;
1086
- }
1087
- pend = pa + cnt;
1088
- }
1005
+ static agooReadyIO
1006
+ con_ready_io(void *ctx) {
1007
+ agooCon c = (agooCon)ctx;
1008
+
1009
+ if (NULL != c->bind) {
1010
+ switch (c->bind->events(c)) {
1011
+ case POLLIN: return AGOO_READY_IN;
1012
+ case POLLOUT: return AGOO_READY_OUT;
1013
+ case POLLIN | POLLOUT: return AGOO_READY_BOTH;
1014
+ default: break;
1089
1015
  }
1090
- while (NULL != (pub = (Pub)queue_pop(&loop->pub_queue, 0.0))) {
1091
- process_pub_con(pub);
1016
+ }
1017
+ return AGOO_READY_NONE;
1018
+ }
1019
+
1020
+ static bool
1021
+ con_ready_check(void *ctx, double now) {
1022
+ agooCon c = (agooCon)ctx;
1023
+
1024
+ if (c->dead || 0 == c->sock) {
1025
+ if (remove_dead_res(c)) {
1026
+ agoo_con_destroy(c);
1027
+
1028
+ return false;
1092
1029
  }
1093
- pp = poll_setup(cons, &loop->pub_queue, pa);
1094
- if (0 > (i = poll(pa, (nfds_t)(pp - pa), 10))) {
1095
- if (EAGAIN == errno) {
1096
- continue;
1097
- }
1098
- log_cat(&error_cat, "Polling error. %s.", strerror(errno));
1099
- // Either a signal or something bad like out of memory. Might as well exit.
1100
- break;
1030
+ } else if (0.0 == c->timeout || now < c->timeout) {
1031
+ return true;
1032
+ } else if (c->closing) {
1033
+ if (remove_dead_res(c)) {
1034
+ agoo_con_destroy(c);
1035
+
1036
+ return false;
1101
1037
  }
1102
- now = dtime();
1103
- if (0 < i) {
1104
- // Check con_queue if an event is waiting.
1105
- if (0 != (pa->revents & POLLIN)) {
1106
- queue_release(&the_server.con_queue);
1107
- while (NULL != (c = (Con)queue_pop(&the_server.con_queue, 0.0))) {
1108
- c->next = cons;
1109
- cons = c;
1110
- ccnt++;
1111
- if (pend - pa < ccnt + 2) {
1112
- size_t cnt = (pend - pa) * 2;
1113
-
1114
- size = sizeof(struct pollfd) * cnt;
1115
- if (NULL == (pa = (struct pollfd*)malloc(size))) {
1116
- log_cat(&error_cat, "Out of memory.");
1117
- log_close();
1118
- exit(EXIT_FAILURE);
1119
-
1120
- return NULL;
1121
- }
1122
- pend = pa + cnt;
1123
- }
1124
- }
1125
- }
1126
- // Check pub_queue if an event is waiting.
1127
- if (0 != (pa[1].revents & POLLIN)) {
1128
- queue_release(&loop->pub_queue);
1129
- while (NULL != (pub = (Pub)queue_pop(&loop->pub_queue, 0.0))) {
1130
- process_pub_con(pub);
1131
- }
1132
- }
1038
+ } else if (AGOO_CON_WS == c->bind->kind || AGOO_CON_SSE == c->bind->kind) {
1039
+ c->timeout = dtime() + CON_TIMEOUT;
1040
+ agoo_ws_ping(c);
1041
+
1042
+ return true;
1043
+ } else {
1044
+ c->closing = true;
1045
+ c->timeout = now + 0.5;
1046
+
1047
+ return true;
1048
+ }
1049
+ return true;
1050
+ }
1051
+
1052
+ static bool
1053
+ con_ready_read(agooReady ready, void *ctx) {
1054
+ agooCon c = (agooCon)ctx;
1055
+
1056
+ if (NULL != c->bind->read) {
1057
+ if (!c->bind->read(c)) {
1058
+ return true;
1133
1059
  }
1134
- prev = NULL;
1135
- for (c = cons; NULL != c; c = next) {
1136
- next = c->next;
1137
- if (0 == c->sock || NULL == c->pp) {
1138
- continue;
1139
- }
1140
- pp = c->pp;
1141
- if (0 != (pp->revents & POLLIN)) {
1142
- if (con_read(c)) {
1143
- c->dead = true;
1144
- goto CON_CHECK;
1145
- }
1146
- }
1147
- if (0 != (pp->revents & POLLOUT)) {
1148
- if (con_write(c)) {
1149
- c->dead = true;
1150
- goto CON_CHECK;
1151
- }
1152
- }
1153
- if (0 != (pp->revents & (POLLERR | POLLHUP | POLLNVAL))) {
1154
- if (0 < c->bcnt) {
1155
- if (0 != (pp->revents & (POLLHUP | POLLNVAL))) {
1156
- log_cat(&error_cat, "Socket %llu closed.", (unsigned long long)c->id);
1157
- } else if (!c->closing) {
1158
- log_cat(&error_cat, "Socket %llu error. %s", (unsigned long long)c->id, strerror(errno));
1060
+ }
1061
+ return false;
1062
+ }
1063
+
1064
+ static bool
1065
+ con_ready_write(void *ctx) {
1066
+ agooCon c = (agooCon)ctx;
1067
+
1068
+ if (NULL != c->res_head) {
1069
+ agooConKind kind = c->res_head->con_kind;
1070
+
1071
+ if (NULL != c->bind->write) {
1072
+ if (c->bind->write(c)) {
1073
+ //if (kind != c->kind && AGOO_CON_ANY != kind) {
1074
+ if (AGOO_CON_ANY != kind) {
1075
+ switch (kind) {
1076
+ case AGOO_CON_WS:
1077
+ c->bind = &ws_bind;
1078
+ break;
1079
+ case AGOO_CON_SSE:
1080
+ c->bind = &sse_bind;
1081
+ break;
1082
+ default:
1083
+ break;
1159
1084
  }
1160
1085
  }
1161
- c->dead = true;
1162
- goto CON_CHECK;
1163
- }
1164
- CON_CHECK:
1165
- if (c->dead || 0 == c->sock) {
1166
- if (remove_dead_res(c)) {
1167
- goto CON_RM;
1168
- }
1169
- } else if (0.0 == c->timeout || now < c->timeout) {
1170
- prev = c;
1171
- continue;
1172
- } else if (c->closing) {
1173
- if (remove_dead_res(c)) {
1174
- goto CON_RM;
1175
- }
1176
- } else if (CON_WS == c->bind->kind || CON_SSE == c->bind->kind) {
1177
- c->timeout = dtime() + CON_TIMEOUT;
1178
- ws_ping(c);
1179
- continue;
1180
- } else {
1181
- c->closing = true;
1182
- c->timeout = now + 0.5;
1183
- prev = c;
1184
- continue;
1185
- }
1186
- prev = c;
1187
- continue;
1188
- CON_RM:
1189
- if (NULL == prev) {
1190
- cons = next;
1191
- } else {
1192
- prev->next = next;
1086
+ return true;
1193
1087
  }
1194
- ccnt--;
1195
- log_cat(&con_cat, "Connection %llu closed.", (unsigned long long)c->id);
1196
- con_destroy(c);
1197
1088
  }
1198
1089
  }
1199
- while (NULL != (c = cons)) {
1200
- cons = c->next;
1201
- con_destroy(c);
1090
+ return false;
1091
+ }
1092
+
1093
+ static void
1094
+ con_ready_destroy(void *ctx) {
1095
+ agoo_con_destroy((agooCon)ctx);
1096
+ }
1097
+
1098
+ static struct _agooHandler con_handler = {
1099
+ .io = con_ready_io,
1100
+ .check = con_ready_check,
1101
+ .read = con_ready_read,
1102
+ .write = con_ready_write,
1103
+ .error = NULL,
1104
+ .destroy = con_ready_destroy,
1105
+ };
1106
+
1107
+ static agooReadyIO
1108
+ queue_ready_io(void *ctx) {
1109
+ return AGOO_READY_IN;
1110
+ }
1111
+
1112
+ static bool
1113
+ con_queue_ready_read(agooReady ready, void *ctx) {
1114
+ agooConLoop loop = (agooConLoop)ctx;
1115
+ struct _agooErr err = AGOO_ERR_INIT;
1116
+ agooCon c;
1117
+
1118
+ agoo_queue_release(&agoo_server.con_queue);
1119
+ while (NULL != (c = (agooCon)agoo_queue_pop(&agoo_server.con_queue, 0.0))) {
1120
+ c->loop = loop;
1121
+ if (AGOO_ERR_OK != agoo_ready_add(&err, ready, c->sock, &con_handler, c)) {
1122
+ agoo_log_cat(&agoo_error_cat, "Failed to add connection to manager. %s", err.msg);
1123
+ agoo_err_clear(&err);
1124
+ }
1125
+ }
1126
+ return true;
1127
+ }
1128
+
1129
+ static struct _agooHandler con_queue_handler = {
1130
+ .io = queue_ready_io,
1131
+ .check = NULL,
1132
+ .read = con_queue_ready_read,
1133
+ .write = NULL,
1134
+ .error = NULL,
1135
+ .destroy = NULL,
1136
+ };
1137
+
1138
+ static bool
1139
+ pub_queue_ready_read(agooReady ready, void *ctx) {
1140
+ agooConLoop loop = (agooConLoop)ctx;
1141
+ agooPub pub;
1142
+
1143
+ agoo_queue_release(&loop->pub_queue);
1144
+ while (NULL != (pub = (agooPub)agoo_queue_pop(&loop->pub_queue, 0.0))) {
1145
+ process_pub_con(pub);
1202
1146
  }
1203
- atomic_fetch_sub(&the_server.running, 1);
1147
+ return true;
1148
+ }
1149
+
1150
+ static struct _agooHandler pub_queue_handler = {
1151
+ .io = queue_ready_io,
1152
+ .check = NULL,
1153
+ .read = pub_queue_ready_read,
1154
+ .write = NULL,
1155
+ .error = NULL,
1156
+ .destroy = NULL,
1157
+ };
1158
+
1159
+ void*
1160
+ agoo_con_loop(void *x) {
1161
+ agooConLoop loop = (agooConLoop)x;
1162
+ struct _agooErr err = AGOO_ERR_INIT;
1163
+ agooReady ready = agoo_ready_create(&err);
1164
+ agooPub pub;
1165
+ agooCon c;
1166
+ int con_queue_fd = agoo_queue_listen(&agoo_server.con_queue);
1167
+ int pub_queue_fd = agoo_queue_listen(&loop->pub_queue);
1204
1168
 
1169
+ if (NULL == ready) {
1170
+ agoo_log_cat(&agoo_error_cat, "Failed to create connection manager. %s", err.msg);
1171
+ exit(EXIT_FAILURE);
1172
+ return NULL;
1173
+ }
1174
+ if (AGOO_ERR_OK != agoo_ready_add(&err, ready, con_queue_fd, &con_queue_handler, loop) ||
1175
+ AGOO_ERR_OK != agoo_ready_add(&err, ready, pub_queue_fd, &pub_queue_handler, loop)) {
1176
+ agoo_log_cat(&agoo_error_cat, "Failed to add queue connection to manager. %s", err.msg);
1177
+ exit(EXIT_FAILURE);
1178
+
1179
+ return NULL;
1180
+ }
1181
+ atomic_fetch_add(&agoo_server.running, 1);
1182
+
1183
+ while (agoo_server.active) {
1184
+ while (NULL != (c = (agooCon)agoo_queue_pop(&agoo_server.con_queue, 0.0))) {
1185
+ c->loop = loop;
1186
+ if (AGOO_ERR_OK != agoo_ready_add(&err, ready, c->sock, &con_handler, c)) {
1187
+ agoo_log_cat(&agoo_error_cat, "Failed to add connection to manager. %s", err.msg);
1188
+ agoo_err_clear(&err);
1189
+ }
1190
+ }
1191
+ while (NULL != (pub = (agooPub)agoo_queue_pop(&loop->pub_queue, 0.0))) {
1192
+ process_pub_con(pub);
1193
+ }
1194
+ if (AGOO_ERR_OK != agoo_ready_go(&err, ready)) {
1195
+ agoo_log_cat(&agoo_error_cat, "IO error. %s", err.msg);
1196
+ agoo_err_clear(&err);
1197
+ }
1198
+ }
1199
+ agoo_ready_destroy(ready);
1200
+ atomic_fetch_sub(&agoo_server.running, 1);
1201
+
1205
1202
  return NULL;
1206
1203
  }
1207
1204
 
1208
- ConLoop
1209
- conloop_create(Err err, int id) {
1210
- ConLoop loop;
1205
+ agooConLoop
1206
+ agoo_conloop_create(agooErr err, int id) {
1207
+ agooConLoop loop;
1211
1208
 
1212
- if (NULL == (loop = (ConLoop)malloc(sizeof(struct _ConLoop)))) {
1213
- err_set(err, ERR_MEMORY, "Failed to allocate memory for a connection thread.");
1209
+ if (NULL == (loop = (agooConLoop)malloc(sizeof(struct _agooConLoop)))) {
1210
+ agoo_err_set(err, AGOO_ERR_MEMORY, "Failed to allocate memory for a connection thread.");
1214
1211
  } else {
1212
+ int stat;
1213
+
1215
1214
  //DEBUG_ALLOC(mem_con, c);
1216
1215
  loop->next = NULL;
1217
- queue_multi_init(&loop->pub_queue, 256, true, false);
1216
+ agoo_queue_multi_init(&loop->pub_queue, 256, true, false);
1218
1217
  loop->id = id;
1219
- pthread_create(&loop->thread, NULL, con_loop, loop);
1218
+ loop->res_head = NULL;
1219
+ loop->res_tail = NULL;
1220
+ if (0 != (stat = pthread_create(&loop->thread, NULL, agoo_con_loop, loop))) {
1221
+ agoo_err_set(err, stat, "Failed to create connection loop. %s", strerror(stat));
1222
+ return NULL;
1223
+ }
1224
+ pthread_mutex_init(&loop->lock, 0);
1220
1225
  }
1221
1226
  return loop;
1222
1227
  }
1228
+
1229
+ void
1230
+ agoo_conloop_destroy(agooConLoop loop) {
1231
+ agooRes res;
1232
+
1233
+ agoo_queue_cleanup(&loop->pub_queue);
1234
+ while (NULL != (res = loop->res_head)) {
1235
+ loop->res_head = res->next;
1236
+ DEBUG_FREE(mem_res, res);
1237
+ free(res);
1238
+ }
1239
+ free(loop);
1240
+ }