Skip to content

File cas.c

File List > broker > cas.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.c -
 */

#ident "$Id$"

#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <assert.h>

#if defined(WINDOWS)
#include <winsock2.h>
#include <windows.h>
#include <process.h>
#include <sys/timeb.h>
#include <dbgHelp.h>
#else /* WINDOWS */
#include <unistd.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <sys/socket.h>
#include <sys/time.h>
#endif /* WINDOWS */

#include "cas_common.h"
#include "cas_common_main.h"
#include "cas_common_vars.h"
#include "broker_shm.h"
#include "broker_util.h"
#include "broker_env_def.h"
#include "broker_filename.h"
#include "cas_log.h"
#include "cas_common_execute.h"
#include "perf_monitor.h"
#include "cas_sql_log2.h"
#include "error_manager.h"
#include "ddl_log.h"

#include "cas.h"
#include "cas_network.h"
#include "cas_function.h"
#include "cas_net_buf.h"
#include "cas_execute.h"
#include "connection_support.hpp"
#include "broker_process_size.h"
#include "cas_ssl.h"

static char cas_db_name[MAX_HA_DBINFO_LENGTH];
static char cas_db_user[SRV_CON_DBUSER_SIZE];
static char cas_db_passwd[SRV_CON_DBPASSWD_SIZE];

/* ========================================================================
 * Function Tables
 * ======================================================================== */
static T_SERVER_FUNC server_fn_table[] = {
  fn_end_tran,          /* CAS_FC_END_TRAN */
  fn_prepare,           /* CAS_FC_PREPARE */
  fn_execute,           /* CAS_FC_EXECUTE */
  fn_get_db_parameter,      /* CAS_FC_GET_DB_PARAMETER */
  fn_set_db_parameter,      /* CAS_FC_SET_DB_PARAMETER */
  fn_close_req_handle,      /* CAS_FC_CLOSE_REQ_HANDLE */
  fn_cursor,            /* CAS_FC_CURSOR */
  fn_fetch,         /* CAS_FC_FETCH */
  fn_schema_info,       /* CAS_FC_SCHEMA_INFO */
  fn_oid_get,           /* CAS_FC_OID_GET */
  fn_oid_put,           /* CAS_FC_OID_SET */
  fn_deprecated,        /* CAS_FC_DEPRECATED1 *//* fn_glo_new */
  fn_deprecated,        /* CAS_FC_DEPRECATED2 *//* fn_glo_save */
  fn_deprecated,        /* CAS_FC_DEPRECATED3 *//* fn_glo_load */
  fn_get_db_version,        /* CAS_FC_GET_DB_VERSION */
  fn_get_class_num_objs,    /* CAS_FC_GET_CLASS_NUM_OBJS */
  fn_oid,           /* CAS_FC_OID_CMD */
  fn_collection,        /* CAS_FC_COLLECTION */
  fn_next_result,       /* CAS_FC_NEXT_RESULT */
  fn_execute_batch,     /* CAS_FC_EXECUTE_BATCH */
  fn_execute_array,     /* CAS_FC_EXECUTE_ARRAY */
  fn_cursor_update,     /* CAS_FC_CURSOR_UPDATE */
  fn_get_attr_type_str,     /* CAS_FC_GET_ATTR_TYPE_STR */
  fn_get_query_info,        /* CAS_FC_GET_QUERY_INFO */
  fn_deprecated,        /* CAS_FC_DEPRECATED4 *//* fn_glo_cmd */
  fn_savepoint,         /* CAS_FC_SAVEPOINT */
  fn_parameter_info,        /* CAS_FC_PARAMETER_INFO */
  fn_xa_prepare,        /* CAS_FC_XA_PREPARE */
  fn_xa_recover,        /* CAS_FC_XA_RECOVER */
  fn_xa_end_tran,       /* CAS_FC_XA_END_TRAN */
  fn_con_close,         /* CAS_FC_CON_CLOSE */
  fn_check_cas,         /* CAS_FC_CHECK_CAS */
  fn_make_out_rs,       /* CAS_FC_MAKE_OUT_RS */
  fn_get_generated_keys,    /* CAS_FC_GET_GENERATED_KEYS */
  fn_lob_new,           /* CAS_FC_LOB_NEW */
  fn_lob_write,         /* CAS_FC_LOB_WRITE */
  fn_lob_read,          /* CAS_FC_LOB_READ */
  fn_end_session,       /* CAS_FC_END_SESSION */
  fn_get_row_count,     /* CAS_FC_GET_ROW_COUNT */
  fn_get_last_insert_id,    /* CAS_FC_GET_LAST_INSERT_ID */
  fn_prepare_and_execute,   /* CAS_FC_PREPARE_AND_EXECUTE */
  fn_cursor_close,      /* CAS_FC_CURSOR_CLOSE */
  fn_not_supported,     /* CAS_FC_GET_SHARD_INFO */
  fn_set_cas_change_mode    /* CAS_FC_SET_CAS_CHANGE_MODE */
};

static const char *server_func_name[] = {
  "end_tran",
  "prepare",
  "execute",
  "get_db_parameter",
  "set_db_parameter",
  "close_req_handle",
  "cursor",
  "fetch",
  "schema_info",
  "oid_get",
  "oid_put",
  "glo_new(deprecated)",
  "glo_save(deprecated)",
  "glo_load(deprecated)",
  "get_db_version",
  "get_class_num_objs",
  "oid",
  "collection",
  "next_result",
  "execute_batch",
  "execute_array",
  "cursor_update",
  "get_attr_type_str",
  "get_query_info",
  "glo_cmd(deprecated)",
  "savepoint",
  "parameter_info",
  "xa_prepare",
  "xa_recover",
  "xa_end_tran",
  "con_close",
  "check_cas",
  "fn_make_out_rs",
  "fn_get_generated_keys",
  "fn_lob_new",
  "fn_lob_write",
  "fn_lob_read",
  "fn_end_session",
  "fn_get_row_count",
  "fn_get_last_insert_id",
  "fn_prepare_and_execute",
  "fn_cursor_close",
  "fn_get_shard_info",
  "fn_set_cas_change_mode"
};


static void set_db_connection_info (void);
static void clear_db_connection_info (void);
static bool need_database_reconnect (void);
static FN_RETURN process_request (SOCKET sock_fd, T_NET_BUF * net_buf, T_REQ_INFO * req_info, SOCKET srv_sock_fd);

#if defined(WINDOWS)
LONG WINAPI CreateMiniDump (struct _EXCEPTION_POINTERS *pException);
#endif /* WINDOWS */

/* Main functions */
static int cas_main (void);
static int shard_cas_main (void);
static int cas_init (void);
static int cas_init_shm (void);
static int cas_register_to_proxy (SOCKET proxy_sock_fd);
static int net_read_process (SOCKET proxy_sock_fd, MSG_HEADER * client_msg_header, T_REQ_INFO * req_info);
static void set_db_parameter (void);

