-
Notifications
You must be signed in to change notification settings - Fork 16
Expand file tree
/
Copy pathmod_manager.c
More file actions
4129 lines (3672 loc) · 138 KB
/
mod_manager.c
File metadata and controls
4129 lines (3672 loc) · 138 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/*
* Copyright The mod_cluster Project Authors
* SPDX-License-Identifier: Apache-2.0
*/
/*
* @author Jean-Frederic Clere
*/
#include "domain.h"
#include "common.h"
#include "apr_lib.h"
#include "apr_uuid.h"
#define CORE_PRIVATE
#include "httpd.h"
#include "scoreboard.h"
#include "sessionid.h"
#define DEFMAXCONTEXT 100
#define DEFMAXNODE 20
#define DEFMAXHOST 20
#define DEFMAXSESSIONID 0 /* it has performance/security impact */
#define MAXMESSSIZE 1024
/* Warning messages */
#define SBALBAD "Balancer name contained an upper case character. We will use \"%s\" instead."
/* Error messages */
#define TYPESYNTAX 1
#define SMESPAR "SYNTAX: Can't parse MCMP message. It might have contained illegal symbols or unknown elements."
#define SBALBIG "SYNTAX: Balancer field too big"
#define SBAFBIG "SYNTAX: A field is too big"
#define SROUBIG "SYNTAX: JVMRoute field too big"
#define SROUBAD "SYNTAX: JVMRoute can't be empty"
#define SDOMBIG "SYNTAX: LBGroup field too big"
#define SHOSBIG "SYNTAX: Host field too big"
#define SPORBIG "SYNTAX: Port field too big"
#define STYPBIG "SYNTAX: Type field too big"
#define SALIBIG "SYNTAX: Alias field too big"
#define SCONBIG "SYNTAX: Context field too big"
#define SFLUBAD "SYNTAX: Flushwait field has bad value"
#define SPNGBAD "SYNTAX: Ping field has bad value"
#define STTLBAD "SYNTAX: TTL field has bad value"
#define STIMBAD "SYNTAX: Timeout field has bad value"
#define SALIBAD "SYNTAX: Alias without Context"
#define SCONBAD "SYNTAX: Context without Alias"
#define NOCONAL "SYNTAX: No Context and Alias in APP command"
#define SBADFLD "SYNTAX: Invalid field \"%s\" in message"
#define SMISFLD "SYNTAX: Mandatory field(s) missing in message"
#define SCMDUNS "SYNTAX: Command is not supported"
#define SMULALB "SYNTAX: Only one Alias in APP command"
#define SMULCTB "SYNTAX: Only one Context in APP command"
#define SREADER "SYNTAX: %s can't read POST data"
#define TYPEMEM 2
#define MNODEUI "MEM: Can't update or insert node with \"%s\" JVMRoute"
#define MNODERM "MEM: Old node with \"%s\" JVMRoute still exists"
#define MBALAUI "MEM: Can't update or insert balancer for node with \"%s\" JVMRoute"
#define MNODERD "MEM: Can't read node with \"%s\" JVMRoute"
#define MHOSTRD "MEM: Can't read host alias for node with \"%s\" JVMRoute"
#define MHOSTUI "MEM: Can't update or insert host alias for node with \"%s\" JVMRoute"
#define MCONTUI "MEM: Can't update or insert context for node with \"%s\" JVMRoute"
#define MNODEET "MEM: Another for the same worker already exist"
/* Protocol version supported */
#define VERSION_PROTOCOL "0.2.1"
/* Internal substitution for node commands */
#define NODE_COMMAND "/NODE_COMMAND"
/* range of the commands */
#define RANGECONTEXT 0
#define RANGENODE 1
#define RANGEDOMAIN 2
/* define content-type */
#define TEXT_PLAIN 1
#define TEXT_XML 2
#define PLAINTEXT_CONTENT_TYPE "text/plain"
#define XML_CONTENT_TYPE "text/xml"
/* Data structure for shared memory block */
typedef struct version_data
{
apr_uint64_t counter;
} version_data;
/* mutex and lock for tables/slotmen */
static apr_global_mutex_t *node_mutex;
static apr_global_mutex_t *context_mutex;
static const char *node_mutex_type = "node-shm";
static const char *context_mutex_type = "context-shm";
/* counter for the version (nodes) */
static ap_slotmem_instance_t *version_node_mem = NULL;
/* shared memory */
static mem_t *contextstatsmem = NULL;
static mem_t *nodestatsmem = NULL;
static mem_t *hoststatsmem = NULL;
static mem_t *balancerstatsmem = NULL;
static mem_t *sessionidstatsmem = NULL;
static mem_t *domainstatsmem = NULL;
/* Used for HCExpr templates with lbmethod_cluster */
static apr_table_t *proxyhctemplate = NULL;
static void set_proxyhctemplate(apr_pool_t *p, apr_table_t *t)
{
proxyhctemplate = apr_table_overlay(p, t, proxyhctemplate);
}
static slotmem_storage_method *storage = NULL;
static balancer_method *balancerhandler = NULL;
static void (*advertise_info)(request_rec *) = NULL;
static APR_OPTIONAL_FN_TYPE(balancer_manage) *balancer_manage = NULL;
module AP_MODULE_DECLARE_DATA manager_module;
static char balancer_nonce[APR_UUID_FORMATTED_LENGTH + 1];
typedef struct mod_manager_config
{
/* base name for the shared memory */
char *basefilename;
/* max number of context supported */
unsigned maxcontext;
/* max number of node supported */
unsigned maxnode;
/* max number of host supported */
unsigned maxhost;
/* max number of session supported */
unsigned maxsessionid;
/* version, the version is increased each time the node update logic is called */
unsigned tableversion;
/* Should be the slotmem persisted (1) or not (0) */
int persistent;
/* check for nonce in the command logic */
int nonce;
/* default name for balancer */
char *balancername;
/* allow aditional display */
int allow_display;
/* allow command logic */
int allow_cmd;
/* don't context in first status page */
int reduce_display;
/* maximum message size */
int maxmesssize;
/* Enable MCMP receiver */
int enable_mcmp_receive;
/* Enable WebSocket Proxy */
int enable_ws_tunnel;
/* WebSocket upgrade header */
char *ws_upgrade_header;
/* AJP secret */
char *ajp_secret;
/* size of the proxy response field buffer */
long response_field_size;
} mod_manager_config;
/* routines for the node_storage_method */
static apr_status_t loc_read_node(int ids, nodeinfo_t **node)
{
return get_node(nodestatsmem, node, ids);
}
static int loc_get_ids_used_node(int *ids)
{
return get_ids_used_node(nodestatsmem, ids);
}
static int loc_get_max_size_node(void)
{
return nodestatsmem ? get_max_size_node(nodestatsmem) : 0;
}
static apr_status_t loc_remove_node(int id)
{
return remove_node(nodestatsmem, id);
}
static apr_status_t loc_find_node(nodeinfo_t **node, const char *route)
{
return find_node(nodestatsmem, node, route);
}
/**
* Increase the version of the nodes table
*/
static void inc_version_node(void)
{
version_data *base;
if (storage->dptr(version_node_mem, 0, (void **)&base) == APR_SUCCESS) {
base->counter++;
}
}
static apr_uint64_t get_version_node(void)
{
version_data *base;
if (storage->dptr(version_node_mem, 0, (void **)&base) == APR_SUCCESS) {
return base->counter;
}
return 0;
}
static void set_version_node(apr_uint64_t val)
{
version_data *base;
if (storage->dptr(version_node_mem, 0, (void **)&base) == APR_SUCCESS) {
base->counter = val;
}
}
/**
* Check is the nodes (in shared memory) were modified since last
* call to worker_nodes_are_updated().
*
* @param data server_rec
* @param pool unused argument
* @return 0 (no update) or X (the version has changed, the local table needs to be updated)
*/
static unsigned loc_worker_nodes_need_update(void *data, apr_pool_t *pool)
{
int size;
server_rec *s = (server_rec *)data;
unsigned last = 0;
mod_manager_config *mconf = ap_get_module_config(s->module_config, &manager_module);
(void)pool;
size = loc_get_max_size_node();
if (size == 0) {
return 0; /* broken */
}
last = get_version_node();
if (last != mconf->tableversion) {
return last;
}
return 0;
}
/**
* Store the last version update in the proccess config
*/
static int loc_worker_nodes_are_updated(void *data, unsigned last)
{
server_rec *s = (server_rec *)data;
mod_manager_config *mconf = ap_get_module_config(s->module_config, &manager_module);
mconf->tableversion = last;
return 0;
}
static apr_status_t loc_lock_nodes(void)
{
return apr_global_mutex_lock(node_mutex);
}
static apr_status_t loc_unlock_nodes(void)
{
return apr_global_mutex_unlock(node_mutex);
}
static int loc_get_max_size_context(void)
{
return contextstatsmem ? get_max_size_context(contextstatsmem) : 0;
}
static int loc_get_max_size_host(void)
{
return hoststatsmem ? get_max_size_host(hoststatsmem) : 0;
}
/**
* Remove the virtual hosts and contexts corresponding the node
*/
static void loc_remove_host_context(int node, apr_pool_t *pool)
{
/* for read the hosts */
int i;
int size = loc_get_max_size_host();
int *id;
int sizecontext = loc_get_max_size_context();
int *idcontext;
if (size == 0) {
return;
}
id = apr_palloc(pool, sizeof(int) * size);
idcontext = apr_palloc(pool, sizeof(int) * sizecontext);
size = get_ids_used_host(hoststatsmem, id);
for (i = 0; i < size; i++) {
hostinfo_t *ou;
if (get_host(hoststatsmem, &ou, id[i]) != APR_SUCCESS) {
continue;
}
if (ou->node == node) {
remove_host(hoststatsmem, ou->id);
}
}
sizecontext = get_ids_used_context(contextstatsmem, idcontext);
for (i = 0; i < sizecontext; i++) {
contextinfo_t *context;
if (get_context(contextstatsmem, &context, idcontext[i]) != APR_SUCCESS) {
continue;
}
if (context->node == node) {
remove_context(contextstatsmem, context->id);
}
}
}
static const struct node_storage_method node_storage = {
loc_read_node,
loc_get_ids_used_node,
loc_get_max_size_node,
loc_worker_nodes_need_update,
loc_worker_nodes_are_updated,
loc_remove_node,
loc_find_node,
loc_remove_host_context,
loc_lock_nodes,
loc_unlock_nodes,
};
/*
* routines for the context_storage_method
*/
static apr_status_t loc_read_context(int ids, contextinfo_t **context)
{
return get_context(contextstatsmem, context, ids);
}
static int loc_get_ids_used_context(int *ids)
{
return get_ids_used_context(contextstatsmem, ids);
}
static apr_status_t loc_lock_contexts(void)
{
return apr_global_mutex_lock(context_mutex);
}
static apr_status_t loc_unlock_contexts(void)
{
return apr_global_mutex_unlock(context_mutex);
}
/* clang-format off */
static const struct context_storage_method context_storage = {
loc_read_context,
loc_get_ids_used_context,
loc_get_max_size_context,
loc_lock_contexts,
loc_unlock_contexts
};
/* clang-format on */
/*
* routines for the host_storage_method
*/
static apr_status_t loc_read_host(int ids, hostinfo_t **host)
{
return get_host(hoststatsmem, host, ids);
}
static int loc_get_ids_used_host(int *ids)
{
return get_ids_used_host(hoststatsmem, ids);
}
static const struct host_storage_method host_storage = {
loc_read_host,
loc_get_ids_used_host,
loc_get_max_size_host,
};
/*
* routines for the balancer_storage_method
*/
static apr_status_t loc_read_balancer(int ids, balancerinfo_t **balancer)
{
return get_balancer(balancerstatsmem, balancer, ids);
}
static int loc_get_ids_used_balancer(int *ids)
{
return get_ids_used_balancer(balancerstatsmem, ids);
}
static int loc_get_max_size_balancer(void)
{
return balancerstatsmem ? get_max_size_balancer(balancerstatsmem) : 0;
}
static const struct balancer_storage_method balancer_storage = {
loc_read_balancer,
loc_get_ids_used_balancer,
loc_get_max_size_balancer,
};
/*
* routines for the sessionid_storage_method
*/
static apr_status_t loc_read_sessionid(int ids, sessionidinfo_t **sessionid)
{
return get_sessionid(sessionidstatsmem, sessionid, ids);
}
static int loc_get_ids_used_sessionid(int *ids)
{
return get_ids_used_sessionid(sessionidstatsmem, ids);
}
static int loc_get_max_size_sessionid(void)
{
return sessionidstatsmem ? get_max_size_sessionid(sessionidstatsmem) : 0;
}
static apr_status_t loc_remove_sessionid(sessionidinfo_t *sessionid)
{
return remove_sessionid(sessionidstatsmem, sessionid);
}
static apr_status_t loc_insert_update_sessionid(sessionidinfo_t *sessionid)
{
return insert_update_sessionid(sessionidstatsmem, sessionid);
}
static const struct sessionid_storage_method sessionid_storage = {
loc_read_sessionid, loc_get_ids_used_sessionid, loc_get_max_size_sessionid,
loc_remove_sessionid, loc_insert_update_sessionid,
};
/*
* routines for the domain_storage_method
*/
static apr_status_t loc_read_domain(int ids, domaininfo_t **domain)
{
return get_domain(domainstatsmem, domain, ids);
}
static int loc_get_ids_used_domain(int *ids)
{
return get_ids_used_domain(domainstatsmem, ids);
}
static int loc_get_max_size_domain(void)
{
return domainstatsmem ? get_max_size_domain(domainstatsmem) : 0;
}
static apr_status_t loc_remove_domain(domaininfo_t *domain)
{
return remove_domain(domainstatsmem, domain);
}
static apr_status_t loc_insert_update_domain(domaininfo_t *domain)
{
return insert_update_domain(domainstatsmem, domain);
}
static apr_status_t loc_find_domain(domaininfo_t **domain, const char *route, const char *balancer)
{
return find_domain(domainstatsmem, domain, route, balancer);
}
/* clang-format off */
static const struct domain_storage_method domain_storage = {
loc_read_domain,
loc_get_ids_used_domain,
loc_get_max_size_domain,
loc_remove_domain,
loc_insert_update_domain,
loc_find_domain,
};
/* clang-format on */
/*
* cleanup logic
*/
static apr_status_t cleanup_manager(void *param)
{
/* shared memory */
contextstatsmem = NULL;
nodestatsmem = NULL;
hoststatsmem = NULL;
balancerstatsmem = NULL;
sessionidstatsmem = NULL;
domainstatsmem = NULL;
version_node_mem = NULL;
(void)param;
return APR_SUCCESS;
}
static void mc_initialize_cleanup(apr_pool_t *p)
{
apr_pool_cleanup_register(p, NULL, cleanup_manager, apr_pool_cleanup_null);
}
static void normalize_balancer_name(char *balancer_name, const server_rec *s)
{
int upper_case_char_found = 0;
char *balancer_name_start = balancer_name;
for (; *balancer_name; ++balancer_name) {
if (!upper_case_char_found) {
upper_case_char_found = apr_isupper(*balancer_name);
}
*balancer_name = apr_tolower(*balancer_name);
}
balancer_name = balancer_name_start;
if (upper_case_char_found) {
ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, s, SBALBAD, balancer_name);
}
}
/*
* This routine is called in the parent; we must register our
* mutex type before the config is processed so that users can
* adjust the mutex settings using the Mutex directive.
*/
static int manager_pre_config(apr_pool_t *pconf, apr_pool_t *plog, apr_pool_t *ptemp)
{
(void)plog;
(void)ptemp;
ap_mutex_register(pconf, node_mutex_type, NULL, APR_LOCK_DEFAULT, 0);
ap_mutex_register(pconf, context_mutex_type, NULL, APR_LOCK_DEFAULT, 0);
proxyhctemplate = apr_table_make(plog, 1);
return OK;
}
/*
* Call after parser the configuration.
* Creates the shared memory.
*/
static int manager_init(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp, server_rec *s)
{
char *node;
char *context;
char *host;
char *balancer;
char *sessionid;
char *domain;
char *version;
apr_uuid_t uuid;
mod_manager_config *mconf = ap_get_module_config(s->module_config, &manager_module);
apr_status_t rv;
(void)plog; /* unused variable */
if (ap_state_query(AP_SQ_MAIN_STATE) == AP_SQ_MS_CREATE_PRE_CONFIG) {
return OK;
}
if (mconf->basefilename) {
node = apr_pstrcat(ptemp, mconf->basefilename, "/manager.node", NULL);
context = apr_pstrcat(ptemp, mconf->basefilename, "/manager.context", NULL);
host = apr_pstrcat(ptemp, mconf->basefilename, "/manager.host", NULL);
balancer = apr_pstrcat(ptemp, mconf->basefilename, "/manager.balancer", NULL);
sessionid = apr_pstrcat(ptemp, mconf->basefilename, "/manager.sessionid", NULL);
domain = apr_pstrcat(ptemp, mconf->basefilename, "/manager.domain", NULL);
version = apr_pstrcat(ptemp, mconf->basefilename, "/manager.version", NULL);
} else {
node = ap_server_root_relative(ptemp, "logs/manager.node");
context = ap_server_root_relative(ptemp, "logs/manager.context");
host = ap_server_root_relative(ptemp, "logs/manager.host");
balancer = ap_server_root_relative(ptemp, "logs/manager.balancer");
sessionid = ap_server_root_relative(ptemp, "logs/manager.sessionid");
domain = ap_server_root_relative(ptemp, "logs/manager.domain");
version = ap_server_root_relative(ptemp, "logs/manager.version");
}
/* Do some sanity checks */
if (mconf->maxhost < mconf->maxnode) {
ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, s, "manager_init: Maxhost value increased to Maxnode (%d)",
mconf->maxnode);
mconf->maxhost = mconf->maxnode;
}
if (mconf->maxcontext < mconf->maxhost) {
ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, s, "manager_init: Maxcontext value increased to Maxhost (%d)",
mconf->maxhost);
mconf->maxcontext = mconf->maxhost;
}
/* Get a provider to handle the shared memory */
storage = ap_lookup_provider(AP_SLOTMEM_PROVIDER_GROUP, "shm", AP_SLOTMEM_PROVIDER_VERSION);
if (storage == NULL) {
ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, "manager_init: ap_lookup_provider %s failed",
AP_SLOTMEM_PROVIDER_GROUP);
return !OK;
}
nodestatsmem = create_mem_node(node, &mconf->maxnode, mconf->persistent + AP_SLOTMEM_TYPE_PREGRAB, p, storage);
if (nodestatsmem == NULL) {
ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, "manager_init: create_mem_node %s failed", node);
return !OK;
}
if (get_last_mem_error(nodestatsmem) != APR_SUCCESS) {
char buf[120];
ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, "manager_init: create_mem_node %s failed: %s", node,
apr_strerror(get_last_mem_error(nodestatsmem), buf, sizeof(buf)));
return !OK;
}
contextstatsmem =
create_mem_context(context, &mconf->maxcontext, mconf->persistent + AP_SLOTMEM_TYPE_PREGRAB, p, storage);
if (contextstatsmem == NULL) {
ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, "manager_init: create_mem_context failed");
return !OK;
}
hoststatsmem = create_mem_host(host, &mconf->maxhost, mconf->persistent + AP_SLOTMEM_TYPE_PREGRAB, p, storage);
if (hoststatsmem == NULL) {
ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, "manager_init: create_mem_host failed");
return !OK;
}
balancerstatsmem =
create_mem_balancer(balancer, &mconf->maxhost, mconf->persistent + AP_SLOTMEM_TYPE_PREGRAB, p, storage);
if (balancerstatsmem == NULL) {
ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, "manager_init: create_mem_balancer failed");
return !OK;
}
if (mconf->maxsessionid) {
/* Only create sessionid stuff if required */
sessionidstatsmem = create_mem_sessionid(sessionid, &mconf->maxsessionid,
mconf->persistent + AP_SLOTMEM_TYPE_PREGRAB, p, storage);
if (sessionidstatsmem == NULL) {
ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, "manager_init: create_mem_sessionid failed");
return !OK;
}
}
domainstatsmem =
create_mem_domain(domain, &mconf->maxnode, mconf->persistent + AP_SLOTMEM_TYPE_PREGRAB, p, storage);
if (domainstatsmem == NULL) {
ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, "manager_init: create_mem_domain failed");
return !OK;
}
/* For the version node we just need a apr_uint64_t in shared memory */
rv = storage->create(&version_node_mem, version, sizeof(apr_uint64_t), 1, AP_SLOTMEM_TYPE_PREGRAB, p);
if (rv != APR_SUCCESS) {
ap_log_error(APLOG_MARK, APLOG_EMERG, rv, s, "manager_init: create_share_version failed");
return !OK;
}
set_version_node(0);
/* Get a provider to ping/pong logics */
balancerhandler = ap_lookup_provider("proxy_cluster", "balancer", "0");
if (balancerhandler == NULL) {
ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s, "manager_init: can't find a ping/pong logic");
}
advertise_info = ap_lookup_provider("advertise", "info", "0");
balancer_manage = APR_RETRIEVE_OPTIONAL_FN(balancer_manage);
/* Retrieve a UUID and store the nonce. */
apr_uuid_get(&uuid);
apr_uuid_format(balancer_nonce, &uuid);
/* Clean up to prevent backgroup thread (proxy_cluster_watchdog_func) to crash */
mc_initialize_cleanup(p);
/* Create global mutex */
if (ap_global_mutex_create(&node_mutex, NULL, node_mutex_type, NULL, s, p, 0) != APR_SUCCESS) {
ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, "manager_init: ap_global_mutex_create %s failed", node_mutex_type);
return !OK;
}
if (ap_global_mutex_create(&context_mutex, NULL, context_mutex_type, NULL, s, p, 0) != APR_SUCCESS) {
ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, "manager_init: ap_global_mutex_create %s failed", node_mutex_type);
return !OK;
}
return OK;
}
static apr_status_t decodeenc(char **ptr);
static char **process_buff(request_rec *r, char *buff)
{
int i = 0;
char *s = buff;
char **ptr = NULL;
for (; *s != '\0'; s++) {
if (*s == '&' || *s == '=') {
i++;
}
}
ptr = apr_palloc(r->pool, sizeof(char *) * (i + 2));
if (ptr == NULL) {
return NULL;
}
s = buff;
ptr[0] = s;
ptr[i + 1] = NULL;
i = 1;
for (; *s != '\0'; s++) {
/* our separators */
if (*s == '&' || *s == '=') {
*s = '\0';
ptr[i] = s + 1;
i++;
}
}
if (decodeenc(ptr) != APR_SUCCESS) {
return NULL;
}
return ptr;
}
static apr_status_t insert_update_host_helper(server_rec *s, mem_t *mem, hostinfo_t *info, char *alias)
{
(void)s;
strncpy(info->host, alias, HOSTALIASZ);
info->host[HOSTALIASZ] = '\0';
return insert_update_host(mem, info);
}
/**
* Insert the hosts from Alias information
*/
static apr_status_t insert_update_hosts(server_rec *s, mem_t *mem, char *str, int node, int vhost)
{
hostinfo_t info;
apr_status_t status;
char *ptr = str;
char *previous = str;
char empty[] = {'\0'};
if (str == NULL) {
ptr = empty;
previous = empty;
}
info.node = node;
info.vhost = vhost;
while (*ptr) {
if (*ptr == ',') {
*ptr = '\0';
status = insert_update_host_helper(s, mem, &info, previous);
if (status != APR_SUCCESS) {
return status;
}
previous = ptr + 1;
}
ptr++;
}
return insert_update_host_helper(s, mem, &info, previous);
}
/**
* Remove the context using the contextinfo_t information
* we read it first then remove it
*/
static void read_remove_context(mem_t *mem, contextinfo_t *context)
{
contextinfo_t *info;
info = read_context(mem, context);
if (info != NULL) {
remove_context(mem, info->id);
}
}
static apr_status_t insert_update_context_helper(server_rec *s, mem_t *mem, contextinfo_t *info, char *context,
int status)
{
(void)s;
info->id = 0;
strncpy(info->context, context, CONTEXTSZ);
info->context[CONTEXTSZ] = '\0';
if (status == REMOVE) {
read_remove_context(mem, info);
return APR_SUCCESS;
}
return insert_update_context(mem, info);
}
/**
* Insert the context from Context information
* Note:
* 1 - if status is REMOVE remove_context will be called
* 2 - return codes of REMOVE are ignored (always success)
*/
static apr_status_t insert_update_contexts(server_rec *s, mem_t *mem, char *str, int node, int vhost, int status)
{
char *ptr = str;
char *previous = str;
apr_status_t ret = APR_SUCCESS;
contextinfo_t info;
char root[] = "/";
if (ptr == NULL) {
ptr = root;
previous = root;
}
info.node = node;
info.vhost = vhost;
info.status = status;
while (*ptr) {
if (*ptr == ',') {
*ptr = '\0';
ret = insert_update_context_helper(s, mem, &info, previous, status);
if (ret != APR_SUCCESS) {
return ret;
}
previous = ptr + 1;
}
ptr++;
}
return insert_update_context_helper(s, mem, &info, previous, status);
}
/**
* Check that the node could be handle as is there were the same
*/
static int is_same_node(const nodeinfo_t *nodeinfo, const nodeinfo_t *node)
{
if (strcmp(nodeinfo->mess.balancer, node->mess.balancer)) {
return 0;
}
if (strcmp(nodeinfo->mess.Host, node->mess.Host)) {
return 0;
}
if (strcmp(nodeinfo->mess.Port, node->mess.Port)) {
return 0;
}
if (strcmp(nodeinfo->mess.Type, node->mess.Type)) {
return 0;
}
if (nodeinfo->mess.reversed != node->mess.reversed) {
return 0;
}
/* Those means the reslist has to be changed */
if (nodeinfo->mess.smax != node->mess.smax) {
return 0;
}
if (nodeinfo->mess.ttl != node->mess.ttl) {
return 0;
}
/* All other fields can be modified without causing problems */
return 1;
}
/**
* Check if another node has the same worker
*/
static int is_same_worker_existing(const request_rec *r, const nodeinfo_t *node)
{
int size, i;
int *id;
size = loc_get_max_size_node();
if (size == 0) {
return 0;
}
id = apr_palloc(r->pool, sizeof(int) * size);
size = get_ids_used_node(nodestatsmem, id);
for (i = 0; i < size; i++) {
nodeinfo_t *ou;
if (get_node(nodestatsmem, &ou, id[i]) != APR_SUCCESS) {
continue;
}
if (is_same_node(ou, node)) {
/* we have a node that corresponds to the same worker */
if (!strcmp(ou->mess.JVMRoute, node->mess.JVMRoute)) {
return 0; /* well it is the same */
}
if (ou->mess.remove) {
if (strcmp(ou->mess.JVMRoute, "REMOVED") == 0) {
/* Look in remove_removed_node, only "REMOVED" have cleaned the contexts/hosts */
return 0; /* well it marked removed */
}
}
ap_log_error(APLOG_MARK, APLOG_WARNING, 0, r->server,
"process_config: nodes %s and %s correspond to the same worker", node->mess.JVMRoute,
ou->mess.JVMRoute);
return 1;
}
}
return 0;
}
/**
* Builds the parameter for mod_balancer
*/
static apr_status_t mod_manager_manage_worker(request_rec *r, const nodeinfo_t *node, const balancerinfo_t *bal)
{
apr_table_t *params;
apr_status_t rv;
int i;
const apr_array_header_t *h;
const apr_table_entry_t *entries;
params = apr_table_make(r->pool, 10);
/* balancer */
apr_table_set(params, "b", node->mess.balancer);
apr_table_set(params, "b_lbm", "cluster");
apr_table_set(params, "b_tmo", apr_psprintf(r->pool, "%d", bal->Timeout));
apr_table_set(params, "b_max", apr_psprintf(r->pool, "%d", bal->Maxattempts));
apr_table_set(params, "b_ss", apr_pstrcat(r->pool, bal->StickySessionCookie, "|", bal->StickySessionPath, NULL));
/* and new worker */
apr_table_set(params, "b_wyes", "1");
apr_table_set(params, "b_nwrkr",
apr_pstrcat(r->pool, node->mess.Type, "://", node->mess.Host, ":", node->mess.Port, NULL));
rv = balancer_manage(r, params);
if (rv != APR_SUCCESS) {
return rv;
}
apr_table_clear(params);
/* now process the worker */
apr_table_set(params, "b", node->mess.balancer);
apr_table_set(params, "w",
apr_pstrcat(r->pool, node->mess.Type, "://", node->mess.Host, ":", node->mess.Port, NULL));
apr_table_set(params, "w_wr", node->mess.JVMRoute);
apr_table_set(params, "w_status_D", "0"); /* Not Dissabled */
/* set the health check (requires mod_proxy_hcheck) */
/* CPING for AJP and OPTIONS for HTTP/1.1 */
apr_table_set(params, "w_hm", strcmp(node->mess.Type, "ajp") ? "OPTIONS" : "CPING");
/* Use 10 sec for the moment, the idea is to adjust it with the STATUS frequency */
apr_table_set(params, "w_hi", "10000");
h = apr_table_elts(proxyhctemplate);
entries = (const apr_table_entry_t *)h->elts;
for (i = 0; i < h->nelts; i++) {
const char *key = translate_balancer_params(entries[i].key);
if (key != NULL) {
apr_table_set(params, key, entries[i].val);
}
}
return balancer_manage(r, params);
}
/**
* Check if the proxy balancer module already has a worker and return the id
*/
static proxy_worker *proxy_node_getid(request_rec *r, const nodeinfo_t *nodeinfo, int *id,
const proxy_server_conf **the_conf)
{
if (balancerhandler != NULL) {
return balancerhandler->proxy_node_getid(r, nodeinfo->mess.balancer, nodeinfo->mess.Type, nodeinfo->mess.Host,
nodeinfo->mess.Port, id, the_conf);
}
return NULL;
}
static void reenable_proxy_worker(request_rec *r, nodeinfo_t *node, proxy_worker *worker, nodeinfo_t *nodeinfo,
const proxy_server_conf *the_conf)
{
if (balancerhandler != NULL) {
balancerhandler->reenable_proxy_worker(r->server, node, worker, nodeinfo, the_conf);
}
}
static int proxy_node_get_free_id(request_rec *r, int node_table_size)
{
if (balancerhandler != NULL) {
return balancerhandler->proxy_node_get_free_id(r, node_table_size);
}
return -1;
}
/*
* Parse boolean parameter where Yes/On are true and No/Off are false.
* @return true iff an input was recognized, false otherwise
*/
static int process_boolean_parameter(const char *val, int *parameter)
{
if (strcasecmp(val, "yes") == 0 || strcasecmp(val, "on") == 0) {
*parameter = 1;
return 1;
} else if (strcasecmp(val, "no") == 0 || strcasecmp(val, "off") == 0) {
*parameter = 0;