Skip to content

File client_support.cpp

File List > connection > client_support.cpp

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.
 *
 */

/*
 * client_support.cpp - higher level of interface routines to the client
 */

#ident "$Id$"

#include "config.h"

#include <stdio.h>
#if !defined(WINDOWS)
#include <signal.h>
#include <sys/param.h>
#include <syslog.h>
#endif /* not WINDOWS */
#include <assert.h>

#include "porting.h"
#include "connection_globals.h"
#include "connection_defs.h"
#if defined(WINDOWS)
#include "wintcp.h"
#else /* WINDOWS */
#include "tcp.h"
#endif /* WINDOWS */
#include "transaction_cl.h"
#include "error_manager.h"
#include "client_support.h"
#include "network_interface_cl.h"
#include "network.h"

#if defined (SERVER_MODE)
#error Belongs to not server module
#endif /* !defined (SERVER_MODE) */

CUB_THREAD_LOCAL class client_support __gv_client_support;

/*
 * css_internal_server_shutdown() -
 *   return:
 */
static void
css_internal_server_shutdown (void)
{
#if !defined(WINDOWS)
  syslog (LOG_ALERT, "Lost connection to server\n");
#endif /* not WINDOWS */
}

client_support::client_support ()
{
  m_css_errno = 0;
}

int
client_support::css_get_errno ()
{
  return m_css_errno;
}

/*
 * css_handle_pipe_shutdown() -
 *   return:
 *   sig(in):
 */
void
client_support::css_handle_pipe_shutdown (int sig)
{
#if 0
  /*
   * TODO: The previous implementation of css_find_exception_conn() was redundant
   * because it consistently returned NULL, making the associated logic meaningless.
   *
   * Before re-implementing, we must verify if registering a custom handler for
   * SIGPIPE is truly preferable over using SIG_IGN.
   * * This section is currently commented out for future review.
   */
  CSS_CONN_ENTRY *conn;
  CSS_MAP_ENTRY *entry;

  conn = m_conn_less.css_find_exception_conn ();
  if (conn != NULL)
    {
      entry = m_conn_less.css_return_entry_from_conn (conn);
      if (entry != NULL)
    {
      css_free_conn (entry->conn);
      m_conn_less.css_remove_queued_connection_by_entry (entry);
    }
      css_internal_server_shutdown ();
    }
  else
#endif
    {
      /* Avoid an infinite loop by checking if the previous handle is myself */
      if (client_support::m_css_Previous_sigpipe_handler != NULL
      && client_support::m_css_Previous_sigpipe_handler != SIG_IGN
      && client_support::m_css_Previous_sigpipe_handler != SIG_DFL
      && client_support::m_css_Previous_sigpipe_handler != client_support::css_handle_pipe_shutdown)
    {
      (*client_support::m_css_Previous_sigpipe_handler) (sig);
    }
    }
}

/*
 * css_set_pipe_signal() - sets up the signal handling mechanism
 *   return:
 *
 * Note: Note that we try to find out if there are any previous handlers.
 *       If so, make note of them so that we can pass on errors on fds that
 *       we do not know.
 */
void
client_support::css_set_pipe_signal (void)
{
#if !defined(WINDOWS)
  client_support::m_css_Previous_sigpipe_handler =
      os_set_signal_handler (SIGPIPE, client_support::css_handle_pipe_shutdown);
  if ((client_support::m_css_Previous_sigpipe_handler == SIG_IGN)
      || (client_support::m_css_Previous_sigpipe_handler == SIG_ERR)
      || (client_support::m_css_Previous_sigpipe_handler == SIG_DFL)
#if !defined(LINUX)
      || (client_support::m_css_Previous_sigpipe_handler == SIG_HOLD)
#endif /* not LINUX */
     )
    {
      client_support::m_css_Previous_sigpipe_handler = NULL;
    }
#endif /* not WINDOWS */
}

/*
 * css_client_init() - initialize the network portion of the client interface
 *   return:
 *   sockid(in): sSocket number for remote host
 *   server_name(in):
 *   host_name(in):
 */
