Skip to content

File cas_cgw.c

File List > broker > cas_cgw.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_cgw.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_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 "broker_cas_cci.h"

#include "cas_cgw_function.h"
#include "cas_cgw_odbc.h"
#include "cas_cgw_execute.h"

#include "cas_ssl.h"

/* ========================================================================
 * Type Definitions
 * ======================================================================== */
/* CGW context structure */
typedef struct
{
  char odbc_resolved_url[CGW_LINK_URL_MAX_LEN];
  char odbc_connect_url[CGW_LINK_URL_MAX_LEN];
  char tmp_name[SRV_CON_DBNAME_SIZE];
  char tmp_user[SRV_CON_DBUSER_SIZE];
  char tmp_passwd[SRV_CON_DBPASSWD_SIZE];
  T_DBMS_TYPE dbms_type;
} CGW_CONTEXT;

/* ========================================================================
 * Global Variable Definitions
 * ======================================================================== */
/* Database connection info */
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];

/* ========================================================================
 * Static Variable Definitions
 * ======================================================================== */
static CGW_CONTEXT *cgw_current_ctx = NULL; /* Global CGW context for db_connect callback */

/* ========================================================================
 * Function Tables
 * ======================================================================== */
static T_SERVER_FUNC server_fn_table[] = {
  fn_cgw_end_tran,      /* CAS_FC_END_TRAN */
  fn_cgw_prepare,       /* CAS_FC_PREPARE */
  fn_cgw_execute,       /* CAS_FC_EXECUTE */
  fn_not_supported,     /* CAS_FC_GET_DB_PARAMETER */
  fn_not_supported,     /* CAS_FC_SET_DB_PARAMETER */
  fn_cgw_close_req_handle,  /* CAS_FC_CLOSE_REQ_HANDLE */
  fn_cgw_cursor,        /* CAS_FC_CURSOR */
  fn_cgw_get_fetch,     /* CAS_FC_FETCH */
  fn_not_supported,     /* CAS_FC_SCHEMA_INFO */
  fn_not_supported,     /* CAS_FC_OID_GET */
  fn_not_supported,     /* CAS_FC_OID_SET */
  fn_not_supported,     /* CAS_FC_DEPRECATED1 */
  fn_not_supported,     /* CAS_FC_DEPRECATED2 */
  fn_not_supported,     /* CAS_FC_DEPRECATED3 */
  fn_cgw_get_db_version,    /* CAS_FC_GET_DB_VERSION */
  fn_not_supported,     /* CAS_FC_GET_CLASS_NUM_OBJS */
  fn_not_supported,     /* CAS_FC_OID_CMD */
  fn_not_supported,     /* CAS_FC_COLLECTION */
  fn_not_supported,     /* CAS_FC_NEXT_RESULT */
  fn_not_supported,     /* CAS_FC_EXECUTE_BATCH */
  fn_not_supported,     /* CAS_FC_EXECUTE_ARRAY */
  fn_not_supported,     /* CAS_FC_CURSOR_UPDATE */
  fn_not_supported,     /* CAS_FC_GET_ATTR_TYPE_STR */
  fn_not_supported,     /* CAS_FC_GET_QUERY_INFO */
  fn_not_supported,     /* CAS_FC_DEPRECATED4 */
  fn_not_supported,     /* CAS_FC_SAVEPOINT */
  fn_not_supported,     /* CAS_FC_PARAMETER_INFO */
  fn_not_supported,     /* CAS_FC_XA_PREPARE */
  fn_not_supported,     /* CAS_FC_XA_RECOVER */
  fn_not_supported,     /* CAS_FC_XA_END_TRAN */
  fn_cgw_con_close,     /* CAS_FC_CON_CLOSE */
  fn_cgw_check_cas,     /* CAS_FC_CHECK_CAS */
  fn_not_supported,     /* CAS_FC_MAKE_OUT_RS */
  fn_not_supported,     /* CAS_FC_GET_GENERATED_KEYS */
  fn_not_supported,     /* CAS_FC_LOB_NEW */
  fn_not_supported,     /* CAS_FC_LOB_WRITE */
  fn_not_supported,     /* CAS_FC_LOB_READ */
  fn_not_supported,     /* CAS_FC_END_SESSION */
  fn_not_supported,     /* CAS_FC_GET_ROW_COUNT */
  fn_not_supported,     /* CAS_FC_GET_LAST_INSERT_ID */
  fn_not_supported,     /* CAS_FC_PREPARE_AND_EXECUTE */
  fn_not_supported,     /* CAS_FC_CURSOR_CLOSE */
  fn_not_supported,     /* CAS_FC_GET_SHARD_INFO */
  fn_not_supported      /* 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",
  "deprecated1",
  "deprecated2",
  "deprecated3",
  "get_db_version",
  "get_class_num_objs",
  "oid",
  "collection",
  "next_result",
  "execute_batch",
  "execute_array",
  "cursor_update",
  "get_attr_type_str",
  "get_query_info",
  "deprecated4",
  "savepoint",
  "parameter_info",
  "xa_prepare",
  "xa_recover",
  "xa_end_tran",
  "con_close",
  "check_cas",
  "make_out_rs",
  "get_generated_keys",
  "lob_new",
  "lob_write",
  "lob_read",
  "end_session",
  "get_row_count",
  "get_last_insert_id",
  "prepare_and_execute",
  "cursor_close",
  "get_shard_info",
  "set_cas_change_mode"
};

static int cgw_cas_main (void);
static int cgw_cas_init (void);
static int cgw_init_shm (void);

/* Callback functions for cas_main_loop() */
static int cgw_pre_db_connect (const char *db_name, const char *db_user, const char *db_passwd, const char *url,
                   void *context);
static int cgw_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 cgw_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 cgw_cleanup_session (void);

static void cas_send_connect_reply_to_driver (T_CAS_PROTOCOL protocol, SOCKET client_sock_fd, char *cas_info);
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)
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 (cgw_cas_init () < 0)
    {
      fprintf (stderr, "CGW 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_CGW_NAME;
#endif /* !WINDOWS */

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

  set_cubrid_home ();

  res = cgw_cas_main ();
  return res;
}

static int
cgw_cas_main (void)
{
  CGW_CONTEXT cgw_ctx = { 0 };
  CAS_MAIN_OPS ops = {
    .init_specific = cgw_init,  /* CGW specific initialization */
    .pre_db_connect = cgw_pre_db_connect,
    .db_connect = cgw_db_connect,
    .post_db_connect = cgw_post_db_connect,
    .cleanup_session = cgw_cleanup_session,
    .process_request = process_request,
    .set_session_id = NULL, /* CGW doesn't use session ID */
    .send_connect_reply = cas_send_connect_reply_to_driver,
    .context = &cgw_ctx
  };

  /* Initialize error log file path for CGW */
  char errplog_path[BROKER_PATH_MAX] = { 0, };
  char errlog_file[BROKER_PATH_MAX] = { 0, };

  sprintf (errlog_file, "%s%s_%d.err",
       get_cubrid_file (FID_CUBRID_ERR_DIR, errplog_path, BROKER_PATH_MAX), shm_appl->broker_name,
       shm_as_index + 1);

  er_init (errlog_file, ER_NEVER_EXIT);

  /* Set global context for db_connect callback */
  cgw_current_ctx = &cgw_ctx;

  return cas_main_loop (&ops);
}

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;

  memset (sessid, 0, DRIVER_SESSION_SIZE);

  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 = 0;
      memcpy (p, &v, SESSION_ID_SIZE);
      p += SESSION_ID_SIZE;
    }
  net_write_stream (client_sock_fd, msgbuf, p - msgbuf);
}