/* Callback functions for cas_main_loop() */
static int cas_db_connect (SOCKET client_sock_fd, const char *db_name, const char *db_user, const char *db_passwd,
               const char *url, T_REQ_INFO * req_info, char *cas_info);
static void cas_post_db_connect (void *context, struct timeval *cas_start_time, int shm_as_index, int client_ip_addr,
                 char *db_name, char *db_user, const char *url, bool is_new_connection);
static void cas_cleanup_session (void);

/* Protocol functions */
static void cas_send_connect_reply_to_driver (T_CAS_PROTOCOL protocol, SOCKET client_sock_fd, char *cas_info);
static void cas_make_session_for_driver (char *out);
static void cas_set_session_id (T_CAS_PROTOCOL protocol, char *session);

#if defined(WINDOWS)
int WINAPI
WinMain (HINSTANCE hInstance,   // handle to current instance
     HINSTANCE hPrevInstance,   // handle to previous instance
     LPSTR lpCmdLine,   // pointer to command line
     int nShowCmd       // show state of window
  )
#else /* WINDOWS */
int
main (int argc, char *argv[])
#endif
{
  int res = 0;

#if !defined(WINDOWS)
  signal (SIGTERM, cas_sig_handler);
  signal (SIGINT, cas_sig_handler);
  signal (SIGSEGV, cas_sig_handler);
  signal (SIGABRT, cas_sig_handler);
  signal (SIGFPE, cas_sig_handler);
  signal (SIGILL, cas_sig_handler);
  signal (SIGBUS, cas_sig_handler);
  signal (SIGSYS, cas_sig_handler);
  signal (SIGUSR1, SIG_IGN);
  signal (SIGPIPE, SIG_IGN);
  signal (SIGXFSZ, SIG_IGN);
#endif /* WINDOWS */

  if (cas_init () < 0)
    {
      fprintf (stderr, "CAS initialization failed. Exiting.\n");
      return -1;
    }

#if !defined(WINDOWS)
  program_name = argv[0];
  if (argc == 2 && strcmp (argv[1], "--version") == 0)
    {
      printf ("%s\n", makestring (BUILD_NUMBER));
      return 0;
    }
#else /* !WINDOWS */
  program_name = APPL_SERVER_CAS_NAME;
#endif /* !WINDOWS */

  memset (&req_info, 0, sizeof (req_info));

  set_cubrid_home ();

  if (cas_shard_flag == ON)
    {
      res = shard_cas_main ();
    }
  else
    {
      res = cas_main ();
    }

  return res;
}

static int
cas_main (void)
{
  CAS_MAIN_OPS ops = {
    .init_specific = NULL,  /* cas.c has no specific initialization */
    .pre_db_connect = NULL, /* No pre-connect processing for cas.c */
    .db_connect = cas_db_connect,
    .post_db_connect = cas_post_db_connect,
    .cleanup_session = cas_cleanup_session,
    .process_request = process_request,
    .set_session_id = cas_set_session_id,
    .send_connect_reply = cas_send_connect_reply_to_driver,
    .context = NULL
  };

  return cas_main_loop (&ops);
}

static void
cas_make_session_for_driver (char *out)
{
  size_t size = 0;
  SESSION_ID session;


  memcpy (out + size, db_get_server_session_key (), SERVER_SESSION_KEY_SIZE);
  size += SERVER_SESSION_KEY_SIZE;
  session = db_get_session_id ();
  session = htonl (session);
  memcpy (out + size, &session, sizeof (SESSION_ID));
  size += sizeof (SESSION_ID);
  memset (out + size, 0, DRIVER_SESSION_SIZE - size);
}

static void
cas_set_session_id (T_CAS_PROTOCOL protocol, char *session)
{
  SESSION_ID id = DB_EMPTY_SESSION;

  if (DOES_CLIENT_UNDERSTAND_THE_PROTOCOL (protocol, PROTOCOL_V3))
    {
      id = *(SESSION_ID *) (session + 8);
      id = ntohl (id);
      db_set_server_session_key (session);
      db_set_session_id (id);
      cas_log_write_and_end (0, false, "session id for connection %u", id);
    }
  else
    {
      /* always create new session for old drivers */
      char key[] =
    { (char) 0xFF, (char) 0xFF, (char) 0xFF, (char) 0xFF, (char) 0xFF, (char) 0xFF, (char) 0xFF, (char) 0xFF };

      cas_log_write_and_end (0, false, "session id (old protocol) for connection 0");
      db_set_server_session_key (key);
      db_set_session_id (DB_EMPTY_SESSION);
    }
}

static void
cas_send_connect_reply_to_driver (T_CAS_PROTOCOL protocol, SOCKET client_sock_fd, char *cas_info)
{
  char msgbuf[CAS_CONNECTION_REPLY_SIZE + 8];
  char *p = msgbuf;
  char sessid[DRIVER_SESSION_SIZE];
  int v;

  cas_make_session_for_driver (sessid);

  if (DOES_CLIENT_UNDERSTAND_THE_PROTOCOL (protocol, PROTOCOL_V4))
    {
      v = htonl (CAS_CONNECTION_REPLY_SIZE);
    }
  else if (DOES_CLIENT_UNDERSTAND_THE_PROTOCOL (protocol, PROTOCOL_V3))
    {
      v = htonl (CAS_CONNECTION_REPLY_SIZE_V3);
    }
  else
    {
      v = htonl (CAS_CONNECTION_REPLY_SIZE_PRIOR_PROTOCOL_V3);
    }
  memcpy (p, &v, sizeof (int));
  p += sizeof (int);
  if (cas_info_size > 0)
    {
      memcpy (p, cas_info, cas_info_size);
      p += cas_info_size;
    }
  v = htonl (getpid ());
  memcpy (p, &v, CAS_PID_SIZE);
  p += CAS_PID_SIZE;
  memcpy (p, cas_bi_get_broker_info (), BROKER_INFO_SIZE);
  p += BROKER_INFO_SIZE;
  if (DOES_CLIENT_UNDERSTAND_THE_PROTOCOL (protocol, PROTOCOL_V4))
    {
      v = htonl (shm_as_index + 1);
      memcpy (p, &v, CAS_PID_SIZE);
      p += CAS_PID_SIZE;
    }
  if (DOES_CLIENT_UNDERSTAND_THE_PROTOCOL (protocol, PROTOCOL_V3))
    {
      memcpy (p, sessid, DRIVER_SESSION_SIZE);
      p += DRIVER_SESSION_SIZE;
    }
  else
    {
      v = htonl (db_get_session_id ());
      memcpy (p, &v, SESSION_ID_SIZE);
      p += SESSION_ID_SIZE;
    }
  net_write_stream (client_sock_fd, msgbuf, p - msgbuf);
}