int
client_support::css_client_init (int sockid, const char *server_name, const char *host_name)
{
  CSS_CONN_ENTRY *conn;
  int error = NO_ERROR;

#if defined(WINDOWS)
  (void) css_windows_startup ();
#endif /* WINDOWS */

  m_service_port_id = sockid;
  css_set_pipe_signal ();

  conn = css_connect_to_cubrid_server ((char *) host_name, (char *) server_name);
  if (conn != NULL)
    {
      CSS_MAP_ENTRY *map = m_conn_less.css_queue_connection (conn, (char *) host_name);
      if (map == NULL)
    {
      css_free_conn (conn);
      error = ER_CSS_ALLOC;
    }
    }
  else
    {
      /* At here, er_errid () can be NO_ERROR */
      error = er_errid ();
      if (error == NO_ERROR)
    {
      error = ER_BO_CONNECT_FAILED;
    }
    }

  return error;
}

#if defined(MULTI_CONN_TO_A_SERVER)
int
client_support::css_client_sub_init (const char *server_name, const char *host_name)
{
  CSS_CONN_ENTRY *conn;
  CSS_MAP_ENTRY *map;
  int error = NO_ERROR;

  conn = css_connect_to_cubrid_server ((char *) host_name, (char *) server_name);
  if (conn != NULL)
    {
      map = m_conn_less.css_queue_connection (conn, (char *) host_name);
      if (map == NULL)
    {
      css_free_conn (conn);
      error = ER_CSS_ALLOC;
    }
    }
  else
    {
      /* At here, er_errid () can be NO_ERROR */
      error = er_errid ();
      if (error == NO_ERROR)
    {
      error = ER_BO_CONNECT_FAILED;
    }
    }

  return error;
}

void
client_support::css_client_sub_terminate (const char *host_name)
{
  CSS_MAP_ENTRY *entry;

  entry = m_conn_less.css_return_open_entry ((char *) host_name);
  if (entry != NULL)
    {
      css_send_close_request (entry->conn);
      css_free_conn (entry->conn);
      m_conn_less.css_remove_queued_connection_by_entry (entry);
    }
}
#endif // defined(MULTI_CONN_TO_A_SERVER)


#if defined(ENABLE_UNUSED_FUNCTION)
/*
 * css_send_request_to_server() - send a request to a server
 *   return: request id
 *   host(in): name of the remote host
 *   request(in): the request to send to the server.
 *   arg_buffer(in): a packed buffer containing all the arguments to be sent to
 *               the server.
 *   arg_buffer_size(in): The size of arg_buffer.
 */
unsigned int
client_support::css_send_request_to_server (char *host, int request, char *arg_buffer, int arg_buffer_size)
{
  CSS_MAP_ENTRY *entry;
  unsigned short rid;

  entry = m_conn_less.css_return_open_entry (host);
  if (entry != NULL)
    {
      entry->conn->set_tran_index (tm_Tran_index);
      entry->conn->invalidate_snapshot = tm_Tran_invalidate_snapshot;
      m_css_errno = css_send_request (entry->conn, (int) request, &rid, arg_buffer, (int) arg_buffer_size);
      if (m_css_errno != NO_ERRORS)
    {
      css_free_conn (entry->conn);
      m_conn_less.css_remove_queued_connection_by_entry (entry);
      return 0;
    }
      tm_Tran_invalidate_snapshot = 0;
    }
  else
    {
      m_css_errno = SERVER_WAS_NOT_FOUND;
      return 0;
    }

  return (m_conn_less.css_make_eid (entry->id, rid));
}
#endif

/*
 * css_send_request_to_server_with_buffer() - send a request to server
 *   return:
 *   host(in): name of the remote host
 *   request(in): the request to send to the server.
 *   arg_buffer(in): a packed buffer containing all the arguments to be sent to the server.
 *   arg_buffer_size(in): The size of arg_buffer.
 *   data_buffer(in): enroll a data buffer to hold the resulting data.
 *   data_buffer_size(in): The size of the data buffer.
 *
 * Note: This routine will allow the client to send a request to a host and
 *       also enroll a data buffer to be filled with returned data.
 */
