File connection_support.cpp¶
File List > connection > connection_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.
*
*/
/*
* connection_support.cpp - general networking function
*/
#ident "$Id$"
#include "config.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <assert.h>
#if defined(WINDOWS)
#include <winsock2.h>
#else /* WINDOWS */
#include <sys/time.h>
#include <sys/ioctl.h>
#include <sys/uio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#include <fcntl.h>
#include <poll.h>
#endif /* !WINDOWS */
#if defined(_AIX)
#include <sys/select.h>
#endif /* _AIX */
#if defined(SOLARIS)
#include <sys/filio.h>
#include <netdb.h> /* for MAXHOSTNAMELEN */
#endif /* SOLARIS */
#include "porting.h"
#include "error_manager.h"
#include "connection_globals.h"
#include "memory_alloc.h"
#include "environment_variable.h"
#include "system_parameter.h"
#include "boot_sr.h"
#if defined(WINDOWS)
#include "wintcp.h"
#else /* WINDOWS */
#include "tcp.h"
#endif /* !WINDOWS */
#include "connection_support.hpp"
#if defined(SERVER_MODE)
#include "span.hpp"
#include "connection_sr.h"
#else
#include "connection_cl.h"
#endif
#if defined(CS_MODE)
#include "network_interface_cl.h"
#endif
#include "storage_common.h"
#if defined (SERVER_MODE) || defined (SA_MODE)
#include "heap_file.h"
#endif /* defined (SERVER_MODE) || defined (SA_MODE) */
#include "dbtype.h"
#include "tz_support.h"
#include "db_date.h"
#include "show_scan.h"
// XXX: SHOULD BE THE LAST INCLUDE HEADER
#include "memory_wrapper.hpp"
#if defined(CS_MODE)
extern bool tran_is_in_libcas (void);
#endif
#if !defined (SERVER_MODE)
#define pthread_mutex_init(a, b)
#define pthread_mutex_destroy(a)
#define pthread_mutex_lock(b) 0
#define pthread_mutex_unlock(a)
static int rv;
#endif /* !SERVER_MODE */
#define INITIAL_IP_NUM 16
#if defined(WINDOWS)
typedef char *caddr_t;
#endif /* WINDOWS */
static const int CSS_TCP_MIN_NUM_RETRIES = 3;
#define CSS_TRUNCATE_BUFFER_SIZE 512
#if !defined (SERVER_MODE)
static void css_default_server_timeout_fn (void);
static CSS_SERVER_TIMEOUT_FN css_server_timeout_fn = css_default_server_timeout_fn;
static bool css_default_check_server_alive_fn (const char *db_name, const char *db_host);
CSS_CHECK_SERVER_ALIVE_FN css_check_server_alive_fn = css_default_check_server_alive_fn;
#endif /* !SERVER_MODE */
#if defined(WINDOWS)
#define CSS_VECTOR_SIZE (1024 * 64)
#if defined(SERVER_MODE)
#define CSS_NUM_INTERNAL_VECTOR_BUF 20
static char *css_Vector_buffer = NULL;
static char *css_Vector_buffer_piece[CSS_NUM_INTERNAL_VECTOR_BUF] = { 0 };
static int css_Vector_buffer_occupied_flag[CSS_NUM_INTERNAL_VECTOR_BUF] = { 0 };
static pthread_mutex_t css_Vector_buffer_mutex = PTHREAD_MUTEX_INITIALIZER;
static pthread_cond_t css_Vector_buffer_cond = PTHREAD_COND_INITIALIZER;
#else /* SERVER_MODE */
static char css_Vector_buffer[CSS_VECTOR_SIZE];
#endif /* SERVER_MODE */
#endif /* WINDOWS */
static int css_sprintf_conn_infoids (SOCKET fd, char *client_user_name, char *client_host_name, int *client_pid);
static int css_send_io_vector (CSS_CONN_ENTRY *conn, struct iovec *vec_p, ssize_t total_len, int vector_length,
int timeout);
static int css_net_send2 (CSS_CONN_ENTRY *conn, const char *buff1, int len1, const char *buff2, int len2);
static int css_net_send3 (CSS_CONN_ENTRY *conn, const char *buff1, int len1, const char *buff2, int len2,
const char *buff3, int len3);
#if defined(SERVER_MODE)
static int css_net_send4 (CSS_CONN_ENTRY *conn, const char *buff1, int len1, const char *buff2, int len2,
const char *buff3, int len3, const char *buff4, int len4);
#endif /* SERVER_MODE */
#if defined(ENABLE_UNUSED_FUNCTION)
static int css_net_send_large_data_with_arg (CSS_CONN_ENTRY *conn, const char *header_buffer, int header_len,
NET_HEADER *header_array, const char **data_array, int num_array);
#endif
#if defined(SERVER_MODE)
static char *css_trim_str (char *str);
#endif
#if !defined (CS_MODE)
static int css_make_access_status_exist_user (THREAD_ENTRY *thread_p, OID *class_oid,
LAST_ACCESS_STATUS **access_status_array, int num_user,
SHOWSTMT_ARRAY_CONTEXT *ctx);
static LAST_ACCESS_STATUS *css_get_access_status_with_name (LAST_ACCESS_STATUS **access_status_array, int num_user,
const char *user_name);
static LAST_ACCESS_STATUS *css_get_unused_access_status (LAST_ACCESS_STATUS **access_status_array, int num_user);
#if defined (SERVER_MODE)
static int css_send_request_with_data_buffer (CSS_CONN_ENTRY *conn, int request, unsigned short *request_id,
const char *arg_buffer, int arg_size, char *reply_buffer, int reply_size);
#endif
#endif /* !CS_MODE */
#if !defined(SERVER_MODE)
static int
css_sprintf_conn_infoids (SOCKET fd, char *user_name, char *host_name, int *client_pid)
{
CSS_CONN_ENTRY *conn;
int tran_index = -1;
conn = css_find_conn_from_fd (fd);
if (conn != NULL && conn->get_tran_index () != -1)
{
if (getuserid (user_name, L_cuserid) == NULL)
{
strcpy (user_name, "");
}
if (GETHOSTNAME (host_name, CUB_MAXHOSTNAMELEN) != 0)
{
strcpy (host_name, "???");
}
*client_pid = getpid ();
tran_index = conn->get_tran_index ();
}
return tran_index;
}
static void
css_default_server_timeout_fn (void)
{
/* do nothing */
return;
}
#elif defined(WINDOWS)
/*
* css_sprintf_conn_infoids() - find client information of given connection
* return: transaction id
* fd(in): socket fd
* tran_index(in): transaction index associated with socket
* client_user_name(in): client user name of socket fd
* client_host_name(in): client host name of socket fd
* client_pid(in): client process of socket fd
*/
static int
css_sprintf_conn_infoids (SOCKET fd, char *user_name, char *host_name, int *client_pid)
{
const char *client_prog_name;
CSS_CONN_ENTRY *conn;
int error, tran_index = -1;
char *client_user_name, *client_host_name;
conn = css_find_conn_from_fd (fd);
if (conn != NULL && conn->get_tran_index () != -1)
{
error = logtb_find_client_name_host_pid (conn->get_tran_index (), &client_prog_name, &client_user_name,
&client_host_name, client_pid);
if (error == NO_ERROR)
{
strncpy (user_name, client_user_name, L_cuserid);
user_name[L_cuserid] = '\0';
strncpy (host_name, client_host_name, CUB_MAXHOSTNAMELEN);
host_name[CUB_MAXHOSTNAMELEN] = '\0';
tran_index = conn->get_tran_index ();
}
else
{
strcpy (user_name, "");
strcpy (host_name, "???");
}
}
return tran_index;
}
#endif /* WINDOWS */
#if defined(WINDOWS) || !defined(SERVER_MODE)
static void
css_set_networking_error (SOCKET fd)
{
char client_user_name[L_cuserid + 1] = { '\0' };
char client_host_name[CUB_MAXHOSTNAMELEN + 1] = { '\0' };
int client_pid;
int client_tranindex;
client_tranindex = css_sprintf_conn_infoids (fd, client_user_name, client_host_name, &client_pid);
if (client_tranindex != -1)
{
er_set_with_oserror (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_CSS_RECV_OR_SEND, 5, fd, client_tranindex,
client_user_name, client_host_name, client_pid);
}
}
#endif
#if defined (ENABLE_UNUSED_FUNCTION)
/*
* css_net_send_no_block () - Sends blocks of zero length packets
* return:
* fd(in): the socket fd
* buffer(in): the buffer full of zero data
* size(in): amout of data to send
*
* Note: This allows the server to either detect one of the following cases:
* The client has gone down (the send fails)
* The client is alive, but not waiting for server input (EWOULDBLOCK)
* The client is waiting for a server request to complete, but is
* still consuming blocks of zero length data. (This could be the
* case when a client is waiting for a lock or query result).
*/
int
css_net_send_no_block (SOCKET fd, const char *buffer, int size)
{
#if defined(WINDOWS)
int rc, total = 0;
unsigned long noblock = 1, block = 0;
int winsock_error;
rc = ioctlsocket (fd, FIONBIO, &noblock);
if (rc == SOCKET_ERROR)
{
return ERROR_ON_WRITE;
}
for (total = 0; total < 2 * size; total += rc)
{
rc = send (fd, buffer, size, 0);
if (rc != size)
{
winsock_error = WSAGetLastError ();
if (rc < 0 && winsock_error != WSAEWOULDBLOCK && winsock_error != WSAEINTR)
{
return ERROR_ON_WRITE;
}
else
{
break;
}
}
}
rc = ioctlsocket (fd, FIONBIO, &block);
if (rc != 0)
{
return ERROR_ON_WRITE;
}
return NO_ERRORS;
#else /* WINDOWS */
int rc, noblock = 1, block = 0, total = 0;
rc = ioctl (fd, FIONBIO, (caddr_t) (&noblock));
if (rc < 0)
{
return ERROR_ON_WRITE;
}
for (total = 0; total < 2 * size; total += rc)
{
errno = 0;
rc = send (fd, buffer, size, 0);
if (rc != size)
{
if (rc <= 0 && errno != EWOULDBLOCK && errno != EINTR && errno != EAGAIN && errno != EACCES)
{
return (ERROR_ON_WRITE);
}
else
{
break;
}
}
}
rc = ioctl (fd, FIONBIO, (caddr_t) (&block));
if (rc < 0)
{
return ERROR_ON_WRITE;
}
return NO_ERRORS;
#endif /* WINDOWS */
}
#endif /* ENABLE_UNUSED_FUNCTION */
/*
* css_readn() - read "n" bytes from a descriptor.
* return: count of bytes actually read
* fd(in): sockert descripter
* ptr(out): buffer
* nbytes(in): count of bytes will be read
* timeout(in): timeout in milli-second
*/
int
css_readn (SOCKET fd, char *ptr, int nbytes, int timeout)
{
int nleft, n;
int remains;
#if defined (WINDOWS)
int winsock_error;
#else
struct pollfd po[1] = { {0, 0, 0} };
#endif /* WINDOWS */
if (fd < 0)
{
er_log_debug (ARG_FILE_LINE, "css_readn: fd < 0");
errno = EINVAL;
return -1;
}
if (nbytes <= 0)
{
return 0;
}
nleft = nbytes;
do
{
#if !defined (WINDOWS)
po[0].fd = fd;
po[0].events = POLLIN;
po[0].revents = 0;
n = poll (po, 1, timeout);
if (n == 0)
{
/* 0 means it timed out and no fd is changed. */
errno = ETIMEDOUT;
return -1;
}
else if (n < 0)
{
if (errno == EINTR)
{
#if !defined (SERVER_MODE)
if (css_server_timeout_fn != NULL)
{
css_server_timeout_fn ();
}
#endif /* !SERVER_MODE */
continue;
}
er_log_debug (ARG_FILE_LINE, "css_readn: %s", strerror (errno));
return -1;
}
else
{
if (po[0].revents & POLLERR || ((po[0].revents & POLLHUP) && ! (po[0].revents & POLLIN)))
{
if (ioctl (fd, FIONREAD, &remains) >= 0)
{
if (remains > 0)
{
er_log_debug (ARG_FILE_LINE, "%d bytes of data pending in buffer (fd = %d)\n", remains, fd);
}
}
errno = EINVAL;
er_log_debug (ARG_FILE_LINE, "css_readn: %s %s", (po[0].revents & POLLERR ? "POLLERR" : "POLLHUP"),
strerror (errno));
return -1;
}
}
#endif /* !WINDOWS */
read_again:
n = recv (fd, ptr, nleft, 0);
if (n == 0)
{
break;
}
if (n < 0)
{
#if !defined(WINDOWS)
if (errno == EAGAIN)
{
continue;
}
if (errno == EINTR)
{
goto read_again;
}
#else
winsock_error = WSAGetLastError ();
/* In Windows 2003, pass large length (such as 120MB) to recv() will temporary unavailable by error number
* WSAENOBUFS (10055) */
if (winsock_error == WSAENOBUFS)
{
goto read_again;
}
if (winsock_error == WSAEINTR)
{
goto read_again;
}
#endif
#if !defined (SERVER_MODE)
css_set_networking_error (fd);
#endif /* !SERVER_MODE */
er_log_debug (ARG_FILE_LINE, "css_readn: returning error n %d, errno %s\n", n, strerror (errno));
return n; /* error, return < 0 */
}
nleft -= n;
ptr += n;
}
while (nleft > 0);
return (nbytes - nleft); /* return >= 0 */
}
/*
* css_read_remaining_bytes() - read remaining data
* return: void
* fd(in): socket descripter
* len(in): count of bytes
*
* Note: This routine will "use up" any remaining data that may be on the
* socket, but for which no space has been allocated.
* This will happen if the client provides a data buffer for a request
* that is too small for the data sent by the server.
*/
void
css_read_remaining_bytes (CSS_CONN_ENTRY *conn, int len)
{
char temp_buffer[CSS_TRUNCATE_BUFFER_SIZE];
int nbytes, buf_size;
while (len > 0)
{
if (len <= SSIZEOF (temp_buffer))
{
buf_size = len;
}
else
{
buf_size = SSIZEOF (temp_buffer);
}
nbytes = css_readn (conn->fd, temp_buffer, buf_size, -1);
/*
* nbytes will be less than the size of the buffer if any of the
* following hold:
* a) the socket has been closed for some reason (e.g., the client
* was killed);
* b) there was some other kind of read error;
* c) we have simply read all of the bytes that were asked for.
*/
if (nbytes < buf_size)
{
break;
}
len -= buf_size;
}
/* TODO: return error or length */
}
/*
* css_net_recv() - reading a "packet" from the socket.
* return: 0 if success, or error code
* fd(in): socket descripter
* buffer(out): buffer for date be read
* maxlen(out): count of bytes was read
* timeout(in): timeout value in milli-second
*/
int
css_net_recv (CSS_CONN_ENTRY *conn, char *buffer, int *maxlen, int timeout)
{
int nbytes;
int templen;
int length_to_read;
int time_unit;
int elapsed;
if (timeout < 0)
{
timeout = INT_MAX;
}
time_unit = timeout > 5000 ? 5000 : timeout;
elapsed = time_unit;
/* read data length */
while (true)
{
nbytes = css_readn (conn->fd, (char *) &templen, sizeof (int), time_unit);
if (nbytes < 0)
{
if (errno == ETIMEDOUT && timeout > elapsed)
{
#if defined (CS_MODE) && !defined (WINDOWS)
if (CHECK_SERVER_IS_ALIVE ())
{
if (css_peer_alive (conn->fd, time_unit) == false)
{
return ERROR_WHEN_READING_SIZE;
}
if (css_check_server_alive_fn != NULL)
{
if (css_check_server_alive_fn (NULL, NULL) == false)
{
return ERROR_WHEN_READING_SIZE;
}
}
}
#endif /* CS_MODE && !WINDOWS */
elapsed += time_unit;
continue;
}
return ERROR_WHEN_READING_SIZE;
}
if (nbytes != sizeof (int))
{
#ifdef CUBRID_DEBUG
er_log_debug (ARG_FILE_LINE, "css_net_recv: returning ERROR_WHEN_READING_SIZE bytes %d \n", nbytes);
#endif
return ERROR_WHEN_READING_SIZE;
}
else
{
break;
}
}
templen = ntohl (templen);
if (templen > *maxlen)
{
length_to_read = *maxlen;
}
else
{
length_to_read = templen;
}
/* read data */
nbytes = css_readn (conn->fd, buffer, length_to_read, timeout);
if (nbytes < length_to_read)
{
#ifdef CUBRID_DEBUG
er_log_debug (ARG_FILE_LINE, "css_net_recv: returning ERROR_ON_READ bytes %d\n", nbytes);
#endif
return ERROR_ON_READ;
}
/*
* This is possible if the data buffer provided by the client is smaller
* than the number of bytes sent by the server
*/
if (nbytes && (templen > nbytes))
{
css_read_remaining_bytes (conn, templen - nbytes);
return RECORD_TRUNCATED;
}
if (nbytes != templen)
{
#ifdef CUBRID_DEBUG
er_log_debug (ARG_FILE_LINE, "css_net_recv: returning READ_LENGTH_MISMATCH bytes %d\n", nbytes);
#endif
return READ_LENGTH_MISMATCH;
}
*maxlen = nbytes;
return NO_ERRORS;
}
#if defined(WINDOWS)
/* We implement css_vector_send on Winsock platforms by copying the pieces into
a temporary buffer before sending. */
/*
* css_writen() - write "n" bytes to a descriptor.
* return: count of bytes actually written
* fd(in): socket descripter
* ptr(in): buffer
* nbytes(in): count of bytes will be written
*
* Note: Use in place of write() when fd is a stream socket.
* Formerly only present when VECTOR was disabled but we now need this
* for the writev() simulation on platforms that don't support the vector
* functions.
*/
static int
css_writen (SOCKET fd, char *ptr, int nbytes)
{
int num_retries = 0, sleep_nsecs = 1;
int nleft, nwritten;
nleft = nbytes;
while (nleft > 0)
{
errno = 0;
nwritten = send (fd, ptr, nleft, 0);
if (nwritten <= 0)
{
int winsock_error;
winsock_error = WSAGetLastError ();
if (winsock_error == WSAEINTR)
{
continue;
}
css_set_networking_error (fd);
return (nwritten);
}
nleft -= nwritten;
ptr += nwritten;
}
return (nbytes - nleft);
}
#if defined(SERVER_MODE)
/*
* alloc_vector_buffer() - allocate vector buffer
* return: index of a free vector_buffer slot
*
* Note: called whenever threads need a vector buffer.
*/
static int
alloc_vector_buffer (void)
{
int i, r;
#ifdef VECTOR_IO_TUNE
int wait_count = 0;
#endif /* VECTOR_IO_TUNE */
r = pthread_mutex_lock (&css_Vector_buffer_mutex);
if (css_Vector_buffer == NULL)
{
r = pthread_cond_init (&css_Vector_buffer_cond, NULL);
css_Vector_buffer = (char *) malloc (CSS_NUM_INTERNAL_VECTOR_BUF * CSS_VECTOR_SIZE);
if (css_Vector_buffer == NULL)
{
r = pthread_mutex_unlock (&css_Vector_buffer_mutex);
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_OUT_OF_VIRTUAL_MEMORY, 1,
(size_t) (CSS_NUM_INTERNAL_VECTOR_BUF * CSS_VECTOR_SIZE));
return -1;
}
for (i = 0; i < CSS_NUM_INTERNAL_VECTOR_BUF; i++)
{
css_Vector_buffer_piece[i] = css_Vector_buffer + i * CSS_VECTOR_SIZE;
}
}
while (1)
{
for (i = 0; i < CSS_NUM_INTERNAL_VECTOR_BUF; i++)
{
if (css_Vector_buffer_occupied_flag[i] == 0)
{
css_Vector_buffer_occupied_flag[i] = 1;
r = pthread_mutex_unlock (&css_Vector_buffer_mutex);
#ifdef VECTOR_IO_TUNE
if (wait_count > 0)
{
fprintf (stderr, "Thread[%d] looped ****** %d ***** to alloc buffer\n", GetCurrentThreadId (),
wait_count);
}
wait_count = 0;
#endif /* VECTOR_IO_TUNE */
return i; /* I found a free slot. */
}
}
#ifdef VECTOR_IO_TUNE
wait_count++;
#endif /* VECTOR_IO_TUNE */
r = pthread_cond_wait (&css_Vector_buffer_cond, &css_Vector_buffer_mutex);
}
}
#endif
#if defined(SERVER_MODE)
/*
* free_vector_buffer() - free vector buffer
* return: void
* index(in): index of buffer will be free
*/
static void
free_vector_buffer (int index)
{
int r;
r = pthread_mutex_lock (&css_Vector_buffer_mutex);
css_Vector_buffer_occupied_flag[index] = 0;
r = pthread_cond_signal (&css_Vector_buffer_cond);
r = pthread_mutex_unlock (&css_Vector_buffer_mutex);
}
#endif /* SERVER_MODE */
/*
* css_vector_send() - Winsock simulation of css_vector_send.
* return: size of sent if success, or error code
* fd(in): socket descripter
* vec(in): vector buffer
* len(in): vector length
* bytes_written(in):
* timeout(in): timeout value in milli-seconds
*
* Note: Does not support the "byte_written" argument for retries, we'll
* internally keep retrying the operation until all the data is written.
* That's what all the callers do anyway.
*/
int
css_vector_send (SOCKET fd, struct iovec *vec[], int *len, int bytes_written, int timeout)
{
int i, total_size, available, amount, rc;
char *src, *dest;
int handle_os_error;
#if defined(SERVER_MODE)
int vb_index;
#endif
/* don't support this, we'll write everything supplied with our own internal retry loop */
handle_os_error = 1;
if (bytes_written)
{
rc = -1;
handle_os_error = 0;
goto error;
}
/* calculate the total size of the stuff we need to send */
total_size = 0;
for (i = 0; i < *len; i++)
{
total_size += (*vec)[i].iov_len;
}
#if defined(SERVER_MODE)
vb_index = alloc_vector_buffer ();
dest = css_Vector_buffer_piece[vb_index];
#else
dest = css_Vector_buffer;
#endif
available = CSS_VECTOR_SIZE;
for (i = 0; i < *len; i++)
{
src = (*vec)[i].iov_base;
amount = (*vec)[i].iov_len;
/* if we've got more than we have room for, fill and send */
while (amount > available)
{
memcpy (dest, src, available);
#if defined(SERVER_MODE)
rc = css_writen (fd, css_Vector_buffer_piece[vb_index], CSS_VECTOR_SIZE);
#else
rc = css_writen (fd, css_Vector_buffer, CSS_VECTOR_SIZE);
#endif
if (rc != CSS_VECTOR_SIZE)
{
goto error;
}
src += available;
amount -= available;
#if defined(SERVER_MODE)
dest = css_Vector_buffer_piece[vb_index];
#else
dest = css_Vector_buffer;
#endif
available = CSS_VECTOR_SIZE;
}
/* if we have some amount that fits within the buffer, store it and move on */
if (amount)
{
memcpy (dest, src, amount);
dest += amount;
available -= amount;
}
}
/* see if we have any residual bytes left to be sent */
if (available < CSS_VECTOR_SIZE)
{
amount = CSS_VECTOR_SIZE - available;
#if defined(SERVER_MODE)
rc = css_writen (fd, css_Vector_buffer_piece[vb_index], amount);
#else
rc = css_writen (fd, css_Vector_buffer, amount);
#endif
if (rc != amount)
{
goto error;
}
}
#if defined(SERVER_MODE)
free_vector_buffer (vb_index);
#endif
return total_size;
error:
/*
* We end up with an error. The error has already been set in css_writen
*/
#if defined(SERVER_MODE)
free_vector_buffer (vb_index);
#endif
return rc;
}
#else /* WINDOWS */
/*
* css_vector_send() -
* return: size of sent if success, or error code
* fd(in): socket descripter
* vec(in): vector buffer
* len(in): vector length
* bytes_written(in):
* timeout(in): timeout value in milli-seconds
*/
static int
css_vector_send (SOCKET fd, struct iovec *vec[], int *len, int bytes_written, int timeout)
{
int i, n;
struct pollfd po[1] = { {0, 0, 0} };
if (fd < 0)
{
er_log_debug (ARG_FILE_LINE, "css_vector_send: fd < 0");
errno = EINVAL;
return -1;
}
if (bytes_written > 0)
{
er_log_debug (ARG_FILE_LINE, "css_vector_send: retry called for %d\n", bytes_written);
for (i = 0; i < *len; i++)
{
if ((*vec)[i].iov_len <= (size_t) bytes_written)
{
bytes_written -= (*vec)[i].iov_len;
}
else
{
break;
}
}
(*vec)[i].iov_len -= bytes_written;
(*vec)[i].iov_base = ((char *) ((*vec)[i].iov_base)) + bytes_written;
(*vec) += i;
*len -= i;
}
while (true)
{
po[0].fd = fd;
po[0].events = POLLOUT;
po[0].revents = 0;
n = poll (po, 1, timeout);
if (n < 0)
{
if (errno == EINTR)
{
continue;
}
er_log_debug (ARG_FILE_LINE, "css_vector_send: EINTR %s\n", strerror (errno));
return -1;
}
else if (n == 0)
{
/* 0 means it timed out and no fd is changed. */
errno = ETIMEDOUT;
return -1;
}
else
{
if (po[0].revents & POLLERR || po[0].revents & POLLHUP)
{
errno = EINVAL;
er_log_debug (ARG_FILE_LINE, "css_vector_send: %s %s\n",
(po[0].revents & POLLERR ? "POLLERR" : "POLLHUP"), strerror (errno));
return -1;
}
}
write_again:
n = writev (fd, *vec, *len);
if (n > 0)
{
return n;
}
else if (n == 0)
{
return 0; /* ??? */
}
else
{
if (errno == EINTR)
{
goto write_again;
}
if (errno == EAGAIN)
{
continue;
}
#if !defined (SERVER_MODE)
css_set_networking_error (fd);
#endif /* !SERVER_MODE */
er_log_debug (ARG_FILE_LINE, "css_vector_send: returning error n %d, errno %s\n", n, strerror (errno));
return n; /* error, return < 0 */
}
}
return -1;
}
#endif /* !WINDOWS */
static void
css_set_io_vector (struct iovec *vec1_p, struct iovec *vec2_p, const char *buff, int len, int *templen)
{
*templen = htonl (len);
vec1_p->iov_base = (caddr_t) templen;
vec1_p->iov_len = sizeof (int);
vec2_p->iov_base = (caddr_t) buff;
vec2_p->iov_len = len;
}
/*
* css_send_io_vector -
* return:
* conn(in):
* vec_p(in):
* total_len(in):
* vector_length(in):
* timeout(in): timeout value in milli-seconds
*/
static int
css_send_io_vector (CSS_CONN_ENTRY *conn, struct iovec *vec_p, ssize_t total_len, int vector_length, int timeout)
{
int rc;
rc = 0;
while (total_len > 0)
{
rc = css_vector_send (conn->fd, &vec_p, &vector_length, rc, timeout);
if (rc < 0)
{
#if !defined (SERVER_MODE)
css_shutdown_conn (conn);
#endif
return ERROR_ON_WRITE;
}
total_len -= rc;
}
return NO_ERRORS;
}
/*
* css_net_send() - send a record to the other end.
* return: enum css_error_code (See connection_defs.h)
* fd(in): socket descripter
* buff(in): buffer for data will be sent
* len(in): length for data will be sent
* timeout(in): timeout value in milli-seconds
*
* Note: Used by client and server.
*/
int
css_net_send (CSS_CONN_ENTRY *conn, const char *buff, int len, int timeout)
{
int templen;
struct iovec iov[2];
int total_len;
css_set_io_vector (& (iov[0]), & (iov[1]), buff, len, &templen);
assert (templen != 0);
total_len = len + sizeof (int);
return css_send_io_vector (conn, iov, total_len, 2, timeout);
}
/*
* css_net_send2() - send a record to the other end.
* return: enum css_error_code (See connection_defs.h)
* conn(in): connection entry
* fd(in): socket descripter
* buff1(in): buffer for data will be sent
* len1(in): length for data will be sent
* buff2(in): buffer for data will be sent
* len2(in): length for data will be sent
*
* Note: Used by client and server.
*/
static int
css_net_send2 (CSS_CONN_ENTRY *conn, const char *buff1, int len1, const char *buff2, int len2)
{
int templen1, templen2;
struct iovec iov[4];
int total_len;
css_set_io_vector (& (iov[0]), & (iov[1]), buff1, len1, &templen1);
css_set_io_vector (& (iov[2]), & (iov[3]), buff2, len2, &templen2);
assert (templen1 != 0);
assert (templen2 != 0);
total_len = len1 + len2 + sizeof (int) * 2;
/* timeout in milli-second in css_send_io_vector() */
return css_send_io_vector (conn, iov, total_len, 4, -1);
}
/*
* css_net_send3() - send a record to the other end.
* return: enum css_error_code (See connection_defs.h)
* conn(in): connection entry
* fd(in): socket descripter
* buff1(in): buffer for data will be sent
* len1(in): length for data will be sent
* buff2(in): buffer for data will be sent
* len2(in): length for data will be sent
* buff3(in): buffer for data will be sent
* len3(in): length for data will be sent
*
* Note: Used by client and server.
*/
static int
css_net_send3 (CSS_CONN_ENTRY *conn, const char *buff1, int len1, const char *buff2, int len2, const char *buff3,
int len3)
{
int templen1, templen2, templen3;
struct iovec iov[6];
int total_len;
css_set_io_vector (& (iov[0]), & (iov[1]), buff1, len1, &templen1);
css_set_io_vector (& (iov[2]), & (iov[3]), buff2, len2, &templen2);
css_set_io_vector (& (iov[4]), & (iov[5]), buff3, len3, &templen3);
assert (templen1 != 0);
assert (templen2 != 0);
assert (templen3 != 0);
total_len = len1 + len2 + len3 + sizeof (int) * 3;
/* timeout in milli-second in css_send_io_vector() */
return css_send_io_vector (conn, iov, total_len, 6, -1);
}
#if defined(SERVER_MODE)
/*
* css_net_send4() - Send a record to the other end.
* return: enum css_error_code (See connection_defs.h)
* conn(in): connection entry
* fd(in): socket descripter
* buff1(in): buffer for data will be sent
* len1(in): length for data will be sent
* buff2(in): buffer for data will be sent
* len2(in): length for data will be sent
* buff3(in): buffer for data will be sent
* len3(in): length for data will be sent
* buff4(in): buffer for data will be sent
* len4(in): length for data will be sent
*
* Note: Used by client and server.
*/
static int
css_net_send4 (CSS_CONN_ENTRY *conn, const char *buff1, int len1, const char *buff2, int len2, const char *buff3,
int len3, const char *buff4, int len4)
{
int templen1, templen2, templen3, templen4;
struct iovec iov[8];
int total_len;
css_set_io_vector (& (iov[0]), & (iov[1]), buff1, len1, &templen1);
css_set_io_vector (& (iov[2]), & (iov[3]), buff2, len2, &templen2);
css_set_io_vector (& (iov[4]), & (iov[5]), buff3, len3, &templen3);
css_set_io_vector (& (iov[6]), & (iov[7]), buff4, len4, &templen4);
assert (templen1 != 0);
assert (templen2 != 0);
assert (templen3 != 0);
assert (templen4 != 0);
total_len = len1 + len2 + len3 + len4 + sizeof (int) * 4;
/* timeout in milli-second in css_send_io_vector() */
return css_send_io_vector (conn, iov, total_len, 8, -1);
}
#endif /* defined(SERVER_MODE) */
#if defined(ENABLE_UNUSED_FUNCTION)
/*
* css_net_send_large_data() -
* return: enum css_error_code (See connection_defs.h)
* conn(in): connection entry
* header_array(in):
* data_array(in):
* num_array(in):
*
* Note: Used by client and server.
*/
static int
css_net_send_large_data (CSS_CONN_ENTRY *conn, NET_HEADER *header_array, const char **data_array, int num_array)
{
int *templen;
struct iovec *iov;
ssize_t total_len;
int rc, i, buffer_size;
iov = (struct iovec *) malloc (sizeof (struct iovec) * (num_array * 4));
if (iov == NULL)
{
return CANT_ALLOC_BUFFER;
}
templen = (int *) malloc (sizeof (int) * (num_array * 2));
if (templen == NULL)
{
free (iov);
return CANT_ALLOC_BUFFER;
}
total_len = 0;
for (i = 0; i < num_array; i++)
{
css_set_io_vector (& (iov[i * 4]), & (iov[i * 4 + 1]), (char *) (&header_array[i]), sizeof (NET_HEADER),
&templen[i * 2]);
total_len += sizeof (NET_HEADER) + sizeof (int);
buffer_size = ntohl (header_array[i].buffer_size);
css_set_io_vector (& (iov[i * 4 + 2]), & (iov[i * 4 + 3]), data_array[i], buffer_size, &templen[i * 2 + 1]);
total_len += buffer_size + sizeof (int);
}
rc = css_send_io_vector (conn, iov, total_len, num_array * 4, -1);
free (iov);
free (templen);
return rc;
}
/*
* css_net_send_large_data_with_arg() -
* return: enum css_error_code (See connection_defs.h)
* conn(in): connection entry
* header_buffer(in):
* header_len(in):
* header_array(in):
* data_array(in):
* num_array(in):
*
* Note: Used by client and server.
*/
static int
css_net_send_large_data_with_arg (CSS_CONN_ENTRY *conn, const char *header_buffer, int header_len,
NET_HEADER *header_array, const char **data_array, int num_array)
{
int *templen;
struct iovec *iov;
ssize_t total_len;
int rc, i, buffer_size;
iov = (struct iovec *) malloc (sizeof (struct iovec) * (num_array * 4 + 2));
if (iov == NULL)
{
return CANT_ALLOC_BUFFER;
}
templen = (int *) malloc (sizeof (int) * (num_array * 2 + 1));
if (templen == NULL)
{
free (iov);
return CANT_ALLOC_BUFFER;
}
total_len = 0;
css_set_io_vector (& (iov[0]), & (iov[1]), header_buffer, header_len, &templen[0]);
total_len += header_len + sizeof (int);
for (i = 0; i < num_array; i++)
{
css_set_io_vector (& (iov[i * 4 + 2]), & (iov[i * 4 + 3]), (char *) (&header_array[i]), sizeof (NET_HEADER),
&templen[i * 2 + 1]);
buffer_size = ntohl (header_array[i].buffer_size);
css_set_io_vector (& (iov[i * 4 + 4]), & (iov[i * 4 + 5]), data_array[i], buffer_size, &templen[i * 2 + 2]);
total_len += (sizeof (NET_HEADER) + buffer_size + sizeof (int) * 2);
}
rc = css_send_io_vector (conn, iov, total_len, num_array * 4 + 2, -1);
free (iov);
free (templen);
return rc;
}
#endif
/*
* css_net_send_buffer_only() - send a buffer only to the other end.
* return: enum css_error_code (See connection_defs.h)
* fd(in): socket descripter
* buff(in): buffer for data will be sent
* len(in): length for data will be sent
* timeout(in): timeout value in milli-seconds
*
* Note: Used by client and server.
*/
int
css_net_send_buffer_only (CSS_CONN_ENTRY *conn, const char *buff, int len, int timeout)
{
struct iovec iov[1];
iov[0].iov_base = (caddr_t) buff;
iov[0].iov_len = len;
return css_send_io_vector (conn, iov, len, 1, timeout);
}
/*
* css_net_read_header() -
* return: enum css_error_code (See connection_defs.h)
* fd(in): socket descripter
* buffer(out): buffer for date be read
* maxlen(out): count of bytes was read
* timeout(in):
*/
int
css_net_read_header (CSS_CONN_ENTRY *conn, char *buffer, int *maxlen, int timeout)
{
return css_net_recv (conn, buffer, maxlen, timeout);
}
void
css_set_net_header (NET_HEADER *header_p, int type, short function_code, int request_id, int buffer_size,
int transaction_id, int invalidate_snapshot, int db_error)
{
unsigned short flags = 0;
header_p->type = htonl (type);
header_p->function_code = htons (function_code);
header_p->request_id = htonl (request_id);
header_p->buffer_size = htonl (buffer_size);
header_p->transaction_id = htonl (transaction_id);
header_p->db_error = htonl (db_error);
if (invalidate_snapshot)
{
flags |= NET_HEADER_FLAG_INVALIDATE_SNAPSHOT;
}
#if defined (CS_MODE)
if (tran_is_in_libcas ())
{
flags |= NET_HEADER_FLAG_METHOD_MODE;
}
#endif
header_p->flags = htons (flags);
}
/*
* css_send_request_with_data_buffer () - transfer a request to the server.
* return: enum css_error_code (See connection_defs.h)
* conn(in): connection entry
* request(in): request number
* request_id(out): request id
* arg_buffer(in): argument data
* arg_size(in): argument data size
* reply_buffer(out): buffer for reply data
* reply_size(in): reply buffer size
*
* Note: used by css_send_request (with NULL as the data buffer).
*/
#if defined (SERVER_MODE)
static int
css_send_request_with_data_buffer (CSS_CONN_ENTRY *conn, int request, unsigned short *request_id,
const char *arg_buffer, int arg_size, char *reply_buffer, int reply_size)
#else
int
connection_support::css_send_request_with_data_buffer (CSS_CONN_ENTRY *conn, int request, unsigned short *request_id,
const char *arg_buffer, int arg_size, char *reply_buffer,
int reply_size)
#endif
{
NET_HEADER local_header = DEFAULT_HEADER_DATA;
NET_HEADER data_header = DEFAULT_HEADER_DATA;
if (!conn || conn->status != CONN_OPEN)
{
return CONNECTION_CLOSED;
}
*request_id = css_get_request_id (conn);
css_set_net_header (&local_header, COMMAND_TYPE, request, *request_id, arg_size, conn->get_tran_index (),
conn->invalidate_snapshot, conn->db_error);
if (reply_buffer && (reply_size > 0))
{
css_queue_user_data_buffer (conn, *request_id, reply_size, reply_buffer);
}
if (arg_size > 0 && arg_buffer != NULL)
{
css_set_net_header (&data_header, DATA_TYPE, 0, *request_id, arg_size, conn->get_tran_index (),
conn->invalidate_snapshot, conn->db_error);
return (css_net_send3 (conn, (char *) &local_header, sizeof (NET_HEADER), (char *) &data_header,
sizeof (NET_HEADER), arg_buffer, arg_size));
}
else
{
/* timeout in milli-second in css_net_send() */
if (css_net_send (conn, (char *) &local_header, sizeof (NET_HEADER), -1) == NO_ERRORS)
{
return NO_ERRORS;
}
}
return ERROR_ON_WRITE;
}
#if !defined (SERVER_MODE)
int
connection_support::css_send_request_with_data_buffer_with_padding (CSS_CONN_ENTRY *conn, int request,
unsigned short *request_id,
const char *arg_buffer, int arg_size, char *reply_buffer, int reply_size)
{
NET_HEADER local_header = DEFAULT_HEADER_DATA;
NET_HEADER data_header = DEFAULT_HEADER_DATA;
if (!conn || conn->status != CONN_OPEN)
{
return CONNECTION_CLOSED;
}
*request_id = css_get_request_id (conn);
css_set_net_header (&local_header, COMMAND_TYPE, request, *request_id, arg_size, conn->get_tran_index (),
conn->invalidate_snapshot, conn->db_error);
if (reply_buffer && (reply_size > 0))
{
css_queue_user_data_buffer (conn, *request_id, reply_size, reply_buffer);
}
if (arg_size > 0 && arg_buffer != NULL)
{
css_set_net_header (&data_header, DATA_TYPE, 0, *request_id, arg_size, conn->get_tran_index (),
conn->invalidate_snapshot, conn->db_error);
return css_net_send_general (conn, -1, (char *) &local_header, sizeof (NET_HEADER), (char *) &data_header,
sizeof (NET_HEADER), arg_buffer, arg_size);
}
else
{
if (css_net_send_general (conn, -1, (char *) &local_header, sizeof (NET_HEADER)) == NO_ERRORS)
{
return NO_ERRORS;
}
}
return ERROR_ON_WRITE;
}
#endif /* !defined (SERVER_MODE) */
/*
* css_send_request() - to send a request to the server without registering
* a data buffer.
* return: enum css_error_code (See connection_defs.h)
* conn(in):
* command(in): request command
* request_id(out): request id
* arg_buffer: argument data
* arg_buffer_size : argument data size
*/
int
#if defined (SERVER_MODE)
css_send_request (CSS_CONN_ENTRY *conn, int command, unsigned short *request_id, const char *arg_buffer,
int arg_buffer_size)
{
return (css_send_request_with_data_buffer (conn, command, request_id, arg_buffer, arg_buffer_size, 0, 0));
}
#else
connection_support::css_send_request (CSS_CONN_ENTRY *conn, int command, unsigned short *request_id,
const char *arg_buffer, int arg_buffer_size)
{
return (css_send_request_with_data_buffer (conn, command, request_id, arg_buffer, arg_buffer_size, 0, 0));
}
#endif
#if defined (ENABLE_UNUSED_FUNCTION)
int
css_send_request_with_socket (SOCKET &socket, int command, unsigned short *request_id, const char *arg_buffer,
int arg_buffer_size)
{
NET_HEADER local_header = DEFAULT_HEADER_DATA;
NET_HEADER data_header = DEFAULT_HEADER_DATA;
if (IS_INVALID_SOCKET (socket))
{
return CONNECTION_CLOSED;
}
*request_id = -1;
css_set_net_header (&local_header, COMMAND_TYPE, command, *request_id, arg_buffer_size, NULL_TRAN_INDEX, 0, 0);
if (arg_buffer_size > 0 && arg_buffer != NULL)
{
css_set_net_header (&data_header, DATA_TYPE, 0, *request_id, arg_buffer_size, NULL_TRAN_INDEX, 0, 0);
return (css_net_send3_with_socket (socket, (char *) &local_header, sizeof (NET_HEADER), (char *) &data_header,
sizeof (NET_HEADER), arg_buffer, arg_buffer_size));
}
else
{
/* timeout in milli-second in css_net_send() */
if (css_net_send_with_socket (socket, (char *) &local_header, sizeof (NET_HEADER), -1) == NO_ERRORS)
{
return NO_ERRORS;
}
}
return ERROR_ON_WRITE;
}
#endif
/*
* css_send_data() - transfer a data packet to the client.
* return: enum css_error_code (See connection_defs.h)
* conn(in): connection entry
* rid(in): request id
* buffer(in): buffer for data will be sent
* buffer_size(in): buffer size
*/
int
css_send_data (CSS_CONN_ENTRY *conn, unsigned short rid, const char *buffer, int buffer_size)
{
NET_HEADER header = DEFAULT_HEADER_DATA;
#if defined(SERVER_MODE)
if (!conn || conn->status == CONN_CLOSED)
#else
if (!conn || conn->status != CONN_OPEN)
#endif
{
return (CONNECTION_CLOSED);
}
css_set_net_header (&header, DATA_TYPE, 0, rid, buffer_size, conn->get_tran_index (), conn->invalidate_snapshot,
conn->db_error);
return (css_net_send2 (conn, (char *) &header, sizeof (NET_HEADER), buffer, buffer_size));
}
#if !defined(SERVER_MODE)
int
connection_support::css_send_data_with_padding (CSS_CONN_ENTRY *conn, unsigned short rid, const char *buffer,
int buffer_size)
{
NET_HEADER header = DEFAULT_HEADER_DATA;
#if defined(SERVER_MODE)
if (!conn || conn->status == CONN_CLOSED)
#else
if (!conn || conn->status != CONN_OPEN)
#endif
{
return (CONNECTION_CLOSED);
}
css_set_net_header (&header, DATA_TYPE, 0, rid, buffer_size, conn->get_tran_index (), conn->invalidate_snapshot,
conn->db_error);
return css_net_send_general (conn, -1, (char *) &header, sizeof (NET_HEADER), buffer, buffer_size);
}
#endif
#if defined(SERVER_MODE)
/*
* css_send_two_data() - transfer a data packet to the client.
* return: enum css_error_code (See connection_defs.h)
* conn(in): connection entry
* rid(in): request id
* buffer1(in): buffer for data will be sent
* buffer1_size(in): buffer size
* buffer2(in): buffer for data will be sent
* buffer2_size(in): buffer size
*/
int
css_send_two_data (CSS_CONN_ENTRY *conn, unsigned short rid, const char *buffer1, int buffer1_size,
const char *buffer2, int buffer2_size)
{
NET_HEADER header1 = DEFAULT_HEADER_DATA;
NET_HEADER header2 = DEFAULT_HEADER_DATA;
if (!conn || conn->status != CONN_OPEN)
{
return (CONNECTION_CLOSED);
}
css_set_net_header (&header1, DATA_TYPE, 0, rid, buffer1_size, conn->get_tran_index (), conn->invalidate_snapshot,
conn->db_error);
css_set_net_header (&header2, DATA_TYPE, 0, rid, buffer2_size, conn->get_tran_index (), conn->invalidate_snapshot,
conn->db_error);
return (css_net_send4 (conn, (char *) &header1, sizeof (NET_HEADER), buffer1, buffer1_size, (char *) &header2,
sizeof (NET_HEADER), buffer2, buffer2_size));
}
#if defined(ENABLE_UNUSED_FUNCTION)
/*
* css_send_large_data() - transfer a data packet to the client.
* return: enum css_error_code (See connection_defs.h)
* conn(in): connection entry
* rid(in): request id
* buffers(in):
* buffers_size(in):
* num_buffers(in):
*
*/
int
css_send_large_data (CSS_CONN_ENTRY *conn, unsigned short rid, const char **buffers, int *buffers_size,
int num_buffers)
{
NET_HEADER *headers;
int i, rc;
if (!conn || conn->status != CONN_OPEN)
{
return (CONNECTION_CLOSED);
}
headers = (NET_HEADER *) malloc (sizeof (NET_HEADER) * num_buffers);
if (headers == NULL)
{
return CANT_ALLOC_BUFFER;
}
for (i = 0; i < num_buffers; i++)
{
css_set_net_header (&headers[i], DATA_TYPE, 0, rid, buffers_size[i], conn->get_tran_index (),
conn->invalidate_snapshot, conn->db_error);
}
rc = css_net_send_large_data (conn, headers, buffers, num_buffers);
free_and_init (headers);
return rc;
}
#endif /* ENABLE_UNUSED_FUNCTION */
#endif /* SERVER_MODE */
#if defined (ENABLE_UNUSED_FUNCTION)
/*
* css_send_error() - transfer an error packet to the client.
* return: enum css_error_code (See connection_defs.h)
* conn(in): connection entry
* rid(in): request id
* buffer(in): buffer for data will be sent
* buffer_size(in): buffer size
*/
int
css_send_error (CSS_CONN_ENTRY *conn, unsigned short rid, const char *buffer, int buffer_size)
{
NET_HEADER header = DEFAULT_HEADER_DATA;
#if defined (SERVER_MODE)
if (!conn || conn->status == CONN_CLOSED)
#else
if (!conn || conn->status != CONN_OPEN)
#endif
{
return (CONNECTION_CLOSED);
}
css_set_net_header (&header, ERROR_TYPE, 0, rid, buffer_size, conn->get_tran_index (), conn->invalidate_snapshot,
conn->db_error);
return (css_net_send2 (conn, (char *) &header, sizeof (NET_HEADER), buffer, buffer_size));
}
#endif /* ENABLE_UNUSED_FUNCTION */
#if !defined(SERVER_MODE)
int
connection_support::css_send_error_with_padding (CSS_CONN_ENTRY *conn, unsigned short rid, const char *buffer,
int buffer_size)
{
NET_HEADER header = DEFAULT_HEADER_DATA;
#if defined (SERVER_MODE)
if (!conn || conn->status == CONN_CLOSED)
#else
if (!conn || conn->status != CONN_OPEN)
#endif
{
return (CONNECTION_CLOSED);
}
css_set_net_header (&header, ERROR_TYPE, 0, rid, buffer_size, conn->get_tran_index (), conn->invalidate_snapshot,
conn->db_error);
return css_net_send_general (conn, -1, (char *) &header, sizeof (NET_HEADER), buffer, buffer_size);
}
#endif
#if defined (ENABLE_UNUSED_FUNCTION)
/*
* css_local_host_name -
* return: enum css_error_code (See connection_defs.h)
*
* conn(in): conn entry
* hostname(out): host name
* namelen(in): size of hostname argument
*/
int
css_local_host_name (CSS_CONN_ENTRY *conn, char *hostname, size_t namelen)
{
if (!conn || conn->status != CONN_OPEN || IS_INVALID_SOCKET (conn->fd))
{
return CONNECTION_CLOSED;
}
if (css_get_sock_name (conn->fd, hostname, namelen) != 0)
{
return OS_ERROR;
}
return NO_ERRORS;
}
/*
* css_peer_host_name -
* return: enum css_error_code (See connection_defs.h)
*
* conn(in): conn entry
* hostname(out): host name
* namelen(in): size of hostname argument
*/
int
css_peer_host_name (CSS_CONN_ENTRY *conn, char *hostname, size_t namelen)
{
if (!conn || conn->status != CONN_OPEN || IS_INVALID_SOCKET (conn->fd))
{
return CONNECTION_CLOSED;
}
if (css_get_peer_name (conn->fd, hostname, namelen) != 0)
{
return OS_ERROR;
}
return NO_ERRORS;
}
#endif /* ENABLE_UNUSED_FUNCTION */
#if !defined (SERVER_MODE)
/*
* css_default_check_server_alive_fn () - check server alive
*
* return:
* db_host(in):
* db_name(in):
*/
static bool
css_default_check_server_alive_fn (const char *db_name, const char *db_host)
{
return true;
}
/*
* css_register_check_server_alive_fn () - regist the callback function
*
* return: void
* callback_fn(in):
*/
void
css_register_check_server_alive_fn (CSS_CHECK_SERVER_ALIVE_FN callback_fn)
{
css_check_server_alive_fn = callback_fn;
}
#endif /* !SERVER_MODE */
/*
* css_ha_server_state_string
*/
const char *
css_ha_server_state_string (HA_SERVER_STATE state)
{
switch (state)
{
case HA_SERVER_STATE_NA:
return "na";
case HA_SERVER_STATE_IDLE:
return HA_SERVER_STATE_IDLE_STR;
case HA_SERVER_STATE_ACTIVE:
return HA_SERVER_STATE_ACTIVE_STR;
case HA_SERVER_STATE_TO_BE_ACTIVE:
return HA_SERVER_STATE_TO_BE_ACTIVE_STR;
case HA_SERVER_STATE_STANDBY:
return HA_SERVER_STATE_STANDBY_STR;
case HA_SERVER_STATE_TO_BE_STANDBY:
return HA_SERVER_STATE_TO_BE_STANDBY_STR;
case HA_SERVER_STATE_MAINTENANCE:
return HA_SERVER_STATE_MAINTENANCE_STR;
case HA_SERVER_STATE_DEAD:
return HA_SERVER_STATE_DEAD_STR;
}
return "invalid";
}
/*
* css_ha_applier_state_string
*/
const char *
css_ha_applier_state_string (HA_LOG_APPLIER_STATE state)
{
switch (state)
{
case HA_LOG_APPLIER_STATE_NA:
return "na";
case HA_LOG_APPLIER_STATE_UNREGISTERED:
return HA_LOG_APPLIER_STATE_UNREGISTERED_STR;
case HA_LOG_APPLIER_STATE_RECOVERING:
return HA_LOG_APPLIER_STATE_RECOVERING_STR;
case HA_LOG_APPLIER_STATE_WORKING:
return HA_LOG_APPLIER_STATE_WORKING_STR;
case HA_LOG_APPLIER_STATE_DONE:
return HA_LOG_APPLIER_STATE_DONE_STR;
case HA_LOG_APPLIER_STATE_ERROR:
return HA_LOG_APPLIER_STATE_ERROR_STR;
}
return "invalid";
}
/*
* css_ha_mode_string
*/
const char *
css_ha_mode_string (HA_MODE mode)
{
switch (mode)
{
case HA_MODE_OFF:
return HA_MODE_OFF_STR;
case HA_MODE_FAIL_OVER:
case HA_MODE_FAIL_BACK:
case HA_MODE_LAZY_BACK:
case HA_MODE_ROLE_CHANGE:
return HA_MODE_ON_STR;
case HA_MODE_REPLICA:
return HA_MODE_REPLICA_STR;
}
return "invalid";
}
#if !defined (SERVER_MODE)
void
css_register_server_timeout_fn (CSS_SERVER_TIMEOUT_FN callback_fn)
{
css_server_timeout_fn = callback_fn;
}
#endif /* !SERVER_MODE */
#if defined(SERVER_MODE)
int
css_check_ip (IP_INFO *ip_info, unsigned char *address)
{
int i;
assert (ip_info && address);
for (i = 0; i < ip_info->num_list; i++)
{
int address_index = i * IP_BYTE_COUNT;
if (ip_info->address_list[address_index] == 0)
{
return NO_ERROR;
}
else if (memcmp ((void *) &ip_info->address_list[address_index + 1], (void *) address,
ip_info->address_list[address_index]) == 0)
{
return NO_ERROR;
}
}
return ER_INACCESSIBLE_IP;
}
int
css_free_ip_info (IP_INFO *ip_info)
{
if (ip_info)
{
free_and_init (ip_info->address_list);
free (ip_info);
}
return NO_ERROR;
}
int
css_read_ip_info (IP_INFO **out_ip_info, char *filename)
{
char buf[32];
FILE *fd_ip_list;
IP_INFO *ip_info;
const char *dbname;
int ip_address_list_buffer_size;
unsigned char i;
bool is_current_db_section;
if (out_ip_info == NULL)
{
return ER_FAILED;
}
fd_ip_list = fopen (filename, "r");
if (fd_ip_list == NULL)
{
er_set_with_oserror (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_OPEN_ACCESS_LIST_FILE, 1, filename);
return ER_OPEN_ACCESS_LIST_FILE;
}
is_current_db_section = false;
ip_info = (IP_INFO *) malloc (sizeof (IP_INFO));
if (ip_info == NULL)
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_OUT_OF_VIRTUAL_MEMORY, 1, sizeof (IP_INFO));
fclose (fd_ip_list);
return ER_OUT_OF_VIRTUAL_MEMORY;
}
ip_info->num_list = 0;
ip_address_list_buffer_size = INITIAL_IP_NUM * IP_BYTE_COUNT;
ip_info->address_list = (unsigned char *) malloc (ip_address_list_buffer_size);
if (ip_info->address_list == NULL)
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_OUT_OF_VIRTUAL_MEMORY, 1, (size_t) ip_address_list_buffer_size);
goto error;
}
dbname = boot_db_name ();
while (fgets (buf, 32, fd_ip_list))
{
char *token, *p, *save = NULL;
int address_index;
p = strchr (buf, '#');
if (p != NULL)
{
*p = '\0';
}
css_trim_str (buf);
if (buf[0] == '\0')
{
continue;
}
if (is_current_db_section == false && strncmp (buf, "[@", 2) == 0 && buf[strlen (buf) - 1] == ']')
{
buf[strlen (buf) - 1] = '\0';
if (strcasecmp (dbname, buf + 2) == 0)
{
is_current_db_section = true;
continue;
}
}
if (is_current_db_section == false)
{
continue;
}
if (strncmp (buf, "[@", 2) == 0 && buf[strlen (buf) - 1] == ']')
{
buf[strlen (buf) - 1] = '\0';
if (strcasecmp (dbname, buf + 2) != 0)
{
break;
}
}
token = strtok_r (buf, ".", &save);
address_index = ip_info->num_list * IP_BYTE_COUNT;
if (address_index >= ip_address_list_buffer_size)
{
ip_address_list_buffer_size *= 2;
ip_info->address_list = (unsigned char *) realloc (ip_info->address_list, ip_address_list_buffer_size);
if (ip_info->address_list == NULL)
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_OUT_OF_VIRTUAL_MEMORY, 1,
(size_t) ip_address_list_buffer_size);
goto error;
}
}
for (i = 0; i < 4; i++)
{
if (token == NULL)
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_INVALID_ACCESS_IP_CONTROL_FILE_FORMAT, 1, filename);
goto error;
}
if (strcmp (token, "*") == 0)
{
break;
}
else
{
int adr = 0, result;
result = parse_int (&adr, token, 10);
if (result != 0 || adr > 255 || adr < 0)
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_INVALID_ACCESS_IP_CONTROL_FILE_FORMAT, 1, filename);
goto error;
}
ip_info->address_list[address_index + 1 + i] = (unsigned char) adr;
}
token = strtok_r (NULL, ".", &save);
if (i == 3 && token != NULL)
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_INVALID_ACCESS_IP_CONTROL_FILE_FORMAT, 1, filename);
goto error;
}
}
ip_info->address_list[address_index] = i;
ip_info->num_list++;
}
fclose (fd_ip_list);
*out_ip_info = ip_info;
return 0;
error:
fclose (fd_ip_list);
css_free_ip_info (ip_info);
assert (er_errid () != NO_ERROR);
return er_errid ();
}
static char *
css_trim_str (char *str)
{
char *p, *s;
if (str == NULL)
{
return (str);
}
for (s = str; *s != '\0' && char_isspace2 (*s); s++)
{
;
}
if (*s == '\0')
{
*str = '\0';
return (str);
}
/* *s must be a non-white char */
for (p = s; *p != '\0'; p++)
{
;
}
for (p--; char_isspace2 (*p); p--)
{
;
}
*++p = '\0';
if (s != str)
{
memmove (str, s, strlen (s) + 1);
}
return (str);
}
#endif
/*
* css_send_magic () - send magic
*
* return: void
* conn(in/out):
*/
int
css_send_magic (CSS_CONN_ENTRY *conn)
{
NET_HEADER header;
memset ((char *) &header, 0, sizeof (NET_HEADER));
memcpy ((char *) &header, css_Net_magic, sizeof (css_Net_magic));
return css_net_send (conn, (const char *) &header, sizeof (NET_HEADER), -1);
}
/*
* css_check_magic () - check magic
*
* return: void
* conn(in/out):
*/
int
css_check_magic (CSS_CONN_ENTRY *conn)
{
int size, nbytes;
unsigned int i;
NET_HEADER header;
char *p;
int timeout = prm_get_integer_value (PRM_ID_TCP_CONNECTION_TIMEOUT) * 1000;
nbytes = css_readn (conn->fd, (char *) &size, sizeof (int), timeout);
if (nbytes != sizeof (int))
{
return ERROR_WHEN_READING_SIZE;
}
size = ntohl (size);
if (size != sizeof (NET_HEADER))
{
return WRONG_PACKET_TYPE;
}
p = (char *) &header;
nbytes = css_readn (conn->fd, p, size, timeout);
if (nbytes != size)
{
return ERROR_ON_READ;
}
for (i = 0; i < sizeof (css_Net_magic); i++)
{
if (* (p++) != css_Net_magic[i])
{
return WRONG_PACKET_TYPE;
}
}
return NO_ERRORS;
}
#if !defined (CS_MODE)
/*
* css_user_access_status_start_scan () - start scan function for show access status
* return: NO_ERROR, or ER_CODE
*
* thread_p(in):
* show_type(in):
* arg_values(in):
* arg_cnt(in):
* ptr(in/out):
*/
int
css_user_access_status_start_scan (THREAD_ENTRY *thread_p, int type, DB_VALUE **arg_values, int arg_cnt, void **ptr)
{
int error = NO_ERROR;
int num_user = 0;
const int num_cols = 4; /* user_name, last_access_time, last_access_host, program_name */
const int default_num_tuple = 10;
OID *class_oid;
SHOWSTMT_ARRAY_CONTEXT *ctx;
LAST_ACCESS_STATUS **access_status_array = NULL;
#if defined(SERVER_MODE)
LAST_ACCESS_STATUS *access_status = NULL;
DB_VALUE *vals;
DB_DATETIME access_time;
#endif
*ptr = NULL;
ctx = showstmt_alloc_array_context (thread_p, default_num_tuple, num_cols);
if (ctx == NULL)
{
assert (er_errid () != NO_ERROR);
error = er_errid ();
return error;
}
#if defined(SERVER_MODE)
num_user = css_Num_access_user;
access_status_array = (LAST_ACCESS_STATUS **) malloc (sizeof (LAST_ACCESS_STATUS *) * num_user);
if (access_status_array == NULL)
{
showstmt_free_array_context (thread_p, ctx);
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_OUT_OF_VIRTUAL_MEMORY, 1, sizeof (LAST_ACCESS_STATUS *) * num_user);
return ER_FAILED;
}
css_get_user_access_status (num_user, access_status_array);
#endif
assert (arg_cnt == 1);
class_oid = db_get_oid (arg_values[0]); /* db_user class oid */
error = css_make_access_status_exist_user (thread_p, class_oid, access_status_array, num_user, ctx);
if (error != NO_ERROR)
{
goto error;
}
#if defined(SERVER_MODE)
while (true)
{
access_status = css_get_unused_access_status (access_status_array, num_user);
if (access_status == NULL)
{
break;
}
vals = showstmt_alloc_tuple_in_context (thread_p, ctx);
if (vals == NULL)
{
assert (er_errid () != NO_ERROR);
error = er_errid ();
goto error;
}
db_make_string_copy (&vals[0], access_status->db_user);
db_localdatetime (&access_status->time, &access_time);
db_make_datetime (&vals[1], &access_time);
db_make_string_copy (&vals[2], access_status->host);
db_make_string_copy (&vals[3], access_status->program_name);
}
#endif /* SERVER_MODE */
if (access_status_array != NULL)
{
free_and_init (access_status_array);
}
*ptr = ctx;
return NO_ERROR;
error:
if (ctx != NULL)
{
showstmt_free_array_context (thread_p, ctx);
}
if (access_status_array != NULL)
{
free_and_init (access_status_array);
}
return error;
}
/*
* css_make_access_status_exist_user () - set access status information of whom are in db_user class
* return: NO_ERROR, or ER_CODE
*
* thread_p(in):
* class_oid(in): db_user class's class oid
* access_status_array(in):
* num_user(in):
* ctx(in):
*/
static int
css_make_access_status_exist_user (THREAD_ENTRY *thread_p, OID *class_oid, LAST_ACCESS_STATUS **access_status_array,
int num_user, SHOWSTMT_ARRAY_CONTEXT *ctx)
{
int error = NO_ERROR;
int i, attr_idx = -1;
bool attr_info_inited;
bool scan_cache_inited;
char *rec_attr_name_p = NULL, *string = NULL;
const char *user_name = NULL;
HFID hfid;
OID inst_oid;
HEAP_CACHE_ATTRINFO attr_info;
HEAP_SCANCACHE scan_cache;
HEAP_ATTRVALUE *heap_value;
SCAN_CODE scan;
RECDES recdes;
DB_VALUE *vals;
DB_DATETIME access_time;
LAST_ACCESS_STATUS *access_status;
MVCC_SNAPSHOT *mvcc_snapshot = NULL;
OID_SET_NULL (&inst_oid);
error = heap_attrinfo_start (thread_p, class_oid, -1, NULL, &attr_info);
if (error != NO_ERROR)
{
return error;
}
attr_info_inited = true;
heap_scancache_quick_start_root_hfid (thread_p, &scan_cache);
scan_cache_inited = true;
if (heap_get_class_record (thread_p, class_oid, &recdes, &scan_cache, PEEK) != S_SUCCESS)
{
assert (er_errid () != NO_ERROR);
error = er_errid ();
goto end;
}
for (i = 0; i < attr_info.num_values; i++)
{
int alloced_string = 0;
bool set_break = false;
string = NULL;
error = or_get_attrname (&recdes, i, &string, &alloced_string);
if (error != NO_ERROR)
{
ASSERT_ERROR ();
goto end;
}
rec_attr_name_p = string;
if (rec_attr_name_p == NULL)
{
continue;
}
if (strcmp ("name", rec_attr_name_p) == 0)
{
attr_idx = i;
set_break = true;
goto clean_string;
}
clean_string:
if (string != NULL && alloced_string == 1)
{
db_private_free_and_init (thread_p, string);
}
if (set_break == true)
{
break;
}
}
heap_scancache_end (thread_p, &scan_cache);
scan_cache_inited = false;
error = heap_get_class_info (thread_p, class_oid, &hfid, NULL, NULL);
if (error != NO_ERROR)
{
goto end;
}
if (HFID_IS_NULL (&hfid))
{
error = ER_FAILED;
goto end;
}
mvcc_snapshot = logtb_get_mvcc_snapshot (thread_p);
if (mvcc_snapshot == NULL)
{
error = ER_FAILED;
goto end;
}
error = heap_scancache_start (thread_p, &scan_cache, &hfid, class_oid, true, mvcc_snapshot);
if (error != NO_ERROR)
{
goto end;
}
scan_cache_inited = true;
while (true)
{
scan = heap_next (thread_p, &hfid, NULL, &inst_oid, &recdes, &scan_cache, PEEK);
if (scan == S_SUCCESS)
{
error = heap_attrinfo_read_dbvalues (thread_p, &inst_oid, &recdes, &attr_info);
if (error != NO_ERROR)
{
goto end;
}
for (i = 0, heap_value = attr_info.values; i < attr_info.num_values; i++, heap_value++)
{
if (heap_value->attrid == attr_idx)
{
user_name = db_get_string (&heap_value->dbvalue);
}
}
}
else if (scan == S_END)
{
break;
}
else
{
error = ER_FAILED;
goto end;
}
vals = showstmt_alloc_tuple_in_context (thread_p, ctx);
if (vals == NULL)
{
assert (er_errid () != NO_ERROR);
error = er_errid ();
goto end;
}
access_status = css_get_access_status_with_name (access_status_array, num_user, user_name);
db_make_string_copy (&vals[0], user_name);
if (access_status != NULL)
{
db_localdatetime (&access_status->time, &access_time);
db_make_datetime (&vals[1], &access_time);
db_make_string_copy (&vals[2], access_status->host);
db_make_string_copy (&vals[3], access_status->program_name);
}
else
{
db_make_null (&vals[1]);
db_make_null (&vals[2]);
db_make_null (&vals[3]);
}
}
end:
if (scan_cache_inited == true)
{
(void) heap_scancache_end (thread_p, &scan_cache);
}
if (attr_info_inited == true)
{
heap_attrinfo_end (thread_p, &attr_info);
}
return error;
}
/*
* css_get_access_status_with_name () - return access status which match with user_name
* return: address of found access status or NULL
*
* access_status_array(in):
* num_user(in):
* user_name(in):
*/
static LAST_ACCESS_STATUS *
css_get_access_status_with_name (LAST_ACCESS_STATUS **access_status_array, int num_user, const char *user_name)
{
int i = 0;
LAST_ACCESS_STATUS *access_status = NULL;
assert (user_name != NULL);
if (access_status_array == NULL)
{
return NULL;
}
for (i = 0; i < num_user; i++)
{
if (access_status_array[i] != NULL && strcmp (access_status_array[i]->db_user, user_name) == 0)
{
access_status = access_status_array[i];
access_status_array[i] = NULL;
break;
}
}
return access_status;
}
/*
* css_get_unused_access_status () - return unused access status from array
* return: address of found access status or NULL
*
* access_status_array(in):
* num_user(in):
*/
static LAST_ACCESS_STATUS *
css_get_unused_access_status (LAST_ACCESS_STATUS **access_status_array, int num_user)
{
int i = 0;
LAST_ACCESS_STATUS *access_status = NULL;
if (access_status_array == NULL)
{
return NULL;
}
for (i = 0; i < num_user; i++)
{
if (access_status_array[i] != NULL)
{
access_status = access_status_array[i];
access_status_array[i] = NULL;
break;
}
}
return access_status;
}
#endif /* CS_MODE */
int
css_platform_independent_poll (POLL_FD *fds, int num_of_fds, int timeout)
{
int rc = 0;
#if defined (WINDOWS)
rc = WSAPoll (fds, num_of_fds, timeout);
#else
rc = poll (fds, num_of_fds, timeout);
#endif
return rc;
}
#if !defined (SERVER_MODE)
/*
* css_send_request_no_reply () - transfer a request to the server (no reply)
* return: enum css_error_code (See connection_defs.h)
* conn(in):
* request(in):
* request_id(in):
* arg_buffer(in):
* arg_size(in):
*
*/
int
connection_support::css_send_request_no_reply (CSS_CONN_ENTRY *conn, int request, unsigned short *request_id,
char *arg_buffer, int arg_size)
{
NET_HEADER req_header = DEFAULT_HEADER_DATA;
NET_HEADER data_header = DEFAULT_HEADER_DATA;
if (!conn || conn->status != CONN_OPEN)
{
return CONNECTION_CLOSED;
}
*request_id = css_get_request_id (conn);
css_set_net_header (&req_header, COMMAND_TYPE, request, *request_id, arg_size, conn->get_tran_index (),
conn->invalidate_snapshot, conn->db_error);
if (arg_size == 0)
{
return css_net_send_general (conn, -1, (char *) &req_header, sizeof (NET_HEADER));
}
css_set_net_header (&data_header, DATA_TYPE, 0, *request_id, arg_size, conn->get_tran_index (),
conn->invalidate_snapshot, conn->db_error);
return css_net_send_general (conn, -1, (char *) &req_header, sizeof (NET_HEADER), (char *) &data_header,
sizeof (NET_HEADER),
arg_buffer, arg_size);
}
/*
* css_send_req_with_2_buffers () - transfer a request to the server
* return: enum css_error_code (See connection_defs.h)
* conn(in):
* request(in):
* request_id(out):
* arg_buffer(in):
* arg_size(in):
* data_buffer(in):
* data_size(in):
* reply_buffer(in):
* reply_size(in):
*
* Note: It is used by css_send_request (with NULL as the data buffer).
*/
int
connection_support::css_send_req_with_2_buffers (CSS_CONN_ENTRY *conn, int request, unsigned short *request_id,
char *arg_buffer, int arg_size, char *data_buffer, int data_size,
char *reply_buffer, int reply_size)
{
NET_HEADER local_header = DEFAULT_HEADER_DATA;
NET_HEADER arg_header = DEFAULT_HEADER_DATA;
NET_HEADER data_header = DEFAULT_HEADER_DATA;
if (data_buffer == NULL || data_size <= 0)
{
return (css_send_request_with_data_buffer_with_padding (conn, request, request_id, arg_buffer, arg_size, reply_buffer,
reply_size));
}
if (!conn || conn->status != CONN_OPEN)
{
return CONNECTION_CLOSED;
}
*request_id = css_get_request_id (conn);
css_set_net_header (&local_header, COMMAND_TYPE, request, *request_id, arg_size, conn->get_tran_index (),
conn->invalidate_snapshot, conn->db_error);
if (reply_buffer && reply_size > 0)
{
css_queue_user_data_buffer (conn, *request_id, reply_size, reply_buffer);
}
css_set_net_header (&arg_header, DATA_TYPE, 0, *request_id, arg_size, conn->get_tran_index (),
conn->invalidate_snapshot, conn->db_error);
css_set_net_header (&data_header, DATA_TYPE, 0, *request_id, data_size, conn->get_tran_index (),
conn->invalidate_snapshot, conn->db_error);
return css_net_send_general (conn, -1, (char *) &local_header, sizeof (NET_HEADER), (char *) &arg_header,
sizeof (NET_HEADER),
arg_buffer, arg_size, (char *) &data_header, sizeof (NET_HEADER), data_buffer, data_size);
}
/*
* css_send_req_with_3_buffers () - transfer a request to the server
* return: enum css_error_code (See connection_defs.h)
* conn(in):
* request(in):
* request_id(in):
* arg_buffer(in):
* arg_size(in):
* data1_buffer(in):
* data1_size(in):
* data2_buffer(in):
* data2_size(in):
* reply_buffer(in):
* reply_size(in):
*
* Note: It is used by css_send_request (with NULL as the data buffer).
*/
int
connection_support::css_send_req_with_3_buffers (CSS_CONN_ENTRY *conn, int request, unsigned short *request_id,
char *arg_buffer,
int arg_size, char *data1_buffer, int data1_size, char *data2_buffer, int data2_size,
char *reply_buffer, int reply_size)
{
NET_HEADER local_header = DEFAULT_HEADER_DATA;
NET_HEADER arg_header = DEFAULT_HEADER_DATA;
NET_HEADER data1_header = DEFAULT_HEADER_DATA;
NET_HEADER data2_header = DEFAULT_HEADER_DATA;
if (data2_buffer == NULL || data2_size <= 0)
{
return (css_send_req_with_2_buffers (conn, request, request_id, arg_buffer, arg_size, data1_buffer, data1_size,
reply_buffer, reply_size));
}
if (!conn || conn->status != CONN_OPEN)
{
return CONNECTION_CLOSED;
}
*request_id = css_get_request_id (conn);
css_set_net_header (&local_header, COMMAND_TYPE, request, *request_id, arg_size, conn->get_tran_index (),
conn->invalidate_snapshot, conn->db_error);
if (reply_buffer && reply_size > 0)
{
css_queue_user_data_buffer (conn, *request_id, reply_size, reply_buffer);
}
css_set_net_header (&arg_header, DATA_TYPE, 0, *request_id, arg_size, conn->get_tran_index (),
conn->invalidate_snapshot, conn->db_error);
css_set_net_header (&data1_header, DATA_TYPE, 0, *request_id, data1_size, conn->get_tran_index (),
conn->invalidate_snapshot, conn->db_error);
css_set_net_header (&data2_header, DATA_TYPE, 0, *request_id, data2_size, conn->get_tran_index (),
conn->invalidate_snapshot, conn->db_error);
return css_net_send_general (conn, -1, (char *) &local_header, sizeof (NET_HEADER), (char *) &arg_header,
sizeof (NET_HEADER),
arg_buffer, arg_size, (char *) &data1_header, sizeof (NET_HEADER), data1_buffer, data1_size,
(char *) &data2_header, sizeof (NET_HEADER), data2_buffer, data2_size);
}
#if 0
/*
* css_send_req_with_large_buffer () - transfer a request to the server
* return:
* conn(in):
* request(in):
* request_id(out):
* arg_buffer(in):
* arg_size(in):
* data_buffer(in):
* data_size(in):
* reply_buffer(in):
* reply_size(in):
*
* Note: It is used by css_send_request (with NULL as the data buffer).
*/
int
css_send_req_with_large_buffer (CSS_CONN_ENTRY *conn, int request, unsigned short *request_id, char *arg_buffer,
int arg_size, char *data_buffer, INT64 data_size, char *reply_buffer, int reply_size)
{
NET_HEADER local_header = DEFAULT_HEADER_DATA;
NET_HEADER *headers;
char **buffer_array;
int num_array, send_data_size;
int rc, i;
if (data_buffer == NULL || data_size <= 0)
{
return (css_send_request_with_data_buffer (conn, request, request_id, arg_buffer, arg_size, reply_buffer,
reply_size));
}
if (!conn || conn->status != CONN_OPEN)
{
return CONNECTION_CLOSED;
}
*request_id = css_get_request_id (conn);
css_set_net_header (&local_header, COMMAND_TYPE, request, *request_id, arg_size, conn->get_tran_index (),
conn->invalidate_snapshot, conn->db_error);
if (reply_buffer && reply_size > 0)
{
css_queue_user_data_buffer (conn, *request_id, reply_size, reply_buffer);
}
num_array = (int) (data_size / INT_MAX) + 2;
headers = (NET_HEADER *) malloc (sizeof (NET_HEADER) * num_array);
if (headers == NULL)
{
return CANT_ALLOC_BUFFER;
}
memset (headers, 0, sizeof (NET_HEADER) * num_array);
buffer_array = (char **) malloc (sizeof (char *) * num_array);
if (buffer_array == NULL)
{
free_and_init (headers);
return CANT_ALLOC_BUFFER;
}
css_set_net_header (&headers[0], DATA_TYPE, 0, *request_id, arg_size, conn->get_tran_index (),
conn->invalidate_snapshot, conn->db_error);
buffer_array[0] = arg_buffer;
for (i = 1; i < num_array; i++)
{
if (data_size > INT_MAX)
{
send_data_size = INT_MAX;
}
else
{
send_data_size = (int) data_size;
}
css_set_net_header (&headers[i], DATA_TYPE, 0, *request_id, send_data_size, conn->get_tran_index (),
conn->invalidate_snapshot, conn->db_error);
buffer_array[i] = data_buffer;
data_buffer += send_data_size;
data_size -= send_data_size;
}
rc = css_net_send_large_data_with_arg (conn, (char *) &local_header, sizeof (NET_HEADER), headers,
(const char **) buffer_array, num_array);
free_and_init (buffer_array);
free_and_init (headers);
return rc;
}
#endif /* 0 */
#endif /* CS_MODE || SA_MODE */
// *INDENT-OFF*
void
css_conn_entry::set_tran_index (int tran_index)
{
// can never be system transaction index
if (tran_index == LOG_SYSTEM_TRAN_INDEX)
{
assert (false);
tran_index = NULL_TRAN_INDEX;
}
transaction_id = tran_index;
}
int
css_conn_entry::get_tran_index ()
{
assert (transaction_id != LOG_SYSTEM_TRAN_INDEX);
return transaction_id;
}
void
css_conn_entry::add_pending_request ()
{
++pending_request_count;
}
size_t
css_conn_entry::start_request ()
{
return --pending_request_count;
}
bool
css_conn_entry::has_pending_request () const
{
return pending_request_count != 0;
}
void
css_conn_entry::init_pending_request ()
{
pending_request_count = 0;
}
void
css_conn_entry::add_working_task ()
{
++working_task_count;
}
size_t
css_conn_entry::end_working_task ()
{
return --working_task_count;
}
void
css_conn_entry::init_working_task ()
{
working_task_count = 0;
}
void
css_conn_entry::release_packet (void *buffer)
{
#if defined(SERVER_MODE)
css_request_release_packet (this, buffer);
#endif
}
// *INDENT-ON*