static int
cas_db_connect (SOCKET client_sock_fd, const char *db_name, const char *db_user, const char *db_passwd, const char *url,
        T_REQ_INFO * req_info, char *cas_info)
{
  int err_code;
  char *db_err_msg = NULL;
  err_code = ux_database_connect ((char *) db_name, (char *) db_user, (char *) db_passwd, &db_err_msg);
  if (err_code < 0)
    {
      char msg_buf[LINE_MAX];
      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,
               err_info.err_indicator, err_info.err_number, db_err_msg);
      if (db_err_msg == NULL)
    {
      snprintf (msg_buf, LINE_MAX, "connect db %s user %s url %s, error:%d.", db_name, db_user, url,
            err_info.err_number);
    }
      else
    {
      snprintf (msg_buf, LINE_MAX, "connect db %s user %s url %s, error:%d, %s", db_name, db_user, url,
            err_info.err_number, db_err_msg);
    }

      cas_log_write_and_end (0, false, msg_buf);
      cas_slow_log_write_and_end (NULL, 0, msg_buf);
      cas_finish_session (client_sock_fd, ssl_client);
      FREE_MEM (db_err_msg);
      return -1;
    }

  return err_code;
}

static void
cas_post_db_connect (void *context, struct timeval *cas_start_time, int shm_as_index, int client_ip_addr, char *db_name,
             char *db_user, const char *url, bool is_new_connection)
{
  SESSION_ID session_id;

  session_id = db_get_session_id ();
  as_info->session_id = session_id;

  if (shm_appl->access_log == ON)
    {
      ACCESS_LOG_TYPE type = (is_new_connection) ? NEW_CONNECTION : CLIENT_CHANGED;

      cas_access_log (cas_start_time, shm_as_index, client_ip_addr, db_name, db_user, type);
    }

  cas_log_write_and_end (0, false, "connect db %s@%s user %s url %s" " session id %u", as_info->database_name,
             as_info->database_host, db_user, url, session_id);

  ux_set_default_setting ();
}

typedef struct
{
  FN_RETURN fn_ret;
} CAS_CLEANUP_CONTEXT;

/* Get fn_ret from cas_main_loop() */
extern FN_RETURN cas_main_fn_ret;

static void
cas_cleanup_session (void)
{
  if (!is_xa_prepared ())
    {
      if (ux_end_tran (CCI_TRAN_ROLLBACK, false, true) < 0)
    {
      as_info->reset_flag = TRUE;
    }
    }

  if (cas_main_fn_ret != FN_KEEP_SESS)
    {
      ux_end_session ();
    }

  if (is_xa_prepared ())
    {
      ux_database_shutdown (true);
      /* Note: db_name, db_user, db_passwd should be available from context */
    }

  if (as_info->reset_flag == TRUE)
    {
      ux_database_shutdown (true);
      as_info->reset_flag = FALSE;
      cas_set_db_connect_status (-1);   /* DB_CONNECTION_STATUS_RESET */
    }
}