unsigned int
client_support::css_send_request_to_server_with_buffer (char *host, int request, char *arg_buffer, int arg_buffer_size,
    char *data_buffer, int data_buffer_size)
{
  CSS_MAP_ENTRY *entry;
  unsigned short rid;

  entry = m_conn_less.css_return_open_entry (host);
  if (entry == NULL)
    {
      m_css_errno = SERVER_WAS_NOT_FOUND;
      return 0;
    }

  entry->conn->set_tran_index (tm_Tran_index);
  entry->conn->invalidate_snapshot = tm_Tran_invalidate_snapshot;
  entry->conn->in_method = tran_is_in_libcas ();

  m_css_errno =
      css_send_request_with_data_buffer_with_padding (entry->conn, request, &rid, arg_buffer, arg_buffer_size,
          data_buffer, data_buffer_size);
  if (m_css_errno != NO_ERRORS)
    {
      css_free_conn (entry->conn);
      m_conn_less.css_remove_queued_connection_by_entry (entry);
      return 0;
    }

  tm_Tran_invalidate_snapshot = 0;
  return (m_conn_less.css_make_eid (entry->id, rid));
}

/*
 * css_send_req_to_server() - send a request to server
 *   return:
 *   host(in): name of the remote host
 *   request(in): the request to send to the server.
 *   arg_buffer(in): a packed buffer containing all the arguments to be sent to the server.
 *   arg_buffer_size(in): The size of arg_buffer.
 *   data_buffer(in): additional data to send to the server
 *   data_buffer_size(in): The size of the data buffer.
 *   reply_buffer(in): enroll a data buffer to hold the resulting data.
 *   reply_buffer_size(in): The size of the reply buffer.
 *
 * Note: This routine will allow the client to send a request to a host and
 *       also enroll a data buffer to be filled with returned data.
 */
unsigned int
client_support::css_send_req_to_server (char *host, int request, char *arg_buffer, int arg_buffer_size,
                    char *data_buffer, int data_buffer_size, char *reply_buffer, int reply_size)
{
  CSS_MAP_ENTRY *entry;
  unsigned short rid;

  entry = m_conn_less.css_return_open_entry (host);
  if (entry == NULL)
    {
      m_css_errno = SERVER_WAS_NOT_FOUND;
      return 0;
    }

  entry->conn->set_tran_index (tm_Tran_index);
  entry->conn->invalidate_snapshot = tm_Tran_invalidate_snapshot;
  entry->conn->in_method = tran_is_in_libcas ();

  /* if the latest query status is committed, fetch won't be issued. */
  assert (!tran_was_latest_query_committed () || request != NET_SERVER_LS_GET_LIST_FILE_PAGE);

  m_css_errno = css_send_req_with_2_buffers (entry->conn, request, &rid, arg_buffer, arg_buffer_size, data_buffer,
        data_buffer_size, reply_buffer, reply_size);
  if (m_css_errno != NO_ERRORS)
    {
      css_free_conn (entry->conn);
      m_conn_less.css_remove_queued_connection_by_entry (entry);
      return 0;
    }

  tm_Tran_invalidate_snapshot = 0;
  return (m_conn_less.css_make_eid (entry->id, rid));
}

#if defined(ENABLE_UNUSED_FUNCTION)
/*
 * css_send_req_to_server_with_large_data() - send a request to server with
 *    large data
 *   return:
 *   host(in): name of the remote host
 *   request(in): the request to send to the server.
 *   arg_buffer(in): a packed buffer containing all the arguments to be
 *               sent to the server.
 *   arg_buffer_size(in): The size of arg_buffer.
 *   data_buffer(in): additional data to send to the server
 *   data_buffer_size(in): The size of the data buffer.
 *   reply_buffer(in): enroll a data buffer to hold the resulting data.
 *   reply_buffer_size(in): The size of the reply buffer.
 *
 * Note: This routine will allow the client to send a request to a host and
 *       also enroll a data buffer to be filled with returned data.
 */
unsigned int
client_support::css_send_req_to_server_with_large_data (char *host, int request, char *arg_buffer, int arg_buffer_size,
    char *data_buffer, INT64 data_buffer_size, char *reply_buffer, int reply_size)
{
  CSS_MAP_ENTRY *entry;
  unsigned short rid;

  entry = m_conn_less.css_return_open_entry (host);
  if (entry != NULL)
    {
      entry->conn->set_tran_index (tm_Tran_index);
      entry->conn->invalidate_snapshot = tm_Tran_invalidate_snapshot;
      m_css_errno =
          css_send_req_with_large_buffer (entry->conn, request, &rid, arg_buffer, arg_buffer_size, data_buffer,
                          data_buffer_size, reply_buffer, reply_size);
      if (m_css_errno == NO_ERRORS)
    {
      tm_Tran_invalidate_snapshot = 0;
      return (m_conn_less.css_make_eid (entry->id, rid));
    }
      else
    {
      css_free_conn (entry->conn);
      m_conn_less.css_remove_queued_connection_by_entry (entry);
      return 0;
    }
    }

  m_css_errno = SERVER_WAS_NOT_FOUND;
  return 0;
}
#endif

