File cas_common_main.c¶
File List > broker > cas_common_main.c
Go to the documentation of this file
/*
* Copyright 2008 Search Solution Corporation
* Copyright 2016 CUBRID Corporation
*
* Licensed 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.
*
*/
/*
* cas_common_main.c
*/
#ident "$Id$"
#include <string.h>
#include <assert.h>
#include <strings.h>
#include <sys/time.h>
#include <time.h>
#if defined(WINDOWS)
#include <windows.h>
#include <dbgHelp.h>
#endif
#if !defined(WINDOWS)
#include <unistd.h>
#include <signal.h>
#include <fcntl.h>
#include <time.h>
#else
#include <signal.h>
#include <time.h>
#endif
#include "cas_common_main.h"
#include "broker_shm.h"
#include "cas_log.h"
#include "cas_handle.h"
#include "error_manager.h"
#include "ddl_log.h"
#include "broker_process_size.h"
#include "cas_common_execute.h"
#include "cas_protocol.h"
#include "cas_common_vars.h"
#include "dbi.h"
#include "perf_monitor.h"
#include "cas_network.h"
#include "broker_env_def.h"
#include "broker_filename.h"
#include "cas_sql_log2.h"
#include "broker_acl.h"
#include "cas_ssl.h"
#include "broker_util.h"
#if !defined(WINDOWS)
#include "broker_recv_fd.h"
#include <netinet/tcp.h>
#endif
static int query_sequence_num;
FN_RETURN cas_main_fn_ret = FN_KEEP_CONN;
static cas_cleanup_callback_t cleanup_callback = NULL;
static cas_database_shutdown_callback_t database_shutdown_callback = NULL;
int
cas_main_loop (CAS_MAIN_OPS * ops)
{
T_NET_BUF net_buf;
SOCKET srv_sock_fd, br_sock_fd, client_sock_fd;
char read_buf[1024];
int err_code;
int one = 1, db_info_size;
int client_ip_addr;
char cas_info[CAS_INFO_SIZE] = { CAS_INFO_STATUS_INACTIVE,
CAS_INFO_RESERVED_DEFAULT,
CAS_INFO_RESERVED_DEFAULT,
CAS_INFO_RESERVED_DEFAULT
};
FN_RETURN fn_ret = FN_KEEP_CONN;
char client_ip_str[16];
bool is_new_connection = true;
DB_CONN_INFO conn_info;
prev_cas_info[CAS_INFO_STATUS] = CAS_INFO_RESERVED_DEFAULT;
/* Initialize */
if (cas_main_init (&net_buf, &srv_sock_fd) < 0)
{
return -1;
}
/* Mode-specific initialization */
if (ops->init_specific && ops->init_specific () < 0)
{
return -1;
}
#if defined(WINDOWS)
__try
{
#endif /* WINDOWS */
for (;;)
{
ssl_client = false;
error_info_clear ();
cas_info[CAS_INFO_STATUS] = CAS_INFO_STATUS_INACTIVE;
unset_hang_check_time ();
br_sock_fd = net_connect_client (srv_sock_fd);
if (IS_INVALID_SOCKET (br_sock_fd))
{
goto finish_cas;
}
req_info.client_version = as_info->clt_version;
memcpy (req_info.driver_info, as_info->driver_info, SRV_CON_CLIENT_INFO_SIZE);
set_cas_info_size ();
#if defined(WINDOWS)
as_info->uts_status = UTS_STATUS_BUSY;
#endif /* WINDOWS */
as_info->fn_status = FN_STATUS_BUSY;
as_info->con_status = CON_STATUS_IN_TRAN;
as_info->transaction_start_time = time (0);
errors_in_transaction = 0;
client_ip_addr = 0;
/* Accept client connection */
if (cas_accept_client (br_sock_fd, &client_sock_fd, &client_ip_addr) < 0)
{
goto finish_cas;
}
set_hang_check_time ();
net_timeout_set (NET_DEFAULT_TIMEOUT);
cas_log_open (broker_name);
cas_slow_log_open (broker_name);
as_info->cur_sql_log2 = shm_appl->sql_log2;
sql_log2_init (broker_name, shm_as_index, as_info->cur_sql_log2, false);
if (as_info->cas_err_log_reset == CAS_LOG_RESET_REOPEN)
{
set_cubrid_file (FID_CUBRID_ERR_DIR, shm_appl->err_log_dir);
as_db_err_log_set (broker_name, shm_proxy_id, shm_shard_id, shm_shard_cas_id, shm_as_index, cas_shard_flag);
er_final (ER_ALL_FINAL);
er_init (NULL, ER_NEVER_EXIT);
as_info->cas_err_log_reset = 0;
}
ut_get_ipv4_string (client_ip_str, sizeof (client_ip_str), (unsigned char *) (&client_ip_addr));
cas_log_write_and_end (0, false, "CLIENT IP %s", client_ip_str);
setsockopt (client_sock_fd, IPPROTO_TCP, TCP_NODELAY, (char *) &one, sizeof (one));
ut_set_keepalive (client_sock_fd);
unset_hang_check_time ();
if (IS_INVALID_SOCKET (client_sock_fd))
{
goto finish_cas;
}
#if !defined(WINDOWS)
else
{
/* send NO_ERROR to client */
if (net_write_int (client_sock_fd, 0) < 0)
{
CLOSE_SOCKET (client_sock_fd);
goto finish_cas;
}
}
#endif
req_info.client_version = as_info->clt_version;
memcpy (req_info.driver_info, as_info->driver_info, SRV_CON_CLIENT_INFO_SIZE);
cas_client_type = as_info->cas_client_type;
if (req_info.client_version < CAS_MAKE_VER (8, 2, 0))
{
db_info_size = SRV_CON_DB_INFO_SIZE_PRIOR_8_2_0;
}
else if (req_info.client_version < CAS_MAKE_VER (8, 4, 0))
{
db_info_size = SRV_CON_DB_INFO_SIZE_PRIOR_8_4_0;
}
else
{
db_info_size = SRV_CON_DB_INFO_SIZE;
}
if (IS_SSL_CLIENT (req_info.driver_info))
{
err_code = cas_init_ssl (client_sock_fd);
if (err_code < 0)
{
net_write_error (client_sock_fd, req_info.client_version, req_info.driver_info, cas_info, cas_info_size,
CAS_ERROR_INDICATOR, CAS_ER_COMMUNICATION, NULL);
goto finish_cas;
}
}
if (net_read_stream (client_sock_fd, read_buf, db_info_size) < 0)
{
cas_info[CAS_INFO_STATUS] = CAS_INFO_STATUS_INACTIVE;
net_write_error (client_sock_fd, req_info.client_version, req_info.driver_info, cas_info, cas_info_size,
CAS_ERROR_INDICATOR, CAS_ER_COMMUNICATION, NULL);
}
else
{
/* Parse DB connection information */
err_code = cas_parse_db_info (read_buf, db_info_size, &req_info, &conn_info);
if (err_code == -2)
{
/* Health check request */
cas_log_write_and_end (0, false, "Incoming health check request from client.");
net_write_int (client_sock_fd, 0);
cas_info[CAS_INFO_STATUS] = CAS_INFO_STATUS_ACTIVE;
net_write_stream (client_sock_fd, cas_info, cas_info_size);
cas_finish_session (client_sock_fd, ssl_client);
goto finish_cas;
}
else if (err_code < 0)
{
goto finish_cas;
}
if (ops->set_session_id)
{
ops->set_session_id ((T_CAS_PROTOCOL) req_info.client_version, conn_info.db_sessionid);
if (db_get_session_id () != DB_EMPTY_SESSION)
{
is_new_connection = false;
}
else
{
is_new_connection = true;
}
}
set_hang_check_time ();
cas_log_debug (ARG_FILE_LINE, "db_name %s db_user %s url %s " "session id %s", conn_info.db_name,
conn_info.db_user, conn_info.url, conn_info.db_sessionid);
if (as_info->reset_flag == TRUE)
{
cas_log_debug (ARG_FILE_LINE, "main: set reset_flag");
if (ops->set_session_id)
{
cas_set_db_connect_status (-1); /* DB_CONNECTION_STATUS_RESET */
}
as_info->reset_flag = FALSE;
}
unset_hang_check_time ();
err_code =
cas_handle_db_connection (client_sock_fd, &req_info, &conn_info, cas_info, client_ip_addr, ops,
is_new_connection);
if (err_code < 0)
{
cas_finish_session (client_sock_fd, ssl_client);
goto finish_cas;
}
set_hang_check_time ();
/* Common post-connection setup */
as_info->auto_commit_mode = FALSE;
cas_log_write_and_end (0, false, "DEFAULT isolation_level %d, " "lock_timeout %d",
cas_default_isolation_level, cas_default_lock_timeout);
as_info->cur_keep_con = shm_appl->keep_connection;
cas_bi_set_statement_pooling (shm_appl->statement_pooling);
if (shm_appl->statement_pooling)
{
as_info->cur_statement_pooling = ON;
}
else
{
as_info->cur_statement_pooling = OFF;
}
cas_bi_set_cci_pconnect (shm_appl->cci_pconnect);
if (DOES_CLIENT_UNDERSTAND_THE_PROTOCOL (req_info.client_version, PROTOCOL_V12))
{
cas_bi_set_oracle_compat_number_behavior (prm_get_bool_value (PRM_ID_ORACLE_COMPAT_NUMBER_BEHAVIOR));
}
cas_info[CAS_INFO_STATUS] = CAS_INFO_STATUS_ACTIVE;
if (ops->send_connect_reply)
{
ops->send_connect_reply ((T_CAS_PROTOCOL) req_info.client_version, client_sock_fd, cas_info);
}
as_info->cci_default_autocommit = shm_appl->cci_default_autocommit;
req_info.need_rollback = TRUE;
gettimeofday (&tran_start_time, NULL);
logddl_set_start_time (&tran_start_time);
gettimeofday (&query_start_time, NULL);
tran_timeout = 0;
query_timeout = 0;
cas_log_error_handler_begin ();
con_status_before_check_cas = -1;
is_first_request = true;
fn_ret = FN_KEEP_CONN;
cas_main_fn_ret = fn_ret;
while (fn_ret == FN_KEEP_CONN)
{
#if !defined(WINDOWS)
signal (SIGUSR1, query_cancel);
#endif /* !WINDOWS */
fn_ret = ops->process_request (client_sock_fd, &net_buf, &req_info, srv_sock_fd);
cas_main_fn_ret = fn_ret;
as_info->fn_status = FN_STATUS_DONE;
is_first_request = false;
cas_log_error_handler_clear ();
#if !defined(WINDOWS)
signal (SIGUSR1, SIG_IGN);
#endif /* !WINDOWS */
as_info->last_access_time = time (NULL);
}
prev_cas_info[CAS_INFO_STATUS] = CAS_INFO_RESERVED_DEFAULT;
if (as_info->cur_statement_pooling)
{
hm_srv_handle_free_all (true);
}
/* Cleanup session */
if (ops->cleanup_session)
{
ops->cleanup_session ();
}
cas_log_error_handler_end ();
}
cas_finish_session (client_sock_fd, ssl_client);
finish_cas:
as_info->fn_status = FN_STATUS_IDLE;
set_hang_check_time ();
#if defined(WINDOWS)
as_info->close_flag = 1;
#endif /* WINDOWS */
if (as_info->con_status != CON_STATUS_CLOSE_AND_CONNECT)
{
memset (as_info->cas_clt_ip, 0x0, sizeof (as_info->cas_clt_ip));
as_info->cas_clt_port = 0;
as_info->driver_version[0] = '\0';
}
as_info->transaction_start_time = (time_t) 0;
cas_log_write_and_end (0, true, "disconnect");
cas_log_write2 (sql_log2_get_filename ());
cas_log_write_and_end (0, false, "STATE idle");
cas_log_close (true);
cas_slow_log_close ();
sql_log2_end (true);
#if defined(WINDOWS)
cas_req_count++;
#endif /* WINDOWS */
unset_hang_check_time ();
if (is_server_aborted ())
{
#if defined(WINDOWS)
CLOSE_SOCKET (srv_sock_fd);
WSACleanup ();
#endif
cas_final ();
return 0;
}
else if (!(as_info->cur_keep_con == KEEP_CON_AUTO && as_info->con_status == CON_STATUS_CLOSE_AND_CONNECT))
{
if (restart_is_needed ())
{
#if defined(WINDOWS)
CLOSE_SOCKET (srv_sock_fd);
WSACleanup ();
#endif
cas_final ();
return 0;
}
else
{
as_info->uts_status = UTS_STATUS_IDLE;
}
}
}
#if defined(WINDOWS)
}
__except (CreateMiniDump (GetExceptionInformation ()))
{
}
#endif /* WINDOWS */
return 0;
}
/* cas_main() common initialization */
int
cas_main_init (T_NET_BUF * net_buf, SOCKET * srv_sock_fd)
{
#if defined(WINDOWS)
int new_port;
#else
char port_name[BROKER_PATH_MAX];
#endif /* WINDOWS */
#if defined(WINDOWS)
if (shm_appl->as_port > 0)
{
new_port = shm_appl->as_port + shm_as_index;
}
else
{
new_port = 0;
}
*srv_sock_fd = net_init_env (&new_port);
#else /* WINDOWS */
ut_get_as_port_name (port_name, broker_name, shm_as_index, BROKER_PATH_MAX);
*srv_sock_fd = net_init_env (port_name);
#endif /* WINDOWS */
if (IS_INVALID_SOCKET (*srv_sock_fd))
{
return -1;
}
net_buf_init (net_buf, cas_get_client_version ());
net_buf->data = (char *) MALLOC (NET_BUF_ALLOC_SIZE);
if (net_buf->data == NULL)
{
return -1;
}
net_buf->alloc_size = NET_BUF_ALLOC_SIZE;
cas_log_open (broker_name);
cas_slow_log_open (broker_name);
cas_log_write_and_end (0, true, "CAS STARTED pid %d", getpid ());
#if defined(WINDOWS)
as_info->as_port = new_port;
#endif /* WINDOWS */
unset_hang_check_time ();
as_info->service_ready_flag = TRUE;
as_info->fn_status = FN_STATUS_CONN;
as_info->con_status = CON_STATUS_IN_TRAN;
as_info->transaction_start_time = time (0);
as_info->cur_keep_con = KEEP_CON_DEFAULT;
query_cancel_flag = 0;
errors_in_transaction = 0;
#if !defined(WINDOWS)
psize_at_start = as_info->psize = getsize (getpid ());
#endif /* !WINDOWS */
if (shm_appl->appl_server_max_size > shm_appl->appl_server_hard_limit)
{
cas_log_write_and_end (0, true,
"CONFIGURATION WARNING - the APPL_SERVER_MAX_SIZE(%dM) is greater than the APPL_SERVER_MAX_SIZE_HARD_LIMIT(%dM)",
shm_appl->appl_server_max_size / ONE_K, shm_appl->appl_server_hard_limit / ONE_K);
}
stripped_column_name = shm_appl->stripped_column_name;
// init error manager with default arguments; should be reinitialized later
er_init (NULL, ER_NEVER_EXIT);
logddl_init (APP_NAME_CAS);
return 0;
}
/* Set cleanup callback (for CGW specific cleanup) */
void
cas_set_cleanup_callback (cas_cleanup_callback_t callback)
{
cleanup_callback = callback;
}
void
cas_set_database_shutdown_callback (cas_database_shutdown_callback_t callback)
{
database_shutdown_callback = callback;
}
int
cas_get_graceful_down_timeout (void)
{
if (as_info->advance_activate_flag)
{
return -1;
}
return 1 * 60; /* 1 min */
}
void
cas_sig_handler (int signo)
{
static int is_doing_signal_handler = 0;
if (is_doing_signal_handler)
{
return;
}
is_doing_signal_handler = 1;
signal (signo, SIG_IGN);
er_print_crash_callstack (signo);
if (signo == SIGTERM || signo == SIGABRT || signo == SIGINT)
{
cas_free (true);
}
as_info->pid = 0;
as_info->uts_status = UTS_STATUS_RESTART;
#ifdef _GCOV
exit (0);
#else
_exit (0);
#endif
}
void
cas_final (void)
{
signal (SIGTERM, SIG_IGN);
signal (SIGINT, SIG_IGN);
cas_free (false);
as_info->pid = 0;
as_info->uts_status = UTS_STATUS_RESTART;
er_final (ER_ALL_FINAL);
exit (0);
}
void
cas_free (bool from_sighandler)
{
#ifdef MEM_DEBUG
int fd;
#endif
int max_process_size;
if (from_sighandler)
{
cas_log_debug (ARG_FILE_LINE, "request cas_free() from the signal handler");
}
else
{
cas_log_debug (ARG_FILE_LINE, "request cas_free() from the cas_final()");
}
if (as_info->cur_statement_pooling && !from_sighandler)
{
hm_srv_handle_free_all (true);
}
#if defined(WINDOWS)
if (shm_appl->use_pdh_flag)
{
if ((as_info->pid == as_info->pdh_pid) && (as_info->pdh_workset > shm_appl->appl_server_max_size))
{
if (cas_log_get_fd_status () == CAS_LOG_FD_OPENED)
{
cas_log_write_and_end (0, true, "CAS MEMORY USAGE (%dM) HAS EXCEEDED MAX SIZE (%dM)",
as_info->pdh_workset / ONE_K, shm_appl->appl_server_max_size / ONE_K);
}
else
{
cas_log_open_and_write (broker_name, 0, true,
"CAS MEMORY USAGE (%dM) HAS EXCEEDED MAX SIZE (%dM)",
as_info->pdh_workset / ONE_K, shm_appl->appl_server_max_size / ONE_K);
}
}
if ((as_info->pid == as_info->pdh_pid) && (as_info->pdh_workset > shm_appl->appl_server_hard_limit))
{
if (cas_log_get_fd_status () == CAS_LOG_FD_OPENED)
{
cas_log_write_and_end (0, true, "CAS MEMORY USAGE (%dM) HAS EXCEEDED HARD LIMIT (%dM)",
as_info->pdh_workset / ONE_K, shm_appl->appl_server_hard_limit / ONE_K);
}
else
{
cas_log_open_and_write (broker_name, 0, true, "CAS MEMORY USAGE (%dM) HAS EXCEEDED HARD LIMIT (%dM)",
as_info->pdh_workset / ONE_K, shm_appl->appl_server_hard_limit / ONE_K);
}
}
}
else
{
if (cas_req_count > 500)
{
if (cas_log_get_fd_status () == CAS_LOG_FD_OPENED)
{
cas_log_write_and_end (0, true, "CAS REQUEST COUNT (%d) HAS EXCEEDED MAX LIMIT (%d)", cas_req_count, 500);
}
else
{
cas_log_open_and_write (broker_name, 0, true, "CAS REQUEST COUNT (%d) HAS EXCEEDED MAX LIMIT (%d)",
cas_req_count, 500);
}
}
}
#else /* WINDOWS */
#if defined(AIX)
/* In linux, getsize() returns VSM(55M). but in AIX, getsize() returns vritual meory size for data(900K). so, the
* size of cub_cas process exceeds 'psize_at_start * 2' very easily. the linux's rule to restart cub_cas is not suit
* for AIX. In AIX, we use 20M as max_process_size. */
max_process_size = (shm_appl->appl_server_max_size > 0) ? shm_appl->appl_server_max_size : 20 * ONE_K;
#else
max_process_size = (shm_appl->appl_server_max_size > 0) ? shm_appl->appl_server_max_size : (psize_at_start * 10);
#endif
if (as_info->psize > max_process_size)
{
if (cas_log_get_fd_status () == CAS_LOG_FD_OPENED)
{
cas_log_write_and_end (0, true, "CAS MEMORY USAGE (%dM) HAS EXCEEDED MAX SIZE (%dM)", as_info->psize / ONE_K,
max_process_size / ONE_K);
}
else
{
cas_log_open_and_write (broker_name, 0, true, "CAS MEMORY USAGE (%dM) HAS EXCEEDED MAX SIZE (%dM)",
as_info->psize / ONE_K, max_process_size / ONE_K);
}
}
if (as_info->psize > shm_appl->appl_server_hard_limit)
{
if (cas_log_get_fd_status () == CAS_LOG_FD_OPENED)
{
cas_log_write_and_end (0, true, "CAS MEMORY USAGE (%dM) HAS EXCEEDED HARD LIMIT (%dM)",
as_info->psize / ONE_K, shm_appl->appl_server_hard_limit / ONE_K);
}
else
{
cas_log_open_and_write (broker_name, 0, true, "CAS MEMORY USAGE (%dM) HAS EXCEEDED HARD LIMIT (%dM)",
as_info->psize / ONE_K, shm_appl->appl_server_hard_limit / ONE_K);
}
}
#endif /* !WINDOWS */
if (cas_log_get_fd_status () == CAS_LOG_FD_OPENED)
{
cas_log_write_and_end (0, true, "CAS TERMINATED pid %d", getpid ());
}
else
{
cas_log_open_and_write (broker_name, 0, true, "CAS TERMINATED pid %d", getpid ());
}
cas_log_close (true);
cas_slow_log_close ();
logddl_destroy ();
#ifdef MEM_DEBUG
fd = open ("mem_debug.log", O_CREAT | O_TRUNC | O_WRONLY, 0666);
if (fd > 0)
{
malloc_dump (fd);
close (fd);
}
#endif
if (cleanup_callback != NULL)
{
cleanup_callback ();
}
if (database_shutdown_callback != NULL)
{
if (from_sighandler)
{
database_shutdown_callback (false);
}
else
{
database_shutdown_callback (true);
}
}
}
/*
* set_hang_check_time() -
* Mark the current time so that cas hang checker thread
* in broker can monitor the status of the cas.
* If the time is set, ALWAYS unset it
* before meeting indefinite blocking operation.
*/
void
set_hang_check_time (void)
{
if (cas_shard_flag == OFF && as_info != NULL && shm_appl != NULL && shm_appl->monitor_hang_flag)
{
as_info->claimed_alive_time = time (NULL);
}
return;
}
/*
* unset_hang_check_time -
* Clear the time and the cas is free from being monitored
* by hang checker in broker.
*/
void
unset_hang_check_time (void)
{
if (cas_shard_flag == OFF && as_info != NULL && shm_appl != NULL && shm_appl->monitor_hang_flag)
{
as_info->claimed_alive_time = (time_t) 0;
}
return;
}
bool
check_server_alive (const char *db_name, const char *db_host)
{
int i, u_index;
char *unusable_db_name;
char *unusable_db_host;
const char *check_db_host = db_host;
const char *check_db_name = db_name;
if (cas_shard_flag == OFF && as_info != NULL && shm_appl != NULL && shm_appl->monitor_server_flag)
{
/* if db_name is NULL, use the CAS shared memory */
if (db_name == NULL)
{
check_db_name = as_info->database_name;
}
/* if db_host is NULL, use the CAS shared memory */
if (db_host == NULL)
{
check_db_host = as_info->database_host;
}
u_index = shm_appl->unusable_databases_seq % 2;
for (i = 0; i < shm_appl->unusable_databases_cnt[u_index]; i++)
{
unusable_db_name = shm_appl->unusable_databases[u_index][i].database_name;
unusable_db_host = shm_appl->unusable_databases[u_index][i].database_host;
if (strcmp (unusable_db_name, check_db_name) == 0 && strcmp (unusable_db_host, check_db_host) == 0)
{
return false;
}
}
}
return true;
}
void
query_cancel (int signo)
{
#if !defined(WINDOWS)
struct timespec ts;
signal (signo, SIG_IGN);
db_set_interrupt (1);
as_info->num_interrupts %= MAX_DIAG_DATA_VALUE;
as_info->num_interrupts++;
clock_gettime (CLOCK_REALTIME, &ts);
query_cancel_time = ts.tv_sec * 1000LL;
query_cancel_time += (ts.tv_nsec / 1000000LL);
query_cancel_flag = 1;
#else
assert (0);
#endif /* !WINDOWS */
}
void
set_cas_info_size (void)
{
if (cas_shard_flag == OFF && as_info->clt_version <= CAS_MAKE_VER (8, 1, 5))
{
cas_info_size = 0;
}
else
{
cas_info_size = CAS_INFO_SIZE;
}
}
int
restart_is_needed (void)
{
if (as_info->num_holdable_results > 0 || as_info->cas_change_mode == CAS_CHANGE_MODE_KEEP)
{
/* we do not want to restart the CAS when there are open holdable results or cas_change_mode is
* CAS_CHANGE_MODE_KEEP */
return 0;
}
#if defined(WINDOWS)
if (shm_appl->use_pdh_flag == TRUE)
{
if ((as_info->pid == as_info->pdh_pid) && (as_info->pdh_workset > shm_appl->appl_server_max_size))
{
return 1;
}
else
{
return 0;
}
}
else
{
if (cas_req_count > 500)
return 1;
else
return 0;
}
#else /* WINDOWS */
int max_process_size;
#if defined(AIX)
/* In linux, getsize() returns VSM(55M). but in AIX, getsize() returns vritual meory size for data(900K). so, the
* size of cub_cas process exceeds 'psize_at_start * 2' very easily. the linux's rule to restart cub_cas is not suit
* for AIX. In AIX, we use 20M as max_process_size. */
max_process_size = (shm_appl->appl_server_max_size > 0) ? shm_appl->appl_server_max_size : 20 * ONE_K;
#else
max_process_size = (shm_appl->appl_server_max_size > 0) ? shm_appl->appl_server_max_size : (psize_at_start * 10);
#endif
if (as_info->psize > max_process_size)
{
return 1;
}
else
{
return 0;
}
#endif /* !WINDOWS */
}
int
query_seq_num_next_value (void)
{
return ++query_sequence_num;
}
int
query_seq_num_current_value (void)
{
return query_sequence_num;
}
T_BROKER_VERSION
cas_get_client_version (void)
{
return req_info.client_version;
}
int
net_read_header_keep_con_on (SOCKET clt_sock_fd, MSG_HEADER * client_msg_header)
{
int ret_value = 0;
int timeout = 0, remained_timeout = 0;
if (as_info->con_status == CON_STATUS_IN_TRAN)
{
net_timeout_set (shm_appl->session_timeout);
}
else
{
net_timeout_set (DEFAULT_CHECK_INTERVAL);
timeout = shm_appl->session_timeout;
remained_timeout = timeout;
}
do
{
if (as_info->con_status == CON_STATUS_OUT_TRAN)
{
remained_timeout -= DEFAULT_CHECK_INTERVAL;
}
if (net_read_header (clt_sock_fd, client_msg_header) < 0)
{
/* if in-transaction state, return network error */
if (as_info->con_status == CON_STATUS_IN_TRAN || !is_net_timed_out ())
{
ret_value = -1;
break;
}
/* if out-of-transaction state, check whether restart is needed */
if (as_info->con_status == CON_STATUS_OUT_TRAN && is_net_timed_out ())
{
if (as_info->reset_flag == TRUE)
{
ret_value = -1;
break;
}
if (timeout > 0 && remained_timeout <= 0)
{
ret_value = -1;
break;
}
}
}
else
{
break;
}
}
while (1);
return ret_value;
}
#if defined(WINDOWS)
LONG WINAPI
CreateMiniDump (struct _EXCEPTION_POINTERS * pException)
{
TCHAR DumpFile[MAX_PATH] = { 0, };
TCHAR DumpPath[MAX_PATH] = { 0, };
SYSTEMTIME SystemTime;
HANDLE FileHandle;
GetLocalTime (&SystemTime);
sprintf (DumpFile, "%d-%d-%d %d_%d_%d.dmp", SystemTime.wYear, SystemTime.wMonth, SystemTime.wDay, SystemTime.wHour,
SystemTime.wMinute, SystemTime.wSecond);
envvar_bindir_file (DumpPath, MAX_PATH, DumpFile);
FileHandle = CreateFile (DumpPath, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (FileHandle != INVALID_HANDLE_VALUE)
{
MINIDUMP_EXCEPTION_INFORMATION MiniDumpExceptionInfo;
BOOL Success;
MiniDumpExceptionInfo.ThreadId = GetCurrentThreadId ();
MiniDumpExceptionInfo.ExceptionPointers = pException;
MiniDumpExceptionInfo.ClientPointers = FALSE;
Success =
MiniDumpWriteDump (GetCurrentProcess (), GetCurrentProcessId (), FileHandle, MiniDumpNormal,
(pException) ? &MiniDumpExceptionInfo : NULL, NULL, NULL);
}
CloseHandle (FileHandle);
ux_database_shutdown (true);
return EXCEPTION_EXECUTE_HANDLER;
}
#endif /* WINDOWS */
/* Accept client connection and perform handshake */
int
cas_accept_client (SOCKET br_sock_fd, SOCKET * client_sock_fd, int *client_ip_addr)
{
#if defined(WINDOWS)
static int one = 1;
*client_sock_fd = br_sock_fd;
if (ioctlsocket (*client_sock_fd, FIONBIO, (u_long *) (&one)) < 0)
{
return -1;
}
memcpy (client_ip_addr, as_info->cas_clt_ip, 4);
#else /* WINDOWS */
int con_status;
char do_not_use_driver_info[SRV_CON_CLIENT_INFO_SIZE];
net_timeout_set (NET_MIN_TIMEOUT);
if (net_read_int (br_sock_fd, &con_status) < 0)
{
cas_log_write_and_end (0, false, "HANDSHAKE ERROR net_read_int(con_status)");
CLOSE_SOCKET (br_sock_fd);
return -1;
}
if (net_write_int (br_sock_fd, as_info->con_status) < 0)
{
cas_log_write_and_end (0, false, "HANDSHAKE ERROR net_write_int(con_status)");
CLOSE_SOCKET (br_sock_fd);
return -1;
}
*client_sock_fd = recv_fd (br_sock_fd, client_ip_addr, do_not_use_driver_info);
if (*client_sock_fd == -1)
{
cas_log_write_and_end (0, false, "HANDSHAKE ERROR recv_fd %d", *client_sock_fd);
CLOSE_SOCKET (br_sock_fd);
return -1;
}
if (net_write_int (br_sock_fd, as_info->uts_status) < 0)
{
cas_log_write_and_end (0, false, "HANDSHAKE ERROR net_write_int(uts_status)");
CLOSE_SOCKET (br_sock_fd);
CLOSE_SOCKET (*client_sock_fd);
return -1;
}
CLOSE_SOCKET (br_sock_fd);
#endif /* WINDOWS */
return 0;
}
/* Parse DB connection information from read buffer */
int
cas_parse_db_info (char *read_buf, int db_info_size, T_REQ_INFO * req_info, DB_CONN_INFO * conn_info)
{
int len;
char *db_name, *db_user, *db_passwd, *url, *db_sessionid;
db_name = read_buf;
db_name[SRV_CON_DBNAME_SIZE - 1] = '\0';
/* Send response to broker health checker */
if (strcmp (db_name, HEALTH_CHECK_DUMMY_DB) == 0)
{
return -2; /* Special return value for health check */
}
db_user = db_name + SRV_CON_DBNAME_SIZE;
db_user[SRV_CON_DBUSER_SIZE - 1] = '\0';
if (db_user[0] == '\0')
{
strcpy (db_user, "PUBLIC");
}
db_passwd = db_user + SRV_CON_DBUSER_SIZE;
db_passwd[SRV_CON_DBPASSWD_SIZE - 1] = '\0';
if (req_info->client_version >= CAS_MAKE_VER (8, 2, 0))
{
url = db_passwd + SRV_CON_DBPASSWD_SIZE;
url[SRV_CON_URL_SIZE - 1] = '\0';
}
else
{
url = NULL;
}
if (req_info->client_version >= CAS_MAKE_VER (8, 4, 0))
{
assert (url != NULL);
db_sessionid = url + SRV_CON_URL_SIZE;
db_sessionid[SRV_CON_DBSESS_ID_SIZE - 1] = '\0';
}
else
{
/* even drivers do not send session id (under RB-8.4.0) the cas_set_session_id() should be called */
db_sessionid = NULL;
}
as_info->driver_version[0] = '\0';
if (DOES_CLIENT_UNDERSTAND_THE_PROTOCOL (req_info->client_version, PROTOCOL_V5))
{
assert (url != NULL);
len = *(url + strlen (url) + 1);
if (len > 0 && len < SRV_CON_VER_STR_MAX_SIZE)
{
memcpy (as_info->driver_version, url + strlen (url) + 2, (int) len);
as_info->driver_version[len] = '\0';
}
else
{
snprintf (as_info->driver_version, SRV_CON_VER_STR_MAX_SIZE, "PROTOCOL V%d",
(int) (CAS_PROTO_VER_MASK & req_info->client_version));
}
}
else if (DOES_CLIENT_UNDERSTAND_THE_PROTOCOL (req_info->client_version, PROTOCOL_V1))
{
char *ver;
CAS_PROTO_TO_VER_STR (&ver, (int) (CAS_PROTO_VER_MASK & req_info->client_version));
strncpy_bufsize (as_info->driver_version, ver);
}
else
{
snprintf (as_info->driver_version, SRV_CON_VER_STR_MAX_SIZE, "%d.%d.%d",
CAS_VER_TO_MAJOR (req_info->client_version), CAS_VER_TO_MINOR (req_info->client_version),
CAS_VER_TO_PATCH (req_info->client_version));
}
cas_log_write_and_end (0, false, "CLIENT VERSION %s", as_info->driver_version);
conn_info->db_name = db_name;
conn_info->db_user = db_user;
conn_info->db_passwd = db_passwd;
conn_info->url = url;
conn_info->db_sessionid = db_sessionid;
return 0;
}
int
cas_handle_db_connection (SOCKET client_sock_fd, T_REQ_INFO * req_info,
DB_CONN_INFO * conn_info, char *cas_info, int client_ip_addr, CAS_MAIN_OPS * ops,
bool is_new_connection)
{
int err_code;
unsigned char *ip_addr;
char client_ip_str[16];
struct timeval cas_start_time;
gettimeofday (&cas_start_time, NULL);
/* Pre-connect processing */
if (ops->pre_db_connect)
{
err_code = ops->pre_db_connect (conn_info->db_name, conn_info->db_user,
conn_info->db_passwd, conn_info->url, ops->context);
if (err_code < 0)
{
char err_msg[1024];
if (conn_info->url && strstr (conn_info->url, "__gateway=true") == NULL)
{
sprintf (err_msg, "Authorization error");
}
else
{
sprintf (err_msg, "%s is not supported DBMS.", shm_appl->cgw_link_server);
}
cas_info[CAS_INFO_STATUS] = CAS_INFO_STATUS_INACTIVE;
net_write_error (client_sock_fd, req_info->client_version, req_info->driver_info, cas_info, cas_info_size,
DBMS_ERROR_INDICATOR, CAS_ER_NOT_AUTHORIZED_CLIENT, err_msg);
return err_code;
}
}
/* Access control check */
ip_addr = (unsigned char *) (&client_ip_addr);
if (shm_appl->access_control)
{
if (access_control_check_right (shm_appl, conn_info->db_name, conn_info->db_user, ip_addr) < 0)
{
char err_msg[1024];
as_info->num_connect_rejected++;
sprintf (err_msg, "Authorization error.(Address is rejected)");
cas_info[CAS_INFO_STATUS] = CAS_INFO_STATUS_INACTIVE;
net_write_error (client_sock_fd, req_info->client_version, req_info->driver_info, cas_info, cas_info_size,
DBMS_ERROR_INDICATOR, CAS_ER_NOT_AUTHORIZED_CLIENT, err_msg);
set_hang_check_time ();
cas_log_write_and_end (0, false, "connect db %s user %s url %s - rejected", conn_info->db_name,
conn_info->db_user, conn_info->url);
if (shm_appl->access_log == ON)
{
cas_access_log (&cas_start_time, shm_as_index, client_ip_addr, conn_info->db_name, conn_info->db_user,
ACL_REJECTED);
}
unset_hang_check_time ();
return -1;
}
}
/* DB connection */
err_code =
ops->db_connect (client_sock_fd, conn_info->db_name, conn_info->db_user, conn_info->db_passwd, conn_info->url,
req_info, cas_info);
if (err_code < 0)
{
return -1;
}
/* Post-connect processing */
if (ops->post_db_connect)
{
ops->post_db_connect (ops->context, &cas_start_time, shm_as_index, client_ip_addr, conn_info->db_name,
conn_info->db_user, conn_info->url, is_new_connection);
}
ut_get_ipv4_string (client_ip_str, sizeof (client_ip_str), (unsigned char *) (&client_ip_addr));
logddl_check_ddl_audit_param ();
logddl_set_broker_info (shm_as_index, shm_appl->broker_name);
logddl_set_ip (client_ip_str);
db_set_client_ip_addr (client_ip_str);
return 0;
}
void
cas_finish_session (SOCKET client_sock_fd, bool ssl_client)
{
CLOSE_SOCKET (client_sock_fd);
if (ssl_client)
{
cas_ssl_close (client_sock_fd);
}
}
void
cas_set_db_connect_status (int status)
{
db_set_connect_status (status);
}
int
cas_get_db_connect_status (void)
{
return db_get_connect_status ();
}
int
net_read_int_keep_con_auto (SOCKET clt_sock_fd, MSG_HEADER * client_msg_header, T_REQ_INFO * req_info,
SOCKET srv_sock_fd)
{
int ret_value = 0;
if (as_info->con_status == CON_STATUS_IN_TRAN)
{
/* holdable results have the same lifespan of a normal session */
net_timeout_set (shm_appl->session_timeout);
}
else
{
net_timeout_set (DEFAULT_CHECK_INTERVAL);
new_req_sock_fd = srv_sock_fd;
}
do
{
if (as_info->cas_log_reset)
{
cas_log_reset (broker_name);
}
if (as_info->cas_slow_log_reset)
{
cas_slow_log_reset (broker_name);
}
if (as_info->con_status != CON_STATUS_IN_TRAN && as_info->reset_flag == TRUE)
{
return -1;
}
if (as_info->con_status == CON_STATUS_CLOSE || as_info->con_status == CON_STATUS_CLOSE_AND_CONNECT)
{
break;
}
if (net_read_header (clt_sock_fd, client_msg_header) < 0)
{
/* if in-transaction state, return network error */
if (as_info->con_status == CON_STATUS_IN_TRAN || !is_net_timed_out ())
{
ret_value = -1;
break;
}
/* if out-of-transaction state, check whether restart is needed */
if (as_info->con_status == CON_STATUS_OUT_TRAN && is_net_timed_out ())
{
if (restart_is_needed ())
{
cas_log_debug (ARG_FILE_LINE, "net_read_int_keep_con_auto: " "restart_is_needed()");
ret_value = -1;
break;
}
if (as_info->reset_flag == TRUE)
{
ret_value = -1;
break;
}
}
}
else
{
break;
}
}
while (1);
new_req_sock_fd = INVALID_SOCKET;
CON_STATUS_LOCK (&(shm_appl->as_info[shm_as_index]), CON_STATUS_LOCK_CAS);
if (as_info->con_status == CON_STATUS_OUT_TRAN)
{
as_info->num_request++;
gettimeofday (&tran_start_time, NULL);
}
logddl_set_start_time (&tran_start_time);
if (as_info->con_status == CON_STATUS_CLOSE || as_info->con_status == CON_STATUS_CLOSE_AND_CONNECT)
{
ret_value = -1;
}
else
{
if (as_info->con_status != CON_STATUS_IN_TRAN)
{
as_info->con_status = CON_STATUS_IN_TRAN;
as_info->transaction_start_time = time (0);
errors_in_transaction = 0;
}
}
CON_STATUS_UNLOCK (&(shm_appl->as_info[shm_as_index]), CON_STATUS_LOCK_CAS);
return ret_value;
}