static int
shard_cas_main (void)
{
  T_NET_BUF net_buf;
  SOCKET proxy_sock_fd = INVALID_SOCKET;
  int err_code;
  int one = 1;
  FN_RETURN fn_ret = FN_KEEP_CONN;

  struct timeval cas_start_time;

  int error;

  bool is_first = true;

  prev_cas_info[CAS_INFO_STATUS] = CAS_INFO_RESERVED_DEFAULT;

  net_buf_init (&net_buf, cas_get_client_version ());
  net_buf.data = (char *) MALLOC (SHARD_NET_BUF_ALLOC_SIZE);
  if (net_buf.data == NULL)
    {
      return -1;
    }
  net_buf.alloc_size = SHARD_NET_BUF_ALLOC_SIZE;

  as_info->service_ready_flag = TRUE;
  as_info->con_status = CON_STATUS_IN_TRAN;
  as_info->cur_keep_con = KEEP_CON_DEFAULT;
  errors_in_transaction = 0;
#if !defined(WINDOWS)
  psize_at_start = as_info->psize = getsize (getpid ());
#endif /* !WINDOWS */

  stripped_column_name = shm_appl->stripped_column_name;

conn_retry:
  if (is_first == false)
    {
      do
    {
      SLEEP_SEC (1);
    }
      while (as_info->uts_status == UTS_STATUS_RESTART || as_info->uts_status == UTS_STATUS_STOP);
    }
  is_first = false;

  net_timeout_set (-1);

  cas_log_open (broker_name);
  cas_slow_log_open (broker_name);
  cas_log_write_and_end (0, true, "CAS STARTED pid %d", getpid ());

  /* This is a only use in proxy-cas internal message */
  req_info.client_version = CAS_PROTO_CURRENT_VER;

  set_cas_info_size ();

  gettimeofday (&cas_start_time, NULL);

  int ret;
  ret = snprintf (cas_db_name, MAX_HA_DBINFO_LENGTH - 1, "%s@%s", shm_appl->shard_conn_info[shm_shard_id].db_name,
          shm_appl->shard_conn_info[shm_shard_id].db_host);

  if (ret < 0)
    {
      assert (false);
      FREE (net_buf.data);
      return -1;
    }

  set_db_connection_info ();

  if (as_info->reset_flag == TRUE)
    {
      cas_log_debug (ARG_FILE_LINE, "main: set reset_flag");
      cas_set_db_connect_status (-1);   /* DB_CONNECTION_STATUS_RESET */
      as_info->reset_flag = FALSE;
    }

#if defined(WINDOWS)
  __try
  {
#endif /* WINDOWS */

    if (cas_db_user[0] != '\0')
      {
    err_code = ux_database_connect (cas_db_name, cas_db_user, cas_db_passwd, NULL);
    if (err_code < 0)
      {
        clear_db_connection_info ();
        SLEEP_SEC (1);
        goto finish_cas;
      }

    ux_set_default_setting ();

    cas_log_write_and_end (0, false, "connect db %s user %s", cas_db_name, cas_db_user);
      }

    as_info->uts_status = UTS_STATUS_IDLE;

  conn_proxy_retry:
    net_timeout_set (NET_DEFAULT_TIMEOUT);

#if defined(WINDOWS)
    proxy_sock_fd = net_connect_proxy (shm_proxy_id);
#else /* WINDOWS */
    proxy_sock_fd = net_connect_proxy ();
#endif /* !WINDOWS */

    if (IS_INVALID_SOCKET (proxy_sock_fd))
      {
    SLEEP_SEC (1);
    goto conn_proxy_retry;
      }

    net_timeout_set (-1);

    setsockopt (proxy_sock_fd, IPPROTO_TCP, TCP_NODELAY, (char *) &one, sizeof (one));

    error = cas_register_to_proxy (proxy_sock_fd);
    if (error)
      {
    CLOSE_SOCKET (proxy_sock_fd);
    SLEEP_SEC (1);
    goto conn_proxy_retry;
      }

#if defined(WINDOWS)
    as_info->uts_status = UTS_STATUS_BUSY;
#endif /* WINDOWS */
    errors_in_transaction = 0;

    net_timeout_set (NET_DEFAULT_TIMEOUT);

    as_info->cur_sql_log2 = shm_appl->sql_log2;
    sql_log2_init (broker_name, shm_as_index, as_info->cur_sql_log2, false);
    setsockopt (proxy_sock_fd, IPPROTO_TCP, TCP_NODELAY, (char *) &one, sizeof (one));

    if (IS_INVALID_SOCKET (proxy_sock_fd))
      {
    goto conn_proxy_retry;
      }

    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);

    if (shm_appl->statement_pooling)
      {
    as_info->cur_statement_pooling = ON;
      }
    else
      {
    as_info->cur_statement_pooling = OFF;
      }
/* TODO : SHARD, assume KEEP_CON_ON*/
    as_info->cur_keep_con = KEEP_CON_ON;

    as_info->cci_default_autocommit = shm_appl->cci_default_autocommit;
    req_info.need_rollback = TRUE;

    gettimeofday (&tran_start_time, NULL);
    gettimeofday (&query_start_time, NULL);
    tran_timeout = 0;
    query_timeout = 0;

    er_init (NULL, ER_NEVER_EXIT);

    for (;;)
      {
    cas_log_error_handler_begin ();
    fn_ret = FN_KEEP_CONN;
    as_info->con_status = CON_STATUS_OUT_TRAN;

    while (fn_ret == FN_KEEP_CONN)
      {
#if !defined(WINDOWS)
        signal (SIGUSR1, query_cancel);
#endif /* !WINDOWS */

        fn_ret = process_request (proxy_sock_fd, &net_buf, &req_info, INVALID_SOCKET);
        cas_log_error_handler_clear ();
#if !defined(WINDOWS)
        signal (SIGUSR1, SIG_IGN);
#endif /* !WINDOWS */
        as_info->last_access_time = time (NULL);

        if (as_info->con_status == CON_STATUS_OUT_TRAN
        && hm_srv_handle_get_current_count () >= shm_appl->max_prepared_stmt_count)
          {
        fn_ret = FN_CLOSE_CONN;
          }
      }
    /* This is a only use in proxy-cas internal message */
    req_info.client_version = CAS_PROTO_CURRENT_VER;

    prev_cas_info[CAS_INFO_STATUS] = CAS_INFO_RESERVED_DEFAULT;

    if (as_info->cur_statement_pooling)
      {
        hm_srv_handle_free_all (true);
      }

    if (!is_xa_prepared ())
      {
        ux_end_tran (CCI_TRAN_ROLLBACK, false, true);
      }

    if (fn_ret != FN_KEEP_SESS)
      {
        ux_end_session ();
      }

    if (as_info->reset_flag == TRUE || is_xa_prepared ())
      {
        ux_database_shutdown (true);
        as_info->reset_flag = FALSE;
        cas_set_db_connect_status (-1); /* DB_CONNECTION_STATUS_RESET */
      }

    cas_log_error_handler_end ();
      finish_cas:
#if defined(WINDOWS)
    as_info->close_flag = 1;
#endif /* WINDOWS */

    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 */
    CLOSE_SOCKET (proxy_sock_fd);

    if (restart_is_needed ())
      {
        cas_final ();
        return 0;
      }
    else if (fn_ret == FN_GRACEFUL_DOWN)
      {
        as_info->uts_status = UTS_STATUS_STOP;
      }
    else
      {
        as_info->uts_status = UTS_STATUS_CON_WAIT;
      }

    goto conn_retry;
      }
#if defined(WINDOWS)
  }
  __except (CreateMiniDump (GetExceptionInformation ()))
  {
  }
#endif /* WINDOWS */

  return 0;
}

static int
cas_init ()
{
  if (cas_init_shm () < 0)
    {
      return -1;
    }

  assert (sizeof (broker_name) == sizeof (shm_appl->broker_name));
  strcpy (broker_name, shm_appl->broker_name);

  set_cubrid_file (FID_SQL_LOG_DIR, shm_appl->log_dir);
  set_cubrid_file (FID_SLOW_LOG_DIR, shm_appl->slow_log_dir);
  set_cubrid_file (FID_CUBRID_ERR_DIR, shm_appl->err_log_dir);

  as_pid_file_create (broker_name, as_info->as_id);
  as_db_err_log_set (broker_name, shm_proxy_id, shm_shard_id, shm_shard_cas_id, shm_as_index, cas_shard_flag);

  /* Set database shutdown callback for cas.c specific implementation */
  cas_set_database_shutdown_callback (ux_database_shutdown);

  if (cas_shard_flag == OFF)
    {
      css_register_check_server_alive_fn (check_server_alive);
      css_register_server_timeout_fn (set_hang_check_time);
    }
  return 0;
}

static int
cas_init_shm (void)
{
  char *p;
  int as_shm_key;
  int pxy_id, shd_id, shard_cas_id, as_id;

  p = getenv (APPL_SERVER_SHM_KEY_STR);
  if (p == NULL)
    {
      goto return_error;
    }

  parse_int (&as_shm_key, p, 10);
  SHARD_ERR ("<CAS> APPL_SERVER_SHM_KEY_STR:[%d:%x]\n", as_shm_key, as_shm_key);
  shm_appl = (T_SHM_APPL_SERVER *) uw_shm_open (as_shm_key, SHM_APPL_SERVER, SHM_MODE_ADMIN);

  if (shm_appl == NULL)
    {
      goto return_error;
    }

  p = getenv (AS_ID_ENV_STR);
  if (p == NULL)
    {
      goto return_error;
    }

  parse_int (&as_id, p, 10);
  SHARD_ERR ("<CAS> AS_ID_ENV_STR:[%d]\n", as_id);
  as_info = &shm_appl->as_info[as_id];

  shm_as_index = as_id;

  cas_shard_flag = shm_appl->shard_flag;

  if (cas_shard_flag == OFF)
    {
      return 0;
    }

  pxy_id = as_info->proxy_id;
  SHARD_ERR ("<CAS> PROXY_ID:[%d]\n", pxy_id);
  shm_proxy_id = pxy_id;

  shd_id = as_info->shard_id;
  SHARD_ERR ("<CAS> SHARD_ID:[%d]\n", shd_id);
  shm_shard_id = shd_id;

  shard_cas_id = as_info->shard_cas_id;
  SHARD_ERR ("<CAS> SHARD_CAS_ID:[%d]\n", shard_cas_id);
  shm_shard_cas_id = shard_cas_id;

  return 0;

#if 1
  /* SHARD TODO : tuning cur_keep_con parameter */
  as_info->cur_keep_con = 1;
#endif

  return 0;
return_error:

  if (shm_appl)
    {
      uw_shm_detach (shm_appl);
      shm_appl = NULL;
    }

  return -1;
}