/*
 * css_send_req_to_server_2_data() - send a request to server
 *   return:
 *   host(in): name of the remote host
 *   request(in): the request to send to the server.
 *   arg_buffer(in): a packed buffer containing all the arguments to be sent to the server.
 *   arg_buffer_size(in): The size of arg_buffer.
 *   data1_buffer(in): additional data to send to the server
 *   data1_buffer_size(in): The size of the data buffer.
 *   data2_buffer(in): additional data to send to the server
 *   data2_buffer_size(in): The size of the data buffer.
 *   reply_buffer(in): enroll a data buffer to hold the resulting data.
 *   reply_buffer_size(in): The size of the reply buffer.
 *
 * Note: This routine will allow the client to send a request and two data
 *       buffers to the server and also enroll a data buffer to be filled with returned data.
 */
unsigned int
client_support::css_send_req_to_server_2_data (char *host, int request, char *arg_buffer, int arg_buffer_size,
    char *data1_buffer, int data1_buffer_size, char *data2_buffer,
    int data2_buffer_size, char *reply_buffer, int reply_size)
{
  CSS_MAP_ENTRY *entry;
  unsigned short rid;

  entry = m_conn_less.css_return_open_entry (host);
  if (entry == NULL)
    {
      m_css_errno = SERVER_WAS_NOT_FOUND;
      return 0;
    }

  entry->conn->set_tran_index (tm_Tran_index);
  entry->conn->invalidate_snapshot = tm_Tran_invalidate_snapshot;
  entry->conn->in_method = tran_is_in_libcas ();

  m_css_errno = css_send_req_with_3_buffers (entry->conn, request, &rid, arg_buffer, arg_buffer_size, data1_buffer,
        data1_buffer_size, data2_buffer, data2_buffer_size, reply_buffer,
        reply_size);
  if (m_css_errno != NO_ERRORS)
    {
      css_free_conn (entry->conn);
      m_conn_less.css_remove_queued_connection_by_entry (entry);
      return 0;
    }

  tm_Tran_invalidate_snapshot = 0;
  return (m_conn_less.css_make_eid (entry->id, rid));
}

/*
 * css_send_req_to_server_no_reply() - send a data request to the server and receive no reply
 *   return:
 *   host(in):
 *   request(in):
 *   arg_buffer(in):
 *   arg_buffer_size(in):
 */
unsigned int
client_support::css_send_req_to_server_no_reply (char *host, int request, char *arg_buffer, int arg_buffer_size)
{
  CSS_MAP_ENTRY *entry;
  unsigned short rid;

  entry = m_conn_less.css_return_open_entry (host);
  if (entry == NULL)
    {
      m_css_errno = SERVER_WAS_NOT_FOUND;
      return 0;
    }

  entry->conn->set_tran_index (tm_Tran_index);
  entry->conn->invalidate_snapshot = tm_Tran_invalidate_snapshot;
  entry->conn->in_method = tran_is_in_libcas ();

  m_css_errno = css_send_request_no_reply (entry->conn, request, &rid, arg_buffer, arg_buffer_size);
  if (m_css_errno != NO_ERRORS)
    {
      css_free_conn (entry->conn);
      m_conn_less.css_remove_queued_connection_by_entry (entry);
      return 0;
    }

  tm_Tran_invalidate_snapshot = 0;
  return (m_conn_less.css_make_eid (entry->id, rid));
}

/*
 * css_queue_receive_data_buffer() - queue a data buffer for the client
 *   return:
 *   eid: enquiry id
 *   buffer: data buffer to queue for expected data.
 *   buffer_size: size of data buffer
 */
