/* * Jabber::mod_perl - mod_perl for jabberd * Copyright (c) 2002 Piers Harding * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA02111-1307USA */ #include "mod_perl.h" static PerlInterpreter *my_perl; /*** The Perl interpreter ***/ /*----------------------------------------------------------------------------------* initialise all the perl handlers that will be used by mod_perl pass them the configuration nad, and the element number pointing to the configuration node *-----------------------------------------------------------------------------------*/ void mod_perl_initialise(nad_t nad, mod_instance_t mi) { int result; int el; SV* sv_rvalue; SV* sv_init_subroutine; dSP; // initial the argument stack ENTER; SAVETMPS; PUSHMARK(SP); // push the NAD onto the stack XPUSHs( sv_2mortal( sv_bless( sv_setref_pv(newSViv(0), Nullch, (void *)nad), gv_stashpv("Jabber::NADs", 0) ) ) ); // push the instance no. of this module in the chain on XPUSHs( sv_2mortal( newSViv(mi->seq) ) ); // push the chain type that we are in on to the stack switch ( mi->chain ) { case chain_SESS_START: XPUSHs( sv_2mortal( newSVpv("SESS_START", 0) ) ); break; case chain_SESS_END: XPUSHs( sv_2mortal( newSVpv("SESS_END", 0) ) ); break; case chain_IN_SESS: XPUSHs( sv_2mortal( newSVpv("IN_SESS", 0) ) ); break; case chain_IN_ROUTER: XPUSHs( sv_2mortal( newSVpv("IN_ROUTER", 0) ) ); break; case chain_OUT_SESS: XPUSHs( sv_2mortal( newSVpv("OUT_SESS", 0) ) ); break; case chain_OUT_ROUTER: XPUSHs( sv_2mortal( newSVpv("OUT_ROUTER", 0) ) ); break; case chain_PKT_SM: XPUSHs( sv_2mortal( newSVpv("PKT_SM", 0) ) ); break; case chain_PKT_USER: XPUSHs( sv_2mortal( newSVpv("PKT_USER", 0) ) ); break; case chain_PKT_ROUTER: XPUSHs( sv_2mortal( newSVpv("PKT_ROUTER", 0) ) ); break; } // push the module instance args on XPUSHs( sv_2mortal( newSVpv(mi->arg, 0) ) ); // hunt down the handlers and push them onto the stack //el = nad_find_elem(nad, 0, -1, "mod_perl", 1); // give the element no. for mod_perl //XPUSHs(sv_2mortal(newSViv(el))); //log_debug(ZONE, "mod_perl config is at el: %d", el); // push the Perl handler module names onto the stack //el = nad_find_elem(nad, el, -1, "handler", 1); //while(el >= 0) //{ // XPUSHs(sv_2mortal(newSVpvn(NAD_CDATA(nad, el), NAD_CDATA_L(nad, el)))); // log_debug(ZONE, "mod_perl handler is at el: %d", el); // el = nad_find_elem(nad, el, -1, "handler", 0); //} // stash away the stack pointer PUTBACK; // do the perl call sv_init_subroutine = newSVpv(mod_perl_method_init, PL_na); log_debug(ZONE, "mod_perl - mod_perl_init: Calling routine: %s", SvPV(sv_init_subroutine,PL_na)); result = perl_call_sv(sv_init_subroutine, G_EVAL | G_DISCARD ); // disassemble the call results log_debug(ZONE, "mod_perl - mod_perl_init: Called routine: %s results: %d", SvPV(sv_init_subroutine,PL_na), result); if(SvTRUE(ERRSV)) log_debug(ZONE, "mod_perl - mod_perl_init: perl call errored: %s", SvPV(ERRSV,PL_na)); SPAGAIN; if (result > 0){ sv_rvalue = POPs; log_debug(ZONE, "mod_perl - mod_perl_init: after call (%s): %d - %s", SvPV(sv_init_subroutine,PL_na), result, SvPV(sv_rvalue,SvCUR(sv_rvalue))); } PUTBACK; FREETMPS; LEAVE; } /*----------------------------------------------------------------------------------* do the onPacket callback - push the pkt oject onto the argument stack and the user must pass back HANDLED or PASS to hand back to the session manager (sm) *-----------------------------------------------------------------------------------*/ mod_ret_t mod_perl_onpacket(mod_instance_t mi, pkt_t pkt) { int result; SV* sv_rvalue; mod_ret_t retr; dSP; log_debug(ZONE, "mod_perl - mod_perl_onpacket"); // initialising the argument stack ENTER; SAVETMPS; PUSHMARK(SP); // push the pkt onto the stack XPUSHs( sv_2mortal( sv_bless( sv_setref_pv(newSViv(0), Nullch, (void *)pkt), gv_stashpv("Jabber::pkt", 0) ) ) ); // push the instance no. of this module in the chain on XPUSHs( sv_2mortal( newSViv(mi->seq) ) ); // push the chain type that we are in on to the stack switch ( mi->chain ) { case chain_SESS_START: XPUSHs( sv_2mortal( newSVpv("SESS_START", 0) ) ); break; case chain_SESS_END: XPUSHs( sv_2mortal( newSVpv("SESS_END", 0) ) ); break; case chain_IN_SESS: XPUSHs( sv_2mortal( newSVpv("IN_SESS", 0) ) ); break; case chain_IN_ROUTER: XPUSHs( sv_2mortal( newSVpv("IN_ROUTER", 0) ) ); break; case chain_OUT_SESS: XPUSHs( sv_2mortal( newSVpv("OUT_SESS", 0) ) ); break; case chain_OUT_ROUTER: XPUSHs( sv_2mortal( newSVpv("OUT_ROUTER", 0) ) ); break; case chain_PKT_SM: XPUSHs( sv_2mortal( newSVpv("PKT_SM", 0) ) ); break; case chain_PKT_USER: XPUSHs( sv_2mortal( newSVpv("PKT_USER", 0) ) ); break; case chain_PKT_ROUTER: XPUSHs( sv_2mortal( newSVpv("PKT_ROUTER", 0) ) ); break; } // push the module instance args on XPUSHs( sv_2mortal( newSVpv(mi->arg, 0) ) ); // stash the stack point PUTBACK; // do the onPacket call log_debug(ZONE, "mod_perl - mod_perl_onpacket: Calling routine: %s", SvPV(sv_on_packet_subroutine,PL_na)); result = perl_call_sv(sv_on_packet_subroutine, G_EVAL | G_SCALAR ); // disassemble the results off the argument stack log_debug(ZONE, "mod_perl - mod_perl_onpacket: Called routine: %s results: %d", SvPV(sv_on_packet_subroutine,PL_na), result); if(SvTRUE(ERRSV)) log_debug(ZONE, "mod_perl - mod_perl_onpacket: perl call errored: %s", SvPV(ERRSV,PL_na)); SPAGAIN; // was this handled or passed? if (result > 0){ sv_rvalue = POPs; log_debug(ZONE, "mod_perl - mod_perl_onpacket: after call (%s): returns(%d) - code(%s)", SvPV(sv_on_packet_subroutine,PL_na), result, SvPV(sv_rvalue,SvCUR(sv_rvalue))); if (SvIV(sv_rvalue) == 1){ //pkt_free( pkt ); log_debug(ZONE, "mod_perl - mod_perl_onpacket: PACKET HANDLED "); retr = mod_HANDLED; } else if (SvIV(sv_rvalue) == 2){ retr = mod_PASS; } else { log_debug(ZONE, "mod_perl - mod_perl_onpacket: PACKET PASSED "); retr = mod_PASS; } } else { log_debug(ZONE, "mod_perl - mod_perl_onpacket: after call (%s): %d - NO RETURN BAD ERROR", SvPV(sv_on_packet_subroutine,PL_na), result); retr = mod_PASS; } PUTBACK; FREETMPS; LEAVE; return retr; } /*----------------------------------------------------------------------------------* Run the perl evaluated code snippet - return the scalar value result *-----------------------------------------------------------------------------------*/ SV* mod_perl_eval_pv(char *subroutine) { SV* my_sv; log_debug(ZONE, "mod_perl Perl eval (PV): %s", subroutine); my_sv = eval_pv(subroutine, FALSE ); if(SvTRUE(ERRSV)) { log_debug(ZONE, "mod_perl Perl eval error (PV): %s", SvPV(ERRSV,PL_na)); //exit(0); } else { log_debug(ZONE, "mod_perl Perl eval successful (PV)"); return my_sv; } } /*----------------------------------------------------------------------------------* Clean up the interpreter at the end of the process life *-----------------------------------------------------------------------------------*/ void mod_perl_destroy() { perl_destruct(my_perl); perl_free(my_perl); log_debug(ZONE, "mod_perl has been cleaned up"); } /*----------------------------------------------------------------------------------* sm mod_perl subroutine reference - registered for handling packets that arrive from active users *-----------------------------------------------------------------------------------*/ static mod_ret_t _mod_perl_in_sess(mod_instance_t mi, sess_t sess, pkt_t pkt) { /* we want messages addressed to /mod_perl */ log_debug(ZONE, "mod_perl_in_sess %d ", pkt->type); /* only allow access to and packets */ if (pkt->type & pkt_MESSAGE || pkt->type & pkt_PRESENCE || pkt->type & pkt_IQ) { if (pkt->from != NULL){ log_debug(ZONE, "mod_perl_in_sess - PROCESSING request of %d from %s", pkt->type, jid_full(pkt->from)); } else { log_debug(ZONE, "mod_perl_in_sess - PROCESSING request of %d", pkt->type); } return mod_perl_onpacket(mi, pkt); } else { return mod_PASS; } } /*----------------------------------------------------------------------------------* sm mod_perl subroutine reference - registered for handling packets that arrive from active users XXX *-----------------------------------------------------------------------------------*/ // mod_ret_t (*out_sess)(mod_instance_t mi, sess_t sess, pkt_t pkt); **< out-sess handler * static mod_ret_t _mod_perl_out_sess(mod_instance_t mi, sess_t sess, pkt_t pkt) { /* we want messages addressed to /mod_perl */ log_debug(ZONE, "mod_perl_out_sess %d ", pkt->type); /* only allow access to and packets */ if (pkt->type & pkt_MESSAGE || pkt->type & pkt_PRESENCE || pkt->type & pkt_IQ) { if (pkt->from != NULL){ log_debug(ZONE, "mod_perl_out_sess - PROCESSING request of %d from %s", pkt->type, jid_full(pkt->from)); } else { log_debug(ZONE, "mod_perl_out_sess - PROCESSING request of %d", pkt->type); } return mod_perl_onpacket(mi, pkt); } else { return mod_PASS; } } /*----------------------------------------------------------------------------------* sm mod_perl subroutine reference - registered for handling packets that arrive from active users *-----------------------------------------------------------------------------------*/ // mod_ret_t (*in_router)(mod_instance_t mi, pkt_t pkt); **< in-router handler * static mod_ret_t _mod_perl_in_router(mod_instance_t mi, pkt_t pkt) { /* we want messages addressed to /mod_perl */ log_debug(ZONE, "mod_perl_in_router %d ", pkt->type); /* only allow access to and packets */ if (pkt->type & pkt_MESSAGE || pkt->type & pkt_PRESENCE || pkt->type & pkt_IQ) { if (pkt->from != NULL){ log_debug(ZONE, "mod_perl_in_router - PROCESSING request of %d from %s", pkt->type, jid_full(pkt->from)); } else { log_debug(ZONE, "mod_perl_in_router - PROCESSING request of %d", pkt->type); } return mod_perl_onpacket(mi, pkt); } else { return mod_PASS; } } /*----------------------------------------------------------------------------------* sm mod_perl subroutine reference - registered for handling packets that arrive from active users XXX *-----------------------------------------------------------------------------------*/ // mod_ret_t (*out_router)(mod_instance_t mi, pkt_t pkt); **< out-router handler * static mod_ret_t _mod_perl_out_router(mod_instance_t mi, pkt_t pkt) { /* we want messages addressed to /mod_perl */ log_debug(ZONE, "mod_perl_out_router %d ", pkt->type); /* only allow access to and packets */ if (pkt->type & pkt_MESSAGE || pkt->type & pkt_PRESENCE || pkt->type & pkt_IQ) { if (pkt->from != NULL){ log_debug(ZONE, "mod_perl_out_router - PROCESSING request of %d from %s", pkt->type, jid_full(pkt->from)); } else { log_debug(ZONE, "mod_perl_out_router - PROCESSING request of %d", pkt->type); } return mod_perl_onpacket(mi, pkt); } else { return mod_PASS; } } /*----------------------------------------------------------------------------------* sm mod_perl subroutine reference - registered for handling packets that are addressed directly to the host *-----------------------------------------------------------------------------------*/ // mod_ret_t (*pkt_sm)(mod_instance_t mi, pkt_t pkt); **< pkt-sm handler * static mod_ret_t _mod_perl_pkt_sm(mod_instance_t mi, pkt_t pkt) { /* we want messages addressed to /mod_perl */ log_debug(ZONE, "mod_perl_pkt_sm - saw a packet from %s - %d ", jid_full(pkt->from), pkt->type); /* only allow access to and packets */ if (pkt->type & pkt_MESSAGE || pkt->type & pkt_PRESENCE || pkt->type & pkt_IQ) { log_debug(ZONE, "mod_perl_pkt_sm - PROCESSING request of %d from %s", pkt->type, jid_full(pkt->from)); return mod_perl_onpacket(mi, pkt); } else { return mod_PASS; } } /*----------------------------------------------------------------------------------* sm mod_perl subroutine reference - registered for handling packets from the router to the user *-----------------------------------------------------------------------------------*/ // mod_ret_t (*pkt_user)(mod_instance_t mi, user_t user, pkt_t pkt); **< pkt-user handler * static mod_ret_t _mod_perl_pkt_user(mod_instance_t mi, user_t user, pkt_t pkt) { /* we want messages addressed to /mod_perl */ log_debug(ZONE, "mod_perl_pkt_user - saw a packet from %s - %d ", jid_full(pkt->from), pkt->type); /* only allow access to and packets */ if (pkt->type & pkt_MESSAGE || pkt->type & pkt_PRESENCE || pkt->type & pkt_IQ) { log_debug(ZONE, "mod_perl_pkt_user - PROCESSING request of %d from %s", pkt->type, jid_full(pkt->from)); return mod_perl_onpacket(mi, pkt); } else { return mod_PASS; } } /*----------------------------------------------------------------------------------* sm mod_perl subroutine reference - registered for handling packets from the router to the user *-----------------------------------------------------------------------------------*/ // mod_ret_t (*pkt_router)(mod_instance_t mi, pkt_t pkt); **< pkt-router handler * static mod_ret_t _mod_perl_pkt_router(mod_instance_t mi, pkt_t pkt) { /* we want messages addressed to /mod_perl */ log_debug(ZONE, "mod_perl_pkt_router "); log_debug(ZONE, "mod_perl_pkt_router - saw a packet from %s - %d ", jid_full(pkt->from), pkt->type); /* only allow access to and packets */ if (pkt->type & pkt_MESSAGE || pkt->type & pkt_PRESENCE || pkt->type & pkt_IQ) { log_debug(ZONE, "mod_perl_pkt_router - PROCESSING request of %d from %s", pkt->type, jid_full(pkt->from)); return mod_perl_onpacket(mi, pkt); } else { return mod_PASS; } } /*----------------------------------------------------------------------------------* sm mod_perl initialisation routine *-----------------------------------------------------------------------------------*/ int mod_perl_init(mod_instance_t mi, char *arg) { module_t mod = mi->mod; log_debug(ZONE, "mod_perl_init - init"); if (!mod->init){ log_debug(ZONE, "mod_perl_init - first time - initilise interpreter"); my_perl = perl_alloc(); perl_construct( my_perl ); perl_parse(my_perl, xs_init, MOD_PERL_NO_PARMS, embedding, NULL); perl_run(my_perl); mod_perl_eval_pv(use_mod_perl); // initialise the pure C Perl modules log_debug(ZONE, "mod_perl_init - first time - boot the Perl modules"); //boot_Jabber__pkt(Nullcv); //boot_Jabber__NADs(Nullcv); boot_Jabber__pkt(my_perl, Nullcv); boot_Jabber__NADs(my_perl, Nullcv); // setup the sv of onpacket code - parse the callback sv_on_packet_subroutine = newSVpv(mod_perl_method_onpacket, PL_na); sv_setpv(sv_on_packet_subroutine, mod_perl_method_onpacket); /* * stash a copy of the config nad * need to register config nad mod->mm->sm->config->nad * look here for the modules to load * and what to run as the init handler */ mod_perl_config = nad_copy(mod->mm->sm->config->nad); log_debug(ZONE, "mod_perl_init - Perl interpreter has been initialised"); } log_debug(ZONE, "mod_perl_init - initialise module instance: %s", arg); // only registered for these chains so far switch ( mi->chain ) { case chain_SESS_START: // mod->sess_start = _mod_perl_sess_start; break; case chain_SESS_END: // mod->sess_end = _mod_perl_sess_end; break; case chain_IN_SESS: mod->in_sess = _mod_perl_in_sess; break; case chain_IN_ROUTER: mod->in_router = _mod_perl_in_router; break; case chain_OUT_SESS: mod->out_sess = _mod_perl_out_sess; break; case chain_OUT_ROUTER: mod->out_router = _mod_perl_out_router; break; case chain_PKT_SM: mod->pkt_sm = _mod_perl_pkt_sm; break; case chain_PKT_USER: mod->pkt_user = _mod_perl_pkt_user; break; case chain_PKT_ROUTER: mod->pkt_router = _mod_perl_pkt_router; break; case chain_USER_LOAD: // mod->user_load = _mod_perl_user_load; break; case chain_USER_CREATE: // mod->user_create = _mod_perl_user_create; break; case chain_USER_DELETE: // mod->user_delete = _mod_perl_user_delete; break; } /* int (*sess_start)(mod_instance_t mi, sess_t sess); **< sess-start handler * void (*sess_end)(mod_instance_t mi, sess_t sess); **< sess-end handler * mod_ret_t (*in_sess)(mod_instance_t mi, sess_t sess, pkt_t pkt); **< in-sess handler * mod_ret_t (*in_router)(mod_instance_t mi, pkt_t pkt); **< in-router handler * mod_ret_t (*out_sess)(mod_instance_t mi, sess_t sess, pkt_t pkt); **< out-sess handler * mod_ret_t (*out_router)(mod_instance_t mi, pkt_t pkt); **< out-router handler * mod_ret_t (*pkt_sm)(mod_instance_t mi, pkt_t pkt); **< pkt-sm handler * mod_ret_t (*pkt_user)(mod_instance_t mi, user_t user, pkt_t pkt); **< pkt-user handler * mod_ret_t (*pkt_router)(mod_instance_t mi, pkt_t pkt); **< pkt-router handler * int (*user_load)(mod_instance_t mi, user_t user); **< user-load handler * int (*user_create)(mod_instance_t mi, jid_t jid); **< user-create handler * void (*user_delete)(mod_instance_t mi, jid_t jid); **< user-delete handler * */ mod_perl_initialise(mod_perl_config, mi); log_debug(ZONE, "mod_perl_init - mod_perl has been initialised"); return 0; }