static FN_RETURN
process_request (SOCKET sock_fd, T_NET_BUF * net_buf, T_REQ_INFO * req_info, SOCKET srv_sock_fd)
{
  MSG_HEADER client_msg_header;
  MSG_HEADER cas_msg_header;
  char *read_msg;
  char func_code;
  int argc;
  void **argv = NULL;
  int err_code;

  int con_status_to_restore, old_con_status;
  T_SERVER_FUNC server_fn;
  FN_RETURN fn_ret = FN_KEEP_CONN;

  error_info_clear ();
  init_msg_header (&client_msg_header);
  init_msg_header (&cas_msg_header);

  old_con_status = as_info->con_status;

  if (cas_shard_flag == ON)
    {
      /* set req_info->client_version in net_read_process */
      err_code = net_read_process (sock_fd, &client_msg_header, req_info);
      if (err_code < 0)
    {
      const char *cas_log_msg = NULL;
      net_write_error (sock_fd, req_info->client_version, req_info->driver_info, cas_msg_header.info_ptr,
               cas_info_size, CAS_ERROR_INDICATOR, CAS_ER_COMMUNICATION, NULL);
      fn_ret = FN_CLOSE_CONN;

      if (is_net_timed_out ())
        {
          if (as_info->reset_flag == TRUE)
        {
          cas_log_msg = "CONNECTION RESET";
        }
          else if (cas_get_graceful_down_timeout () > 0)
        {
          cas_log_msg = "SESSION TIMEOUT AND EXPIRE IDLE TIMEOUT";
          fn_ret = FN_GRACEFUL_DOWN;
        }
          else
        {
          if (as_info->con_status == CON_STATUS_IN_TRAN)
            {
              cas_log_msg = "SESSION TIMEOUT";
            }
          else
            {
              cas_log_msg = "CONNECTION WAIT TIMEOUT";
            }
        }
        }
      else
        {
          cas_log_msg = "COMMUNICATION ERROR net_read_header()";
        }
      cas_log_write_and_end (0, true, cas_log_msg);
      return fn_ret;
    }
      else
    {
      as_info->uts_status = UTS_STATUS_BUSY;

      if (need_database_reconnect ())
        {
          assert (as_info->fixed_shard_user == false);

          set_db_connection_info ();

          err_code = ux_database_connect (cas_db_name, cas_db_user, cas_db_passwd, NULL);
          if (err_code < 0)
        {
          clear_db_connection_info ();
          net_write_error (sock_fd, req_info->client_version, req_info->driver_info, cas_msg_header.info_ptr,
                   cas_info_size, err_info.err_indicator, err_info.err_number, err_info.err_string);
          return FN_CLOSE_CONN;
        }

          ux_set_default_setting ();

          cas_log_write_and_end (0, false, "connect db %s user %s", cas_db_name, cas_db_user);
        }
    }
    }
  else
    {
      unset_hang_check_time ();
      if (as_info->cur_keep_con == KEEP_CON_AUTO)
    {
      err_code = net_read_int_keep_con_auto (sock_fd, &client_msg_header, req_info, srv_sock_fd);
    }
      else
    {
      err_code = net_read_header_keep_con_on (sock_fd, &client_msg_header);

      if (as_info->cur_keep_con == KEEP_CON_ON && as_info->con_status == CON_STATUS_OUT_TRAN)
        {
          as_info->con_status = CON_STATUS_IN_TRAN;
          as_info->transaction_start_time = time (0);
          errors_in_transaction = 0;
        }
    }
      if (err_code < 0)
    {
      const char *cas_log_msg = NULL;

      fn_ret = FN_CLOSE_CONN;

      if (as_info->reset_flag)
        {
          cas_log_msg = "RESET";
          cas_log_write_and_end (0, true, cas_log_msg);
          fn_ret = FN_KEEP_SESS;
          db_set_keep_session (true);
        }
      if (as_info->con_status == CON_STATUS_CLOSE_AND_CONNECT)
        {
          cas_log_msg = "CHANGE CLIENT";
          fn_ret = FN_KEEP_SESS;
          db_set_keep_session (true);
        }

      if (cas_log_msg == NULL)
        {
          if (is_net_timed_out ())
        {
          if (as_info->reset_flag == TRUE)
            {
              cas_log_msg = "CONNECTION RESET";
            }
          else
            {
              cas_log_msg = "SESSION TIMEOUT";
            }
        }
          else
        {
          cas_log_msg = "COMMUNICATION ERROR net_read_header()";
        }
        }
      cas_log_write_and_end (0, true, cas_log_msg);
      return fn_ret;
    }
    }

#if !defined(WINDOWS)
  /* Before start to execute a new request, try to reset a previous interrupt request we might have. The interrupt
   * request arrived too late to interrupt the previous request and still remains. */
  db_set_interrupt (0);
#endif /* !WINDOWS */

  if (cas_shard_flag == ON)
    {
      set_db_parameter ();
    }

  if (shm_appl->session_timeout < 0)
    net_timeout_set (NET_DEFAULT_TIMEOUT);
  else
    net_timeout_set (MIN (shm_appl->session_timeout, NET_DEFAULT_TIMEOUT));

  if (cas_shard_flag == ON && req_info->client_version == 0)
    {
      assert (0);
      req_info->client_version = CAS_PROTO_CURRENT_VER;
    }

  read_msg = (char *) MALLOC (*(client_msg_header.msg_body_size_ptr));
  if (read_msg == NULL)
    {
      net_write_error (sock_fd, req_info->client_version, req_info->driver_info, cas_msg_header.info_ptr, cas_info_size,
               CAS_ERROR_INDICATOR, CAS_ER_NO_MORE_MEMORY, NULL);
      return FN_CLOSE_CONN;
    }
  if (net_read_stream (sock_fd, read_msg, *(client_msg_header.msg_body_size_ptr)) < 0)
    {
      FREE_MEM (read_msg);
      net_write_error (sock_fd, req_info->client_version, req_info->driver_info, cas_msg_header.info_ptr, cas_info_size,
               CAS_ERROR_INDICATOR, CAS_ER_COMMUNICATION, NULL);
      cas_log_write_and_end (0, true, "COMMUNICATION ERROR net_read_stream()");
      return FN_CLOSE_CONN;
    }

  argc = net_decode_str (read_msg, *(client_msg_header.msg_body_size_ptr), &func_code, &argv);
  if (argc < 0)
    {
      FREE_MEM (read_msg);
      net_write_error (sock_fd, req_info->client_version, req_info->driver_info, cas_msg_header.info_ptr, cas_info_size,
               CAS_ERROR_INDICATOR, CAS_ER_COMMUNICATION, NULL);
      return FN_CLOSE_CONN;
    }

  if (func_code <= 0 || func_code >= CAS_FC_MAX)
    {
      FREE_MEM (argv);
      FREE_MEM (read_msg);
      net_write_error (sock_fd, req_info->client_version, req_info->driver_info, cas_msg_header.info_ptr, cas_info_size,
               CAS_ERROR_INDICATOR, CAS_ER_COMMUNICATION, NULL);
      return FN_CLOSE_CONN;
    }

  /* PROTOCOL_V2 is used only 9.0.0 */
  if (DOES_CLIENT_MATCH_THE_PROTOCOL (req_info->client_version, PROTOCOL_V2))
    {
      switch (func_code)
    {
    case CAS_FC_PREPARE_AND_EXECUTE:
      func_code = CAS_FC_PREPARE_AND_EXECUTE_FOR_PROTO_V2;
      break;
    case CAS_FC_CURSOR_CLOSE:
      func_code = CAS_FC_CURSOR_CLOSE_FOR_PROTO_V2;
      break;
    default:
      break;
    }
    }

  con_status_to_restore = -1;

  if (FUNC_NEEDS_RESTORING_CON_STATUS (func_code))
    {
      if (is_first_request == true)
    {
      /* If this request is the first request after connection established, con_status should be
       * CON_STATUS_OUT_TRAN. */
      con_status_to_restore = CON_STATUS_OUT_TRAN;
    }
      else if (con_status_before_check_cas != -1)
    {
      con_status_to_restore = con_status_before_check_cas;
    }
      else
    {
      con_status_to_restore = old_con_status;
    }

      con_status_before_check_cas = -1;
    }
  else if (func_code == CAS_FC_CHECK_CAS)
    {
      con_status_before_check_cas = old_con_status;
    }
  else
    {
      con_status_before_check_cas = -1;
    }

  strcpy (as_info->log_msg, server_func_name[func_code - 1]);

  server_fn = server_fn_table[func_code - 1];

  if (prev_cas_info[CAS_INFO_STATUS] != CAS_INFO_RESERVED_DEFAULT)
    {
      assert (prev_cas_info[CAS_INFO_STATUS] == client_msg_header.info_ptr[CAS_INFO_STATUS]);
#if defined (PROTOCOL_EXTENDS_DEBUG)    /* for debug cas <-> JDBC info */
      if (prev_cas_info[CAS_INFO_STATUS] != client_msg_header.info_ptr[CAS_INFO_STATUS])
    {
      cas_log_debug (ARG_FILE_LINE,
             "[%d][PREV : %d, RECV : %d], " "[preffunc : %d, recvfunc : %d], [REQ: %d, REQ: %d], "
             "[JID : %d] \n", func_code - 1, prev_cas_info[CAS_INFO_STATUS],
             client_msg_header.info_ptr[CAS_INFO_STATUS], prev_cas_info[CAS_INFO_RESERVED_1],
             client_msg_header.info_ptr[CAS_INFO_RESERVED_1], prev_cas_info[CAS_INFO_RESERVED_2],
             client_msg_header.info_ptr[CAS_INFO_RESERVED_2],
             client_msg_header.info_ptr[CAS_INFO_RESERVED_3]);
    }
#endif /* end for debug */
    }

  req_info->need_auto_commit = TRAN_NOT_AUTOCOMMIT;

  cas_send_result_flag = TRUE;

  /* for 9.0 driver */
  if (DOES_CLIENT_MATCH_THE_PROTOCOL (req_info->client_version, PROTOCOL_V2))
    {
      ux_set_utype_for_enum (CCI_U_TYPE_STRING);
    }

  /* for driver less than 10.0 */
  if (!DOES_CLIENT_UNDERSTAND_THE_PROTOCOL (req_info->client_version, PROTOCOL_V7))
    {
      ux_set_utype_for_datetimetz (CCI_U_TYPE_DATETIME);
      ux_set_utype_for_timestamptz (CCI_U_TYPE_TIMESTAMP);
      ux_set_utype_for_datetimeltz (CCI_U_TYPE_DATETIME);
      ux_set_utype_for_timestampltz (CCI_U_TYPE_TIMESTAMP);
    }

  /* driver version < 10.2 */
  if (!DOES_CLIENT_UNDERSTAND_THE_PROTOCOL (req_info->client_version, PROTOCOL_V8))
    {
      ux_set_utype_for_json (CCI_U_TYPE_STRING);
    }

  as_info->fn_status = FN_STATUS_BUSY;

  net_buf->client_version = req_info->client_version;
  set_hang_check_time ();
  fn_ret = (*server_fn) (sock_fd, argc, argv, net_buf, req_info);
  set_hang_check_time ();

  /* set back original utype for enum, date-time, JSON */
  if (DOES_CLIENT_MATCH_THE_PROTOCOL (req_info->client_version, PROTOCOL_V2))
    {
      ux_set_utype_for_enum (CCI_U_TYPE_ENUM);
    }

  /* for driver less than 10.0 */
  if (!DOES_CLIENT_UNDERSTAND_THE_PROTOCOL (req_info->client_version, PROTOCOL_V7))
    {
      ux_set_utype_for_datetimetz (CCI_U_TYPE_DATETIMETZ);
      ux_set_utype_for_timestamptz (CCI_U_TYPE_TIMESTAMPTZ);
      ux_set_utype_for_datetimeltz (CCI_U_TYPE_DATETIMETZ);
      ux_set_utype_for_timestampltz (CCI_U_TYPE_TIMESTAMPTZ);
    }

  /* driver version < 10.2 */
  if (!DOES_CLIENT_UNDERSTAND_THE_PROTOCOL (req_info->client_version, PROTOCOL_V8))
    {
      ux_set_utype_for_json (CCI_U_TYPE_JSON);
    }

  cas_log_debug (ARG_FILE_LINE, "process_request: %s() err_code %d", server_func_name[func_code - 1],
         err_info.err_number);

  if (con_status_to_restore != -1)
    {
      CON_STATUS_LOCK (as_info, CON_STATUS_LOCK_CAS);
      as_info->con_status = con_status_to_restore;
      CON_STATUS_UNLOCK (as_info, CON_STATUS_LOCK_CAS);
    }


  if (cas_shard_flag == ON && (func_code == CAS_FC_PREPARE || func_code == CAS_FC_CHECK_CAS)
      && (client_msg_header.info_ptr[CAS_INFO_ADDITIONAL_FLAG] & CAS_INFO_FLAG_MASK_FORCE_OUT_TRAN))
    {
      /* for shard dummy prepare */
      /* for connection check */
      req_info->need_auto_commit = TRAN_AUTOROLLBACK;
    }


  if (fn_ret == FN_KEEP_CONN && net_buf->err_code == 0 && as_info->con_status == CON_STATUS_IN_TRAN
      && req_info->need_auto_commit != TRAN_NOT_AUTOCOMMIT && err_info.err_number != CAS_ER_STMT_POOLING)
    {
      /* no communication error and auto commit is needed */
      err_code = ux_auto_commit (net_buf, req_info);
      if (err_code < 0)
    {
      fn_ret = FN_CLOSE_CONN;
    }
      else
    {
      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 (!ux_is_database_connected ())
        {
          fn_ret = FN_CLOSE_CONN;
        }
      else if (restart_is_needed ())
        {
          fn_ret = FN_KEEP_SESS;
          db_set_keep_session (true);
        }
      if (shm_appl->sql_log2 != as_info->cur_sql_log2)
        {
          sql_log2_end (false);
          as_info->cur_sql_log2 = shm_appl->sql_log2;
          sql_log2_init (broker_name, shm_as_index, as_info->cur_sql_log2, true);
        }
    }
      as_info->num_transactions_processed %= MAX_DIAG_DATA_VALUE;
      as_info->num_transactions_processed++;

      /* should be OUT_TRAN in auto commit */
      CON_STATUS_LOCK (as_info, CON_STATUS_LOCK_CAS);
      if (as_info->con_status == CON_STATUS_IN_TRAN)
    {
      as_info->con_status = CON_STATUS_OUT_TRAN;
    }
      CON_STATUS_UNLOCK (as_info, CON_STATUS_LOCK_CAS);
    }

  if ((func_code == CAS_FC_EXECUTE) || (func_code == CAS_FC_SCHEMA_INFO))
    {
      as_info->num_requests_received %= MAX_DIAG_DATA_VALUE;
      as_info->num_requests_received++;
    }
  else if (func_code == CAS_FC_END_TRAN)
    {
      as_info->num_transactions_processed %= MAX_DIAG_DATA_VALUE;
      as_info->num_transactions_processed++;
    }

  as_info->log_msg[0] = '\0';
  if (as_info->con_status == CON_STATUS_IN_TRAN)
    {
      cas_msg_header.info_ptr[CAS_INFO_STATUS] = CAS_INFO_STATUS_ACTIVE;
    }
  else
    {
      cas_msg_header.info_ptr[CAS_INFO_STATUS] = CAS_INFO_STATUS_INACTIVE;
    }

  if (func_code == CAS_FC_EXECUTE || func_code == CAS_FC_EXECUTE_ARRAY || func_code == CAS_FC_EXECUTE_BATCH
      || err_info.err_number < 0)
    {
      logddl_write_end ();
    }

  if (net_buf->err_code)
    {
      net_write_error (sock_fd, req_info->client_version, req_info->driver_info, cas_msg_header.info_ptr, cas_info_size,
               CAS_ERROR_INDICATOR, net_buf->err_code, NULL);
      fn_ret = FN_CLOSE_CONN;
      goto exit_on_end;
    }

  if (cas_send_result_flag && net_buf->data != NULL)
    {

      cas_msg_header.info_ptr[CAS_INFO_ADDITIONAL_FLAG] &= ~CAS_INFO_FLAG_MASK_AUTOCOMMIT;
      cas_msg_header.info_ptr[CAS_INFO_ADDITIONAL_FLAG] |=
    (as_info->cci_default_autocommit & CAS_INFO_FLAG_MASK_AUTOCOMMIT);

      if (cas_shard_flag == ON)
    {
      cas_msg_header.info_ptr[CAS_INFO_ADDITIONAL_FLAG] &= ~CAS_INFO_FLAG_MASK_FORCE_OUT_TRAN;
    }
#if defined (PROTOCOL_EXTENDS_DEBUG)    /* for debug cas<->jdbc info */
      cas_msg_header.info_ptr[CAS_INFO_RESERVED_1] = func_code - 1;
      cas_msg_header.info_ptr[CAS_INFO_RESERVED_2] = as_info->num_requests_received % 128;
      prev_cas_info[CAS_INFO_STATUS] = cas_msg_header.info_ptr[CAS_INFO_STATUS];
      prev_cas_info[CAS_INFO_RESERVED_1] = cas_msg_header.info_ptr[CAS_INFO_RESERVED_1];
      prev_cas_info[CAS_INFO_RESERVED_2] = cas_msg_header.info_ptr[CAS_INFO_RESERVED_2];
#endif /* end for debug */



      *(cas_msg_header.msg_body_size_ptr) = htonl (net_buf->data_size);
      memcpy (net_buf->data, cas_msg_header.msg_body_size_ptr, NET_BUF_HEADER_MSG_SIZE);

      if (cas_info_size > 0)
    {
      memcpy (net_buf->data + NET_BUF_HEADER_MSG_SIZE, cas_msg_header.info_ptr, cas_info_size);
    }

      assert (NET_BUF_CURR_SIZE (net_buf) <= net_buf->alloc_size);
      if (net_write_stream (sock_fd, net_buf->data, NET_BUF_CURR_SIZE (net_buf)) < 0)
    {
      cas_log_write_and_end (0, true, "COMMUNICATION ERROR net_write_stream()");
    }
    }

  if (cas_shard_flag == OFF && cas_send_result_flag && net_buf->post_send_file != NULL)
    {
      err_code = net_write_from_file (sock_fd, net_buf->post_file_size, net_buf->post_send_file);
      unlink (net_buf->post_send_file);
      if (err_code < 0)
    {
      fn_ret = FN_CLOSE_CONN;
      goto exit_on_end;
    }
    }


  if (as_info->reset_flag
      &&
      ((as_info->con_status != CON_STATUS_IN_TRAN && as_info->num_holdable_results < 1
    && as_info->cas_change_mode == CAS_CHANGE_MODE_AUTO) || (cas_get_db_connect_status () == -1)))
    {
      cas_log_debug (ARG_FILE_LINE, "process_request: reset_flag && !CON_STATUS_IN_TRAN");
      fn_ret = FN_KEEP_SESS;
      db_set_keep_session (true);
      goto exit_on_end;
    }


exit_on_end:

  if (cas_shard_flag == ON && as_info->con_status != CON_STATUS_IN_TRAN && as_info->uts_status == UTS_STATUS_BUSY)
    {
      as_info->uts_status = UTS_STATUS_IDLE;
    }


  net_buf_clear (net_buf);

  FREE_MEM (read_msg);
  FREE_MEM (argv);

  return fn_ret;
}