int
client_support::css_queue_receive_data_buffer (unsigned int eid, char *buffer, int buffer_size)
{
  CSS_MAP_ENTRY *entry;
  unsigned short rid;
  int rc = NO_ERRORS;

  if (buffer && (buffer_size > 0))
    {
      entry = m_conn_less.css_return_entry_from_eid (eid);
      if (entry != NULL)
    {
      rid = CSS_RID_FROM_EID (eid);
      rc = css_queue_user_data_buffer (entry->conn, rid, buffer_size, buffer);
    }
    }

  if (rc != NO_ERRORS)
    {
      return rc;
    }
  else
    {
      return 0;
    }
}

/*
 * css_send_error_to_server() - send an error buffer to the server
 *   return:
 *   host(in): name of the server machine
 *   eid(in): enquiry id
 *   buffer(in): data buffer to queue for expected data.
 *   buffer_size(in): size of data buffer
 */
unsigned int
client_support::css_send_error_to_server (char *host, unsigned int eid, char *buffer, int buffer_size)
{
  CSS_MAP_ENTRY *entry;

  assert (er_errid () != NO_ERROR);

  entry = m_conn_less.css_return_open_entry (host);
  if (entry == NULL)
    {
      m_css_errno = SERVER_WAS_NOT_FOUND;
      return m_css_errno;
    }

  entry->conn->set_tran_index (tm_Tran_index);
  entry->conn->invalidate_snapshot = tm_Tran_invalidate_snapshot;
  entry->conn->in_method = tran_is_in_libcas ();
  entry->conn->db_error = er_errid ();

  m_css_errno = css_send_error_with_padding (entry->conn, CSS_RID_FROM_EID (eid), buffer, buffer_size);
  if (m_css_errno != NO_ERRORS)
    {
      css_free_conn (entry->conn);
      m_conn_less.css_remove_queued_connection_by_entry (entry);
      return m_css_errno;
    }

  tm_Tran_invalidate_snapshot = 0;
  entry->conn->db_error = 0;
  return 0;
}

/*
 * css_send_data_to_server() - send a data buffer to the server
 *   return:
 *   host(in): name of the server machine
 *   eid(in): enquiry id
 *   buffer(in): data buffer to queue for expected data.
 *   buffer_size(in): size of data buffer
 */
unsigned int
client_support::css_send_data_to_server (char *host, unsigned int eid, char *buffer, int buffer_size)
{
  CSS_MAP_ENTRY *entry;

  entry = m_conn_less.css_return_open_entry (host);
  if (entry == NULL)
    {
      m_css_errno = SERVER_WAS_NOT_FOUND;
      return m_css_errno;
    }

  entry->conn->set_tran_index (tm_Tran_index);
  entry->conn->invalidate_snapshot = tm_Tran_invalidate_snapshot;
  entry->conn->in_method = tran_is_in_libcas ();

  m_css_errno = css_send_data_with_padding (entry->conn, CSS_RID_FROM_EID (eid), buffer, buffer_size);
  if (m_css_errno != NO_ERRORS)
    {
      css_free_conn (entry->conn);
      m_conn_less.css_remove_queued_connection_by_entry (entry);
      return m_css_errno;
    }

  tm_Tran_invalidate_snapshot = 0;
  return 0;
}

/*
 * css_test_for_server_errors() -
 *   return: error id from the server
 *   entry(in):
 *   eid(in):
 */
int
client_support::css_test_for_server_errors (CSS_MAP_ENTRY *entry, unsigned int eid)
{
  char *error_buffer;
  int error_size, rc, errid = NO_ERROR;

  if (css_return_queued_error (entry->conn, CSS_RID_FROM_EID (eid), &error_buffer, &error_size, &rc))
    {
      errid = er_set_area_error (error_buffer);
      free_and_init (error_buffer);
    }
  return errid;
}

/*
 * css_receive_data_from_server() - return data that was sent by the server
 *   return:
 *   eid(in): enquiry id
 *   buffer(out): data buffer to be returned
 *   size(out): size of data buffer that was returned
 */
unsigned int
client_support::css_receive_data_from_server (unsigned int eid, char **buffer, int *size)
{
  return css_receive_data_from_server_with_timeout (eid, buffer, size, -1);
}

/*
 * css_receive_data_from_server_with_timeout() - return data that was sent by the server
 *   return:
 *   eid(in): enquiry id
 *   buffer(out): data buffer to be returned
 *   size(out): size of data buffer that was returned
 *   timeout(in) : timeout in milli-second
 */