static int
cgw_pre_db_connect (const char *db_name, const char *db_user, const char *db_passwd, const char *url, void *context)
{
  CGW_CONTEXT *cgw_ctx = (CGW_CONTEXT *) context;
  const char *find_gateway;

  if (url == NULL)
    {
      return -1;
    }

  find_gateway = strstr (url, "__gateway=true");
  if (find_gateway == NULL)
    {
      return -1;        /* Will be handled as authorization error */
    }

  cgw_ctx->dbms_type = cgw_is_supported_dbms (shm_appl->cgw_link_server);
  cgw_set_dbms_type (cgw_ctx->dbms_type);

  strncpy (cgw_ctx->tmp_name, db_name, SRV_CON_DBNAME_SIZE - 1);
  cgw_ctx->tmp_name[SRV_CON_DBNAME_SIZE - 1] = '\0';
  strncpy (cgw_ctx->tmp_user, db_user, SRV_CON_DBUSER_SIZE - 1);
  cgw_ctx->tmp_user[SRV_CON_DBUSER_SIZE - 1] = '\0';
  strncpy (cgw_ctx->tmp_passwd, db_passwd, SRV_CON_DBPASSWD_SIZE - 1);
  cgw_ctx->tmp_passwd[SRV_CON_DBPASSWD_SIZE - 1] = '\0';

  if (cgw_ctx->dbms_type == CAS_CGW_DBMS_ORACLE)
    {
      snprintf (cgw_ctx->odbc_connect_url, CGW_LINK_URL_MAX_LEN, ORACLE_CONNECT_URL_FORMAT,
        shm_appl->cgw_link_odbc_driver_name,
        cgw_ctx->tmp_name,
        shm_appl->cgw_link_server_port,
        cgw_ctx->tmp_name, cgw_ctx->tmp_user, cgw_ctx->tmp_passwd, shm_appl->cgw_link_connect_url_property);

      snprintf (cgw_ctx->odbc_resolved_url, CGW_LINK_URL_MAX_LEN, ORACLE_CONNECT_URL_FORMAT,
        shm_appl->cgw_link_odbc_driver_name,
        cgw_ctx->tmp_name,
        shm_appl->cgw_link_server_port,
        cgw_ctx->tmp_name, cgw_ctx->tmp_user, "********", shm_appl->cgw_link_connect_url_property);
    }
  else if (cgw_ctx->dbms_type == CAS_CGW_DBMS_MYSQL || cgw_ctx->dbms_type == CAS_CGW_DBMS_MARIADB)
    {
      snprintf (cgw_ctx->odbc_connect_url, CGW_LINK_URL_MAX_LEN, MYSQL_CONNECT_URL_FORMAT,
        shm_appl->cgw_link_odbc_driver_name,
        shm_appl->cgw_link_server_ip,
        shm_appl->cgw_link_server_port,
        cgw_ctx->tmp_name, cgw_ctx->tmp_user, cgw_ctx->tmp_passwd, shm_appl->cgw_link_connect_url_property);

      snprintf (cgw_ctx->odbc_resolved_url, CGW_LINK_URL_MAX_LEN, MYSQL_CONNECT_URL_FORMAT,
        shm_appl->cgw_link_odbc_driver_name,
        shm_appl->cgw_link_server_ip,
        shm_appl->cgw_link_server_port,
        cgw_ctx->tmp_name, cgw_ctx->tmp_user, "********", shm_appl->cgw_link_connect_url_property);
    }
  else
    {
      return -1;        /* Unsupported DBMS */
    }

  return 0;
}