static int
net_read_process (SOCKET proxy_sock_fd, MSG_HEADER * client_msg_header, T_REQ_INFO * req_info)
{
  int ret_value = 0;
  int timeout = 0, remained_timeout = 0;
  bool is_proxy_conn_wait_timeout = false;

  if (as_info->con_status == CON_STATUS_IN_TRAN)
    {
      net_timeout_set (shm_appl->session_timeout);
    }
  else
    {
      net_timeout_set (DEFAULT_CHECK_INTERVAL);

      timeout = cas_get_graceful_down_timeout ();
      if (timeout < 0 && as_info->database_user[0] != '\0')
    {
      timeout = as_info->proxy_conn_wait_timeout;
      is_proxy_conn_wait_timeout = true;
    }

      remained_timeout = timeout;
    }

  do
    {
      if (as_info->cas_log_reset)
    {
      cas_log_reset (broker_name);
    }

      if (as_info->con_status == CON_STATUS_CLOSE)
    {
      break;
    }
      else if (as_info->con_status == CON_STATUS_OUT_TRAN)
    {
      remained_timeout -= DEFAULT_CHECK_INTERVAL;
    }

      /*
       * net_read_header error case. case 1 : disconnect with proxy_sock_fd case 2 : CON_STATUS_IN_TRAN &&
       * session_timeout case 3 : reset_flag is TRUE */
      if (net_read_header (proxy_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 (restart_is_needed ())
        {
          cas_log_debug (ARG_FILE_LINE, "net_read_process: " "restart_is_needed()");
          ret_value = -1;
          break;
        }

          /* this is not real timeout. try again. */
          if (timeout < 0 || remained_timeout > 0)
        {
          continue;
        }

          if (is_proxy_conn_wait_timeout)
        {
          as_info->database_user[0] = '\0';
          as_info->database_passwd[0] = '\0';
        }

          /* MYSQL_CONNECT_TIMEOUT case */
          /* SHARD_CAS expire idle time and restart case */
          ret_value = -1;
          break;
        }
    }
      else
    {
      break;
    }
    }
  while (1);

  CON_STATUS_LOCK (as_info, 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)
    {
      ret_value = -1;
    }
  else
    {
      if (as_info->con_status != CON_STATUS_IN_TRAN)
    {
      if (ret_value >= 0)
        {
          as_info->con_status = CON_STATUS_IN_TRAN;
          errors_in_transaction = 0;
        }

      cas_log_write_client_ip (as_info->cas_clt_ip);

      /* This is a real client protocol version */
      req_info->client_version = as_info->clt_version;
      memcpy (req_info->driver_info, as_info->driver_info, SRV_CON_CLIENT_INFO_SIZE);
      cas_log_write_and_end (0, false, "CLIENT VERSION %s", as_info->driver_version);
    }
    }

  CON_STATUS_UNLOCK (as_info, CON_STATUS_LOCK_CAS);

  return ret_value;
}