unsigned int
client_support::css_receive_data_from_server_with_timeout (unsigned int eid, char **buffer, int *size, int timeout)
{
  CSS_MAP_ENTRY *entry;
  int rid;

  entry = m_conn_less.css_return_entry_from_eid (eid);
  if (entry == NULL)
    {
      m_css_errno = SERVER_WAS_NOT_FOUND;
      return m_css_errno;
    }

  rid = CSS_RID_FROM_EID (eid);
  m_css_errno = css_receive_data (entry->conn, rid, buffer, size, timeout);
  if (m_css_errno == NO_ERRORS || m_css_errno == SERVER_ABORTED)
    {
      css_test_for_server_errors (entry, eid);
    }

  return m_css_errno == NO_ERRORS ? 0 : m_css_errno;
}

#if defined (ENABLE_UNUSED_FUNCTION)
/*
 * css_receive_error_from_server() - return error data from the server
 *   return:
 *   eid(in): enquiry id
 *   buffer(out): error buffer to be returned
 *   size(out): size of error buffer that was returned
 */
unsigned int
client_support::css_receive_error_from_server (unsigned int eid, char **buffer, int *size)
{
  CSS_MAP_ENTRY *entry;

  entry = m_conn_less.css_return_entry_from_eid (eid);
  if (entry != NULL)
    {
      m_css_errno = css_receive_error (entry->conn, CSS_RID_FROM_EID (eid), buffer, size);
      if (m_css_errno == NO_ERRORS)
    {
      return 0;
    }
      else
    {
      /*
       * Normally, we disconnect upon any type of receive error.  However,
       * in the case of allocation errors, we want to continue and
       * propagate the error.
       */
      if (m_css_errno != CANT_ALLOC_BUFFER)
        {
          css_free_conn (entry->conn);
          m_conn_less.css_remove_queued_connection_by_entry (entry);
        }
      return m_css_errno;
    }
    }

  m_css_errno = SERVER_WAS_NOT_FOUND;
  return m_css_errno;
}
#endif /* ENABLE_UNUSED_FUNCTION */

/*
 * css_terminate() - "gracefully" terminate all requests
 *   server_error(in):
 *   return: void
 */
void
client_support::css_terminate (bool server_error)
{
  CSS_MAP_ENTRY *entry;

  entry = m_conn_less.css_get_map_entry();
  while (entry)
    {
      if (server_error && entry->conn)
    {
      entry->conn->status = CONN_CLOSING;
    }
      css_send_close_request (entry->conn);
      css_free_conn (entry->conn);
      m_conn_less.css_remove_queued_connection_by_entry (entry);
      entry = m_conn_less.css_get_map_entry();
    }

#if defined(WINDOWS)
  css_windows_shutdown ();
#endif /* WINDOWS */

  /*
   * If there was a previous signal handler. restore it at this point.
   */
#if !defined(WINDOWS)
  if (client_support::m_css_Previous_sigpipe_handler != NULL)
    {
      (void) os_set_signal_handler (SIGPIPE, client_support::m_css_Previous_sigpipe_handler);
      client_support::m_css_Previous_sigpipe_handler = NULL;
    }
#endif /* not WINDOWS */
}

/*
 * css_cleanup_client_queues() -
 *   return:
 *   host_name(in):
 */
void
client_support::css_cleanup_client_queues (char *host_name)
{
  CSS_MAP_ENTRY *entry;

  entry = m_conn_less.css_return_open_entry (host_name);
  if (entry != NULL)
    {
      css_remove_all_unexpected_packets (entry->conn);
    }
}

/*
 * css_ha_server_state - return the current HA server state
 *   return: one of HA_SERVER_STATE
 */
HA_SERVER_STATE
css_ha_server_state (void)
{
  return boot_change_ha_mode (HA_SERVER_STATE_NA, false, 0);
}

#if !defined(NDEBUG) || defined(MULTI_CONN_TO_A_SERVER)
pthread_t gv_main_tid;

__attribute__ ((constructor))
static void get_main_thread_id ()
{
  gv_main_tid = pthread_self ();
}
#endif

pthread_t
css_get_thread_id ()
{
  static THREAD_LOCAL pthread_t tid = pthread_self ();
  return tid;
}