blob: 6605bf2773bef7dcba6bf1736aae2a6774dd4f26 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (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.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <axis2_listener_manager.h>
#include <axis2_const.h>
#include <axutil_hash.h>
#include <axis2_transport_receiver.h>
/**
* keep information about the listener for a given transport
*/
typedef struct axis2_transport_listener_state
{
int waiting_calls;
axis2_transport_receiver_t *listener;
} axis2_transport_listener_state_t;
struct axis2_listener_manager
{
/** hash map of listeners */
axis2_transport_listener_state_t *listener_map[AXIS2_TRANSPORT_ENUM_MAX];
axutil_thread_t *listener_thread[AXIS2_TRANSPORT_ENUM_MAX];
/** configuration context */
axis2_conf_ctx_t *conf_ctx;
};
typedef struct axis2_listener_manager_worker_func_args
{
const axutil_env_t *env;
axis2_listener_manager_t *listner_manager;
axis2_transport_receiver_t *listener;
} axis2_listener_manager_worker_func_args_t;
void *AXIS2_THREAD_FUNC axis2_listener_manager_worker_func(
axutil_thread_t * thd,
void *data);
AXIS2_EXTERN axis2_listener_manager_t *AXIS2_CALL
axis2_listener_manager_create(
const axutil_env_t * env)
{
axis2_listener_manager_t *listener_manager = NULL;
int i = 0;
AXIS2_ENV_CHECK(env, NULL);
listener_manager = AXIS2_MALLOC(env->allocator, sizeof(axis2_listener_manager_t));
if(!listener_manager)
{
AXIS2_ERROR_SET(env->error, AXIS2_ERROR_NO_MEMORY, AXIS2_FAILURE);
AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI, "No memory. Cannot create listener manager.");
return NULL;
}
listener_manager->conf_ctx = NULL;
for(i = 0; i < AXIS2_TRANSPORT_ENUM_MAX; i++)
{
listener_manager->listener_map[i] = NULL;
listener_manager->listener_thread[i] = NULL;
}
return listener_manager;
}
AXIS2_EXTERN axis2_status_t AXIS2_CALL
axis2_listener_manager_make_sure_started(
axis2_listener_manager_t * listener_manager,
const axutil_env_t * env,
const AXIS2_TRANSPORT_ENUMS transport,
axis2_conf_ctx_t * conf_ctx)
{
axis2_transport_listener_state_t *tl_state = NULL;
AXIS2_PARAM_CHECK(env->error, conf_ctx, AXIS2_FAILURE);
if(listener_manager->conf_ctx)
{
if(conf_ctx != listener_manager->conf_ctx)
{
AXIS2_ERROR_SET(env->error, AXIS2_ERROR_CLIENT_SIDE_SUPPORT_ONLY_ONE_CONF_CTX,
AXIS2_FAILURE);
AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI,
"Only one configuration context is supported at client side.");
return AXIS2_FAILURE;
}
}
else
{
listener_manager->conf_ctx = conf_ctx;
}
tl_state = listener_manager->listener_map[transport];
if(!tl_state)
{
/*means this transport not yet started, start the transport */
axis2_transport_in_desc_t *transport_in = NULL;
axis2_conf_t *conf = NULL;
axis2_transport_receiver_t *listener = NULL;
conf = axis2_conf_ctx_get_conf(conf_ctx, env);
if(conf)
{
transport_in = axis2_conf_get_transport_in(conf, env, transport);
if(transport_in)
{
listener = axis2_transport_in_desc_get_recv(transport_in, env);
if(listener)
{
#ifdef AXIS2_SVR_MULTI_THREADED
axutil_thread_t *worker_thread = NULL;
#endif
axis2_listener_manager_worker_func_args_t *arg_list = NULL;
arg_list = AXIS2_MALLOC(env->allocator,
sizeof(axis2_listener_manager_worker_func_args_t));
if(!arg_list)
{
AXIS2_ERROR_SET(env->error, AXIS2_ERROR_NO_MEMORY, AXIS2_FAILURE);
AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI,
"No memory. Cannot create listener manager worker function arguments.");
return AXIS2_FAILURE;
}
arg_list->env = env;
arg_list->listner_manager = listener_manager;
arg_list->listener = listener;
#ifdef AXIS2_SVR_MULTI_THREADED
if (env->thread_pool)
{
worker_thread =
axutil_thread_pool_get_thread(env->thread_pool,
axis2_listener_manager_worker_func,
(void *) arg_list);
if (!worker_thread)
{
AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI,
"Thread creation failed"
"Invoke non blocking failed");
}
else
{
/*axutil_thread_pool_thread_detach(env->thread_pool,
worker_thread);*/
/* we should not detach this, because, in the dual channel case
we should be able to terminate the thread before deleting the listener */
}
}
else
{
AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI,
"Thread pool not set in environment."
" Cannot invoke call non blocking");
}
#else
AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI, "Threading not enabled."
" Cannot start separate listener");
return AXIS2_FAILURE;
#endif
tl_state = AXIS2_MALLOC(env->allocator,
sizeof(axis2_transport_listener_state_t));
if(!tl_state)
{
AXIS2_ERROR_SET(env->error, AXIS2_ERROR_NO_MEMORY, AXIS2_FAILURE);
AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI,
"No memory. Cannot create transport listener state.");
}
else
{
tl_state->listener = listener;
tl_state->waiting_calls = 0;
listener_manager->listener_map[transport] = tl_state;
#ifdef AXIS2_SVR_MULTI_THREADED
listener_manager->listener_thread[transport] = worker_thread;
#endif
}
}
}
}
}
if(tl_state)
{
tl_state->waiting_calls++;
return AXIS2_SUCCESS;
}
else
return AXIS2_FAILURE;
}
AXIS2_EXTERN axis2_status_t AXIS2_CALL
axis2_listener_manager_stop(
axis2_listener_manager_t * listener_manager,
const axutil_env_t * env,
const AXIS2_TRANSPORT_ENUMS transport)
{
axis2_transport_listener_state_t *tl_state = NULL;
axis2_status_t status = AXIS2_FAILURE;
axutil_thread_t *listener_thread = NULL;
tl_state = listener_manager->listener_map[transport];
listener_thread = listener_manager->listener_thread[transport];
if(tl_state)
{
tl_state->waiting_calls--;
if(tl_state->waiting_calls == 0)
{
status = axis2_transport_receiver_stop(tl_state->listener, env);
if(status == AXIS2_SUCCESS)
listener_manager->listener_map[transport] = NULL;
}
}
if(listener_thread)
{
axutil_thread_pool_exit_thread(env->thread_pool, listener_thread);
listener_manager->listener_thread[transport] = NULL;
}
return status;
}
AXIS2_EXTERN axis2_endpoint_ref_t *AXIS2_CALL
axis2_listener_manager_get_reply_to_epr(
const axis2_listener_manager_t * listener_manager,
const axutil_env_t * env,
const axis2_char_t * svc_name,
const AXIS2_TRANSPORT_ENUMS transport)
{
axis2_transport_listener_state_t *tl_state = NULL;
tl_state = listener_manager->listener_map[transport];
if(tl_state)
{
return axis2_transport_receiver_get_reply_to_epr(tl_state->listener, env, svc_name);
}
return NULL;
}
AXIS2_EXTERN void AXIS2_CALL
axis2_listener_manager_free(
axis2_listener_manager_t * listener_manager,
const axutil_env_t * env)
{
int i = 0;
for(i = 0; i < AXIS2_TRANSPORT_ENUM_MAX; i++)
{
if(listener_manager->listener_map[i])
AXIS2_FREE(env->allocator, listener_manager->listener_map[i]);
}
AXIS2_FREE(env->allocator, listener_manager);
}
AXIS2_EXTERN axis2_conf_ctx_t *AXIS2_CALL
axis2_listener_manager_get_conf_ctx(
const axis2_listener_manager_t * listener_manager,
const axutil_env_t * env)
{
return listener_manager->conf_ctx;
}
void *AXIS2_THREAD_FUNC
axis2_listener_manager_worker_func(
axutil_thread_t * thd,
void *data)
{
axis2_listener_manager_worker_func_args_t *args_list = NULL;
const axutil_env_t *th_env = NULL;
args_list = (axis2_listener_manager_worker_func_args_t *)data;
if(!args_list)
return NULL;
th_env = axutil_init_thread_env(args_list->env);
/* Start the protocol server. For examlle if protocol is http axis2_http_server_start function
* of the axis2_http_receiver is called.
*/
if(args_list->listener)
{
axis2_transport_receiver_start(args_list->listener, th_env);
}
return NULL;
}