static int
cas_register_to_proxy (SOCKET proxy_sock_fd)
{
  MSG_HEADER proxy_msg_header;
  char func_code = 0x01;

  /* proxy/cas connection handshake */
  init_msg_header (&proxy_msg_header);

  *(proxy_msg_header.msg_body_size_ptr) = sizeof (char) /* func_code */  +
    sizeof (int) /* shard_id */  +
    sizeof (int) /* cas_id */ ;

  if (net_write_header (proxy_sock_fd, &proxy_msg_header))
    {
      cas_log_write_and_end (0, false, "HANDSHAKE ERROR send msg_header");
      return -1;
    }

  if (net_write_stream (proxy_sock_fd, &func_code, 1) < 0)
    {
      cas_log_write_and_end (0, false, "HANDSHAKE ERROR send func_code");
      return -1;
    }

  if (net_write_int (proxy_sock_fd, shm_shard_id) < 0)
    {
      cas_log_write_and_end (0, false, "HANDSHAKE ERROR send shard_id");
      return -1;
    }

  if (net_write_int (proxy_sock_fd, shm_shard_cas_id) < 0)
    {
      cas_log_write_and_end (0, false, "HANDSHAKE ERROR send cas_id");
      return -1;
    }

  return 0;
}

static void
set_db_parameter (void)
{
  int cur_isolation_level;
  int cur_lock_timeout;
  int isolation_level = as_info->isolation_level;
  int lock_timeout = as_info->lock_timeout;

  if (isolation_level == CAS_USE_DEFAULT_DB_PARAM)
    {
      isolation_level = cas_default_isolation_level;
    }

  if (lock_timeout == CAS_USE_DEFAULT_DB_PARAM)
    {
      lock_timeout = cas_default_lock_timeout;
    }

  ux_get_tran_setting (&cur_lock_timeout, &cur_isolation_level);
  if (cur_lock_timeout != lock_timeout)
    {
      ux_set_lock_timeout (lock_timeout);

      cas_log_write_and_end (0, false, "set_db_parameter lock_timeout %d", lock_timeout);
    }

  if (cur_isolation_level != isolation_level)
    {
      ux_set_isolation_level (isolation_level, NULL);

      cas_log_write_and_end (0, false, "set_db_parameter isolation_level %d", isolation_level);
    }
}

