File network_cl.c¶
File List > communication > network_cl.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.
*
*/
/*
* network_cl.c - client side support functions.
*/
#ident "$Id$"
#include "config.h"
#include <stdio.h>
#include <string.h>
#include <assert.h>
/* for performance metering */
#if !defined(WINDOWS)
#include <sys/time.h>
#include <sys/resource.h>
#endif /* !WINDDOWS */
#include <vector>
#include "network.h"
#include "network_interface_cl.h"
#include "chartype.h"
#include "server_interface.h"
#include "memory_alloc.h"
#include "databases_file.h"
#include "error_manager.h"
#include "system_parameter.h"
#include "environment_variable.h"
#include "boot_cl.h"
#include "query_method.hpp"
#include "method_callback.hpp"
#include "release_string.h"
#include "log_comm.h"
#include "file_io.h"
#include "locator.h"
#include "db.h"
#include "client_support.h"
#include "perf_monitor.h"
#include "log_writer.h"
#include "object_representation.h"
#include "packer.hpp"
#include "network_histogram.hpp"
#if !defined (CS_MODE)
#error Does not belong to cs module
#endif /* !defined (CS_MODE) */
/* RAII guard: flush callback_handler's deferred query_handler queue on every return
path of method callback helpers. PL/SP execution pushes handlers into the process-wide
singleton; early-return paths would otherwise leak stale handlers that a later client
request frees. er_stack_push/pop keeps handler dtor er_set()s from clobbering the outer error. */
namespace
{
struct deferred_flush_guard
{
~deferred_flush_guard ()
{
cubmethod::callback_handler * h = cubmethod::get_callback_handler ();
if (h->has_deferred_query_handler () && !tran_is_in_libcas ())
{
er_stack_push ();
h->free_deferred_query_handler ();
er_stack_pop ();
}
}
};
}
/*
* To check for errors from the comm system. Note that if we get any error
* other than RECORD_TRUNCATED or CANT_ALLOC_BUFFER, we will call it a
* SERVER_CRASHED error. Also note that CANT_ALLOC_BUFFER allows the
* calling function to continue whereas other errors disconnect and escape
* the function.
*/
#define COMPARE_SIZE_AND_BUFFER(replysize, size, replybuf, buf) \
compare_size_and_buffer((replysize), (size), (replybuf), (buf), \
__FILE__, __LINE__)
#define COMPARE_AND_FREE_BUFFER(queued, reply) \
do { \
if (((reply) != NULL) && ((reply) != (queued))) { \
free_and_init ((reply)); \
} \
(reply) = NULL; \
} while (0)
/* avoid truncation when dumping large plans */
#define PLAN_DUMP_STREAM_CHUNK_SIZE (64 * 1024)
#if defined(CS_MODE)
#if !defined(MULTI_CONN_TO_A_SERVER)
unsigned short method_request_id; // TODO: dive into class connection_cl // ctshim
#else
unsigned short method_request_id;
#endif
#endif /* CS_MODE */
/* Contains the name of the current sever host machine. */
static char net_Server_host[CUB_MAXHOSTNAMELEN + 1] = { 0x00, };
/* Contains the name of the current server name. */
static char net_Server_name[DB_MAX_IDENTIFIER_LENGTH + 1] = { 0x00, };
static void return_error_to_server (char *host, unsigned int eid);
static int client_capabilities (void);
static int check_server_capabilities (int server_cap, int client_type, int rel_compare,
REL_COMPATIBILITY * compatibility, const char *server_host, int opt_cap);
static int net_set_alloc_err_if_not_set (int err, const char *file, const int line);
static void net_consume_expected_packets (int rc, int num_packets);
static int compare_size_and_buffer (int *replysize, int size, char **replybuf, char *buf, const char *file,
const int line);
static int net_client_request_internal (int request, char *argbuf, int argsize, char *replybuf, int replysize,
char *databuf, int datasize, char *replydata, int replydatasize);
static int set_server_error (int error);
/*
* set_server_error -
*
* return:
* error(in):
*
* Note:
*/
static int
set_server_error (int error)
{
int server_error;
switch (error)
{
case CANT_ALLOC_BUFFER:
server_error = ER_NET_CANT_ALLOC_BUFFER;
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, server_error, 0);
break;
case RECORD_TRUNCATED:
server_error = ER_NET_DATA_TRUNCATED;
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, server_error, 0);
break;
case REQUEST_REFUSED:
assert (er_errid () != NO_ERROR);
server_error = er_errid ();
break;
case SERVER_ABORTED:
/* server error may not be set when SERVER_ABORTED is given. server may send ABORT_TYPE for some cases and the
* server error will not be delivered for the case. */
server_error = er_errid ();
/* those errors are generated by the net_server_request() so that do not fall to server crash handling */
switch (server_error)
{
case ER_DB_NO_MODIFICATIONS:
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, server_error, 0);
return server_error;
case ER_AU_DBA_ONLY:
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, server_error, 1, "");
return server_error;
}
[[fallthrough]];
default:
server_error = ER_NET_SERVER_CRASHED;
er_set_with_oserror (ER_ERROR_SEVERITY, ARG_FILE_LINE, server_error, 0);
break;
}
er_log_debug (ARG_FILE_LINE, "set_server_error(%d) server_error %d\n", error, server_error);
db_Connect_status = DB_CONNECTION_STATUS_NOT_CONNECTED;
if (net_Server_name[0] != '\0')
{
net_Server_name[0] = '\0';
net_Server_host[0] = '\0';
boot_server_die_or_changed ();
}
return server_error;
}
/*
* return_error_to_server -
*
* return:
*
* host(in):
* eid(in):
*
* Note:
*/
static void
return_error_to_server (char *host, unsigned int eid)
{
char *area;
OR_ALIGNED_BUF (1024) a_buffer;
char *buffer;
int length = 1024;
buffer = OR_ALIGNED_BUF_START (a_buffer);
area = er_get_area_error (buffer, &length);
if (area != NULL)
{
__gv_cvar.css_send_error_to_server (host, eid, area, length);
}
}
/*
* client_capabilities -
*
* return:
*/
static int
client_capabilities (void)
{
int capabilities = 0;
capabilities |= NET_CAP_INTERRUPT_ENABLED;
if (db_Disable_modifications > 0)
{
capabilities |= NET_CAP_UPDATE_DISABLED;
}
if (db_need_ignore_repl_delay ())
{
capabilities |= NET_CAP_HA_IGNORE_REPL_DELAY;
}
return capabilities;
}
/*
* check_server_capabilities -
*
* return:
*/
static int
check_server_capabilities (int server_cap, int client_type, int rel_compare,
REL_COMPATIBILITY * compatibility, const char *server_host, int opt_cap)
{
int client_cap;
assert (compatibility != NULL);
client_cap = client_capabilities ();
client_cap |= opt_cap;
/* interrupt-ability should be same */
if ((client_cap ^ server_cap) & NET_CAP_INTERRUPT_ENABLED)
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_NET_HS_INCOMPAT_INTERRUPTIBILITY, 3, net_Server_host,
get_capability_string (client_cap, NET_CAP_INTERRUPT_ENABLED),
get_capability_string (server_cap, NET_CAP_INTERRUPT_ENABLED));
server_cap ^= NET_CAP_INTERRUPT_ENABLED;
}
/* replica only client should check whether the server is replica */
if (BOOT_REPLICA_ONLY_BROKER_CLIENT_TYPE (client_type))
{
if (~server_cap & NET_CAP_HA_REPLICA)
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_NET_HS_HA_REPLICA_ONLY, 1, net_Server_host);
server_cap ^= NET_CAP_HA_REPLICA;
}
}
else
{
/* update-ability should be same */
if ((client_cap ^ server_cap) & NET_CAP_UPDATE_DISABLED)
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_NET_HS_INCOMPAT_RW_MODE, 3, net_Server_host,
get_capability_string (client_cap, NET_CAP_UPDATE_DISABLED),
get_capability_string (server_cap, NET_CAP_UPDATE_DISABLED));
server_cap ^= NET_CAP_UPDATE_DISABLED;
db_set_host_status (net_Server_host, DB_HS_MISMATCHED_RW_MODE);
}
}
/*
* check HA replication delay
* if client_cap is on, it checks the server delay status
* else, it ignores the delay status.
*/
if (client_cap & NET_CAP_HA_REPL_DELAY & server_cap)
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_NET_HS_HA_REPL_DELAY, 1, net_Server_host);
server_cap ^= NET_CAP_HA_REPL_DELAY;
db_set_host_status (net_Server_host, DB_HS_HA_DELAYED);
}
/* network protocol compatibility */
if (*compatibility == REL_NOT_COMPATIBLE)
{
if (rel_compare < 0 && ((server_cap & NET_CAP_BACKWARD_COMPATIBLE) || (client_cap & NET_CAP_FORWARD_COMPATIBLE)))
{
/*
* The client is older than the server but the server has a backward
* compatible capability or the client has a forward compatible
* capability.
*/
*compatibility = REL_FORWARD_COMPATIBLE;
}
if (rel_compare > 0 && ((server_cap & NET_CAP_FORWARD_COMPATIBLE) || (client_cap & NET_CAP_BACKWARD_COMPATIBLE)))
{
/*
* The client is newer than the server but the server has a forward
* compatible capability or the client has a backward compatible
* capability.
*/
*compatibility = REL_BACKWARD_COMPATIBLE;
}
}
/* remote connection capability */
if ((server_cap & NET_CAP_REMOTE_DISABLED)
&& !BOOT_IS_ALLOWED_CLIENT_TYPE_IN_MT_MODE (server_host, boot_Host_name, client_type))
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_NET_HS_REMOTE_DISABLED, 1, net_Server_host);
server_cap ^= NET_CAP_REMOTE_DISABLED;
}
return server_cap;
}
/*
* net_set_alloc_err_if_not_set
*
* return:
*
* err(in):
* file(in):
* line(in):
*
*/
static int
net_set_alloc_err_if_not_set (int err, const char *file, const int line)
{
/* don't set error if there already is one */
if (err == NO_ERROR)
{
err = ER_NET_CANT_ALLOC_BUFFER;
er_set (ER_ERROR_SEVERITY, file, line, err, 0);
}
return err;
}
static void
net_consume_expected_packets (int rc, int num_packets)
{
char *reply = NULL;
int i, size = 0;
for (i = 0; i < num_packets; i++)
{
__gv_cvar.css_receive_data_from_server (rc, &reply, &size);
if (reply != NULL)
{
free_and_init (reply);
}
}
}
/*
* compare_size_and_buffer -
*
* return:
*
* replysize(in):
* size(in):
* replybuf(in):
* buf(in):
* file(in):
* line(in):
*
* Note:
* Compares sizes and buffers that have been queued with the actual
* received values after a data read. Called by macro of the same name.
*/
static int
compare_size_and_buffer (int *replysize, int size, char **replybuf, char *buf, const char *file, const int line)
{
int err = NO_ERROR;
if (size <= 0)
{
return NO_ERROR;
}
if (size != *replysize)
{
err = ER_NET_DATASIZE_MISMATCH;
er_set (ER_ERROR_SEVERITY, file, line, err, 2, *replysize, size);
*replysize = size;
}
if (buf != *replybuf)
{
err = ER_NET_UNUSED_BUFFER;
er_set (ER_ERROR_SEVERITY, file, line, err, 0);
/* free it ? */
*replybuf = buf;
}
return err;
}
/*
* net_client_request_no_reply -
*
* return:
*
* request(in): server request id
* argbuf(in): argument buffer (small)
* argsize(in): byte size of argbuf
*
*/
int
net_client_request_no_reply (int request, char *argbuf, int argsize)
{
unsigned int rc;
int error;
error = NO_ERROR;
assert (request == NET_SERVER_LOG_SET_INTERRUPT || request == NET_SERVER_LD_INTERRUPT);
if (net_Server_name[0] == '\0')
{
/* need to have a more appropriate "unexpected disconnect" message */
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_NET_SERVER_CRASHED, 0);
error = -1;
return error;
}
if (histo_is_collecting ())
{
histo_add_request (request, argsize);
}
rc = __gv_cvar.css_send_req_to_server_no_reply (net_Server_host, request, argbuf, argsize);
if (rc == 0)
{
error = __gv_cvar.css_get_errno ();
return set_server_error (error);
}
return error;
}
/*
* net_client_request_internal -
*
* return: error status
*
* request(in): server request id
* argbuf(in): argument buffer (small)
* argsize(in): byte size of argbuf
* replybuf(in): reply argument buffer (small)
* replysize(in): size of reply argument buffer
* databuf(in): data buffer to send (large)
* datasize(in): size of data buffer
* replydata(in): receive data buffer (large)
* replydatasize(in): size of expected reply data
*
* Note: This is one of two functions that is called to perform a server
* request. All network interface routines will call either this
* function or net_client_request2.
*/
static int
net_client_request_internal (int request, char *argbuf, int argsize, char *replybuf, int replysize,
char *databuf, int datasize, char *replydata, int replydatasize)
{
unsigned int rc;
int size;
int error;
char *reply = NULL;
error = 0;
if (net_Server_name[0] == '\0')
{
/* need to have a more appropriate "unexpected disconnect" message */
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_NET_SERVER_CRASHED, 0);
error = -1;
return error;
}
if (histo_is_collecting ())
{
histo_add_request (request, argsize + datasize);
}
rc =
__gv_cvar.css_send_req_to_server (net_Server_host, request, argbuf, argsize, databuf, datasize, replybuf,
replysize);
if (rc == 0)
{
error = __gv_cvar.css_get_errno ();
return set_server_error (error);
}
if (rc)
{
if (replydata != NULL)
{
__gv_cvar.css_queue_receive_data_buffer (rc, replydata, replydatasize);
}
error = __gv_cvar.css_receive_data_from_server (rc, &reply, &size);
if (error != NO_ERROR)
{
COMPARE_AND_FREE_BUFFER (replybuf, reply);
return set_server_error (error);
}
else
{
error = COMPARE_SIZE_AND_BUFFER (&replysize, size, &replybuf, reply);
}
if (replydata != NULL)
{
error = __gv_cvar.css_receive_data_from_server (rc, &reply, &size);
if (error != NO_ERROR)
{
COMPARE_AND_FREE_BUFFER (replydata, reply);
return set_server_error (error);
}
else
{
error = COMPARE_SIZE_AND_BUFFER (&replydatasize, size, &replydata, reply);
}
}
}
if (histo_is_collecting ())
{
histo_finish_request (request, replysize + replydatasize);
}
return error;
}
/*
* net_client_request -
*
* return: error status
*
* request(in): server request id
* argbuf(in): argument buffer (small)
* argsize(in): byte size of argbuf
* replybuf(in): reply argument buffer (small)
* replysize(in): size of reply argument buffer
* databuf(in): data buffer to send (large)
* datasize(in): size of data buffer
* replydata(in): receive data buffer (large)
* replydatasize(in): size of expected reply data
*
* Note: This is one of two functions that is called to perform a server
* request. All network interface routines will call either this
* function or net_client_request2.
*/
int
net_client_request (int request, char *argbuf, int argsize, char *replybuf, int replysize, char *databuf,
int datasize, char *replydata, int replydatasize)
{
return (net_client_request_internal (request, argbuf, argsize, replybuf, replysize, databuf, datasize, replydata,
replydatasize));
}
#if defined(ENABLE_UNUSED_FUNCTION)
/*
* net_client_request_send_large_data -
*
* return: error status
*
* request(in): server request id
* argbuf(in): argument buffer (small)
* argsize(in): byte size of argbuf
* replybuf(in): reply argument buffer (small)
* replysize(in): size of reply argument buffer
* databuf(in): data buffer to send (large)
* datasize(in): size of data buffer
* replydata(in): receive data buffer (large)
* replydatasize(in): size of expected reply data
*
* Note: This is one of two functions that is called to perform a server
* request. All network interface routines will call either this
* function or net_client_request2.
*/
int
net_client_request_send_large_data (int request, char *argbuf, int argsize, char *replybuf, int replysize,
char *databuf, INT64 datasize, char *replydata, int replydatasize)
{
unsigned int rc;
int size;
int error;
char *reply = NULL;
error = 0;
if (net_Server_name[0] == '\0')
{
/* need to have a more appropriate "unexpected disconnect" message */
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_NET_SERVER_CRASHED, 0);
error = -1;
return error;
}
#if defined(HISTO)
if (net_Histo_setup)
{
histo_add_request (request, argsize + datasize);
}
#endif /* HISTO */
rc =
__gv_cvar.css_send_req_to_server_with_large_data (net_Server_host, request, argbuf, argsize, databuf, datasize,
replybuf, replysize);
if (rc == 0)
{
error = __gv_cvar.css_get_errno ();
return set_server_error (error);
}
if (rc)
{
if (replydata != NULL)
{
__gv_cvar.css_queue_receive_data_buffer (rc, replydata, replydatasize);
}
error = __gv_cvar.css_receive_data_from_server (rc, &reply, &size);
if (error != NO_ERROR)
{
COMPARE_AND_FREE_BUFFER (replybuf, reply);
return set_server_error (error);
}
else
{
error = COMPARE_SIZE_AND_BUFFER (&replysize, size, &replybuf, reply);
}
if (replydata != NULL)
{
error = __gv_cvar.css_receive_data_from_server (rc, &reply, &size);
if (error != NO_ERROR)
{
COMPARE_AND_FREE_BUFFER (replydata, reply);
return set_server_error (error);
}
else
{
error = COMPARE_SIZE_AND_BUFFER (&replydatasize, size, &replydata, reply);
}
}
}
#if defined(HISTO)
if (net_Histo_setup)
{
histo_finish_request (request, replysize + replydatasize);
}
#endif /* HISTO */
return error;
}
/*
* net_client_request_recv_large_data -
*
* return: error status
*
* request(in): server request id
* argbuf(in): argument buffer (small)
* argsize(in): byte size of argbuf
* replybuf(in): reply argument buffer (small)
* replysize(in): size of reply argument buffer
* databuf(in): data buffer to send (large)
* datasize(in): size of data buffer
* replydata(in): receive data buffer (large)
* replydatasize_ptr(in): size of expected reply data
*
* Note:
*/
int
net_client_request_recv_large_data (int request, char *argbuf, int argsize, char *replybuf, int replysize,
char *databuf, int datasize, char *replydata, INT64 * replydatasize_ptr)
{
unsigned int rc;
int size;
int error;
INT64 reply_datasize;
int num_data;
char *reply = NULL, *ptr, *packed_desc;
int i, packed_desc_size;
error = 0;
*replydatasize_ptr = 0;
if (net_Server_name[0] == '\0')
{
/* need to have a more appropriate "unexpected disconnect" message */
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_NET_SERVER_CRASHED, 0);
error = -1;
}
else
{
#if defined(HISTO)
if (net_Histo_setup)
{
histo_add_request (request, argsize + datasize);
}
#endif /* HISTO */
rc =
__gv_cvar.css_send_req_to_server (net_Server_host, request, argbuf, argsize, databuf, datasize, replybuf,
replysize);
if (rc == 0)
{
return set_server_error (__gv_cvar.css_get_errno ());
}
error = __gv_cvar.css_receive_data_from_server (rc, &reply, &size);
if (error != NO_ERROR || reply == NULL)
{
COMPARE_AND_FREE_BUFFER (replybuf, reply);
return set_server_error (error);
}
else
{
error = COMPARE_SIZE_AND_BUFFER (&replysize, size, &replybuf, reply);
}
/* here we assume that the first integer in the reply is the length of the following data block */
ptr = or_unpack_int64 (reply, &reply_datasize);
num_data = (int) (reply_datasize / INT_MAX + 1);
if (reply_datasize)
{
for (i = 0; i < num_data; i++)
{
packed_desc_size = MIN ((int) reply_datasize, INT_MAX);
packed_desc = (char *) malloc (packed_desc_size);
if (packed_desc == NULL)
{
return set_server_error (CANT_ALLOC_BUFFER);
}
__gv_cvar.css_queue_receive_data_buffer (rc, packed_desc, packed_desc_size);
error = __gv_cvar.css_receive_data_from_server (rc, &reply, &size);
if (error != NO_ERROR || reply == NULL)
{
COMPARE_AND_FREE_BUFFER (packed_desc, reply);
free_and_init (packed_desc);
return set_server_error (error);
}
else
{
memcpy (replydata, reply, size);
COMPARE_AND_FREE_BUFFER (packed_desc, reply);
free_and_init (packed_desc);
}
*replydatasize_ptr += size;
reply_datasize -= size;
replydata += size;
}
}
#if defined(HISTO)
if (net_Histo_setup)
{
histo_finish_request (request, replysize + *replydatasize_ptr);
}
#endif /* HISTO */
}
return error;
}
#endif /* ENABLE_UNUSED_FUNCTION */
/*
* net_client_request2 -
*
* return: error status
*
* request(in): server request id
* argbuf(in): argument buffer (small)
* argsize(in): byte size of argbuf
* replybuf(in): reply argument buffer (small)
* replysize(in): size of reply argument buffer
* databuf(in): data buffer to send (large)
* datasize(in): size of data buffer
* replydata_ptr(in): receive data buffer (large)
* replydatasize_ptr(in): size of expected reply data
*
* Note: This is one of two functions that is called to perform a server
* request. All network interface routines will call either this
* functino or net_client_request.
* This is similar to net_client_request but the size of the reply
* data buffer is not known and must be determined from the first
* field in the reply argument buffer.
*/
int
net_client_request2 (int request, char *argbuf, int argsize, char *replybuf, int replysize, char *databuf,
int datasize, char **replydata_ptr, int *replydatasize_ptr)
{
unsigned int rc;
int size;
int reply_datasize, error;
char *reply = NULL, *replydata;
error = 0;
*replydata_ptr = NULL;
*replydatasize_ptr = 0;
if (net_Server_name[0] == '\0')
{
/* need to have a more appropriate "unexpected disconnect" message */
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_NET_SERVER_CRASHED, 0);
error = -1;
return error;
}
if (histo_is_collecting ())
{
histo_add_request (request, argsize + datasize);
}
rc =
__gv_cvar.css_send_req_to_server (net_Server_host, request, argbuf, argsize, databuf, datasize, replybuf,
replysize);
if (rc == 0)
{
error = __gv_cvar.css_get_errno ();
return set_server_error (error);
}
error = __gv_cvar.css_receive_data_from_server (rc, &reply, &size);
if (error != NO_ERROR || reply == NULL)
{
COMPARE_AND_FREE_BUFFER (replybuf, reply);
return set_server_error (error);
}
else
{
error = COMPARE_SIZE_AND_BUFFER (&replysize, size, &replybuf, reply);
}
/* here we assume that the first integer in the reply is the length of the following data block */
or_unpack_int (reply, &reply_datasize);
if (reply_datasize)
{
if ((error == NO_ERROR) && (replydata = (char *) malloc (reply_datasize)) != NULL)
{
__gv_cvar.css_queue_receive_data_buffer (rc, replydata, reply_datasize);
error = __gv_cvar.css_receive_data_from_server (rc, &reply, &size);
if (error != NO_ERROR)
{
COMPARE_AND_FREE_BUFFER (replydata, reply);
free_and_init (replydata);
return set_server_error (error);
}
else
{
error = COMPARE_SIZE_AND_BUFFER (&reply_datasize, size, &replydata, reply);
}
*replydata_ptr = reply;
*replydatasize_ptr = size;
}
else
{
error = net_set_alloc_err_if_not_set (error, ARG_FILE_LINE);
net_consume_expected_packets (rc, 1);
}
}
if (histo_is_collecting ())
{
int recevied = replysize + (replydatasize_ptr ? *replydatasize_ptr : 0);
histo_finish_request (request, recevied);
}
return error;
}
/*
* net_client_request2_no_malloc -
*
* return: error status
*
* request(in): server request id
* argbuf(in): argument buffer (small)
* argsize(in): byte size of argbuf
* replybuf(in): reply argument buffer (small)
* replysize(in): size of reply argument buffer
* databuf(in): data buffer to send (large)
* datasize(in): size of data buffer
* replydata(in): receive data buffer (large)
* replydatasize_ptr(in): size of expected reply data
*
* Note: This is one of two functions that is called to perform a server
* request. All network interface routines will call either this
* functino or net_client_request.
* This is similar to net_client_request but the size of the reply
* data buffer is not known and must be determined from the first
* field in the reply argument buffer.
*/
int
net_client_request2_no_malloc (int request, char *argbuf, int argsize, char *replybuf, int replysize,
char *databuf, int datasize, char *replydata, int *replydatasize_ptr)
{
unsigned int rc;
int size;
int reply_datasize, error;
char *reply = NULL;
error = 0;
*replydatasize_ptr = 0;
if (net_Server_name[0] == '\0')
{
/* need to have a more appropriate "unexpected disconnect" message */
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_NET_SERVER_CRASHED, 0);
error = -1;
}
else
{
if (histo_is_collecting ())
{
histo_add_request (request, argsize + datasize);
}
rc =
__gv_cvar.css_send_req_to_server (net_Server_host, request, argbuf, argsize, databuf, datasize, replybuf,
replysize);
if (rc == 0)
{
return set_server_error (__gv_cvar.css_get_errno ());
}
error = __gv_cvar.css_receive_data_from_server (rc, &reply, &size);
if (error != NO_ERROR || reply == NULL)
{
COMPARE_AND_FREE_BUFFER (replybuf, reply);
return set_server_error (error);
}
else
{
error = COMPARE_SIZE_AND_BUFFER (&replysize, size, &replybuf, reply);
}
/* here we assume that the first integer in the reply is the length of the following data block */
or_unpack_int (reply, &reply_datasize);
if (reply_datasize > 0)
{
__gv_cvar.css_queue_receive_data_buffer (rc, replydata, reply_datasize);
error = __gv_cvar.css_receive_data_from_server (rc, &reply, &size);
if (error != NO_ERROR)
{
COMPARE_AND_FREE_BUFFER (replydata, reply);
return set_server_error (error);
}
else
{
error = COMPARE_SIZE_AND_BUFFER (&reply_datasize, size, &replydata, reply);
}
*replydatasize_ptr = size;
}
if (histo_is_collecting ())
{
int recevied = replysize + (replydatasize_ptr ? *replydatasize_ptr : 0);
histo_finish_request (request, recevied);
}
}
return error;
}
/*
* net_client_request_3_data -
*
* return: error status (0 = success, non-zero = error)
*
* request(in): server request id
* argbuf(in): argument buffer (small)
* argsize(in): byte size of argbuf
* databuf1(in): first data buffer to send
* datasize1(in): size of first data buffer
* databuf2(in): second data buffer to send
* datasize2(in): size of second data buffer
* reply0(in): first reply argument buffer (small)
* replysize0(in): size of first reply argument buffer
* reply1(in): second reply argument buffer
* replysize1(in): size of second reply argument buffer
* reply2(in): third reply argument buffer
* replysize2(in): size of third reply argument buffer
*
* Note: This is one of two functions that is called to perform a server
* request. All network interface routines will call either this
* functino or net_client_request2.
*/
int
net_client_request_3_data (int request, char *argbuf, int argsize, char *databuf1, int datasize1,
char *databuf2, int datasize2, char *reply0, int replysize0, char *reply1,
int replysize1, char *reply2, int replysize2)
{
unsigned int rid;
int rc;
int size;
int p1_size, p2_size, error;
char *reply = NULL, *ptr = NULL;
error = rc = 0;
if (net_Server_name[0] == '\0')
{
/* need to have a more appropriate "unexpected disconnect" message */
rc = ER_NET_SERVER_CRASHED;
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, rc, 0);
}
else
{
if (histo_is_collecting ())
{
histo_add_request (request, argsize + datasize1 + datasize2);
}
rid =
__gv_cvar.css_send_req_to_server_2_data (net_Server_host, request, argbuf, argsize, databuf1, datasize1,
databuf2, datasize2, NULL, 0);
if (rid == 0)
{
return set_server_error (__gv_cvar.css_get_errno ());
}
__gv_cvar.css_queue_receive_data_buffer (rid, reply0, replysize0);
error = __gv_cvar.css_receive_data_from_server (rid, &reply, &size);
if (error != NO_ERROR || reply == NULL)
{
COMPARE_AND_FREE_BUFFER (reply0, reply);
return set_server_error (error);
}
else
{
/* Ignore this error status here, since the caller must check it */
ptr = or_unpack_int (reply0, &error);
ptr = or_unpack_int (ptr, &p1_size);
(void) or_unpack_int (ptr, &p2_size);
if (p1_size == 0)
{
COMPARE_AND_FREE_BUFFER (reply0, reply);
return rc;
}
__gv_cvar.css_queue_receive_data_buffer (rid, reply1, p1_size);
if (p2_size > 0)
{
__gv_cvar.css_queue_receive_data_buffer (rid, reply2, p2_size);
}
error = __gv_cvar.css_receive_data_from_server (rid, &reply, &size);
if (error != NO_ERROR)
{
COMPARE_AND_FREE_BUFFER (reply1, reply);
return set_server_error (error);
}
else
{
error = COMPARE_SIZE_AND_BUFFER (&replysize1, size, &reply1, reply);
}
if (p2_size > 0)
{
error = __gv_cvar.css_receive_data_from_server (rid, &reply, &size);
if (error != NO_ERROR)
{
COMPARE_AND_FREE_BUFFER (reply2, reply);
return set_server_error (error);
}
else
{
error = COMPARE_SIZE_AND_BUFFER (&replysize2, size, &reply2, reply);
}
}
}
if (histo_is_collecting ())
{
histo_finish_request (request, replysize1 + replysize2);
}
}
return rc;
}
/*
* net_client_request_with_callback -
*
* return: error status
*
* request(in): server request id
* argbuf(in): argument buffer (small)
* argsize(in): byte size of argbuf
* replybuf(in): reply argument buffer (small)
* replysize(in): size of reply argument buffer
* databuf1(in): first data buffer to send (large)
* datasize1(in): size of first data buffer
* databuf2(in): second data buffer to send (large)
* datasize2(in): size of second data buffer
* replydata_ptr1(in): first receive data buffer (large)
* replydatasize_ptr1(in): size of first expected reply data
* replydata_ptr2(in): second receive data buffer (large)
* replydatasize_ptr2(in): size of second expected reply data
*
* Note: This is one of the functions that is called to perform a server request.
* This is similar to net_client_request2, but the first
* field in the reply argument buffer is a request code which can
* cause the client to perform actions such as call methods. When
* the actions are completed, a reply is sent to the server. Eventually
* the server responds to the original request with a request code
* that indicates that the request is complete and this routine returns.
*/
int
net_client_request_with_callback (int request, char *argbuf, int argsize, char *replybuf, int replysize,
char *databuf1, int datasize1, char *databuf2, int datasize2,
char **replydata_listid, int *replydatasize_listid, char **replydata_page,
int *replydatasize_page, char **replydata_plan, int *replydatasize_plan)
{
deferred_flush_guard _flush_guard;
unsigned int rc;
int size, error;
int reply_datasize_listid, reply_datasize_page, reply_datasize_plan, remaining_size;
char *reply = NULL, *replydata, *ptr;
QUERY_SERVER_REQUEST server_request;
int server_request_num;
error = NO_ERROR;
*replydata_listid = NULL;
*replydata_page = NULL;
if (replydata_plan != NULL)
{
*replydata_plan = NULL;
}
*replydatasize_listid = 0;
*replydatasize_page = 0;
if (replydatasize_plan != NULL)
{
*replydatasize_plan = 0;
}
if (net_Server_name[0] == '\0')
{
/* need to have a more appropriate "unexpected disconnect" message */
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_NET_SERVER_CRASHED, 0);
error = -1;
}
else
{
if (histo_is_collecting ())
{
histo_add_request (request, argsize + datasize1 + datasize2);
}
rc =
__gv_cvar.css_send_req_to_server_2_data (net_Server_host, request, argbuf, argsize, databuf1, datasize1,
databuf2, datasize2, replybuf, replysize);
if (rc == 0)
{
return set_server_error (__gv_cvar.css_get_errno ());
}
do
{
error = __gv_cvar.css_receive_data_from_server (rc, &reply, &size);
if (error != NO_ERROR || reply == NULL)
{
COMPARE_AND_FREE_BUFFER (replybuf, reply);
return set_server_error (error);
}
#if 0
else
{
error = COMPARE_SIZE_AND_BUFFER (&replysize, size, &replybuf, reply);
}
#endif
ptr = or_unpack_int (reply, &server_request_num);
server_request = (QUERY_SERVER_REQUEST) server_request_num;
switch (server_request)
{
case QUERY_END:
/* here we assume that the first integer in the reply is the length of the following data block */
ptr = or_unpack_int (ptr, &reply_datasize_listid);
ptr = or_unpack_int (ptr, &reply_datasize_page);
ptr = or_unpack_int (ptr, &reply_datasize_plan);
COMPARE_AND_FREE_BUFFER (replybuf, reply);
remaining_size = reply_datasize_listid + reply_datasize_page + reply_datasize_plan;
// 1. Read list_id
if (0 < remaining_size)
{
if (0 < reply_datasize_listid)
{
if ((error == NO_ERROR) && (replydata = (char *) malloc (reply_datasize_listid)) != NULL)
{
__gv_cvar.css_queue_receive_data_buffer (rc, replydata, reply_datasize_listid);
error = __gv_cvar.css_receive_data_from_server (rc, &reply, &size);
if (error != NO_ERROR)
{
COMPARE_AND_FREE_BUFFER (replydata, reply);
free_and_init (replydata);
return set_server_error (error);
}
error = COMPARE_SIZE_AND_BUFFER (&reply_datasize_listid, size, &replydata, reply);
*replydata_listid = reply;
*replydatasize_listid = size;
reply = NULL;
}
else
{
error = net_set_alloc_err_if_not_set (error, ARG_FILE_LINE);
net_consume_expected_packets (rc, 1);
}
}
else
{
// Even though its size is 0, it should also be consumed.
assert (reply_datasize_listid == 0);
net_consume_expected_packets (rc, 1);
}
remaining_size -= reply_datasize_listid;
}
// 2. Read page if exists
//
// Note that not all list files have a page. list file for insert may not have one.
if (0 < remaining_size)
{
if (0 < reply_datasize_page)
{
if ((error == NO_ERROR) && (replydata = (char *) malloc (DB_PAGESIZE)) != NULL)
{
__gv_cvar.css_queue_receive_data_buffer (rc, replydata, reply_datasize_page);
error = __gv_cvar.css_receive_data_from_server (rc, &reply, &size);
if (error != NO_ERROR)
{
COMPARE_AND_FREE_BUFFER (replydata, reply);
free_and_init (replydata);
return set_server_error (error);
}
error = COMPARE_SIZE_AND_BUFFER (&reply_datasize_page, size, &replydata, reply);
*replydata_page = reply;
*replydatasize_page = size;
reply = NULL;
}
else
{
error = net_set_alloc_err_if_not_set (error, ARG_FILE_LINE);
net_consume_expected_packets (rc, 1);
}
}
else
{
// Even though its size is 0, it should also be consumed.
assert (reply_datasize_page == 0);
net_consume_expected_packets (rc, 1);
}
remaining_size -= reply_datasize_page;
}
// 3. Read plan if exists
if (0 < remaining_size)
{
if (0 < reply_datasize_plan)
{
if ((error == NO_ERROR) && (replydata = (char *) malloc (reply_datasize_plan + 1)) != NULL)
{
__gv_cvar.css_queue_receive_data_buffer (rc, replydata, reply_datasize_plan);
error = __gv_cvar.css_receive_data_from_server (rc, &reply, &size);
if (error != NO_ERROR)
{
COMPARE_AND_FREE_BUFFER (replydata, reply);
free_and_init (replydata);
return set_server_error (error);
}
error = COMPARE_SIZE_AND_BUFFER (&reply_datasize_plan, size, &replydata, reply);
if (replydata_plan != NULL)
{
*replydata_plan = reply;
}
if (replydatasize_plan != NULL)
{
*replydatasize_plan = size;
}
reply = NULL;
}
else
{
error = net_set_alloc_err_if_not_set (error, ARG_FILE_LINE);
net_consume_expected_packets (rc, 1);
}
}
else
{
// When you want to append a reply argument,
// you should remove the assertion and handle zero-size case.
assert (0 < reply_datasize_plan);
}
remaining_size -= reply_datasize_plan;
}
assert (remaining_size == 0);
break;
case METHOD_CALL:
{
char *methoddata;
int methoddata_size;
er_clear ();
error = NO_ERROR;
/* here we assume that the first integer in the reply is the length of the following data block */
or_unpack_int (ptr, &methoddata_size);
COMPARE_AND_FREE_BUFFER (replybuf, reply);
methoddata = (char *) malloc (methoddata_size);
if (methoddata != NULL)
{
__gv_cvar.css_queue_receive_data_buffer (rc, methoddata, methoddata_size);
error = __gv_cvar.css_receive_data_from_server (rc, &reply, &size);
if (error != NO_ERROR)
{
COMPARE_AND_FREE_BUFFER (methoddata, reply);
free_and_init (methoddata);
return set_server_error (error);
}
else
{
#if defined(CS_MODE)
bool need_to_reset = false;
if (method_request_id == 0)
{
method_request_id = CSS_RID_FROM_EID (rc);
need_to_reset = true;
}
#endif /* CS_MODE */
error = COMPARE_SIZE_AND_BUFFER (&methoddata_size, size, &methoddata, reply);
if (error == NO_ERROR)
{
COMPARE_AND_FREE_BUFFER (methoddata, reply);
error = method_dispatch (rc, methoddata, methoddata_size);
free_and_init (methoddata);
}
if (error != NO_ERROR)
{
assert (er_errid () != NO_ERROR);
error = er_errid ();
if (error == NO_ERROR)
{
error = ER_NET_SERVER_DATA_RECEIVE;
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error, 0);
}
}
#if defined(CS_MODE)
if (need_to_reset == true)
{
method_request_id = 0;
need_to_reset = false;
}
#endif /* CS_MODE */
}
}
else
{
error = net_set_alloc_err_if_not_set (error, ARG_FILE_LINE);
net_consume_expected_packets (rc, 1);
}
if (error != NO_ERROR)
{
return_error_to_server (net_Server_host, rc);
#if defined(CS_MODE)
// NOTE: To avoid error -495, method_error should be called after return_error_to_server()
method_error (rc, error);
#endif
}
/* expecting another reply */
__gv_cvar.css_queue_receive_data_buffer (rc, replybuf, replysize);
}
break;
/*
* A code of END_CALLBACK is followed immediately by an
* integer returning status from the remote call. The second
* integer represents the return value and must be returned
* to the calling function.
*/
case END_CALLBACK:
/* The calling function will have to ignore this value in the reply buffer. */
error = NO_ERROR;
break;
case ASYNC_OBTAIN_USER_INPUT:
{
FILEIO_REMOTE_PROMPT_TYPE prompt_id;
int length;
char *promptdata = NULL;
char user_response_buffer[FILEIO_MAX_USER_RESPONSE_SIZE + 1];
char *user_response_ptr = user_response_buffer;
int pr_status = ER_FAILED;
int pr_len = 0;
bool response_needed = false;
bool retry_in = true;
int x;
/* The following variables are need to decode the data packet */
char *display_string;
char *prompt = NULL;
char *failure_prompt = NULL;
char *secondary_prompt = NULL;
int range_lower, range_higher;
int reprompt_value;
int error2;
int result = 0;
char *a_ptr;
ptr = or_unpack_int (ptr, &x);
prompt_id = (FILEIO_REMOTE_PROMPT_TYPE) x;
ptr = or_unpack_int (ptr, &length);
COMPARE_AND_FREE_BUFFER (replybuf, reply);
promptdata = (char *) malloc (MAX (length, FILEIO_MAX_USER_RESPONSE_SIZE + OR_INT_SIZE));
if (promptdata != NULL)
{
__gv_cvar.css_queue_receive_data_buffer (rc, promptdata, length);
error = __gv_cvar.css_receive_data_from_server (rc, &reply, &length);
if (error != NO_ERROR || reply == NULL)
{
server_request = END_CALLBACK;
COMPARE_AND_FREE_BUFFER (promptdata, reply);
free_and_init (promptdata);
return set_server_error (error);
}
else
{
ptr = or_unpack_string_nocopy (reply, &prompt);
/*
* the following data are used depending on prompt type
* but will always be in the input stream
*/
ptr = or_unpack_string_nocopy (ptr, &failure_prompt);
ptr = or_unpack_int (ptr, &range_lower);
ptr = or_unpack_int (ptr, &range_higher);
ptr = or_unpack_string_nocopy (ptr, &secondary_prompt);
ptr = or_unpack_int (ptr, &reprompt_value);
}
display_string = prompt;
memset (user_response_buffer, 0, sizeof (user_response_buffer));
while (error == NO_ERROR && retry_in)
{
/* Display prompt, then get user's input. */
fprintf (stdout, display_string);
pr_status = ER_FAILED;
pr_len = 0;
retry_in = false;
if (prompt_id != FILEIO_PROMPT_DISPLAY_ONLY)
{
error2 = scanf ("%2000s", user_response_ptr);
if (error2 > 0)
{
/* basic input int validation before we send it back */
switch (prompt_id)
{
case FILEIO_PROMPT_RANGE_TYPE:
/* Numeric range checking */
result = str_to_int32 (&x, &a_ptr, user_response_ptr, 10);
if (result != 0 || x < range_lower || x > range_higher)
{
fprintf (stdout, failure_prompt);
retry_in = true;
}
else
{
response_needed = true;
pr_status = NO_ERROR;
}
break;
/*
* simply boolean (y, yes, 1, n, no, 0)
* validation
*/
case FILEIO_PROMPT_BOOLEAN_TYPE:
if ((char_tolower (*user_response_ptr) == 'y') || (*user_response_ptr == '1')
|| (intl_mbs_casecmp (user_response_ptr, "yes") == 0))
{
response_needed = true;
pr_status = NO_ERROR;
/* convert all affirmate answers into '1' */
strcpy (user_response_ptr, "1");
}
else
{
/* assume negative */
response_needed = true;
pr_status = NO_ERROR;
/* convert all negative answers into '0' */
strcpy (user_response_ptr, "0");
}
break;
/* no validation to do */
case FILEIO_PROMPT_STRING_TYPE:
response_needed = true;
pr_status = NO_ERROR;
break;
/* Validate initial prompt, then post secondary prompt */
case FILEIO_PROMPT_RANGE_WITH_SECONDARY_STRING_TYPE:
/* Numeric range checking on the first promp, but user's answer we really want is
* the second prompt */
result = str_to_int32 (&x, &a_ptr, user_response_ptr, 10);
if (result != 0 || x < range_lower || x > range_higher)
{
fprintf (stdout, failure_prompt);
retry_in = true;
}
else if (x == reprompt_value)
{
/* The first answer requires another prompt */
display_string = secondary_prompt;
retry_in = true;
prompt_id = FILEIO_PROMPT_STRING_TYPE;
/* moving the response buffer ptr forward insures that both the first response
* and the second are included in the buffer. (no delimiter or null bytes
* allowed) */
user_response_ptr += strlen (user_response_ptr);
}
else
{
/* This answer was sufficient */
response_needed = true;
pr_status = NO_ERROR;
}
break;
default:
/* should we treat this as an error? */
response_needed = true;
pr_status = NO_ERROR;
}
}
else if (error2 == 0)
{
retry_in = true;
}
else
{
pr_status = ER_FAILED;
}
}
else
{
response_needed = true;
pr_status = NO_ERROR;
}
} /* while */
/* Return the user's answer to the server. All of the cases above should get to here after looping
* or whatever is necessary and provide indication of local errors (pr_status), as well as provide
* a string in user_response. We send back to the server an int (status) followed by a string. */
/* check for overflow, could be dangerous */
pr_len = (int) strlen (user_response_buffer);
if (pr_len > FILEIO_MAX_USER_RESPONSE_SIZE)
{
error = ER_NET_DATA_TRUNCATED;
er_set (ER_FATAL_ERROR_SEVERITY, ARG_FILE_LINE, error, 0);
pr_status = ER_FAILED;
}
if (error)
{
pr_status = ER_FAILED;
}
/* we already malloced large enough buffer, reuse promptdata */
ptr = or_pack_int (promptdata, pr_status);
if (response_needed)
{
ptr = or_pack_string_with_length (ptr, user_response_buffer, pr_len);
}
error2 = net_client_send_data (rc, promptdata, CAST_STRLEN (ptr - promptdata));
if (error2 != NO_ERROR)
{
/* the error should have already been generated */
server_request = END_CALLBACK;
}
if (error == NO_ERROR && error2 != NO_ERROR)
{
error = error2;
}
if (error != NO_ERROR)
{
server_request = END_CALLBACK;
/* Do we need to tell the server about it? */
return_error_to_server (net_Server_host, rc);
}
COMPARE_AND_FREE_BUFFER (promptdata, reply);
free_and_init (promptdata);
}
else
{
/* send back some kind of error to server */
error = net_set_alloc_err_if_not_set (error, ARG_FILE_LINE);
net_consume_expected_packets (rc, 1);
/* Do we need to tell the server? */
server_request = END_CALLBACK; /* force a stop */
return_error_to_server (net_Server_host, rc);
}
}
/* expecting another reply */
__gv_cvar.css_queue_receive_data_buffer (rc, replybuf, replysize);
break;
case CONSOLE_OUTPUT:
{
int length;
char *print_data, *print_str;
ptr = or_unpack_int (ptr, &length);
ptr = or_unpack_int (ptr, &length);
COMPARE_AND_FREE_BUFFER (replybuf, reply);
print_data = (char *) malloc (length);
if (print_data != NULL)
{
__gv_cvar.css_queue_receive_data_buffer (rc, print_data, length);
error = __gv_cvar.css_receive_data_from_server (rc, &reply, &length);
if (error != NO_ERROR || reply == NULL)
{
server_request = END_CALLBACK;
COMPARE_AND_FREE_BUFFER (print_data, reply);
free_and_init (print_data);
return set_server_error (error);
}
else
{
ptr = or_unpack_string_nocopy (reply, &print_str);
fprintf (stdout, print_str);
fflush (stdout);
}
free_and_init (print_data);
}
}
/* expecting another reply */
__gv_cvar.css_queue_receive_data_buffer (rc, replybuf, replysize);
error = NO_ERROR;
break;
default:
error = ER_NET_SERVER_DATA_RECEIVE;
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error, 0);
server_request = QUERY_END;
break;
}
}
while (server_request != END_CALLBACK && server_request != QUERY_END);
if (histo_is_collecting ())
{
int recevied = replysize
+ (replydatasize_listid ? *replydatasize_listid : 0)
+ (replydatasize_page ? *replydatasize_page : 0) + (replydatasize_plan ? *replydatasize_plan : 0);
histo_finish_request (request, recevied);
}
}
return error;
}
int
net_client_request_method_callback (int request, char *argbuf, int argsize, char *replybuf, int replysize,
char **replydata_ptr, int *replydatasize_ptr)
{
deferred_flush_guard _flush_guard;
unsigned int rc;
int error;
QUERY_SERVER_REQUEST server_request;
int server_request_num;
char *reply = NULL, *ptr = NULL, *replydata = NULL;
int size, replydata_size = 0;
error = NO_ERROR;
*replydata_ptr = NULL;
*replydatasize_ptr = 0;
if (net_Server_name[0] == '\0')
{
error = ER_NET_SERVER_CRASHED;
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error, 0);
return error;
}
else
{
if (histo_is_collecting ())
{
histo_add_request (request, argsize);
}
rc = __gv_cvar.css_send_req_to_server_2_data (net_Server_host, request, argbuf, argsize, NULL, 0, NULL, 0,
replybuf, replysize);
if (rc == 0)
{
return set_server_error (__gv_cvar.css_get_errno ());
}
}
do
{
error = __gv_cvar.css_receive_data_from_server (rc, &reply, &size);
if (error != NO_ERROR || reply == NULL)
{
COMPARE_AND_FREE_BUFFER (replybuf, reply);
return set_server_error (error);
}
ptr = or_unpack_int (reply, &server_request_num);
server_request = (QUERY_SERVER_REQUEST) server_request_num;
switch (server_request)
{
case METHOD_CALL:
{
char *methoddata;
int methoddata_size;
er_clear ();
error = NO_ERROR;
/* here we assume that the first integer in the reply is the length of the following data block */
or_unpack_int (ptr, &methoddata_size);
COMPARE_AND_FREE_BUFFER (replybuf, reply);
methoddata = (char *) malloc (methoddata_size);
if (methoddata != NULL)
{
__gv_cvar.css_queue_receive_data_buffer (rc, methoddata, methoddata_size);
error = __gv_cvar.css_receive_data_from_server (rc, &reply, &size);
if (error != NO_ERROR)
{
COMPARE_AND_FREE_BUFFER (methoddata, reply);
free_and_init (methoddata);
return set_server_error (error);
}
else
{
#if defined(CS_MODE)
bool need_to_reset = false;
if (method_request_id == 0)
{
method_request_id = CSS_RID_FROM_EID (rc);
need_to_reset = true;
}
#endif /* CS_MODE */
error = COMPARE_SIZE_AND_BUFFER (&methoddata_size, size, &methoddata, reply);
if (error == NO_ERROR)
{
COMPARE_AND_FREE_BUFFER (methoddata, reply);
error = method_dispatch (rc, methoddata, methoddata_size);
free_and_init (methoddata);
}
if (error != NO_ERROR)
{
assert (er_errid () != NO_ERROR);
error = er_errid ();
if (error == NO_ERROR)
{
error = ER_NET_SERVER_DATA_RECEIVE;
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error, 0);
}
}
#if defined(CS_MODE)
if (need_to_reset == true)
{
method_request_id = 0;
need_to_reset = false;
}
#endif /* CS_MODE */
}
}
else
{
error = net_set_alloc_err_if_not_set (error, ARG_FILE_LINE);
net_consume_expected_packets (rc, 1);
}
if (error != NO_ERROR)
{
return_error_to_server (net_Server_host, rc);
#if defined(CS_MODE)
// NOTE: To avoid error -495, method_error should be called after return_error_to_server()
method_error (rc, error);
#endif
}
/* expecting another reply */
__gv_cvar.css_queue_receive_data_buffer (rc, replybuf, replysize);
}
break;
case END_CALLBACK: /* get result */
{
ptr = or_unpack_int (ptr, &replydata_size);
COMPARE_AND_FREE_BUFFER (replybuf, reply);
if (replydata_size < 0)
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_NET_SERVER_CRASHED, 0);
return ER_NET_SERVER_CRASHED;
}
else if (replydata_size > 0)
{
replydata = (char *) malloc (replydata_size);
if (replydata == NULL)
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_OUT_OF_VIRTUAL_MEMORY, 1, (size_t) replydata_size);
return ER_OUT_OF_VIRTUAL_MEMORY;
}
__gv_cvar.css_queue_receive_data_buffer (rc, replydata, replydata_size);
error = __gv_cvar.css_receive_data_from_server (rc, &reply, &size);
if (error != NO_ERROR)
{
COMPARE_AND_FREE_BUFFER (replydata, reply);
free_and_init (replydata);
return set_server_error (error);
}
else
{
error = COMPARE_SIZE_AND_BUFFER (&replydata_size, size, &replydata, reply);
}
*replydata_ptr = replydata;
*replydatasize_ptr = replydata_size;
}
else
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_NET_SERVER_DATA_RECEIVE, 0);
return ER_NET_SERVER_DATA_RECEIVE;
}
ptr = or_unpack_int (ptr, &error);
}
break;
default:
error = ER_NET_SERVER_DATA_RECEIVE;
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error, 0);
server_request = END_CALLBACK;
break;
}
}
while (server_request != END_CALLBACK);
if (histo_is_collecting ())
{
int recevied = replysize + (replydatasize_ptr ? *replydatasize_ptr : 0);
histo_finish_request (request, recevied);
}
return error;
}
/*
* net_client_check_log_header -
*
* return:
* Note:
*/
int
net_client_check_log_header (LOGWR_CONTEXT * ctx_ptr, char *argbuf, int argsize, char *replybuf,
int replysize, char **logpg_area_buf, bool verbose)
{
unsigned int rc;
char *reply = NULL;
char *ptr;
int error = NO_ERROR;
int size;
int fillsize;
int request = NET_SERVER_LOGWR_GET_LOG_PAGES;
QUERY_SERVER_REQUEST server_request;
int server_request_num;
if (net_Server_name[0] == '\0')
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_NET_SERVER_CRASHED, 0);
error = ER_NET_SERVER_CRASHED;
}
else
{
if (histo_is_collecting ())
{
histo_add_request (request, argsize);
}
if (ctx_ptr->rc == -1)
{
/* HEADER PAGE REQUEST */
rc =
__gv_cvar.css_send_req_to_server_2_data (net_Server_host, request, argbuf, argsize, NULL, 0, NULL, 0,
replybuf, replysize);
if (rc == 0)
{
return set_server_error (__gv_cvar.css_get_errno ());
}
ctx_ptr->rc = rc;
}
else
{
/* END PROTOCOL */
rc = ctx_ptr->rc;
error = net_client_send_data (rc, argbuf, argsize);
if (error != NO_ERROR)
{
return error;
}
(void) __gv_cvar.css_queue_receive_data_buffer (rc, replybuf, replysize);
}
error = __gv_cvar.css_receive_data_from_server (rc, &reply, &size);
if (error != NO_ERROR || reply == NULL)
{
COMPARE_AND_FREE_BUFFER (replybuf, reply);
return set_server_error (error);
}
else
{
error = COMPARE_SIZE_AND_BUFFER (&replysize, size, &replybuf, reply);
if (error != NO_ERROR)
{
return error;
}
}
ptr = or_unpack_int (reply, &server_request_num);
server_request = (QUERY_SERVER_REQUEST) server_request_num;
switch (server_request)
{
case GET_NEXT_LOG_PAGES:
{
int length;
char *logpg_area;
char *reply_logpg = NULL;
ptr = or_unpack_int (ptr, (int *) (&length));
if (length <= 0)
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_NET_SERVER_CRASHED, 0);
error = ER_NET_SERVER_CRASHED;
}
logpg_area = (char *) malloc (length);
if (logpg_area == NULL)
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_OUT_OF_VIRTUAL_MEMORY, 1, (size_t) length);
error = ER_OUT_OF_VIRTUAL_MEMORY;
}
__gv_cvar.css_queue_receive_data_buffer (rc, logpg_area, length);
error = __gv_cvar.css_receive_data_from_server (rc, &reply_logpg, &fillsize);
if (error != NO_ERROR)
{
COMPARE_AND_FREE_BUFFER (logpg_area, reply_logpg);
return set_server_error (error);
}
else
{
*logpg_area_buf = logpg_area;
}
}
break;
case END_CALLBACK:
error = NO_ERROR;
break;
default:
error = ER_NET_SERVER_DATA_RECEIVE;
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error, 0);
break;
}
}
if (histo_is_collecting ())
{
histo_finish_request (request, replysize);
}
return error;
}
/*
* net_client_request_with_logwr_context -
*
* return:
* Note:
*/
int
net_client_request_with_logwr_context (LOGWR_CONTEXT * ctx_ptr, int request, char *argbuf, int argsize,
char *replybuf, int replysize, char *databuf1, int datasize1,
char *databuf2, int datasize2)
{
unsigned int rc;
int size;
int error = NO_ERROR;
int request_error;
char *reply = NULL, *ptr;
QUERY_SERVER_REQUEST server_request;
int server_request_num;
bool do_read;
if (net_Server_name[0] == '\0')
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_NET_SERVER_CRASHED, 0);
error = ER_NET_SERVER_CRASHED;
}
else
{
if (histo_is_collecting ())
{
histo_add_request (request, argsize + datasize1 + datasize2);
}
if (ctx_ptr->rc == -1)
{
/* It sends a new request */
rc =
__gv_cvar.css_send_req_to_server_2_data (net_Server_host, request, argbuf, argsize, databuf1, datasize1,
databuf2, datasize2, replybuf, replysize);
if (rc == 0)
{
return set_server_error (__gv_cvar.css_get_errno ());
}
ctx_ptr->rc = rc;
}
else
{
/* It sends the same request with new arguments */
rc = ctx_ptr->rc;
error = net_client_send_data (rc, argbuf, argsize);
if (error != NO_ERROR)
{
return error;
}
(void) __gv_cvar.css_queue_receive_data_buffer (rc, replybuf, replysize);
}
do
{
do_read = false;
#ifndef WINDOWS
if (logwr_Gl.mode == LOGWR_MODE_SEMISYNC)
{
error = __gv_cvar.css_receive_data_from_server_with_timeout (rc, &reply, &size, 1000);
}
else
#endif
error = __gv_cvar.css_receive_data_from_server (rc, &reply, &size);
if (error != NO_ERROR || reply == NULL)
{
COMPARE_AND_FREE_BUFFER (replybuf, reply);
return set_server_error (error);
}
else
{
error = COMPARE_SIZE_AND_BUFFER (&replysize, size, &replybuf, reply);
if (error != NO_ERROR)
{
return error;
}
}
ptr = or_unpack_int (reply, &server_request_num);
server_request = (QUERY_SERVER_REQUEST) server_request_num;
switch (server_request)
{
case GET_NEXT_LOG_PAGES:
{
int length;
ptr = or_unpack_int (ptr, (int *) (&length));
error = net_client_get_next_log_pages (rc, replybuf, replysize, length);
}
break;
case END_CALLBACK:
if (logwr_Gl.mode == LOGWR_MODE_SEMISYNC)
{
logwr_Gl.force_flush = true;
error = logwr_set_hdr_and_flush_info ();
if (error == NO_ERROR)
{
error = logwr_write_log_pages ();
}
logwr_Gl.action = (LOGWR_ACTION) (logwr_Gl.action & LOGWR_ACTION_DELAYED_WRITE);
}
ptr = or_unpack_int (ptr, &request_error);
if (request_error != ctx_ptr->last_error)
{
/* By server error or shutdown */
error = request_error;
if (error != ER_HA_LW_FAILED_GET_LOG_PAGE)
{
error = ER_NET_SERVER_CRASHED;
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error, 0);
}
}
ctx_ptr->shutdown = true;
break;
default:
/* TODO: handle the unknown request as an error */
if (logwr_Gl.mode == LOGWR_MODE_SEMISYNC)
{
logwr_Gl.force_flush = true;
error = logwr_set_hdr_and_flush_info ();
if (error == NO_ERROR)
{
error = logwr_write_log_pages ();
}
logwr_Gl.action = (LOGWR_ACTION) (logwr_Gl.action & LOGWR_ACTION_DELAYED_WRITE);
}
error = ER_NET_SERVER_DATA_RECEIVE;
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error, 0);
ctx_ptr->shutdown = true;
break;
}
}
while (do_read /* server_request != END_CALLBACK */ );
if (histo_is_collecting ())
{
histo_finish_request (request, replysize);
}
}
return error;
}
/*
* net_client_logwr_send_end_msg
*
* return:
* note:
*/
void
net_client_logwr_send_end_msg (int rc, int error)
{
OR_ALIGNED_BUF (OR_INT_SIZE * 2 + OR_INT64_SIZE) a_request;
char *request;
char *ptr;
request = OR_ALIGNED_BUF_START (a_request);
/* END REQUEST */
ptr = or_pack_int64 (request, LOGPB_HEADER_PAGE_ID);
ptr = or_pack_int (ptr, LOGWR_MODE_ASYNC);
ptr = or_pack_int (ptr, error);
net_client_send_data (rc, request, OR_ALIGNED_BUF_SIZE (a_request));
return;
}
/*
* net_client_get_next_log_pages -
*
* return:
*
* rc(in): pre-allocated data buffer
* replybuf(in): reply argument buffer
* replysize(in): reply argument buffer size
* ptr(in): pre-allocated data buffer
*
* Note:
*/
int
net_client_get_next_log_pages (int rc, char *replybuf, int replysize, int length)
{
char *reply = NULL;
int error;
if (logwr_Gl.logpg_area_size < length)
{
/*
* It means log_buffer_size/log_page_size are different between master
* and slave.
* In this case, we have to disconnect from server and try to reconnect.
*/
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_NET_SERVER_CRASHED, 0);
return ER_NET_SERVER_CRASHED;
}
(void) __gv_cvar.css_queue_receive_data_buffer (rc, logwr_Gl.logpg_area, logwr_Gl.logpg_area_size);
error = __gv_cvar.css_receive_data_from_server (rc, &reply, &logwr_Gl.logpg_fill_size);
if (error != NO_ERROR)
{
COMPARE_AND_FREE_BUFFER (logwr_Gl.logpg_area, reply);
return set_server_error (error);
}
else
{
error = logwr_set_hdr_and_flush_info ();
if (error != NO_ERROR)
{
COMPARE_AND_FREE_BUFFER (logwr_Gl.logpg_area, reply);
return error;
}
switch (logwr_Gl.mode)
{
case LOGWR_MODE_SYNC:
case LOGWR_MODE_SEMISYNC:
error = logwr_write_log_pages ();
break;
case LOGWR_MODE_ASYNC:
logwr_Gl.action = (LOGWR_ACTION) (logwr_Gl.action | LOGWR_ACTION_ASYNC_WRITE);
break;
default:
break;
}
}
COMPARE_AND_FREE_BUFFER (logwr_Gl.logpg_area, reply);
return error;
}
/*
* net_client_request_recv_copyarea -
*
* return:
*
* request(in):
* argbuf(in):
* argsize(in):
* replybuf(in):
* replysize(in):
* reply_copy_area(in):
*
* Note:
*/
int
net_client_request_recv_copyarea (int request, char *argbuf, int argsize, char *replybuf, int replysize,
LC_COPYAREA ** reply_copy_area)
{
unsigned int rc;
int size;
int error;
char *reply = NULL;
int content_size;
char *content_ptr = NULL;
int num_objs;
char *packed_desc = NULL;
int packed_desc_size;
int decode_endian = 1;
error = NO_ERROR;
if (net_Server_name[0] == '\0')
{
/* need to have a more appropriate "unexpected disconnect" message */
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_NET_SERVER_CRASHED, 0);
return ER_FAILED;
}
if (histo_is_collecting ())
{
histo_add_request (request, argsize);
}
rc = __gv_cvar.css_send_req_to_server (net_Server_host, request, argbuf, argsize, NULL, 0, replybuf, replysize);
if (rc == 0)
{
return set_server_error (__gv_cvar.css_get_errno ());
}
/*
* Receive replybuf
*/
error = __gv_cvar.css_receive_data_from_server (rc, &reply, &size);
if (error != NO_ERROR || reply == NULL)
{
COMPARE_AND_FREE_BUFFER (replybuf, reply);
return set_server_error (error);
}
error = COMPARE_SIZE_AND_BUFFER (&replysize, size, &replybuf, reply);
/*
* Receive copyarea
* Here assume that the next two integers in the reply are the lengths of
* the copy descriptor and content descriptor
*/
reply = or_unpack_int (reply, &num_objs);
reply = or_unpack_int (reply, &packed_desc_size);
reply = or_unpack_int (reply, &content_size);
if (request == NET_SERVER_LC_FETCHALL)
{
reply = or_unpack_int (reply, &decode_endian);
}
if (packed_desc_size == 0 && content_size == 0)
{
return error;
}
if (error == NO_ERROR && reply_copy_area != NULL)
{
*reply_copy_area = locator_recv_allocate_copyarea (num_objs, &packed_desc, packed_desc_size, &content_ptr,
content_size);
if (*reply_copy_area != NULL)
{
if (packed_desc != NULL && packed_desc_size > 0)
{
__gv_cvar.css_queue_receive_data_buffer (rc, packed_desc, packed_desc_size);
error = __gv_cvar.css_receive_data_from_server (rc, &reply, &size);
if (error != NO_ERROR)
{
COMPARE_AND_FREE_BUFFER (packed_desc, reply);
free_and_init (packed_desc);
locator_free_copy_area (*reply_copy_area);
*reply_copy_area = NULL;
return set_server_error (error);
}
else
{
locator_unpack_copy_area_descriptor (num_objs, *reply_copy_area, packed_desc,
((decode_endian == 0) ? packed_desc_size : -1));
COMPARE_AND_FREE_BUFFER (packed_desc, reply);
free_and_init (packed_desc);
}
}
if (content_size > 0)
{
error = __gv_cvar.css_queue_receive_data_buffer (rc, content_ptr, content_size);
if (error != NO_ERROR)
{
net_consume_expected_packets (rc, 1);
}
else
{
error = __gv_cvar.css_receive_data_from_server (rc, &reply, &size);
}
COMPARE_AND_FREE_BUFFER (content_ptr, reply);
if (error != NO_ERROR)
{
if (packed_desc != NULL)
{
free_and_init (packed_desc);
}
locator_free_copy_area (*reply_copy_area);
*reply_copy_area = NULL;
return set_server_error (error);
}
}
}
else
{
int num_packets = 0;
ASSERT_ERROR_AND_SET (error);
if (packed_desc_size > 0)
{
num_packets++;
}
if (content_size > 0)
{
num_packets++;
}
net_consume_expected_packets (rc, num_packets);
}
if (packed_desc != NULL)
{
free_and_init (packed_desc);
}
}
else
{
int num_packets = 0;
if (error == NO_ERROR)
{
error = ER_FAILED;
}
if (packed_desc_size > 0)
{
num_packets++;
}
if (content_size > 0)
{
num_packets++;
}
net_consume_expected_packets (rc, num_packets);
}
if (histo_is_collecting ())
{
histo_finish_request (request, replysize + content_size + packed_desc_size);
}
return error;
}
/*
* net_client_request_2recv_copyarea -
*
* return:
*
* request(in):
* argbuf(in):
* argsize(in):
* replybuf(in):
* replysize(in):
* databuf(in):
* datasize(in):
* recvbuffer(in):
* recvbuffer_size(in):
* reply_copy_area(in):
* eid(in):
*
* Note:
*/
int
net_client_request_2recv_copyarea (int request, char *argbuf, int argsize, char *replybuf, int replysize,
char *databuf, int datasize, char *recvbuffer, int recvbuffer_size,
LC_COPYAREA ** reply_copy_area, int *eid)
{
unsigned int rc;
int size;
int p_size, error;
char *reply = NULL;
int content_size;
char *content_ptr = NULL;
int num_objs;
char *packed_desc = NULL;
int packed_desc_size;
error = NO_ERROR;
if (net_Server_name[0] == '\0')
{
/* need to have a more appropriate "unexpected disconnect" message */
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_NET_SERVER_CRASHED, 0);
return ER_FAILED;
}
if (histo_is_collecting ())
{
histo_add_request (request, argsize + datasize);
}
rc =
__gv_cvar.css_send_req_to_server (net_Server_host, request, argbuf, argsize, databuf, datasize, replybuf,
replysize);
if (rc == 0)
{
return set_server_error (__gv_cvar.css_get_errno ());
}
*eid = rc;
/*
* Receive replybuf
*/
error = __gv_cvar.css_receive_data_from_server (rc, &reply, &size);
if (error != NO_ERROR)
{
COMPARE_AND_FREE_BUFFER (replybuf, reply);
return set_server_error (error);
}
else
{
error = COMPARE_SIZE_AND_BUFFER (&replysize, size, &replybuf, reply);
}
/*
* Receive recvbuffer
* Here we assume that the first integer in the reply is the length
* of the following data block
*/
replybuf = or_unpack_int (replybuf, &p_size);
if (recvbuffer_size < p_size)
{
/* too big for what we allocated */
error = set_server_error (CANT_ALLOC_BUFFER);
}
if (p_size > 0)
{
if (error)
{
/* maintain error status. If we continued without checking this, error could become NO_ERROR and caller
* would never know. */
__gv_cvar.css_receive_data_from_server (rc, &reply, &size);
if (reply != NULL)
{
free_and_init (reply);
}
}
else
{
__gv_cvar.css_queue_receive_data_buffer (rc, recvbuffer, p_size);
error = __gv_cvar.css_receive_data_from_server (rc, &reply, &size);
if (error != NO_ERROR)
{
COMPARE_AND_FREE_BUFFER (recvbuffer, reply);
return set_server_error (error);
}
else
{
/* we expect that the sizes won't match, but we must be sure that the we can accomodate the data in our
* buffer. So, don't use COMPARE_SIZE_AND_BUFFER() here. */
if (recvbuffer_size < size)
{
error = ER_NET_DATASIZE_MISMATCH;
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error, 2, recvbuffer_size, size);
}
else
{
recvbuffer_size = size;
}
if (reply != recvbuffer)
{
error = ER_NET_UNUSED_BUFFER;
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error, 0);
free_and_init (reply);
}
}
}
}
/*
* Receive copyarea
* Here assume that the next two integers in the reply are the lengths of
* the copy descriptor and content descriptor
*/
replybuf = or_unpack_int (replybuf, &num_objs);
replybuf = or_unpack_int (replybuf, &packed_desc_size);
replybuf = or_unpack_int (replybuf, &content_size);
/* allocate the copyarea */
*reply_copy_area = NULL;
if (packed_desc_size == 0 && content_size == 0)
{
return error;
}
if (error == NO_ERROR)
{
*reply_copy_area = locator_recv_allocate_copyarea (num_objs, &packed_desc, packed_desc_size, &content_ptr,
content_size);
if (*reply_copy_area != NULL)
{
if (packed_desc != NULL && packed_desc_size > 0)
{
__gv_cvar.css_queue_receive_data_buffer (rc, packed_desc, packed_desc_size);
error = __gv_cvar.css_receive_data_from_server (rc, &reply, &size);
if (error != NO_ERROR)
{
COMPARE_AND_FREE_BUFFER (packed_desc, reply);
free_and_init (packed_desc);
return set_server_error (error);
}
else
{
locator_unpack_copy_area_descriptor (num_objs, *reply_copy_area, packed_desc, -1);
COMPARE_AND_FREE_BUFFER (packed_desc, reply);
free_and_init (packed_desc);
}
}
if (content_size > 0)
{
__gv_cvar.css_queue_receive_data_buffer (rc, content_ptr, content_size);
error = __gv_cvar.css_receive_data_from_server (rc, &reply, &size);
COMPARE_AND_FREE_BUFFER (content_ptr, reply);
if (error != NO_ERROR)
{
if (packed_desc != NULL)
{
free_and_init (packed_desc);
}
return set_server_error (error);
}
}
}
else
{
int num_packets = 0;
ASSERT_ERROR_AND_SET (error);
if (packed_desc_size > 0)
{
num_packets++;
}
if (content_size > 0)
{
num_packets++;
}
net_consume_expected_packets (rc, num_packets);
}
if (packed_desc != NULL)
{
free_and_init (packed_desc);
}
}
else
{
int num_packets = 0;
assert (error != NO_ERROR);
if (packed_desc_size > 0)
{
num_packets++;
}
if (content_size > 0)
{
num_packets++;
}
net_consume_expected_packets (rc, num_packets);
}
if (histo_is_collecting ())
{
histo_finish_request (request, replysize + recvbuffer_size + content_size + packed_desc_size);
}
return error;
}
/*
* net_client_request_3_data_recv_copyarea -
*
* return:
*
* request(in):
* argbuf(in):
* argsize(in):
* databuf1(in):
* datasize1(in):
* databuf2(in):
* datasize2(in):
* replybuf(in):
* replysize(in):
* reply_copy_area(out): copy area sent by server
*
* Note:
*/
int
net_client_request_3_data_recv_copyarea (int request, char *argbuf, int argsize, char *databuf1,
int datasize1, char *databuf2, int datasize2, char *replybuf,
int replysize, LC_COPYAREA ** reply_copy_area)
{
unsigned int rid;
int size;
int error;
char *reply = NULL;
int content_size;
char *content_ptr = NULL;
int num_objs;
char *packed_desc = NULL;
int packed_desc_size;
// test code
int success;
error = NO_ERROR;
if (net_Server_name[0] == '\0')
{
/* need to have a more appropriate "unexpected disconnect" message */
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_NET_SERVER_CRASHED, 0);
return ER_FAILED;
}
if (histo_is_collecting ())
{
histo_add_request (request, argsize + datasize1 + datasize2);
}
rid =
__gv_cvar.css_send_req_to_server_2_data (net_Server_host, request, argbuf, argsize, databuf1, datasize1, databuf2,
datasize2, replybuf, replysize);
if (rid == 0)
{
return set_server_error (__gv_cvar.css_get_errno ());
}
error = __gv_cvar.css_receive_data_from_server (rid, &reply, &size);
if (error != NO_ERROR || reply == NULL)
{
COMPARE_AND_FREE_BUFFER (replybuf, reply);
return set_server_error (error);
}
else
{
error = COMPARE_SIZE_AND_BUFFER (&replysize, size, &replybuf, reply);
}
replybuf = or_unpack_int (replybuf, &num_objs);
replybuf = or_unpack_int (replybuf, &packed_desc_size);
replybuf = or_unpack_int (replybuf, &content_size);
replybuf = or_unpack_int (replybuf, &success);
*reply_copy_area = NULL;
if (packed_desc_size == 0 && content_size == 0)
{
return error;
}
if (error == NO_ERROR)
{
*reply_copy_area = locator_recv_allocate_copyarea (num_objs, &packed_desc, packed_desc_size, &content_ptr,
content_size);
if (*reply_copy_area != NULL)
{
if (packed_desc != NULL && packed_desc_size > 0)
{
__gv_cvar.css_queue_receive_data_buffer (rid, packed_desc, packed_desc_size);
error = __gv_cvar.css_receive_data_from_server (rid, &reply, &size);
if (error != NO_ERROR)
{
COMPARE_AND_FREE_BUFFER (packed_desc, reply);
free_and_init (packed_desc);
return set_server_error (error);
}
else
{
locator_unpack_copy_area_descriptor (num_objs, *reply_copy_area, packed_desc, -1);
COMPARE_AND_FREE_BUFFER (packed_desc, reply);
free_and_init (packed_desc);
}
}
if (content_size > 0)
{
__gv_cvar.css_queue_receive_data_buffer (rid, content_ptr, content_size);
error = __gv_cvar.css_receive_data_from_server (rid, &reply, &size);
COMPARE_AND_FREE_BUFFER (content_ptr, reply);
if (error != NO_ERROR)
{
if (packed_desc != NULL)
{
free_and_init (packed_desc);
}
return set_server_error (error);
}
}
}
else
{
int num_packets = 0;
ASSERT_ERROR_AND_SET (error);
if (packed_desc_size > 0)
{
num_packets++;
}
if (content_size > 0)
{
num_packets++;
}
net_consume_expected_packets (rid, num_packets);
}
if (packed_desc != NULL)
{
free_and_init (packed_desc);
}
}
else
{
int num_packets = 0;
assert (error != NO_ERROR);
if (packed_desc_size > 0)
{
num_packets++;
}
if (content_size > 0)
{
num_packets++;
}
net_consume_expected_packets (rid, num_packets);
}
if (histo_is_collecting ())
{
histo_finish_request (request, replysize + content_size + packed_desc_size);
}
return error;
}
/*
* net_client_recv_copyarea -
*
* return:
*
* request(in):
* replybuf(in):
* replysize(in):
* recvbuffer(in):
* recvbuffer_size(in):
* reply_copy_area(in):
* rc(in):
*
* Note:
*/
int
net_client_recv_copyarea (int request, char *replybuf, int replysize, char *recvbuffer, int recvbuffer_size,
LC_COPYAREA ** reply_copy_area, int rc)
{
int size;
int error, p_size;
char *reply = NULL;
int content_size;
char *content_ptr = NULL;
int num_objs;
char *packed_desc = NULL;
int packed_desc_size;
error = NO_ERROR;
if (net_Server_name[0] == '\0')
{
/* need to have a more appropriate "unexpected disconnect" message */
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_NET_SERVER_CRASHED, 0);
return ER_FAILED;
}
if (histo_is_collecting ())
{
histo_add_request (request, 0);
}
/*
* Receive replybuf
*/
__gv_cvar.css_queue_receive_data_buffer (rc, replybuf, replysize);
error = __gv_cvar.css_receive_data_from_server (rc, &reply, &size);
if (error != NO_ERROR)
{
COMPARE_AND_FREE_BUFFER (replybuf, reply);
return set_server_error (error);
}
else
{
error = COMPARE_SIZE_AND_BUFFER (&replysize, size, &replybuf, reply);
}
/*
* Receive recvbuffer
* Here we assume that the first integer in the reply is the length
* of the following data block
*/
replybuf = or_unpack_int (replybuf, &p_size);
if (recvbuffer_size < p_size)
{
error = set_server_error (CANT_ALLOC_BUFFER);
}
if (p_size > 0)
{
if (error)
{
/* maintain error status. If we continued without checking this, error could become NO_ERROR and caller
* would never know. */
__gv_cvar.css_receive_data_from_server (rc, &reply, &size);
if (reply != NULL)
{
free_and_init (reply);
}
}
else
{
__gv_cvar.css_queue_receive_data_buffer (rc, recvbuffer, p_size);
error = __gv_cvar.css_receive_data_from_server (rc, &reply, &size);
if (error != NO_ERROR)
{
COMPARE_AND_FREE_BUFFER (recvbuffer, reply);
return set_server_error (error);
}
if (recvbuffer_size < size)
{
/* we expect that the sizes won't match, but we must be sure that the we can accomodate the data in
* our buffer. So, don't use COMPARE_SIZE_AND_BUFFER() here. */
error = ER_NET_DATASIZE_MISMATCH;
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error, 2, recvbuffer_size, size);
}
else
{
recvbuffer_size = size;
}
if (reply != recvbuffer)
{
error = ER_NET_UNUSED_BUFFER;
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error, 0);
free_and_init (reply);
}
}
}
/*
* Receive copyarea
* Here assume that the next two integers in the reply are the lengths of
* the copy descriptor and content descriptor
*/
replybuf = or_unpack_int (replybuf, &num_objs);
replybuf = or_unpack_int (replybuf, &packed_desc_size);
replybuf = or_unpack_int (replybuf, &content_size);
/* allocate the copyarea */
*reply_copy_area = NULL;
if (packed_desc_size == 0 && content_size == 0)
{
return error;
}
if (error == NO_ERROR)
{
*reply_copy_area =
locator_recv_allocate_copyarea (num_objs, &packed_desc, packed_desc_size, &content_ptr, content_size);
if (*reply_copy_area != NULL)
{
if (packed_desc != NULL && packed_desc_size > 0)
{
__gv_cvar.css_queue_receive_data_buffer (rc, packed_desc, packed_desc_size);
error = __gv_cvar.css_receive_data_from_server (rc, &reply, &size);
if (error != NO_ERROR)
{
COMPARE_AND_FREE_BUFFER (packed_desc, reply);
free_and_init (packed_desc);
return set_server_error (error);
}
locator_unpack_copy_area_descriptor (num_objs, *reply_copy_area, packed_desc, -1);
COMPARE_AND_FREE_BUFFER (packed_desc, reply);
free_and_init (packed_desc);
}
if (content_size > 0)
{
__gv_cvar.css_queue_receive_data_buffer (rc, content_ptr, content_size);
error = __gv_cvar.css_receive_data_from_server (rc, &reply, &size);
COMPARE_AND_FREE_BUFFER (content_ptr, reply);
if (error != NO_ERROR)
{
if (packed_desc != NULL)
{
free_and_init (packed_desc);
}
return set_server_error (error);
}
}
}
else
{
int num_packets = 0;
ASSERT_ERROR_AND_SET (error);
if (packed_desc_size > 0)
{
num_packets++;
}
if (content_size > 0)
{
num_packets++;
}
net_consume_expected_packets (rc, num_packets);
}
if (packed_desc != NULL)
{
free_and_init (packed_desc);
}
}
else
{
int num_packets = 0;
assert (error != NO_ERROR);
if (packed_desc_size > 0)
{
num_packets++;
}
if (content_size > 0)
{
num_packets++;
}
net_consume_expected_packets (rc, num_packets);
}
if (histo_is_collecting ())
{
histo_finish_request (request, replysize + recvbuffer_size + content_size + packed_desc_size);
}
return error;
}
/*
* net_client_request_3recv_copyarea -
*
* return:
*
* request(in):
* argbuf(in):
* argsize(in):
* replybuf(in):
* replysize(in):
* databuf(in):
* datasize(in):
* recvbuffer(in):
* recvbuffer_size(in):
* reply_copy_area(in):
*
* Note:
*/
int
net_client_request_3recv_copyarea (int request, char *argbuf, int argsize, char *replybuf, int replysize,
char *databuf, int datasize, char **recvbuffer, int *recvbuffer_size,
LC_COPYAREA ** reply_copy_area)
{
unsigned int rc;
int size;
int p_size, error;
char *reply = NULL;
int content_size;
char *content_ptr = NULL;
int num_objs;
char *packed_desc = NULL;
int packed_desc_size;
error = NO_ERROR;
*recvbuffer = NULL;
*recvbuffer_size = 0;
if (net_Server_name[0] == '\0')
{
/* need to have a more appropriate "unexpected disconnect" message */
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_NET_SERVER_CRASHED, 0);
return ER_FAILED;
}
if (histo_is_collecting ())
{
histo_add_request (request, argsize + datasize);
}
rc =
__gv_cvar.css_send_req_to_server (net_Server_host, request, argbuf, argsize, databuf, datasize, replybuf,
replysize);
if (rc == 0)
{
return set_server_error (__gv_cvar.css_get_errno ());
}
/*
* Receive replybuf
*/
error = __gv_cvar.css_receive_data_from_server (rc, &reply, &size);
if (error != NO_ERROR)
{
COMPARE_AND_FREE_BUFFER (replybuf, reply);
return set_server_error (error);
}
else
{
error = COMPARE_SIZE_AND_BUFFER (&replysize, size, &replybuf, reply);
}
/*
* Receive recvbuffer
* Here we assume that the first integer in the reply is the length
* of the following data block
*/
replybuf = or_unpack_int (replybuf, &p_size);
if (p_size > 0)
{
*recvbuffer_size = p_size;
if ((error == NO_ERROR) && (*recvbuffer = (char *) malloc (p_size)) != NULL)
{
__gv_cvar.css_queue_receive_data_buffer (rc, *recvbuffer, p_size);
error = __gv_cvar.css_receive_data_from_server (rc, &reply, &size);
if (error != NO_ERROR)
{
COMPARE_AND_FREE_BUFFER (*recvbuffer, reply);
free_and_init (*recvbuffer);
return set_server_error (error);
}
else
{
error = COMPARE_SIZE_AND_BUFFER (recvbuffer_size, size, recvbuffer, reply);
}
COMPARE_AND_FREE_BUFFER (*recvbuffer, reply);
}
else
{
*recvbuffer_size = 0;
error = net_set_alloc_err_if_not_set (error, ARG_FILE_LINE);
net_consume_expected_packets (rc, 1);
}
}
/*
* Receive copyarea
* Here assume that the next two integers in the reply are the lengths of
* the copy descriptor and content descriptor
*/
replybuf = or_unpack_int (replybuf, &num_objs);
replybuf = or_unpack_int (replybuf, &packed_desc_size);
replybuf = or_unpack_int (replybuf, &content_size);
/* allocate the copyarea */
*reply_copy_area = NULL;
if (packed_desc_size == 0 && content_size == 0)
{
return error;
}
if ((error == NO_ERROR)
&& ((*reply_copy_area = locator_recv_allocate_copyarea (num_objs, &packed_desc, packed_desc_size, &content_ptr,
content_size)) != NULL))
{
if (packed_desc != NULL && packed_desc_size > 0)
{
__gv_cvar.css_queue_receive_data_buffer (rc, packed_desc, packed_desc_size);
error = __gv_cvar.css_receive_data_from_server (rc, &reply, &size);
if (error != NO_ERROR)
{
COMPARE_AND_FREE_BUFFER (packed_desc, reply);
free_and_init (packed_desc);
return set_server_error (error);
}
locator_unpack_copy_area_descriptor (num_objs, *reply_copy_area, packed_desc, -1);
COMPARE_AND_FREE_BUFFER (packed_desc, reply);
free_and_init (packed_desc);
}
if (content_size > 0)
{
__gv_cvar.css_queue_receive_data_buffer (rc, content_ptr, content_size);
error = __gv_cvar.css_receive_data_from_server (rc, &reply, &size);
COMPARE_AND_FREE_BUFFER (content_ptr, reply);
if (error != NO_ERROR)
{
if (packed_desc != NULL)
{
free_and_init (packed_desc);
}
return set_server_error (error);
}
}
if (packed_desc != NULL)
{
free_and_init (packed_desc);
}
}
else
{
int num_packets = 0;
if (error == NO_ERROR)
{
ASSERT_ERROR_AND_SET (error);
}
if (packed_desc_size > 0)
{
num_packets++;
}
if (content_size > 0)
{
num_packets++;
}
net_consume_expected_packets (rc, num_packets);
}
if (histo_is_collecting ())
{
int recevied = replysize + (recvbuffer_size ? *recvbuffer_size : 0) + content_size + packed_desc_size;
histo_finish_request (request, recevied);
}
return error;
}
/*
* net_client_request_recv_stream -
*
* return:
*
* request(in):
* argbuf(in):
* argsize(in):
* replybuf(in):
* replybuf_size(in):
* databuf(in):
* datasize(in):
* outfp(in):
*
* Note:
*/
int
net_client_request_recv_stream (int request, char *argbuf, int argsize, char *replybuf, int replybuf_size,
char *databuf, int datasize, FILE * outfp)
{
unsigned int rc;
int size;
int error;
char *reply = NULL;
char *send_argbuffer;
int send_argsize;
char *recv_replybuf;
int recv_replybuf_size;
char *reply_streamdata = NULL;
int reply_streamdata_size = PLAN_DUMP_STREAM_CHUNK_SIZE;
int file_size;
error = NO_ERROR;
send_argsize = argsize + OR_INT_SIZE;
recv_replybuf_size = replybuf_size + OR_INT_SIZE;
send_argbuffer = (char *) malloc (send_argsize);
if (send_argbuffer == NULL)
{
error = ER_NET_CANT_ALLOC_BUFFER;
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error, 0);
return error;
}
or_pack_int (send_argbuffer, reply_streamdata_size);
if (argsize > 0)
{
memcpy (send_argbuffer + OR_INT_SIZE, argbuf, argsize);
}
recv_replybuf = (char *) malloc (recv_replybuf_size);
if (recv_replybuf == NULL)
{
free_and_init (send_argbuffer);
error = ER_NET_CANT_ALLOC_BUFFER;
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error, 0);
return error;
}
reply_streamdata = (char *) malloc (reply_streamdata_size);
if (reply_streamdata == NULL)
{
free_and_init (send_argbuffer);
free_and_init (recv_replybuf);
error = ER_NET_CANT_ALLOC_BUFFER;
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error, 0);
return error;
}
if (net_Server_name[0] == '\0')
{
/* need to have a more appropriate "unexpected disconnect" message */
free_and_init (send_argbuffer);
free_and_init (recv_replybuf);
free_and_init (reply_streamdata);
error = ER_NET_SERVER_CRASHED;
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error, 0);
return error;
}
if (histo_is_collecting ())
{
histo_add_request (request, send_argsize + datasize);
}
rc =
__gv_cvar.css_send_req_to_server (net_Server_host, request, send_argbuffer, send_argsize, databuf, datasize,
recv_replybuf, recv_replybuf_size);
if (rc == 0)
{
error = set_server_error (__gv_cvar.css_get_errno ());
goto end;
}
error = __gv_cvar.css_receive_data_from_server (rc, &reply, &size);
if (error != NO_ERROR)
{
COMPARE_AND_FREE_BUFFER (recv_replybuf, reply);
error = set_server_error (error);
goto end;
}
else
{
error = COMPARE_SIZE_AND_BUFFER (&recv_replybuf_size, size, &recv_replybuf, reply);
}
/* Get total size of file to transfered */
or_unpack_int (recv_replybuf, &file_size);
if (replybuf)
{
memcpy (replybuf, recv_replybuf + OR_INT_SIZE, recv_replybuf_size - OR_INT_SIZE);
}
if (histo_is_collecting ())
{
histo_finish_request (request, recv_replybuf_size + file_size);
}
while (file_size > 0)
{
__gv_cvar.css_queue_receive_data_buffer (rc, reply_streamdata, reply_streamdata_size);
error = __gv_cvar.css_receive_data_from_server (rc, &reply, &size);
if (error != NO_ERROR)
{
COMPARE_AND_FREE_BUFFER (reply_streamdata, reply);
error = set_server_error (error);
goto end;
}
if (reply != reply_streamdata)
{
error = ER_NET_UNUSED_BUFFER;
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error, 0);
COMPARE_AND_FREE_BUFFER (reply_streamdata, reply);
break;
}
if (size > reply_streamdata_size)
{
error = ER_NET_DATASIZE_MISMATCH;
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error, 2, reply_streamdata_size, size);
break;
}
file_size -= size;
fwrite (reply_streamdata, 1, size, outfp);
}
end:
free_and_init (send_argbuffer);
free_and_init (recv_replybuf);
free_and_init (reply_streamdata);
return error;
}
/*
* net_client_ping_server -ping the server
*
* return:
*/
int
net_client_ping_server (int client_val, int *server_val, int timeout)
{
OR_ALIGNED_BUF (OR_INT_SIZE) a_request;
char *request = OR_ALIGNED_BUF_START (a_request);
OR_ALIGNED_BUF (OR_INT_SIZE) a_reply;
char *reply_buf = OR_ALIGNED_BUF_START (a_reply);
char *reply = NULL;
int eid, error, reply_size;
er_log_debug (ARG_FILE_LINE, "The net_client_ping_server() is calling.");
error = NO_ERROR;
if (net_Server_host[0] == '\0' || net_Server_name[0] == '\0')
{
error = ER_NET_NO_SERVER_HOST;
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error, 0);
return error;
}
/* you can envelope something useful into the request */
or_pack_int (request, client_val);
eid =
__gv_cvar.css_send_request_to_server_with_buffer (net_Server_host, NET_SERVER_PING, request, OR_INT_SIZE,
reply_buf, OR_INT_SIZE);
if (eid == 0)
{
error = ER_NET_CANT_CONNECT_SERVER;
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error, 2, net_Server_name, net_Server_host);
return error;
}
error = __gv_cvar.css_receive_data_from_server_with_timeout (eid, &reply, &reply_size, timeout);
if (error || reply == NULL)
{
COMPARE_AND_FREE_BUFFER (reply_buf, reply);
error = ER_NET_SERVER_DATA_RECEIVE;
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error, 0);
return error;
}
/* you can get something useful from the server */
if (server_val)
{
or_unpack_int (reply, server_val);
}
COMPARE_AND_FREE_BUFFER (reply_buf, reply);
return error;
}
/*
* net_client_ping_server_with_handshake -
*
* return:
*/
int
net_client_ping_server_with_handshake (int client_type, bool check_capabilities, int opt_cap)
{
const char *client_release;
char *server_release, *server_host, *server_handshake, *ptr;
int error = NO_ERROR;
OR_ALIGNED_BUF (REL_MAX_RELEASE_LENGTH + (OR_INT_SIZE * 2) + CUB_MAXHOSTNAMELEN) a_request;
char *request = OR_ALIGNED_BUF_START (a_request);
OR_ALIGNED_BUF (REL_MAX_RELEASE_LENGTH + (OR_INT_SIZE * 3) + CUB_MAXHOSTNAMELEN) a_reply;
char *reply = OR_ALIGNED_BUF_START (a_reply), *reply_ptr;
int reply_size = OR_ALIGNED_BUF_SIZE (a_reply);
int eid, request_size, server_capabilities, server_bit_platform;
int strlen1, strlen2;
REL_COMPATIBILITY compat;
if (net_Server_host[0] == '\0' || net_Server_name[0] == '\0')
{
error = ER_NET_NO_SERVER_HOST;
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error, 0);
return error;
}
client_release = rel_release_string ();
request_size = (or_packed_string_length (client_release, &strlen1) + (OR_INT_SIZE * 2)
+ or_packed_string_length (boot_Host_name, &strlen2));
ptr = or_pack_string_with_length (request, client_release, strlen1);
ptr = or_pack_int (ptr, client_capabilities ());
ptr = or_pack_int (ptr, rel_bit_platform ());
ptr = or_pack_int (ptr, client_type);
ptr = or_pack_string_with_length (ptr, boot_Host_name, strlen2);
eid =
__gv_cvar.css_send_request_to_server_with_buffer (net_Server_host, NET_SERVER_PING_WITH_HANDSHAKE, request,
request_size, reply, reply_size);
if (eid == 0)
{
error = ER_NET_CANT_CONNECT_SERVER;
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error, 2, net_Server_name, net_Server_host);
return error;
}
reply_ptr = reply;
error = __gv_cvar.css_receive_data_from_server (eid, &reply_ptr, &reply_size);
if (error)
{
COMPARE_AND_FREE_BUFFER (reply, reply_ptr);
error = ER_NET_SERVER_DATA_RECEIVE;
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error, 0);
return error;
}
if (reply != reply_ptr)
{
error = ER_NET_UNUSED_BUFFER;
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error, 0);
free_and_init (reply_ptr);
return error;
}
ptr = or_unpack_string_nocopy (reply, &server_release);
ptr = or_unpack_string_nocopy (ptr, &server_handshake); /* for backward compatibility */
ptr = or_unpack_int (ptr, &server_capabilities);
ptr = or_unpack_int (ptr, &server_bit_platform);
ptr = or_unpack_string_nocopy (ptr, &server_host);
/* get the error code which was from the server if it exists */
error = er_errid ();
if (error != NO_ERROR)
{
return error;
}
/* check bits model */
if (server_bit_platform != rel_bit_platform ())
{
error = ER_NET_DIFFERENT_BIT_PLATFORM;
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error, 2, server_bit_platform, rel_bit_platform ());
return error;
}
/* If we can't get the server version, we have to disconnect it. */
if (server_release == NULL)
{
error = ER_NET_HS_UNKNOWN_SERVER_REL;
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error, 0);
return error;
}
/*
* 1. get the result of compatibility check.
* 2. check if the both capabilities of client and server are compatible.
* 3. check if the server has a capability to make it compatible.
*/
compat = rel_get_net_compatible (client_release, server_release);
if ((check_capabilities == true || server_capabilities & NET_CAP_REMOTE_DISABLED)
&& check_server_capabilities (server_capabilities, client_type, rel_compare (client_release, server_release),
&compat, server_host, opt_cap) != server_capabilities)
{
error = ER_NET_SERVER_HAND_SHAKE;
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error, 1, net_Server_host);
return error;
}
if (compat == REL_NOT_COMPATIBLE)
{
error = ER_NET_DIFFERENT_RELEASE;
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error, 2, server_release, client_release);
return error;
}
return error;
}
#if defined(ENABLE_UNUSED_FUNCTION)
/*
* net_client_shutdown_server -
*
* return:
*
* Note: Sends the server shutdown request to the server.
* This is not used and I'm not sure if it even works.
* Need to be careful that we don't expect a reply here.
*/
void
net_client_shutdown_server (void)
{
css_send_request_to_server (net_Server_host, NET_SERVER_SHUTDOWN, NULL, 0);
}
#endif /* ENABLE_UNUSED_FUNCTION */
/*
* net_client_init -
*
* return: error code
*
* dbname(in): server name
* hostname(in): server host name
*
* Note: This is called during startup to initialize the client side
* communications. It sets up CSS and verifies connection with the server.
*/
int
net_client_init (const char *dbname, const char *hostname)
{
int error = NO_ERROR;
/* don't really need to do this every time but bruce says its ok - we probably need to guarentee that a css_terminate
* is always called before this */
error = __gv_cvar.css_client_init (prm_get_integer_value (PRM_ID_TCP_PORT_ID), dbname, hostname);
if (error != NO_ERROR)
{
goto end;
}
/* since urgent_message_handler() doesn't do anything yet, just use the default handler provided by css which writes
* things to the system console */
/* set our host/server names for further css communication */
if (hostname != NULL && strlen (hostname) <= CUB_MAXHOSTNAMELEN)
{
strcpy (net_Server_host, hostname);
if (dbname != NULL && strlen (dbname) <= DB_MAX_IDENTIFIER_LENGTH)
{
strcpy (net_Server_name, dbname);
}
else
{
error = ER_NET_INVALID_SERVER_NAME;
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error, 1, dbname);
}
}
else
{
error = ER_NET_INVALID_HOST_NAME;
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error, 1, hostname);
}
/* On error, flush any state that may have been initialized by css. This is important for the PC's since we must
* shutdown Winsock after it has been opened by css_client_init. */
end:
if (error)
{
__gv_cvar.css_terminate (false);
}
return error;
}
#if defined(MULTI_CONN_TO_A_SERVER)
int
net_client_sub_init ()
{
return __gv_cvar.css_client_sub_init (net_Server_name, net_Server_host);
}
void
net_client_sub_final ()
{
__gv_cvar.css_client_sub_terminate (net_Server_host);
}
#endif
/*
* net_cleanup_client_queues -
*
* return:
*
* Note:
*/
void
net_cleanup_client_queues (void)
{
if (net_Server_host[0] != '\0' && net_Server_name[0] != '\0')
{
__gv_cvar.css_cleanup_client_queues (net_Server_host);
}
}
/*
* net_client_final -
*
* return: error cod
*
* Note: This is called during shutdown to close the communication interface.
*/
int
net_client_final (bool server_error)
{
__gv_cvar.css_terminate (server_error);
return NO_ERROR;
}
/*
* net_client_send_data -
*
* return:
*
* host(in):
* rc(in):
* databuf(in):
* datasize(in):
*
* Note: Send a data buffer to the server.
*/
int
net_client_send_data (unsigned int rc, char *databuf, int datasize)
{
int error;
if (databuf != NULL)
{
error = __gv_cvar.css_send_data_to_server (net_Server_host, rc, databuf, datasize);
if (error != NO_ERROR)
{
return set_server_error (error);
}
}
return NO_ERROR;
}
/*
* net_client_receive_action -
*
* return:
*
* rc(in):
* action(in):
*
* Note:
*/
int
net_client_receive_action (int rc, int *action)
{
int size;
int error;
char *reply = NULL;
int replysize = OR_INT_SIZE;
error = NO_ERROR;
if (net_Server_name[0] == '\0')
{
/* need to have a more appropriate "unexpected disconnect" message */
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_NET_SERVER_CRASHED, 0);
return ER_NET_SERVER_CRASHED;
}
error = __gv_cvar.css_receive_data_from_server (rc, &reply, &size);
if (error != NO_ERROR || reply == NULL)
{
if (reply != NULL)
{
free_and_init (reply);
}
return set_server_error (error);
}
if (size != replysize)
{
error = ER_NET_DATASIZE_MISMATCH;
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error, 2, replysize, size);
replysize = size;
if (reply != NULL)
{
free_and_init (reply);
}
return set_server_error (error);
}
or_unpack_int (reply, action);
free_and_init (reply);
return error;
}