47
43
#include <EXTERN.h>
51
47
#include <semaphore.h>
53
static const char rcsid[] = "$Id: rlm_perl.c,v 1.13 2004/02/26 19:04:34 aland Exp $";
50
extern char **environ;
53
static const char rcsid[] = "$Id: rlm_perl.c,v 1.13.4.3 2006/01/10 11:46:24 nbk Exp $";
58
* Pool of Perl's clones (genetically cloned) ;)
61
typedef struct pool_handle {
62
struct pool_handle *next;
63
struct pool_handle *prev;
64
enum {busy, idle} status;
65
unsigned int request_count;
66
PerlInterpreter *clone;
70
typedef struct PERL_POOL {
80
int max_request_per_clone;
84
time_t time_when_last_added;
57
90
* Define a structure for our module configuration.
103
143
offsetof(PERL_INST,func_detach), NULL, "detach"},
104
144
{ "func_xlat", PW_TYPE_STRING_PTR,
105
145
offsetof(PERL_INST,func_xlat), NULL, "xlat"},
146
{ "func_pre_proxy", PW_TYPE_STRING_PTR,
147
offsetof(PERL_INST,func_pre_proxy), NULL, "pre_proxy"},
148
{ "func_post_proxy", PW_TYPE_STRING_PTR,
149
offsetof(PERL_INST,func_post_proxy), NULL, "post_proxy"},
150
{ "func_post_auth", PW_TYPE_STRING_PTR,
151
offsetof(PERL_INST,func_post_auth), NULL, "post_auth"},
106
152
{ "perl_flags", PW_TYPE_STRING_PTR,
107
153
offsetof(PERL_INST,perl_flags), NULL, NULL},
108
154
{ "func_start_accounting", PW_TYPE_STRING_PTR,
119
165
EXTERN_C void boot_DynaLoader(pTHX_ CV* cv);
122
* We share one perl interpreter among all of the instances
123
* of this module. And clone it for every thread if we have perl
169
* We use one perl to clone from it i.e. main boss
170
* We clone it for every instance if we have perl
124
171
* with -Duseithreads compiled in
126
173
static PerlInterpreter *interp;
131
* Pool of Perl's clones (genetically cloned) ;)
134
typedef struct pool_handle {
135
struct pool_handle *next;
136
struct pool_handle *prev;
137
enum {busy, idle} status;
138
unsigned int request_count;
139
PerlInterpreter *clone;
142
typedef struct PERL_POOL {
150
int min_spare_clones;
151
int max_spare_clones;
152
int max_request_per_clone;
155
time_t time_when_last_added;
158
static PERL_POOL perl_pool;
160
175
static const CONF_PARSER pool_conf[] = {
161
{ "max_clones", PW_TYPE_INTEGER, 0, &perl_pool.max_clones, "32"},
162
{ "start_clones",PW_TYPE_INTEGER, 0, &perl_pool.start_clones, "5"},
163
{ "min_spare_clones",PW_TYPE_INTEGER, 0, &perl_pool.min_spare_clones, "3"},
164
{ "max_spare_clones",PW_TYPE_INTEGER, 0, &perl_pool.max_spare_clones, "3"},
165
{ "cleanup_delay",PW_TYPE_INTEGER, 0, &perl_pool.cleanup_delay, "5"},
166
{ "max_request_per_clone",PW_TYPE_INTEGER, 0, &perl_pool.max_request_per_clone, "0"},
176
{ "max_clones", PW_TYPE_INTEGER, offsetof(PERL_POOL, max_clones), NULL, "32"},
177
{ "start_clones",PW_TYPE_INTEGER, offsetof(PERL_POOL, start_clones), NULL, "5"},
178
{ "min_spare_clones",PW_TYPE_INTEGER, offsetof(PERL_POOL, min_spare_clones),NULL, "3"},
179
{ "max_spare_clones",PW_TYPE_INTEGER, offsetof(PERL_POOL,max_spare_clones),NULL, "3"},
180
{ "cleanup_delay",PW_TYPE_INTEGER, offsetof(PERL_POOL,cleanup_delay),NULL, "5"},
181
{ "max_request_per_clone",PW_TYPE_INTEGER, offsetof(PERL_POOL,max_request_per_clone),NULL, "0"},
167
182
{ NULL, -1, 0, NULL, NULL } /* end the list */
311
328
next = handle->next;
313
330
if (prev == NULL) {
314
perl_pool.head = next;
331
inst->perl_pool->head = next;
316
333
prev->next = next;
319
336
if (next == NULL) {
320
perl_pool.tail = prev;
337
inst->perl_pool->tail = prev;
322
339
next->prev = prev;
324
perl_pool.current_clones--;
341
inst->perl_pool->current_clones--;
342
MUTEX_DESTROY(&handle->lock);
327
static void move2tail(POOL_HANDLE *handle)
346
static void move2tail(POOL_HANDLE *handle, PERL_INST *inst)
329
348
POOL_HANDLE *prev;
330
349
POOL_HANDLE *next;
332
if (perl_pool.head == NULL) {
351
if (inst->perl_pool->head == NULL) {
334
353
handle->prev = NULL;
335
354
handle->next = NULL;
336
perl_pool.head = handle;
337
perl_pool.tail = handle;
355
inst->perl_pool->head = handle;
356
inst->perl_pool->tail = handle;
341
if (perl_pool.tail == handle) {
360
if (inst->perl_pool->tail == handle) {
389
411
handle->prev = NULL;
390
412
handle->next = NULL;
391
413
handle->status = idle;
392
handle->clone = rlm_perl_clone();
414
handle->clone = rlm_perl_clone(inst->perl);
393
415
handle->request_count = 0;
394
perl_pool.current_clones++;
416
MUTEX_INIT(&handle->lock);
417
inst->perl_pool->current_clones++;
418
move2tail(handle, inst);
397
420
now = time(NULL);
398
perl_pool.time_when_last_added = now;
421
inst->perl_pool->time_when_last_added = now;
403
static POOL_HANDLE *pool_pop()
426
static POOL_HANDLE *pool_pop(PERL_INST *inst)
405
428
POOL_HANDLE *handle;
406
429
POOL_HANDLE *found;
425
448
if (found == NULL) {
426
if (perl_pool.current_clones < perl_pool.max_clones ) {
449
if (inst->perl_pool->current_clones < inst->perl_pool->max_clones ) {
429
perl_pool.current_clones++;
451
found = pool_grow(inst);
431
453
if (found == NULL) {
432
454
radlog(L_ERR,"Cannot grow pool returning");
433
MUTEX_UNLOCK(&perl_pool.mutex);
455
MUTEX_UNLOCK(&inst->perl_pool->mutex);
437
radlog(L_ERR,"reached maximum clones %d cannot grow",
438
perl_pool.current_clones);
439
MUTEX_UNLOCK(&perl_pool.mutex);
459
radlog(L_ERR,"rlm_perl:: reached maximum clones %d cannot grow",
460
inst->perl_pool->current_clones);
461
MUTEX_UNLOCK(&inst->perl_pool->mutex);
466
move2tail(found, inst);
445
467
found->status = busy;
446
perl_pool.active_clones++;
468
MUTEX_LOCK(&found->lock);
469
inst->perl_pool->active_clones++;
447
470
found->request_count++;
451
MUTEX_UNLOCK(&perl_pool.mutex);
474
MUTEX_UNLOCK(&inst->perl_pool->mutex);
452
475
radlog(L_DBG,"perl_pool: item 0x%lx asigned new request. Handled so far: %d",
453
476
(unsigned long) found->clone, found->request_count);
456
static int pool_release(POOL_HANDLE *handle) {
479
static int pool_release(POOL_HANDLE *handle, PERL_INST *inst) {
458
481
POOL_HANDLE *tmp, *tmp2;
464
MUTEX_LOCK(&perl_pool.mutex);
465
handle->status = idle;
466
perl_pool.active_clones--;
468
spare = perl_pool.current_clones - perl_pool.active_clones;
487
MUTEX_LOCK(&inst->perl_pool->mutex);
490
* If detach is set then just release the mutex
492
if (inst->perl_pool->detach == yes ) {
493
handle->status = idle;
494
MUTEX_UNLOCK(&handle->lock);
495
MUTEX_UNLOCK(&inst->perl_pool->mutex);
499
MUTEX_UNLOCK(&handle->lock);
500
handle->status = idle;
501
inst->perl_pool->active_clones--;
503
spare = inst->perl_pool->current_clones - inst->perl_pool->active_clones;
470
505
radlog(L_DBG,"perl_pool total/active/spare [%d/%d/%d]"
471
, perl_pool.current_clones, perl_pool.active_clones, spare);
506
, inst->perl_pool->current_clones, inst->perl_pool->active_clones, spare);
473
if (spare < perl_pool.min_spare_clones) {
474
t = perl_pool.min_spare_clones - spare;
508
if (spare < inst->perl_pool->min_spare_clones) {
509
t = inst->perl_pool->min_spare_clones - spare;
475
510
for (i=0;i<t; i++) {
476
if ((tmp = pool_grow()) == NULL) {
477
MUTEX_UNLOCK(&perl_pool.mutex);
511
if ((tmp = pool_grow(inst)) == NULL) {
512
MUTEX_UNLOCK(&inst->perl_pool->mutex);
481
MUTEX_UNLOCK(&perl_pool.mutex);
516
MUTEX_UNLOCK(&inst->perl_pool->mutex);
484
519
now = time(NULL);
485
if ((now - perl_pool.time_when_last_added) < perl_pool.cleanup_delay) {
486
MUTEX_UNLOCK(&perl_pool.mutex);
520
if ((now - inst->perl_pool->time_when_last_added) < inst->perl_pool->cleanup_delay) {
521
MUTEX_UNLOCK(&inst->perl_pool->mutex);
489
if (spare > perl_pool.max_spare_clones) {
490
spare -= perl_pool.max_spare_clones;
491
for (tmp = perl_pool.head; (tmp !=NULL ) && (spare > 0) ; tmp = tmp2) {
524
if (spare > inst->perl_pool->max_spare_clones) {
525
spare -= inst->perl_pool->max_spare_clones;
526
for (tmp = inst->perl_pool->head; (tmp !=NULL ) && (spare > 0) ; tmp = tmp2) {
492
527
tmp2 = tmp->next;
494
529
if(tmp->status == idle) {
495
530
rlm_destroy_perl(tmp->clone);
496
delete_pool_handle(tmp);
497
perl_pool.current_clones--;
531
delete_pool_handle(tmp,inst);
538
* If the clone have reached max_request_per_clone clean it.
540
if (inst->perl_pool->max_request_per_clone > 0 ) {
541
if (handle->request_count > inst->perl_pool->max_request_per_clone) {
542
rlm_destroy_perl(handle->clone);
543
delete_pool_handle(handle,inst);
506
MUTEX_UNLOCK(&perl_pool.mutex);
549
MUTEX_UNLOCK(&inst->perl_pool->mutex);
509
static int init_pool (CONF_SECTION *conf) {
552
static int init_pool (CONF_SECTION *conf, PERL_INST *inst) {
510
553
POOL_HANDLE *handle;
513
MUTEX_INIT(&perl_pool.mutex);
557
pool = rad_malloc(sizeof(PERL_POOL));
558
memset(pool,0,sizeof(PERL_POOL));
560
inst->perl_pool = pool;
562
MUTEX_INIT(&pool->mutex);
516
565
* Read The Config
520
cf_section_parse(conf,NULL,pool_conf);
569
cf_section_parse(conf,pool,pool_conf);
570
inst->perl_pool = pool;
571
inst->perl_pool->detach = no;
522
for(t = 0;t < perl_pool.start_clones ;t++){
523
if ((handle = pool_grow()) == NULL) {
573
for(t = 0;t < inst->perl_pool->start_clones ;t++){
574
if ((handle = pool_grow(inst)) == NULL) {
537
588
* Try to avoid putting too much stuff in here - it's better to
538
589
* do it in instantiate() where it is not global.
590
* I use one global interpetator to make things more fastest for
591
* Threading env I clone new perl from this interp.
540
593
static int perl_init(void)
542
596
if ((interp = perl_alloc()) == NULL) {
543
radlog(L_INFO, "rlm_perl: No memory for allocating new perl !");
597
radlog(L_DBG, "rlm_perl: No memory for allocating new perl !");
547
601
perl_construct(interp);
548
602
PL_perl_destruct_level = 2;
591
645
* The xlat function
593
647
static int perl_xlat(void *instance, REQUEST *request, char *fmt, char * out,
594
int freespace, RADIUS_ESCAPE_STRING func)
648
size_t freespace, RADIUS_ESCAPE_STRING func)
597
651
PERL_INST *inst= (PERL_INST *) instance;
598
652
PerlInterpreter *perl;
599
char params[1024], *tmp_ptr, *ptr, *tmp;
653
char params[1024], *ptr, *tmp;
605
659
#ifdef USE_ITHREADS
606
660
POOL_HANDLE *handle;
608
if ((handle = pool_pop()) == NULL) {
662
if ((handle = pool_pop(instance)) == NULL) {
687
739
static int perl_instantiate(CONF_SECTION *conf, void **instance)
689
741
PERL_INST *inst = (PERL_INST *) instance;
690
HV *rad_reply_hv = newHV();
691
HV *rad_check_hv = newHV();
692
HV *rad_request_hv = newHV();
745
HV *rad_request_proxy_hv;
746
HV *rad_request_proxy_reply_hv;
694
749
char *embed[4], *xlat_name;
695
750
int exitstatus = 0, argc=0;
725
exitstatus = perl_parse(interp, xs_init, argc, embed, NULL);
781
inst->perl = perl_clone(interp ,CLONEf_KEEP_PTR_TABLE);
785
PERL_SET_CONTEXT(inst->perl);
787
if ((inst->perl = perl_alloc()) == NULL) {
788
radlog(L_ERR, "rlm_perl: No memory for allocating new perl !");
792
perl_construct(inst->perl);
727
795
#if PERL_REVISION >= 5 && PERL_VERSION >=8
728
796
PL_exit_flags |= PERL_EXIT_DESTRUCT_END;
799
exitstatus = perl_parse(inst->perl, xs_init, argc, embed, NULL);
731
804
if(!exitstatus) {
732
exitstatus = perl_run(interp);
805
exitstatus = perl_run(inst->perl);
734
radlog(L_INFO,"rlm_perl: perl_parse failed: %s not found or has syntax errors. \n", inst->module);
807
radlog(L_ERR,"rlm_perl: perl_parse failed: %s not found or has syntax errors. \n", inst->module);
738
813
newXS("radiusd::radlog",XS_radiusd_radlog, "rlm_perl.c");
815
rad_reply_hv = newHV();
816
rad_check_hv = newHV();
817
rad_request_hv = newHV();
818
rad_request_proxy_hv = newHV();
819
rad_request_proxy_reply_hv = newHV();
740
821
rad_reply_hv = get_hv("RAD_REPLY",1);
741
822
rad_check_hv = get_hv("RAD_CHECK",1);
742
823
rad_request_hv = get_hv("RAD_REQUEST",1);
824
rad_request_proxy_hv = get_hv("RAD_REQUEST_PROXY",1);
825
rad_request_proxy_reply_hv = get_hv("RAD_REQUEST_PROXY_REPLY",1);
744
827
xlat_name = cf_section_name2(conf);
745
828
if (xlat_name == NULL)
910
996
rad_reply_hv = get_hv("RAD_REPLY",1);
911
997
rad_check_hv = get_hv("RAD_CHECK",1);
912
998
rad_request_hv = get_hv("RAD_REQUEST",1);
999
rad_request_proxy_hv = get_hv("RAD_REQUEST_PROXY",1);
1000
rad_request_proxy_reply_hv = get_hv("RAD_REQUEST_PROXY_REPLY",1);
916
1003
perl_store_vps(request->reply->vps, rad_reply_hv);
917
1004
perl_store_vps(request->config_items, rad_check_hv);
918
1005
perl_store_vps(request->packet->vps, rad_request_hv);
1007
if (request->proxy != NULL) {
1008
perl_store_vps(request->proxy->vps, rad_request_proxy_hv);
1010
hv_undef(rad_request_proxy_hv);
1013
if (request->proxy_reply !=NULL) {
1014
perl_store_vps(request->proxy_reply->vps, rad_request_proxy_reply_hv);
1016
hv_undef(rad_request_proxy_reply_hv);
958
1058
pairmove(&request->config_items, &vp);
964
* Do we want to allow this?
966
if ((get_hv_content(rad_request_hv, &vp)) > 0 ) {
967
pairfree(&request->packet->vps);
968
request->packet->vps = vp;
1062
if ((get_hv_content(rad_request_proxy_reply_hv, &vp)) > 0 && request->proxy_reply != NULL) {
1063
pairfree(&request->proxy_reply->vps);
1064
pairmove(&request->proxy_reply->vps, &vp);
973
1068
#ifdef USE_ITHREADS
974
pool_release(handle);
1069
pool_release(handle,instance);
975
1070
radlog(L_DBG,"Unreserve perl at address 0x%lx", (unsigned long) handle->clone);
1057
1149
* Check for simultaneouse-use
1060
1151
static int perl_checksimul(void *instance, REQUEST *request)
1062
1153
return rlmperl_call(instance, request,
1063
1154
((PERL_INST *)instance)->func_checksimul);
1159
static int perl_pre_proxy(void *instance, REQUEST *request)
1161
return rlmperl_call(instance, request,
1162
((PERL_INST *)instance)->func_pre_proxy);
1165
* Post-Proxy request
1167
static int perl_post_proxy(void *instance, REQUEST *request)
1169
return rlmperl_call(instance, request,
1170
((PERL_INST *)instance)->func_post_proxy);
1175
static int perl_post_auth(void *instance, REQUEST *request)
1177
return rlmperl_call(instance, request,
1178
((PERL_INST *)instance)->func_post_auth);
1067
1181
* Detach a instance give a chance to a module to make some internal setup ...
1072
1186
int exitstatus=0,count=0;
1074
1188
#ifdef USE_ITHREADS
1075
POOL_HANDLE *handle;
1077
for (handle = perl_pool.head; handle; handle = handle->next) {
1079
radlog(L_INFO,"Detach perl 0x%lx", (unsigned long) handle->clone);
1189
POOL_HANDLE *handle, *tmp, *tmp2;
1191
MUTEX_LOCK(&inst->perl_pool->mutex);
1192
inst->perl_pool->detach = yes;
1193
MUTEX_UNLOCK(&inst->perl_pool->mutex);
1195
for (handle = inst->perl_pool->head; handle != NULL; handle = handle->next) {
1197
radlog(L_DBG,"Detach perl 0x%lx", (unsigned long) handle->clone);
1081
1199
* Wait until clone becomes idle
1084
while (handle->status == busy) {
1201
MUTEX_LOCK(&handle->lock);
1088
1204
* Give a clones chance to run detach function
1109
radlog(L_INFO,"detach at 0x%lx returned status %d",
1227
radlog(L_DBG,"detach at 0x%lx returned status %d",
1110
1228
(unsigned long) handle->clone, exitstatus);
1231
MUTEX_UNLOCK(&handle->lock);
1117
* FIXME: For more efficienty we don't
1118
* free entire pool. We only reread config flags thus way
1119
* we can extend pool_size.
1237
for (tmp = inst->perl_pool->head; tmp !=NULL ; tmp = tmp2) {
1239
radlog(L_DBG,"rlm_perl:: Destroy perl");
1240
rlm_perl_destruct(tmp->clone);
1241
delete_pool_handle(tmp,inst);
1124
PERL_SET_CONTEXT(interp);
1125
1246
#endif /* USE_ITHREADS */
1247
PERL_SET_CONTEXT(inst->perl);
1249
dSP; ENTER; SAVETMPS;
1129
1252
count = call_pv(inst->func_detach, G_SCALAR | G_EVAL );
1149
1274
if (inst->func_accounting) free(inst->func_accounting);
1150
1275
if (inst->func_preacct) free(inst->func_preacct);
1151
1276
if (inst->func_checksimul) free(inst->func_checksimul);
1277
if (inst->func_pre_proxy) free(inst->func_pre_proxy);
1278
if (inst->func_post_proxy) free(inst->func_post_proxy);
1279
if (inst->func_post_auth) free(inst->func_post_auth);
1152
1280
if (inst->func_detach) free(inst->func_detach);
1283
free(inst->perl_pool->head);
1284
free(inst->perl_pool->tail);
1285
MUTEX_DESTROY(&inst->perl_pool->mutex);
1286
free(inst->perl_pool);
1287
rlm_perl_destruct(inst->perl);
1289
perl_destruct(inst->perl);
1290
perl_free(inst->perl);
1155
1294
return exitstatus;
1159
1297
* The module name should be the only globally exported symbol.
1160
1298
* That is, everything else should be 'static'.