static void
set_db_connection_info (void)
{
  if (as_info->fixed_shard_user)
    {
      strncpy (as_info->database_user, shm_appl->shard_conn_info[shm_shard_id].db_user, SRV_CON_DBUSER_SIZE - 1);
      as_info->database_user[SRV_CON_DBUSER_SIZE - 1] = '\0';

      strncpy (as_info->database_passwd, shm_appl->shard_conn_info[shm_shard_id].db_password,
           SRV_CON_DBPASSWD_SIZE - 1);
      as_info->database_passwd[SRV_CON_DBUSER_SIZE - 1] = '\0';
    }

  strncpy (cas_db_user, as_info->database_user, SRV_CON_DBUSER_SIZE - 1);
  cas_db_user[SRV_CON_DBUSER_SIZE - 1] = '\0';

  strncpy (cas_db_passwd, as_info->database_passwd, SRV_CON_DBPASSWD_SIZE - 1);
  cas_db_passwd[SRV_CON_DBPASSWD_SIZE - 1] = '\0';

  cas_log_debug (ARG_FILE_LINE, "db_name %s db_user %s", cas_db_name, cas_db_user);
}

static void
clear_db_connection_info (void)
{
  if (as_info->fixed_shard_user)
    {
      return;
    }

  cas_db_user[0] = '\0';
  cas_db_passwd[0] = '\0';
  as_info->database_user[0] = '\0';
  as_info->database_passwd[0] = '\0';
}

static bool
need_database_reconnect (void)
{
  if (as_info->force_reconnect)
    {
      return true;
    }
  if (strcasecmp (cas_db_user, as_info->database_user))
    {
      return true;
    }

  if (strcmp (cas_db_passwd, as_info->database_passwd))
    {
      return true;
    }

  return false;
}