1 #include "../uwsgi.h"
2
3 extern struct uwsgi_server uwsgi;
4
5 /*
6
7 uWSGI Legions subsystem
8
9 A Legion is a group of uWSGI instances sharing a single object. This single
10 object can be owned only by the instance with the higher valor. Such an instance is the
11 Lord of the Legion. There can only be one (and only one) Lord for each Legion.
12 If a member of a Legion spawns with an higher valor than the current Lord, it became the new Lord.
13
14
15 */
16
uwsgi_legion_get_by_socket(int fd)17 struct uwsgi_legion *uwsgi_legion_get_by_socket(int fd) {
18 struct uwsgi_legion *ul = uwsgi.legions;
19 while (ul) {
20 if (ul->socket == fd) {
21 return ul;
22 }
23 ul = ul->next;
24 }
25
26 return NULL;
27 }
28
uwsgi_legion_get_by_name(char * name)29 struct uwsgi_legion *uwsgi_legion_get_by_name(char *name) {
30 struct uwsgi_legion *ul = uwsgi.legions;
31 while (ul) {
32 if (!strcmp(name, ul->legion)) {
33 return ul;
34 }
35 ul = ul->next;
36 }
37
38 return NULL;
39 }
40
41
uwsgi_parse_legion(char * key,uint16_t keylen,char * value,uint16_t vallen,void * data)42 void uwsgi_parse_legion(char *key, uint16_t keylen, char *value, uint16_t vallen, void *data) {
43 struct uwsgi_legion *ul = (struct uwsgi_legion *) data;
44
45 if (!uwsgi_strncmp(key, keylen, "legion", 6)) {
46 ul->legion = value;
47 ul->legion_len = vallen;
48 }
49 else if (!uwsgi_strncmp(key, keylen, "valor", 5)) {
50 ul->valor = uwsgi_str_num(value, vallen);
51 }
52 else if (!uwsgi_strncmp(key, keylen, "name", 4)) {
53 ul->name = value;
54 ul->name_len = vallen;
55 }
56 else if (!uwsgi_strncmp(key, keylen, "pid", 3)) {
57 ul->pid = uwsgi_str_num(value, vallen);
58 }
59 else if (!uwsgi_strncmp(key, keylen, "unix", 4)) {
60 ul->unix_check = uwsgi_str_num(value, vallen);
61 }
62 else if (!uwsgi_strncmp(key, keylen, "checksum", 8)) {
63 ul->checksum = uwsgi_str_num(value, vallen);
64 }
65 else if (!uwsgi_strncmp(key, keylen, "uuid", 4)) {
66 if (vallen == 36) {
67 memcpy(ul->uuid, value, 36);
68 }
69 }
70 else if (!uwsgi_strncmp(key, keylen, "lord_valor", 10)) {
71 ul->lord_valor = uwsgi_str_num(value, vallen);
72 }
73 else if (!uwsgi_strncmp(key, keylen, "lord_uuid", 9)) {
74 if (vallen == 36) {
75 memcpy(ul->lord_uuid, value, 36);
76 }
77 }
78 else if (!uwsgi_strncmp(key, keylen, "scroll", 6)) {
79 ul->scroll = value;
80 ul->scroll_len = vallen;
81 }
82 else if (!uwsgi_strncmp(key, keylen, "dead", 4)) {
83 ul->dead = 1;
84 }
85 }
86
87 // this function is called when a node is added or removed (heavy locking is needed)
legion_rebuild_scrolls(struct uwsgi_legion * ul)88 static void legion_rebuild_scrolls(struct uwsgi_legion *ul) {
89 uint64_t max_size = ul->scrolls_max_size;
90
91 // first, try to add myself
92 if (ul->scroll_len + (uint64_t) 2 > max_size) {
93 uwsgi_log("[DANGER] you have configured a too much tiny buffer for the scrolls list !!! tune it with --legion-scroll-list-max-size\n");
94 ul->scroll_len = 0;
95 return;
96 }
97
98 char *ptr = ul->scrolls;
99 *ptr ++= (uint8_t) (ul->scroll_len & 0xff);
100 *ptr ++= (uint8_t) ((ul->scroll_len >> 8) &0xff);
101 memcpy(ptr, ul->scroll, ul->scroll_len); ptr += ul->scroll_len;
102 ul->scrolls_len = 2 + ul->scroll_len;
103 // ok start adding nodes;
104 struct uwsgi_legion_node *uln = ul->nodes_head;
105 while(uln) {
106 if (ul->scrolls_len + 2 + uln->scroll_len > max_size) {
107 uwsgi_log("[DANGER] you have configured a too much tiny buffer for the scrolls list !!! tune it with --legion-scroll-list-max-size\n");
108 return;
109 }
110 *ptr ++= (uint8_t) (uln->scroll_len & 0xff);
111 *ptr ++= (uint8_t) ((uln->scroll_len >> 8) &0xff);
112 memcpy(ptr, uln->scroll, uln->scroll_len); ptr += uln->scroll_len;
113 ul->scrolls_len += 2 + uln->scroll_len;
114 uln = uln->next;
115 }
116 }
117
118 // critical section (remember to lock when you use it)
uwsgi_legion_add_node(struct uwsgi_legion * ul,uint16_t valor,char * name,uint16_t name_len,char * uuid)119 struct uwsgi_legion_node *uwsgi_legion_add_node(struct uwsgi_legion *ul, uint16_t valor, char *name, uint16_t name_len, char *uuid) {
120
121 struct uwsgi_legion_node *node = uwsgi_calloc(sizeof(struct uwsgi_legion_node));
122 if (!name_len)
123 goto error;
124 node->name = uwsgi_calloc(name_len);
125 node->name_len = name_len;
126 memcpy(node->name, name, name_len);
127 node->valor = valor;
128 memcpy(node->uuid, uuid, 36);
129
130 if (ul->nodes_tail) {
131 node->prev = ul->nodes_tail;
132 ul->nodes_tail->next = node;
133 }
134
135 ul->nodes_tail = node;
136
137 if (!ul->nodes_head) {
138 ul->nodes_head = node;
139 }
140
141
142 return node;
143
144
145 error:
146 free(node);
147 return NULL;
148 }
149
150 // critical section (remember to lock when you use it)
uwsgi_legion_remove_node(struct uwsgi_legion * ul,struct uwsgi_legion_node * node)151 void uwsgi_legion_remove_node(struct uwsgi_legion *ul, struct uwsgi_legion_node *node) {
152 // check if the node is the first one
153 if (node == ul->nodes_head) {
154 ul->nodes_head = node->next;
155 }
156
157 // check if the node is the last one
158 if (node == ul->nodes_tail) {
159 ul->nodes_tail = node->prev;
160 }
161
162 if (node->prev) {
163 node->prev->next = node->next;
164 }
165
166 if (node->next) {
167 node->next->prev = node->prev;
168 }
169
170 if (node->name_len) {
171 free(node->name);
172 }
173
174 if (node->scroll_len) {
175 free(node->scroll);
176 }
177
178 free(node);
179
180 legion_rebuild_scrolls(ul);
181 }
182
uwsgi_legion_get_node(struct uwsgi_legion * ul,uint64_t valor,char * name,uint16_t name_len,char * uuid)183 struct uwsgi_legion_node *uwsgi_legion_get_node(struct uwsgi_legion *ul, uint64_t valor, char *name, uint16_t name_len, char *uuid) {
184 struct uwsgi_legion_node *nodes = ul->nodes_head;
185 while (nodes) {
186 if (valor != nodes->valor)
187 goto next;
188 if (name_len != nodes->name_len)
189 goto next;
190 if (memcmp(nodes->name, name, name_len))
191 goto next;
192 if (memcmp(nodes->uuid, uuid, 36))
193 goto next;
194 return nodes;
195 next:
196 nodes = nodes->next;
197 }
198 return NULL;
199 }
200
legions_check_nodes()201 static void legions_check_nodes() {
202
203 struct uwsgi_legion *legion = uwsgi.legions;
204 while (legion) {
205 time_t now = uwsgi_now();
206
207 struct uwsgi_legion_node *node = legion->nodes_head;
208 while (node) {
209 if (now - node->last_seen > uwsgi.legion_tolerance) {
210 struct uwsgi_legion_node *tmp_node = node;
211 node = node->next;
212 uwsgi_log("[uwsgi-legion] %s: %.*s valor: %llu uuid: %.*s left Legion %s\n", tmp_node->valor > 0 ? "node" : "arbiter", tmp_node->name_len, tmp_node->name, tmp_node->valor, 36, tmp_node->uuid, legion->legion);
213 uwsgi_wlock(legion->lock);
214 uwsgi_legion_remove_node(legion, tmp_node);
215 uwsgi_rwunlock(legion->lock);
216 // trigger node_left hooks
217 struct uwsgi_string_list *usl = legion->node_left_hooks;
218 while (usl) {
219 int ret = uwsgi_legion_action_call("node_left", legion, usl);
220 if (ret) {
221 uwsgi_log("[uwsgi-legion] ERROR, node_left hook returned: %d\n", ret);
222 }
223 usl = usl->next;
224 }
225 continue;
226 }
227 node = node->next;
228 }
229
230 legion = legion->next;
231 }
232 }
233
234 struct uwsgi_legion_node *uwsgi_legion_get_lord(struct uwsgi_legion *);
235
legions_report_quorum(struct uwsgi_legion * ul,uint64_t best_valor,char * best_uuid,int votes)236 static void legions_report_quorum(struct uwsgi_legion *ul, uint64_t best_valor, char *best_uuid, int votes) {
237 struct uwsgi_legion_node *nodes = ul->nodes_head;
238 uwsgi_log("[uwsgi-legion] --- WE HAVE QUORUM FOR LEGION %s !!! (valor: %llu uuid: %.*s checksum: %llu votes: %d) ---\n", ul->legion, best_valor, 36, best_uuid, ul->checksum, votes);
239 while (nodes) {
240 uwsgi_log("[uwsgi-legion-node] %s: %.*s valor: %llu uuid: %.*s last_seen: %d vote_valor: %llu vote_uuid: %.*s\n", nodes->valor > 0 ? "node" : "arbiter", nodes->name_len, nodes->name, nodes->valor, 36, nodes->uuid, nodes->last_seen, nodes->lord_valor, 36, nodes->lord_uuid);
241 nodes = nodes->next;
242 }
243 uwsgi_log("[uwsgi-legion] --- END OF QUORUM REPORT ---\n");
244 }
245
uwsgi_legion_checksum(struct uwsgi_legion * ul)246 uint64_t uwsgi_legion_checksum(struct uwsgi_legion *ul) {
247 uint16_t i;
248 uint64_t checksum = ul->valor;
249 for(i=0;i<36;i++) {
250 checksum += ul->uuid[i];
251 }
252
253 struct uwsgi_legion_node *nodes = ul->nodes_head;
254 while (nodes) {
255 checksum += nodes->valor;
256 for(i=0;i<36;i++) {
257 checksum += nodes->uuid[i];
258 }
259 nodes = nodes->next;
260 }
261
262 return checksum;
263
264 }
265
legions_check_nodes_step2()266 static void legions_check_nodes_step2() {
267 struct uwsgi_legion *ul = uwsgi.legions;
268 while (ul) {
269 // ok now we can check the status of the lord
270 int i_am_the_best = 0;
271 uint64_t best_valor = 0;
272 char best_uuid[36];
273 struct uwsgi_legion_node *node = uwsgi_legion_get_lord(ul);
274 if (node) {
275 // a node is the best candidate
276 best_valor = node->valor;
277 memcpy(best_uuid, node->uuid, 36);
278 }
279 // go on if i am not an arbiter
280 // no potential Lord is available, i will propose myself
281 // but only if i am not suspended...
282 else if (ul->valor > 0 && uwsgi_now() > ul->suspended_til) {
283 best_valor = ul->valor;
284 memcpy(best_uuid, ul->uuid, 36);
285 i_am_the_best = 1;
286 }
287 else {
288 // empty lord
289 memset(best_uuid, 0, 36);
290 }
291
292 // calculate the checksum
293 uint64_t new_checksum = uwsgi_legion_checksum(ul);
294 if (new_checksum != ul->checksum) {
295 ul->changed = 1;
296 }
297 ul->checksum = new_checksum;
298
299 // ... ok let's see if all of the nodes agree on the lord
300 // ... but first check if i am not alone...
301 int votes = 1;
302 struct uwsgi_legion_node *nodes = ul->nodes_head;
303 while (nodes) {
304 if (nodes->checksum != ul->checksum) {
305 votes = 0;
306 break;
307 }
308 if (nodes->lord_valor != best_valor) {
309 votes = 0;
310 break;
311 }
312 if (memcmp(nodes->lord_uuid, best_uuid, 36)) {
313 votes = 0;
314 break;
315 }
316 votes++;
317 nodes = nodes->next;
318 }
319
320 // we have quorum !!!
321 if (votes > 0 && votes >= ul->quorum) {
322 if (!ul->joined) {
323 // triggering join hooks
324 struct uwsgi_string_list *usl = ul->join_hooks;
325 while (usl) {
326 int ret = uwsgi_legion_action_call("join", ul, usl);
327 if (ret) {
328 uwsgi_log("[uwsgi-legion] ERROR, join hook returned: %d\n", ret);
329 }
330 usl = usl->next;
331 }
332 ul->joined = 1;
333 }
334 // something changed ???
335 if (ul->changed) {
336 legions_report_quorum(ul, best_valor, best_uuid, votes);
337 ul->changed = 0;
338 }
339 if (i_am_the_best) {
340 if (!ul->i_am_the_lord) {
341 // triggering lord hooks
342 uwsgi_log("[uwsgi-legion] attempting to become the Lord of the Legion %s\n", ul->legion);
343 struct uwsgi_string_list *usl = ul->lord_hooks;
344 while (usl) {
345 int ret = uwsgi_legion_action_call("lord", ul, usl);
346 if (ret) {
347 uwsgi_log("[uwsgi-legion] ERROR, lord hook returned: %d\n", ret);
348 if (uwsgi.legion_death_on_lord_error) {
349 ul->dead = 1;
350 uwsgi_legion_announce(ul);
351 ul->suspended_til = uwsgi_now() + uwsgi.legion_death_on_lord_error;
352 uwsgi_log("[uwsgi-legion] suspending myself from Legion \"%s\" for %d seconds\n", ul->legion, uwsgi.legion_death_on_lord_error);
353 goto next;
354 }
355 }
356 usl = usl->next;
357 }
358 if (ul->scroll_len > 0 && ul->scroll_len <= ul->lord_scroll_size) {
359 uwsgi_wlock(ul->lock);
360 ul->lord_scroll_len = ul->scroll_len;
361 memcpy(ul->lord_scroll, ul->scroll, ul->lord_scroll_len);
362 uwsgi_rwunlock(ul->lock);
363 }
364 else {
365 ul->lord_scroll_len = 0;
366 }
367 uwsgi_log("[uwsgi-legion] i am now the Lord of the Legion %s\n", ul->legion);
368 ul->i_am_the_lord = uwsgi_now();
369 // trick: reduce the time needed by the old lord to unlord itself
370 uwsgi_legion_announce(ul);
371 }
372 }
373 else {
374 if (ul->i_am_the_lord) {
375 uwsgi_log("[uwsgi-legion] a new Lord (valor: %llu uuid: %.*s) raised for Legion %s...\n", ul->lord_valor, 36, ul->lord_uuid, ul->legion);
376 if (ul->lord_scroll_len > 0) {
377 uwsgi_log("*********** The New Lord Scroll ***********\n");
378 uwsgi_log("%.*s\n", ul->lord_scroll_len, ul->lord_scroll);
379 uwsgi_log("*********** End of the New Lord Scroll ***********\n");
380 }
381 // no more lord, trigger unlord hooks
382 struct uwsgi_string_list *usl = ul->unlord_hooks;
383 while (usl) {
384 int ret = uwsgi_legion_action_call("unlord", ul, usl);
385 if (ret) {
386 uwsgi_log("[uwsgi-legion] ERROR, unlord hook returned: %d\n", ret);
387 }
388 usl = usl->next;
389 }
390 ul->i_am_the_lord = 0;
391 }
392 }
393 }
394 else if (votes > 0 && votes < ul->quorum && (uwsgi_now() - ul->last_warning >= 60)) {
395 uwsgi_log("[uwsgi-legion] no quorum: only %d vote(s) for Legion %s, %d needed to elect a Lord\n", votes, ul->legion, ul->quorum);
396 // no more quorum, leave the Lord state
397 if (ul->i_am_the_lord) {
398 uwsgi_log("[uwsgi-legion] i cannot be The Lord of The Legion %s without a quorum ...\n", ul->legion);
399 // no more lord, trigger unlord hooks
400 struct uwsgi_string_list *usl = ul->unlord_hooks;
401 while (usl) {
402 int ret = uwsgi_legion_action_call("unlord", ul, usl);
403 if (ret) {
404 uwsgi_log("[uwsgi-legion] ERROR, unlord hook returned: %d\n", ret);
405 }
406 usl = usl->next;
407 }
408 ul->i_am_the_lord = 0;
409 }
410 ul->last_warning = uwsgi_now();
411 }
412 next:
413 ul = ul->next;
414 }
415 }
416
417 // check who should be the lord of the legion
uwsgi_legion_get_lord(struct uwsgi_legion * ul)418 struct uwsgi_legion_node *uwsgi_legion_get_lord(struct uwsgi_legion *ul) {
419
420 char best_uuid[36];
421
422 memcpy(best_uuid, ul->uuid, 36);
423 uint64_t best_valor = ul->valor;
424
425 struct uwsgi_legion_node *best_node = NULL;
426
427 struct uwsgi_legion_node *nodes = ul->nodes_head;
428 while (nodes) {
429 // skip arbiters
430 if (nodes->valor == 0) goto next;
431 if (nodes->valor > best_valor) {
432 best_node = nodes;
433 best_valor = nodes->valor;
434 memcpy(best_uuid, nodes->uuid, 36);
435 }
436 else if (nodes->valor == best_valor) {
437 if (uwsgi_uuid_cmp(nodes->uuid, best_uuid) > 0) {
438 best_node = nodes;
439 best_valor = nodes->valor;
440 memcpy(best_uuid, nodes->uuid, 36);
441 }
442 }
443 next:
444 nodes = nodes->next;
445 }
446
447 // first round ? (skip first round if arbiter)
448 if (ul->valor > 0 && ul->lord_valor == 0) {
449 ul->changed = 1;
450 }
451 else if (best_valor != ul->lord_valor) {
452 ul->changed = 1;
453 }
454 else {
455 if (memcmp(best_uuid, ul->lord_uuid, 36)) {
456 ul->changed = 1;
457 }
458 }
459
460 ul->lord_valor = best_valor;
461 memcpy(ul->lord_uuid, best_uuid, 36);
462
463 if (!best_node) return NULL;
464
465 if (best_node->scroll_len > 0 && best_node->scroll_len <= ul->lord_scroll_size) {
466 uwsgi_wlock(ul->lock);
467 ul->lord_scroll_len = best_node->scroll_len;
468 memcpy(ul->lord_scroll, best_node->scroll, ul->lord_scroll_len);
469 uwsgi_rwunlock(ul->lock);
470 }
471 else {
472 ul->lord_scroll_len = 0;
473 }
474
475 return best_node;
476 }
477
478
legion_loop(void * foobar)479 static void *legion_loop(void *foobar) {
480
481 time_t last_round = uwsgi_now();
482
483 unsigned char *crypted_buf = uwsgi_malloc(UMAX16 - EVP_MAX_BLOCK_LENGTH - 4);
484 unsigned char *clear_buf = uwsgi_malloc(UMAX16);
485
486 struct uwsgi_legion legion_msg;
487
488 if (!uwsgi.legion_freq)
489 uwsgi.legion_freq = 3;
490 if (!uwsgi.legion_tolerance)
491 uwsgi.legion_tolerance = 15;
492 if (!uwsgi.legion_skew_tolerance)
493 uwsgi.legion_skew_tolerance = 60;
494
495 int first_round = 1;
496 for (;;) {
497 int timeout = uwsgi.legion_freq;
498 time_t now = uwsgi_now();
499 if (now > last_round) {
500 timeout -= (now - last_round);
501 if (timeout < 0) {
502 timeout = 0;
503 }
504 }
505 last_round = now;
506 // wait for event
507 int interesting_fd = -1;
508 if (uwsgi_instance_is_reloading || uwsgi_instance_is_dying) return NULL;
509 int rlen = event_queue_wait(uwsgi.legion_queue, timeout, &interesting_fd);
510
511 if (rlen < 0 && errno != EINTR) {
512 if (uwsgi_instance_is_reloading || uwsgi_instance_is_dying) return NULL;
513 uwsgi_nuclear_blast();
514 return NULL;
515 }
516
517 now = uwsgi_now();
518 if (timeout == 0 || rlen == 0 || (now - last_round) >= timeout) {
519 struct uwsgi_legion *legions = uwsgi.legions;
520 while (legions) {
521 uwsgi_legion_announce(legions);
522 legions = legions->next;
523 }
524 last_round = now;
525 }
526
527 // check the nodes
528 legions_check_nodes();
529
530 if (rlen > 0) {
531 struct uwsgi_legion *ul = uwsgi_legion_get_by_socket(interesting_fd);
532 if (!ul)
533 continue;
534 // ensure the first 4 bytes are valid
535 ssize_t len = read(ul->socket, crypted_buf, (UMAX16 - EVP_MAX_BLOCK_LENGTH - 4));
536 if (len < 0) {
537 uwsgi_error("[uwsgi-legion] read()");
538 continue;
539 }
540 else if (len < 4) {
541 uwsgi_log("[uwsgi-legion] invalid packet size: %d\n", (int) len);
542 continue;
543 }
544
545 struct uwsgi_header *uh = (struct uwsgi_header *) crypted_buf;
546
547 if (uh->modifier1 != 109) {
548 uwsgi_log("[uwsgi-legion] invalid modifier1");
549 continue;
550 }
551
552 int d_len = 0;
553 int d2_len = 0;
554 // decrypt packet using the secret
555 if (EVP_DecryptInit_ex(ul->decrypt_ctx, NULL, NULL, NULL, NULL) <= 0) {
556 uwsgi_error("[uwsgi-legion] EVP_DecryptInit_ex()");
557 continue;
558 }
559
560 if (EVP_DecryptUpdate(ul->decrypt_ctx, clear_buf, &d_len, crypted_buf + 4, len - 4) <= 0) {
561 uwsgi_error("[uwsgi-legion] EVP_DecryptUpdate()");
562 continue;
563 }
564
565 if (EVP_DecryptFinal_ex(ul->decrypt_ctx, clear_buf + d_len, &d2_len) <= 0) {
566 ERR_print_errors_fp(stderr);
567 uwsgi_log("[uwsgi-legion] EVP_DecryptFinal_ex()\n");
568 continue;
569 }
570
571 d_len += d2_len;
572
573 if (d_len != uh->pktsize) {
574 uwsgi_log("[uwsgi-legion] invalid packet size\n");
575 continue;
576 }
577
578 // parse packet
579 memset(&legion_msg, 0, sizeof(struct uwsgi_legion));
580 if (uwsgi_hooked_parse((char *) clear_buf, d_len, uwsgi_parse_legion, &legion_msg)) {
581 uwsgi_log("[uwsgi-legion] invalid packet\n");
582 continue;
583 }
584
585 if (uwsgi_strncmp(ul->legion, ul->legion_len, legion_msg.legion, legion_msg.legion_len)) {
586 uwsgi_log("[uwsgi-legion] invalid legion name\n");
587 continue;
588 }
589
590 // check for loop packets... (expecially when in multicast mode)
591 if (!uwsgi_strncmp(uwsgi.hostname, uwsgi.hostname_len, legion_msg.name, legion_msg.name_len)) {
592 if (legion_msg.pid == ul->pid) {
593 if (legion_msg.valor == ul->valor) {
594 if (!memcmp(legion_msg.uuid, ul->uuid, 36)) {
595 continue;
596 }
597 }
598 }
599 }
600
601 // check for "tolerable" unix time
602 if (legion_msg.unix_check < (uwsgi_now() - uwsgi.legion_skew_tolerance)) {
603 uwsgi_log("[uwsgi-legion] untolerable packet received for Legion %s , check your clock !!!\n", ul->legion);
604 continue;
605 }
606
607 // check if the node is already accounted
608 struct uwsgi_legion_node *node = uwsgi_legion_get_node(ul, legion_msg.valor, legion_msg.name, legion_msg.name_len, legion_msg.uuid);
609 if (!node) {
610 // if a lord hook election fails, a node can announce itself as dead for long time...
611 if (legion_msg.dead) continue;
612 // add the new node
613 uwsgi_wlock(ul->lock);
614 node = uwsgi_legion_add_node(ul, legion_msg.valor, legion_msg.name, legion_msg.name_len, legion_msg.uuid);
615 if (!node) continue;
616 if (legion_msg.scroll_len > 0) {
617 node->scroll = uwsgi_malloc(legion_msg.scroll_len);
618 node->scroll_len = legion_msg.scroll_len;
619 memcpy(node->scroll, legion_msg.scroll, node->scroll_len);
620 }
621 // we are still locked (and safe), let's rebuild the scrolls list
622 legion_rebuild_scrolls(ul);
623 uwsgi_rwunlock(ul->lock);
624 uwsgi_log("[uwsgi-legion] %s: %.*s valor: %llu uuid: %.*s joined Legion %s\n", node->valor > 0 ? "node" : "arbiter", node->name_len, node->name, node->valor, 36, node->uuid, ul->legion);
625 // trigger node_joined hooks
626 struct uwsgi_string_list *usl = ul->node_joined_hooks;
627 while (usl) {
628 int ret = uwsgi_legion_action_call("node_joined", ul, usl);
629 if (ret) {
630 uwsgi_log("[uwsgi-legion] ERROR, node_joined hook returned: %d\n", ret);
631 }
632 usl = usl->next;
633 }
634 }
635 // remove node announcing death
636 else if (legion_msg.dead) {
637 uwsgi_log("[uwsgi-legion] %s: %.*s valor: %llu uuid: %.*s announced its death to Legion %s\n", node->valor > 0 ? "node" : "arbiter", node->name_len, node->name, node->valor, 36, node->uuid, ul->legion);
638 uwsgi_wlock(ul->lock);
639 uwsgi_legion_remove_node(ul, node);
640 uwsgi_rwunlock(ul->lock);
641 continue;
642 }
643
644 node->last_seen = uwsgi_now();
645 node->lord_valor = legion_msg.lord_valor;
646 node->checksum = legion_msg.checksum;
647 memcpy(node->lord_uuid, legion_msg.lord_uuid, 36);
648
649 }
650
651 // skip the first round if i no packet is received
652 if (first_round) {
653 first_round = 0;
654 continue;
655 }
656 legions_check_nodes_step2();
657 }
658
659 return NULL;
660 }
661
uwsgi_legion_action_call(char * phase,struct uwsgi_legion * ul,struct uwsgi_string_list * usl)662 int uwsgi_legion_action_call(char *phase, struct uwsgi_legion *ul, struct uwsgi_string_list *usl) {
663 struct uwsgi_legion_action *ula = uwsgi_legion_action_get(usl->custom_ptr);
664 if (!ula) {
665 uwsgi_log("[uwsgi-legion] ERROR unable to find legion_action \"%s\"\n", (char *) usl->custom_ptr);
666 return -1;
667 }
668
669 if (ula->log_msg) {
670 uwsgi_log("[uwsgi-legion] (phase: %s legion: %s) %s\n", phase, ul->legion, ula->log_msg);
671 }
672 else {
673 uwsgi_log("[uwsgi-legion] (phase: %s legion: %s) calling %s\n", phase, ul->legion, usl->value);
674 }
675 return ula->func(ul, usl->value + usl->custom);
676 }
677
legion_action_cmd(struct uwsgi_legion * ul,char * arg)678 static int legion_action_cmd(struct uwsgi_legion *ul, char *arg) {
679 return uwsgi_run_command_and_wait(NULL, arg);
680 }
681
legion_action_signal(struct uwsgi_legion * ul,char * arg)682 static int legion_action_signal(struct uwsgi_legion *ul, char *arg) {
683 return uwsgi_signal_send(uwsgi.signal_socket, atoi(arg));
684 }
685
legion_action_log(struct uwsgi_legion * ul,char * arg)686 static int legion_action_log(struct uwsgi_legion *ul, char *arg) {
687 char *logline = uwsgi_concat2(arg, "\n");
688 uwsgi_log(logline);
689 free(logline);
690 return 0;
691 }
692
legion_action_alarm(struct uwsgi_legion * ul,char * arg)693 static int legion_action_alarm(struct uwsgi_legion *ul, char *arg) {
694 char *space = strchr(arg,' ');
695 if (!space) {
696 uwsgi_log("invalid alarm action syntax, must be: <alarm> <msg>\n");
697 return -1;
698 }
699 *space = 0;
700 uwsgi_alarm_trigger(arg, space+1, strlen(space+1));
701 *space = ' ';
702 return 0;
703 }
704
uwsgi_start_legions()705 void uwsgi_start_legions() {
706 pthread_t legion_loop_t;
707
708 if (!uwsgi.legions)
709 return;
710
711 // register embedded actions
712 uwsgi_legion_action_register("cmd", legion_action_cmd);
713 uwsgi_legion_action_register("exec", legion_action_cmd);
714 uwsgi_legion_action_register("signal", legion_action_signal);
715 uwsgi_legion_action_register("log", legion_action_log);
716 uwsgi_legion_action_register("alarm", legion_action_alarm);
717
718 uwsgi.legion_queue = event_queue_init();
719 struct uwsgi_legion *legion = uwsgi.legions;
720 while (legion) {
721 char *colon = strchr(legion->addr, ':');
722 if (colon) {
723 legion->socket = bind_to_udp(legion->addr, 0, 0);
724 }
725 else {
726 legion->socket = bind_to_unix_dgram(legion->addr);
727 }
728 if (legion->socket < 0 || event_queue_add_fd_read(uwsgi.legion_queue, legion->socket)) {
729 uwsgi_log("[uwsgi-legion] unable to activate legion %s\n", legion->legion);
730 exit(1);
731 }
732 uwsgi_socket_nb(legion->socket);
733 legion->pid = uwsgi.mypid;
734 uwsgi_uuid(legion->uuid);
735 struct uwsgi_string_list *usl = legion->setup_hooks;
736 while (usl) {
737 int ret = uwsgi_legion_action_call("setup", legion, usl);
738 if (ret) {
739 uwsgi_log("[uwsgi-legion] ERROR, setup hook returned: %d\n", ret);
740 }
741 usl = usl->next;
742 }
743 legion = legion->next;
744 }
745
746 #ifndef UWSGI_UUID
747 uwsgi_log("WARNING: you are not using libuuid to generate Legions UUID\n");
748 #endif
749
750 if (pthread_create(&legion_loop_t, NULL, legion_loop, NULL)) {
751 uwsgi_error("pthread_create()");
752 uwsgi_log("unable to run the legion server !!!\n");
753 }
754 else {
755 uwsgi_log("legion manager thread enabled\n");
756 }
757
758 }
759
uwsgi_legion_add(struct uwsgi_legion * ul)760 void uwsgi_legion_add(struct uwsgi_legion *ul) {
761 struct uwsgi_legion *old_legion = NULL, *legion = uwsgi.legions;
762 while (legion) {
763 old_legion = legion;
764 legion = legion->next;
765 }
766
767 if (old_legion) {
768 old_legion->next = ul;
769 }
770 else {
771 uwsgi.legions = ul;
772 }
773 }
774
uwsgi_legion_announce(struct uwsgi_legion * ul)775 int uwsgi_legion_announce(struct uwsgi_legion *ul) {
776 time_t now = uwsgi_now();
777
778 if (now <= ul->suspended_til) return 0;
779 ul->suspended_til = 0;
780
781 struct uwsgi_buffer *ub = uwsgi_buffer_new(4096);
782 unsigned char *encrypted = NULL;
783
784 if (uwsgi_buffer_append_keyval(ub, "legion", 6, ul->legion, ul->legion_len))
785 goto err;
786 if (uwsgi_buffer_append_keynum(ub, "valor", 5, ul->valor))
787 goto err;
788 if (uwsgi_buffer_append_keynum(ub, "unix", 4, now))
789 goto err;
790 if (uwsgi_buffer_append_keynum(ub, "lord", 4, ul->i_am_the_lord ? ul->i_am_the_lord : 0))
791 goto err;
792 if (uwsgi_buffer_append_keyval(ub, "name", 4, uwsgi.hostname, uwsgi.hostname_len))
793 goto err;
794 if (uwsgi_buffer_append_keynum(ub, "pid", 3, ul->pid))
795 goto err;
796 if (uwsgi_buffer_append_keyval(ub, "uuid", 4, ul->uuid, 36))
797 goto err;
798 if (uwsgi_buffer_append_keynum(ub, "checksum", 8, ul->checksum))
799 goto err;
800 if (uwsgi_buffer_append_keynum(ub, "lord_valor", 10, ul->lord_valor))
801 goto err;
802 if (uwsgi_buffer_append_keyval(ub, "lord_uuid", 9, ul->lord_uuid, 36))
803 goto err;
804
805 if (ul->scroll_len > 0) {
806 if (uwsgi_buffer_append_keyval(ub, "scroll", 6, ul->scroll, ul->scroll_len))
807 goto err;
808 }
809
810 if (ul->dead) {
811 if (uwsgi_buffer_append_keyval(ub, "dead", 4, "1", 1))
812 goto err;
813 }
814
815 encrypted = uwsgi_malloc(ub->pos + 4 + EVP_MAX_BLOCK_LENGTH);
816 if (EVP_EncryptInit_ex(ul->encrypt_ctx, NULL, NULL, NULL, NULL) <= 0) {
817 uwsgi_error("[uwsgi-legion] EVP_EncryptInit_ex()");
818 goto err;
819 }
820
821 int e_len = 0;
822
823 if (EVP_EncryptUpdate(ul->encrypt_ctx, encrypted + 4, &e_len, (unsigned char *) ub->buf, ub->pos) <= 0) {
824 uwsgi_error("[uwsgi-legion] EVP_EncryptUpdate()");
825 goto err;
826 }
827
828 int tmplen = 0;
829 if (EVP_EncryptFinal_ex(ul->encrypt_ctx, encrypted + 4 + e_len, &tmplen) <= 0) {
830 uwsgi_error("[uwsgi-legion] EVP_EncryptFinal_ex()");
831 goto err;
832 }
833
834 e_len += tmplen;
835 uint16_t pktsize = ub->pos;
836 encrypted[0] = 109;
837 encrypted[1] = (unsigned char) (pktsize & 0xff);
838 encrypted[2] = (unsigned char) ((pktsize >> 8) & 0xff);
839 encrypted[3] = 0;
840
841 struct uwsgi_string_list *usl = ul->nodes;
842 while (usl) {
843 if (sendto(ul->socket, encrypted, e_len + 4, 0, usl->custom_ptr, usl->custom) != e_len + 4) {
844 uwsgi_error("[uwsgi-legion] sendto()");
845 }
846 usl = usl->next;
847 }
848
849 uwsgi_buffer_destroy(ub);
850 free(encrypted);
851 return 0;
852 err:
853 uwsgi_buffer_destroy(ub);
854 free(encrypted);
855 return -1;
856 }
857
uwsgi_opt_legion_mcast(char * opt,char * value,void * foobar)858 void uwsgi_opt_legion_mcast(char *opt, char *value, void *foobar) {
859 uwsgi_opt_legion(opt, value, foobar);
860 char *legion = uwsgi_str(value);
861 char *space = strchr(legion, ' ');
862 // over engineering
863 if (!space) exit(1);
864 *space = 0;
865 struct uwsgi_legion *ul = uwsgi_legion_get_by_name(legion);
866 if (!ul) {
867 uwsgi_log("unknown legion: %s\n", legion);
868 exit(1);
869 }
870 uwsgi_legion_register_node(ul, uwsgi_str(ul->addr));
871 free(legion);
872 }
873
uwsgi_opt_legion_node(char * opt,char * value,void * foobar)874 void uwsgi_opt_legion_node(char *opt, char *value, void *foobar) {
875
876 char *legion = uwsgi_str(value);
877
878 char *space = strchr(legion, ' ');
879 if (!space) {
880 uwsgi_log("invalid legion-node syntax, must be <legion> <addr>\n");
881 exit(1);
882 }
883 *space = 0;
884
885 struct uwsgi_legion *ul = uwsgi_legion_get_by_name(legion);
886 if (!ul) {
887 uwsgi_log("unknown legion: %s\n", legion);
888 exit(1);
889 }
890
891 uwsgi_legion_register_node(ul, space + 1);
892
893 }
894
uwsgi_legion_register_node(struct uwsgi_legion * ul,char * addr)895 void uwsgi_legion_register_node(struct uwsgi_legion *ul, char *addr) {
896 struct uwsgi_string_list *usl = uwsgi_string_new_list(&ul->nodes, addr);
897 char *port = strchr(addr, ':');
898 if (!port) {
899 uwsgi_log("[uwsgi-legion] invalid udp address: %s\n", addr);
900 exit(1);
901 }
902 // no need to zero the memory, socket_to_in_addr will do that
903 struct sockaddr_in *sin = uwsgi_malloc(sizeof(struct sockaddr_in));
904 usl->custom = socket_to_in_addr(addr, port, 0, sin);
905 usl->custom_ptr = sin;
906 }
907
uwsgi_opt_legion_quorum(char * opt,char * value,void * foobar)908 void uwsgi_opt_legion_quorum(char *opt, char *value, void *foobar) {
909
910 char *legion = uwsgi_str(value);
911
912 char *space = strchr(legion, ' ');
913 if (!space) {
914 uwsgi_log("invalid legion-quorum syntax, must be <legion> <quorum>\n");
915 exit(1);
916 }
917 *space = 0;
918
919 struct uwsgi_legion *ul = uwsgi_legion_get_by_name(legion);
920 if (!ul) {
921 uwsgi_log("unknown legion: %s\n", legion);
922 exit(1);
923 }
924
925 ul->quorum = atoi(space+1);
926 free(legion);
927 }
928
uwsgi_opt_legion_scroll(char * opt,char * value,void * foobar)929 void uwsgi_opt_legion_scroll(char *opt, char *value, void *foobar) {
930
931 char *legion = uwsgi_str(value);
932
933 char *space = strchr(legion, ' ');
934 if (!space) {
935 uwsgi_log("invalid legion-scroll syntax, must be <legion> <scroll>\n");
936 exit(1);
937 }
938 *space = 0;
939
940 struct uwsgi_legion *ul = uwsgi_legion_get_by_name(legion);
941 if (!ul) {
942 uwsgi_log("unknown legion: %s\n", legion);
943 exit(1);
944 }
945
946 ul->scroll = space+1;
947 ul->scroll_len = strlen(ul->scroll);
948 // DO NOT FREE IT !!!
949 //free(legion);
950 }
951
952
953
uwsgi_opt_legion_hook(char * opt,char * value,void * foobar)954 void uwsgi_opt_legion_hook(char *opt, char *value, void *foobar) {
955
956 char *event = strchr(opt, '-');
957 if (!event) {
958 uwsgi_log("[uwsgi-legion] invalid option name (%s), this should not happen (possible bug)\n", opt);
959 exit(1);
960 }
961
962 char *legion = uwsgi_str(value);
963
964 char *space = strchr(legion, ' ');
965 if (!space) {
966 uwsgi_log("[uwsgi-legion] invalid %s syntax, must be <legion> <action>\n", opt);
967 exit(1);
968 }
969 *space = 0;
970
971 struct uwsgi_legion *ul = uwsgi_legion_get_by_name(legion);
972 if (!ul) {
973 uwsgi_log("[uwsgi-legion] unknown legion: %s\n", legion);
974 exit(1);
975 }
976
977 uwsgi_legion_register_hook(ul, event + 1, space + 1);
978 }
979
uwsgi_legion_register_hook(struct uwsgi_legion * ul,char * event,char * action)980 void uwsgi_legion_register_hook(struct uwsgi_legion *ul, char *event, char *action) {
981
982 struct uwsgi_string_list *usl = NULL;
983
984 if (!strcmp(event, "lord")) {
985 usl = uwsgi_string_new_list(&ul->lord_hooks, action);
986 }
987 else if (!strcmp(event, "unlord")) {
988 usl = uwsgi_string_new_list(&ul->unlord_hooks, action);
989 }
990 else if (!strcmp(event, "setup")) {
991 usl = uwsgi_string_new_list(&ul->setup_hooks, action);
992 }
993 else if (!strcmp(event, "death")) {
994 usl = uwsgi_string_new_list(&ul->death_hooks, action);
995 }
996 else if (!strcmp(event, "join")) {
997 usl = uwsgi_string_new_list(&ul->join_hooks, action);
998 }
999 else if (!strcmp(event, "node-joined")) {
1000 usl = uwsgi_string_new_list(&ul->node_joined_hooks, action);
1001 }
1002 else if (!strcmp(event, "node-left")) {
1003 usl = uwsgi_string_new_list(&ul->node_left_hooks, action);
1004 }
1005
1006 else {
1007 uwsgi_log("[uwsgi-legion] invalid event: %s\n", event);
1008 exit(1);
1009 }
1010
1011 if (!usl)
1012 return;
1013
1014 char *hook = strchr(action, ':');
1015 if (!hook) {
1016 uwsgi_log("[uwsgi-legion] invalid %s action: %s\n", event, action);
1017 exit(1);
1018 }
1019
1020 // pointer to action plugin
1021 usl->custom_ptr = uwsgi_concat2n(action, hook - action, "", 0);;
1022 // add that to check the plugin value
1023 usl->custom = hook - action + 1;
1024
1025 }
1026
uwsgi_opt_legion(char * opt,char * value,void * foobar)1027 void uwsgi_opt_legion(char *opt, char *value, void *foobar) {
1028
1029 // legion addr valor algo:secret
1030 char *legion = uwsgi_str(value);
1031 char *space = strchr(legion, ' ');
1032 if (!space) {
1033 uwsgi_log("invalid legion syntax, must be <legion> <addr> <valor> <algo:secret>\n");
1034 exit(1);
1035 }
1036 *space = 0;
1037 char *addr = space + 1;
1038
1039 space = strchr(addr, ' ');
1040 if (!space) {
1041 uwsgi_log("invalid legion syntax, must be <legion> <addr> <valor> <algo:secret>\n");
1042 exit(1);
1043 }
1044 *space = 0;
1045 char *valor = space + 1;
1046
1047 space = strchr(valor, ' ');
1048 if (!space) {
1049 uwsgi_log("invalid legion syntax, must be <legion> <addr> <valor> <algo:secret>\n");
1050 exit(1);
1051 }
1052 *space = 0;
1053 char *algo_secret = space + 1;
1054
1055 char *colon = strchr(algo_secret, ':');
1056 if (!colon) {
1057 uwsgi_log("invalid legion syntax, must be <legion> <addr> <valor> <algo:secret>\n");
1058 exit(1);
1059 }
1060 *colon = 0;
1061 char *secret = colon + 1;
1062
1063 uwsgi_legion_register(legion, addr, valor, algo_secret, secret);
1064 }
1065
uwsgi_legion_register(char * legion,char * addr,char * valor,char * algo,char * secret)1066 struct uwsgi_legion *uwsgi_legion_register(char *legion, char *addr, char *valor, char *algo, char *secret) {
1067 char *iv = strchr(secret, ' ');
1068 if (iv) {
1069 *iv = 0;
1070 iv++;
1071 }
1072
1073 if (!uwsgi.ssl_initialized) {
1074 uwsgi_ssl_init();
1075 }
1076
1077 #if OPENSSL_VERSION_NUMBER < 0x10100000L
1078 EVP_CIPHER_CTX *ctx = uwsgi_malloc(sizeof(EVP_CIPHER_CTX));
1079 EVP_CIPHER_CTX_init(ctx);
1080 #else
1081 EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
1082 #endif
1083
1084 const EVP_CIPHER *cipher = EVP_get_cipherbyname(algo);
1085 if (!cipher) {
1086 uwsgi_log("[uwsgi-legion] unable to find algorithm/cipher %s\n", algo);
1087 exit(1);
1088 }
1089
1090 int cipher_len = EVP_CIPHER_key_length(cipher);
1091 size_t s_len = strlen(secret);
1092 if ((unsigned int) cipher_len > s_len) {
1093 char *secret_tmp = uwsgi_malloc(cipher_len);
1094 memcpy(secret_tmp, secret, s_len);
1095 memset(secret_tmp + s_len, 0, cipher_len - s_len);
1096 secret = secret_tmp;
1097 }
1098
1099 int iv_len = EVP_CIPHER_iv_length(cipher);
1100 size_t s_iv_len = 0;
1101 if (iv) {
1102 s_iv_len = strlen(iv);
1103 }
1104 if ((unsigned int) iv_len > s_iv_len) {
1105 char *secret_tmp = uwsgi_malloc(iv_len);
1106 memcpy(secret_tmp, iv, s_iv_len);
1107 memset(secret_tmp + s_iv_len, '0', iv_len - s_iv_len);
1108 iv = secret_tmp;
1109 }
1110
1111 if (EVP_EncryptInit_ex(ctx, cipher, NULL, (const unsigned char *) secret, (const unsigned char *) iv) <= 0) {
1112 uwsgi_error("EVP_EncryptInit_ex()");
1113 exit(1);
1114 }
1115
1116 #if OPENSSL_VERSION_NUMBER < 0x10100000L
1117 EVP_CIPHER_CTX *ctx2 = uwsgi_malloc(sizeof(EVP_CIPHER_CTX));
1118 EVP_CIPHER_CTX_init(ctx2);
1119 #else
1120 EVP_CIPHER_CTX *ctx2 = EVP_CIPHER_CTX_new();
1121 #endif
1122
1123 if (EVP_DecryptInit_ex(ctx2, cipher, NULL, (const unsigned char *) secret, (const unsigned char *) iv) <= 0) {
1124 uwsgi_error("EVP_DecryptInit_ex()");
1125 exit(1);
1126 }
1127
1128 // we use shared memory, as we want to export legion status to the api
1129 struct uwsgi_legion *ul = uwsgi_calloc_shared(sizeof(struct uwsgi_legion));
1130 ul->legion = legion;
1131 ul->legion_len = strlen(ul->legion);
1132
1133 ul->valor = strtol(valor, (char **) NULL, 10);
1134 ul->addr = addr;
1135
1136 ul->encrypt_ctx = ctx;
1137 ul->decrypt_ctx = ctx2;
1138
1139 if (!uwsgi.legion_scroll_max_size) {
1140 uwsgi.legion_scroll_max_size = 4096;
1141 }
1142
1143 if (!uwsgi.legion_scroll_list_max_size) {
1144 uwsgi.legion_scroll_list_max_size = 32768;
1145 }
1146
1147 ul->lord_scroll_size = uwsgi.legion_scroll_max_size;
1148 ul->lord_scroll = uwsgi_calloc_shared(ul->lord_scroll_size);
1149 ul->scrolls_max_size = uwsgi.legion_scroll_list_max_size;
1150 ul->scrolls = uwsgi_calloc_shared(ul->scrolls_max_size);
1151
1152 uwsgi_legion_add(ul);
1153
1154 return ul;
1155 }
1156
uwsgi_legion_action_get(char * name)1157 struct uwsgi_legion_action *uwsgi_legion_action_get(char *name) {
1158 struct uwsgi_legion_action *ula = uwsgi.legion_actions;
1159 while (ula) {
1160 if (!strcmp(name, ula->name)) {
1161 return ula;
1162 }
1163 ula = ula->next;
1164 }
1165 return NULL;
1166 }
1167
uwsgi_legion_action_register(char * name,int (* func)(struct uwsgi_legion *,char *))1168 struct uwsgi_legion_action *uwsgi_legion_action_register(char *name, int (*func) (struct uwsgi_legion *, char *)) {
1169 struct uwsgi_legion_action *found_ula = uwsgi_legion_action_get(name);
1170 if (found_ula) {
1171 uwsgi_log("[uwsgi-legion] action \"%s\" is already registered !!!\n", name);
1172 return found_ula;
1173 }
1174
1175 struct uwsgi_legion_action *old_ula = NULL, *ula = uwsgi.legion_actions;
1176 while (ula) {
1177 old_ula = ula;
1178 ula = ula->next;
1179 }
1180
1181 ula = uwsgi_calloc(sizeof(struct uwsgi_legion_action));
1182 ula->name = name;
1183 ula->func = func;
1184
1185 if (old_ula) {
1186 old_ula->next = ula;
1187 }
1188 else {
1189 uwsgi.legion_actions = ula;
1190 }
1191
1192 return ula;
1193 }
1194
uwsgi_legion_announce_death(void)1195 void uwsgi_legion_announce_death(void) {
1196 struct uwsgi_legion *legion = uwsgi.legions;
1197 while (legion) {
1198 legion->dead = 1;
1199 uwsgi_legion_announce(legion);
1200 legion = legion->next;
1201 }
1202 }
1203
uwsgi_legion_atexit(void)1204 void uwsgi_legion_atexit(void) {
1205 struct uwsgi_legion *legion = uwsgi.legions;
1206 while (legion) {
1207 if (getpid() != legion->pid)
1208 goto next;
1209 struct uwsgi_string_list *usl = legion->death_hooks;
1210 while (usl) {
1211 int ret = uwsgi_legion_action_call("death", legion, usl);
1212 if (ret) {
1213 uwsgi_log("[uwsgi-legion] ERROR, death hook returned: %d\n", ret);
1214 }
1215 usl = usl->next;
1216 }
1217 next:
1218 legion = legion->next;
1219 }
1220
1221 // this must be called only by the master !!!
1222 if (!uwsgi.workers) return;
1223 if (uwsgi.workers[0].pid != getpid()) return;
1224 uwsgi_legion_announce_death();
1225 }
1226
uwsgi_legion_i_am_the_lord(char * name)1227 int uwsgi_legion_i_am_the_lord(char *name) {
1228 struct uwsgi_legion *legion = uwsgi_legion_get_by_name(name);
1229 if (!legion) return 0;
1230 if (legion->i_am_the_lord) {
1231 return 1;
1232 }
1233 return 0;
1234 }
1235
uwsgi_legion_lord_scroll(char * name,uint16_t * rlen)1236 char *uwsgi_legion_lord_scroll(char *name, uint16_t *rlen) {
1237 char *buf = NULL;
1238 struct uwsgi_legion *legion = uwsgi_legion_get_by_name(name);
1239 if (!legion) return 0;
1240 uwsgi_rlock(legion->lock);
1241 if (legion->lord_scroll_len > 0) {
1242 buf = uwsgi_malloc(legion->lord_scroll_len);
1243 memcpy(buf, legion->lord_scroll, legion->lord_scroll_len);
1244 *rlen = legion->lord_scroll_len;
1245 }
1246 uwsgi_rwunlock(legion->lock);
1247 return buf;
1248 }
1249
uwsgi_legion_scrolls(char * name,uint64_t * rlen)1250 char *uwsgi_legion_scrolls(char *name, uint64_t *rlen) {
1251 char *buf = NULL;
1252 struct uwsgi_legion *legion = uwsgi_legion_get_by_name(name);
1253 if (!legion) return NULL;
1254 uwsgi_rlock(legion->lock);
1255 buf = uwsgi_malloc(legion->scrolls_len);
1256 memcpy(buf, legion->scrolls, legion->scrolls_len);
1257 *rlen = legion->scrolls_len;
1258 uwsgi_rwunlock(legion->lock);
1259 return buf;
1260 }
1261