static int
cgw_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;

  if (cgw_current_ctx == NULL)
    {
      return -1;
    }

  err_code = cgw_database_connect (cgw_current_ctx->dbms_type, cgw_current_ctx->odbc_connect_url, (char *) db_name,
                   (char *) db_user, (char *) db_passwd);

  if (err_code < 0)
    {
      char msg_buf[LINE_MAX];
      cas_info[CAS_INFO_STATUS] = CAS_INFO_STATUS_INACTIVE;

      err_code = ERROR_INFO_SET (db_error_code (), DBMS_ERROR_INDICATOR);
      db_err_msg = (char *) db_error_string (1);
      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 url %s, error:%d", cgw_current_ctx->odbc_connect_url,
            err_info.err_number);
    }
      else
    {
      snprintf (msg_buf, LINE_MAX, "connect url %s, error:%d, %s", cgw_current_ctx->odbc_connect_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);
      return err_code;
    }

  return err_code;
}

static void
cgw_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)
{
  CGW_CONTEXT *cgw_ctx = (CGW_CONTEXT *) context;

  cas_bi_set_dbms_type (cgw_ctx->dbms_type);
  cas_log_write_and_end (0, false, "connect db %s@%s user %s url %s", cgw_ctx->tmp_name,
             shm_appl->cgw_link_server_ip, cgw_ctx->tmp_user, cgw_ctx->odbc_resolved_url);
}

static void
cgw_cleanup_session (void)
{
  extern FN_RETURN cas_main_fn_ret;

  if (ux_cgw_end_tran (CCI_TRAN_ROLLBACK, false, true) < 0)
    {
      as_info->reset_flag = TRUE;
    }
}

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)
    {
      assert (0);
      return FN_CLOSE_CONN;
    }
  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 (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_cgw_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_cgw_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;
    }
    }

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
cgw_cas_init ()
{
  if (cgw_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 cleanup callback for CGW specific cleanup */
  cas_set_cleanup_callback (cgw_cleanup);

  return 0;
}

static int
cgw_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;
    }

return_error:

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

  return -1;
}