2006-09-10 23:20:44 +00:00
/*
* FreeSWITCH Modular Media Switching Software Library / Soft - Switch Application
* Copyright ( C ) 2005 / 2006 , Anthony Minessale II < anthmct @ yahoo . com >
*
* Version : MPL 1.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 ( the " License " ) ; you may not use this file except in compliance with
* the License . You may obtain a copy of the License at
* http : //www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an " AS IS " basis ,
* WITHOUT WARRANTY OF ANY KIND , either express or implied . See the License
* for the specific language governing rights and limitations under the
* License .
*
* The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft - Switch Application
*
* The Initial Developer of the Original Code is
* Anthony Minessale II < anthmct @ yahoo . com >
* Portions created by the Initial Developer are Copyright ( C )
* the Initial Developer . All Rights Reserved .
*
* Contributor ( s ) :
*
* Brian Fertig < brian . fertig @ convergencetek . com >
2006-12-21 17:11:43 +00:00
* Johny Kadarisman < jkr888 @ gmail . com >
2007-05-10 18:51:47 +00:00
* Traun Leyden < tleyden @ branchcut . com >
2006-09-10 23:20:44 +00:00
*
* mod_python . c - - Python Module
*
*/
2006-09-17 21:28:31 +00:00
# include <Python.h>
2006-09-10 23:20:44 +00:00
# ifndef _REENTRANT
# define _REENTRANT
# endif
# ifndef _GNU_SOURCE
# define _GNU_SOURCE
# endif
# include <switch.h>
2007-05-07 21:27:42 +00:00
2007-06-01 18:50:34 +00:00
PyThreadState * mainThreadState = NULL ;
2007-05-07 21:27:42 +00:00
2006-11-14 06:13:04 +00:00
void init_freeswitch ( void ) ;
2006-12-21 17:11:43 +00:00
static switch_api_interface_t python_run_interface ;
2006-09-10 23:20:44 +00:00
2007-06-13 17:48:49 +00:00
SWITCH_MODULE_LOAD_FUNCTION ( mod_python_load ) ;
SWITCH_MODULE_SHUTDOWN_FUNCTION ( mod_python_shutdown ) ;
SWITCH_MODULE_DEFINITION ( mod_python , mod_python_load , mod_python_shutdown , NULL ) ;
2006-09-10 23:20:44 +00:00
2007-05-07 21:27:42 +00:00
static void eval_some_python ( char * uuid , char * args )
{
2007-05-10 18:51:47 +00:00
PyThreadState * tstate = NULL ;
2007-05-07 21:27:42 +00:00
char * dupargs = NULL ;
char * argv [ 128 ] = { 0 } ;
int argc ;
int lead = 0 ;
2007-06-15 17:25:41 +00:00
char * script = NULL ;
PyObject * module = NULL ;
PyObject * function = NULL ;
PyObject * arg = NULL ;
PyObject * result = NULL ;
2007-05-07 21:27:42 +00:00
if ( args ) {
2007-06-15 17:25:41 +00:00
dupargs = strdup ( args ) ;
2007-05-07 21:27:42 +00:00
} else {
2007-06-15 17:25:41 +00:00
return ;
2007-05-07 21:27:42 +00:00
}
assert ( dupargs ! = NULL ) ;
if ( ! ( argc = switch_separate_string ( dupargs , ' ' , argv , ( sizeof ( argv ) / sizeof ( argv [ 0 ] ) ) ) ) ) {
2007-06-15 17:25:41 +00:00
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_ERROR , " No module name specified! \n " ) ;
goto done ;
2007-05-07 21:27:42 +00:00
}
script = argv [ 0 ] ;
2007-05-08 16:08:48 +00:00
lead = 1 ;
2007-05-07 21:27:42 +00:00
2007-06-15 17:25:41 +00:00
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_NOTICE , " Invoking py module: %s \n " , script ) ;
tstate = PyThreadState_New ( mainThreadState - > interp ) ;
if ( ! tstate ) {
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_ERROR , " error acquiring tstate \n " ) ;
goto done ;
}
// swap in thread state
PyEval_AcquireThread ( tstate ) ;
init_freeswitch ( ) ;
// import the module
module = PyImport_ImportModule ( ( char * ) script ) ;
if ( ! module ) {
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_ERROR , " Error importing module \n " ) ;
PyErr_Print ( ) ;
PyErr_Clear ( ) ;
goto done_swap_out ;
}
// reload the module
module = PyImport_ReloadModule ( module ) ;
if ( ! module ) {
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_ERROR , " Error reloading module \n " ) ;
PyErr_Print ( ) ;
PyErr_Clear ( ) ;
goto done_swap_out ;
}
// get the handler function to be called
function = PyObject_GetAttrString ( module , " handler " ) ;
if ( ! function ) {
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_ERROR , " Module does not define handler(uuid) \n " ) ;
PyErr_Print ( ) ;
PyErr_Clear ( ) ;
goto done_swap_out ;
}
if ( uuid ) {
// build a tuple to pass the args, the uuid of session
arg = Py_BuildValue ( " (s) " , uuid ) ;
if ( ! arg ) {
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_ERROR , " Error building args \n " ) ;
PyErr_Print ( ) ;
PyErr_Clear ( ) ;
goto done_swap_out ;
}
2007-05-08 15:44:44 +00:00
}
2007-06-15 17:25:41 +00:00
else {
arg = PyTuple_New ( 1 ) ;
PyObject * nada = Py_BuildValue ( " " ) ;
PyTuple_SetItem ( arg , 0 , nada ) ;
2007-05-08 15:44:44 +00:00
}
2007-05-07 21:27:42 +00:00
2007-06-15 17:25:41 +00:00
// invoke the handler
result = PyEval_CallObjectWithKeywords ( function , arg , ( PyObject * ) NULL ) ;
2007-05-07 21:27:42 +00:00
2007-06-15 17:25:41 +00:00
// check the result and print out any errors
if ( ! result ) {
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_ERROR , " Error calling python script \n " ) ;
PyErr_Print ( ) ;
PyErr_Clear ( ) ;
2007-05-07 21:27:42 +00:00
}
2007-06-15 17:25:41 +00:00
goto done_swap_out ;
2007-05-07 21:27:42 +00:00
done :
2007-06-15 17:25:41 +00:00
switch_safe_free ( dupargs ) ;
2007-05-07 21:27:42 +00:00
2007-06-15 17:25:41 +00:00
done_swap_out :
// decrement ref counts
Py_XDECREF ( module ) ;
Py_XDECREF ( function ) ;
Py_XDECREF ( arg ) ;
Py_XDECREF ( result ) ;
// swap out thread state
PyEval_ReleaseThread ( tstate ) ;
2007-05-07 21:27:42 +00:00
switch_safe_free ( dupargs ) ;
2007-06-15 17:25:41 +00:00
2007-05-07 21:27:42 +00:00
}
2006-09-10 23:20:44 +00:00
static void python_function ( switch_core_session_t * session , char * data )
{
2007-05-07 21:27:42 +00:00
eval_some_python ( switch_core_session_get_uuid ( session ) , ( char * ) data ) ;
}
struct switch_py_thread {
char * args ;
switch_memory_pool_t * pool ;
} ;
static void * SWITCH_THREAD_FUNC py_thread_run ( switch_thread_t * thread , void * obj )
{
switch_memory_pool_t * pool ;
struct switch_py_thread * pt = ( struct switch_py_thread * ) obj ;
eval_some_python ( NULL , strdup ( pt - > args ) ) ;
2006-09-10 23:20:44 +00:00
2007-05-07 21:27:42 +00:00
pool = pt - > pool ;
switch_core_destroy_memory_pool ( & pool ) ;
2006-09-10 23:20:44 +00:00
2007-05-07 21:27:42 +00:00
return NULL ;
2006-09-10 23:20:44 +00:00
}
2007-05-12 21:36:15 +00:00
SWITCH_STANDARD_API ( launch_python )
2006-12-21 17:11:43 +00:00
{
2007-05-07 21:27:42 +00:00
switch_thread_t * thread ;
switch_threadattr_t * thd_attr = NULL ;
switch_memory_pool_t * pool ;
struct switch_py_thread * pt ;
2006-12-21 17:11:43 +00:00
2007-05-12 21:36:15 +00:00
if ( switch_strlen_zero ( cmd ) ) {
2007-03-29 22:31:56 +00:00
stream - > write_function ( stream , " USAGE: %s \n " , python_run_interface . syntax ) ;
return SWITCH_STATUS_SUCCESS ;
}
2007-05-07 21:27:42 +00:00
switch_core_new_memory_pool ( & pool ) ;
assert ( pool ! = NULL ) ;
2006-12-21 17:11:43 +00:00
2007-05-07 21:27:42 +00:00
pt = switch_core_alloc ( pool , sizeof ( * pt ) ) ;
assert ( pt ! = NULL ) ;
2006-12-21 17:11:43 +00:00
2007-05-07 21:27:42 +00:00
pt - > pool = pool ;
2007-05-12 21:36:15 +00:00
pt - > args = switch_core_strdup ( pt - > pool , cmd ) ;
2007-05-07 21:27:42 +00:00
switch_threadattr_create ( & thd_attr , pt - > pool ) ;
switch_threadattr_detach_set ( thd_attr , 1 ) ;
switch_threadattr_stacksize_set ( thd_attr , SWITCH_THREAD_STACKSIZE ) ;
switch_thread_create ( & thread , thd_attr , py_thread_run , pt , pt - > pool ) ;
2006-12-21 17:11:43 +00:00
2007-03-29 22:31:56 +00:00
stream - > write_function ( stream , " OK \n " ) ;
return SWITCH_STATUS_SUCCESS ;
2006-12-21 17:11:43 +00:00
}
2007-06-13 20:40:06 +00:00
static switch_application_interface_t python_application_interface = {
2006-09-10 23:20:44 +00:00
/*.interface_name */ " python " ,
2007-02-26 21:38:10 +00:00
/*.application_function */ python_function ,
NULL , NULL , NULL ,
2007-03-29 22:31:56 +00:00
/* flags */ SAF_NONE ,
/* should we support no media mode here? If so, we need to detect the mode, and either disable the media functions or indicate media if/when we need */
/*.next */ NULL
2006-09-10 23:20:44 +00:00
} ;
2006-12-21 17:11:43 +00:00
static switch_api_interface_t python_run_interface = {
2007-03-29 22:31:56 +00:00
/*.interface_name */ " python " ,
/*.desc */ " run a python script " ,
/*.function */ launch_python ,
/*.syntax */ " python </path/to/script> " ,
/*.next */ NULL
2006-12-21 17:11:43 +00:00
} ;
2006-09-10 23:20:44 +00:00
static switch_loadable_module_interface_t python_module_interface = {
/*.module_name */ modname ,
/*.endpoint_interface */ NULL ,
/*.timer_interface */ NULL ,
/*.dialplan_interface */ NULL ,
/*.codec_interface */ NULL ,
/*.application_interface */ & python_application_interface ,
2006-12-21 17:11:43 +00:00
/*.api_interface */ & python_run_interface ,
2006-09-10 23:20:44 +00:00
/*.file_interface */ NULL ,
/*.speech_interface */ NULL ,
/*.directory_interface */ NULL
} ;
2007-06-13 17:48:49 +00:00
SWITCH_MODULE_LOAD_FUNCTION ( mod_python_load )
2006-09-10 23:20:44 +00:00
{
/* connect my internal structure to the blank pointer passed to me */
* module_interface = & python_module_interface ;
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_NOTICE , " Python Framework Loading... \n " ) ;
2007-05-07 21:27:42 +00:00
2007-06-15 17:25:41 +00:00
if ( ! Py_IsInitialized ( ) ) {
2007-05-07 21:27:42 +00:00
2007-06-15 17:25:41 +00:00
// initialize python system
Py_Initialize ( ) ;
2007-05-07 21:27:42 +00:00
2007-06-15 17:25:41 +00:00
// create GIL and a threadstate
PyEval_InitThreads ( ) ;
2006-09-10 23:20:44 +00:00
2007-06-15 17:25:41 +00:00
// save threadstate since it's interp field will be needed
// to create new threadstates, and will be needed for shutdown
mainThreadState = PyThreadState_Get ( ) ;
// swap out threadstate since the call threads will create
// their own and swap in their threadstate
PyThreadState_Swap ( NULL ) ;
// release GIL
PyEval_ReleaseLock ( ) ;
}
2007-05-08 15:44:44 +00:00
2006-09-10 23:20:44 +00:00
/* indicate that the module should continue to be loaded */
return SWITCH_STATUS_SUCCESS ;
}
/*
2007-05-07 21:27:42 +00:00
Called when the system shuts down */
2007-06-13 17:48:49 +00:00
SWITCH_MODULE_SHUTDOWN_FUNCTION ( mod_python_shutdown )
2007-05-07 21:27:42 +00:00
{
2007-05-10 18:51:47 +00:00
PyInterpreterState * mainInterpreterState ;
PyThreadState * myThreadState ;
2007-05-07 21:27:42 +00:00
2007-05-10 18:51:47 +00:00
PyEval_AcquireLock ( ) ;
mainInterpreterState = mainThreadState - > interp ;
myThreadState = PyThreadState_New ( mainInterpreterState ) ;
PyThreadState_Swap ( myThreadState ) ;
PyEval_ReleaseLock ( ) ;
2007-05-07 21:27:42 +00:00
2007-05-10 18:51:47 +00:00
Py_Finalize ( ) ;
PyEval_ReleaseLock ( ) ;
return SWITCH_STATUS_SUCCESS ;
2007-05-07 21:27:42 +00:00
}
2006-09-10 23:20:44 +00:00
/* Return the number of arguments of the application command line */