8
0
mirror of https://github.com/FirebirdSQL/firebird.git synced 2025-01-31 04:03:03 +01:00
firebird-mirror/src/remote/xnet.cpp

2704 lines
65 KiB
C++
Raw Normal View History

2001-05-23 15:26:42 +02:00
/*
* PROGRAM: JRD Remote Interface/Server
* MODULE: xnet.cpp
2001-05-23 15:26:42 +02:00
* DESCRIPTION: Interprocess Server Communications module.
*
* The contents of this file are subject to the Interbase Public
* License Version 1.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.Inprise.com/IPL.html
*
* Software distributed under the License is distributed on an
* "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express
* or implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code was created by Inprise Corporation
* and its predecessors. Portions created by Inprise Corporation are
* Copyright (C) Inprise Corporation.
*
* All Rights Reserved.
* Contributor(s): ______________________________________.
2002-10-30 07:40:58 +01:00
*
* 2003.05.01 Victor Seryodkin, Dmitry Yemanov: Completed XNET implementation
2001-05-23 15:26:42 +02:00
*/
#include "firebird.h"
2001-05-23 15:26:42 +02:00
#include "../jrd/ib_stdio.h"
#include "../remote/remote.h"
2003-11-08 17:40:17 +01:00
#include "../jrd/y_ref.h"
#include "../jrd/ibase.h"
2001-05-23 15:26:42 +02:00
#include "../jrd/thd.h"
#include "../jrd/iberr.h"
#include "../remote/xnet.h"
2003-07-15 04:43:36 +02:00
#include "../utilities/install/install_nt.h"
2001-05-23 15:26:42 +02:00
#include "../remote/proto_proto.h"
#include "../remote/remot_proto.h"
#include "../remote/xnet_proto.h"
#include "../remote/serve_proto.h"
#include "../remote/os/win32/window.h"
2001-05-23 15:26:42 +02:00
#include "../jrd/gds_proto.h"
#include "../jrd/isc_proto.h"
#include "../jrd/sch_proto.h"
#include "../jrd/thd_proto.h"
#include <time.h>
2001-05-23 15:26:42 +02:00
#ifdef WIN_NT
#include <windows.h>
#endif /* WIN_NT */
#ifdef WIN_NT
#define ERRNO GetLastError()
#endif
#ifdef UNIX
#define ERRNO errno
#endif
#ifndef SYS_ERR
2003-11-08 17:40:17 +01:00
#define SYS_ERR isc_arg_win32
2001-05-23 15:26:42 +02:00
#endif
#define MAX_SEQUENCE 256
static int accept_connection(PORT, P_CNCT *);
static PORT xnet_alloc_port(PORT, UCHAR *, ULONG, UCHAR *, ULONG);
2001-05-23 15:26:42 +02:00
static PORT aux_connect(PORT, PACKET *, XDR_INT(*)(void));
static PORT aux_request(PORT, PACKET *);
static void xnet_cleanup_comm(XCC);
static void xnet_cleanup_port(PORT);
2001-05-23 15:26:42 +02:00
static void disconnect(PORT);
static void exit_handler(PORT);
2001-05-23 15:26:42 +02:00
static PORT receive(PORT, PACKET *);
static int send_full(PORT, PACKET *);
static int send_partial(PORT, PACKET *);
#ifdef SUPERCLIENT
static HANDLE server_process_handle = 0;
static void xnet_on_server_shutdown(PORT port);
#else
static TEXT XNET_command_line[MAXPATHLEN + 32], *XNET_p;
2003-09-15 21:27:24 +02:00
static XPM xnet_make_xpm(ULONG, time_t);
#endif // SUPERCLIENT
2001-05-23 15:26:42 +02:00
static int xdrxnet_create(XDR *, PORT, UCHAR *, USHORT, enum xdr_op);
2001-05-23 15:26:42 +02:00
static int xnet_destroy(XDR *);
static bool_t xnet_getbytes(XDR *, SCHAR *, u_int);
static bool_t xnet_getlong(XDR *, SLONG *);
static u_int xnet_getpostn(XDR *);
static caddr_t xnet_inline(XDR *, u_int);
static bool_t xnet_putlong(XDR *, SLONG *);
static bool_t xnet_putbytes(XDR*, const SCHAR*, u_int);
2001-05-23 15:26:42 +02:00
static bool_t xnet_setpostn(XDR *, u_int);
static bool_t xnet_read(XDR * xdrs);
static bool_t xnet_write(XDR * xdrs);
2001-05-23 15:26:42 +02:00
static xdr_t::xdr_ops xnet_ops = {
xnet_getlong,
xnet_putlong,
xnet_getbytes,
xnet_putbytes,
xnet_getpostn,
xnet_setpostn,
xnet_inline,
xnet_destroy
};
#ifndef MAX_PTYPE
#define MAX_PTYPE ptype_out_of_band
#endif
static ULONG pages_per_slot = XPS_DEF_PAGES_PER_CLI;
static ULONG slots_per_map = XPS_DEF_NUM_CLI;
2001-05-23 15:26:42 +02:00
static XPM client_maps = NULL;
2001-05-23 15:26:42 +02:00
#ifdef WIN_NT
static HANDLE xnet_connect_mutex = 0;
static HANDLE xnet_connect_map_h = 0;
static CADDR_T xnet_connect_map = 0;
static HANDLE xnet_connect_event = 0;
static HANDLE xnet_response_event = 0;
static DWORD CurrentProcessId;
#endif /* WIN_NT */
static bool_t xnet_initialized = FALSE;
static bool_t xnet_shutdown = FALSE;
static bool_t xnet_mutex_ready = FALSE;
2003-09-14 02:26:30 +02:00
#ifdef SUPERCLIENT
static bool_t xnet_connect_init();
2003-09-14 02:26:30 +02:00
#endif
static void xnet_connect_fini();
static void xnet_release_all(void);
#ifdef XNET_LOCK
#undef XNET_LOCK
2001-05-23 15:26:42 +02:00
#endif
#ifdef XNET_UNLOCK
#undef XNET_UNLOCK
#endif
2001-05-23 15:26:42 +02:00
static MUTX_T xnet_mutex;
#if defined(SUPERCLIENT)
#define XNET_LOCK THD_mutex_lock(&xnet_mutex)
#define XNET_UNLOCK THD_mutex_unlock(&xnet_mutex)
#elif defined(SUPERSERVER)
#define XNET_LOCK if (!xnet_shutdown) \
THREAD_EXIT; \
THD_mutex_lock(&xnet_mutex); \
if (!xnet_shutdown) \
THREAD_ENTER;
#define XNET_UNLOCK THD_mutex_unlock(&xnet_mutex)
#else // CS
#define XNET_LOCK
#define XNET_UNLOCK
#endif
static int xnet_error(PORT, TEXT *, ISC_STATUS, int, ULONG);
#define XNET_ERROR(po,fu,op,st) xnet_error(po,fu,op,st,__LINE__);
#define XNET_LOG_ERROR(msg) xnet_log_error(__LINE__,msg)
#define XNET_LOG_ERRORC(msg) xnet_log_error(__LINE__,msg,ERRNO)
static void xnet_log_error(int source_line_num, char* err_msg, ULONG err_code=0)
{
/**************************************
*
* x n e t _ l o g _ e r r o r
*
**************************************
*
* Functional description
* Error logging when port isn;t yet allocated
*
**************************************/
char err_msg_buff[256];
if (err_code)
2003-09-14 02:26:30 +02:00
sprintf(err_msg_buff, "XNET error (xnet:%d) %s Win32 error = %"ULONGFORMAT"\n",
source_line_num,err_msg,err_code);
else
sprintf(err_msg_buff, "XNET error (xnet:%d) %s\n",
source_line_num,err_msg);
gds__log(err_msg_buff);
}
2001-05-23 15:26:42 +02:00
PORT XNET_analyze(
TEXT* file_name,
USHORT* file_length,
ISC_STATUS* status_vector,
const TEXT* node_name, const TEXT* user_string,
2003-12-03 09:19:24 +01:00
bool uv_flag)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* X N E T _ a n a l y z e
*
**************************************
*
* Functional description
* Client performs attempt to establish connection
* based on the set of protocols.
* If a connection is established, return a port block,
* otherwise return NULL.
2001-05-23 15:26:42 +02:00
*
**************************************/
RDB rdb;
PORT port;
PACKET *packet;
P_CNCT *cnct;
TEXT *p, user_id[128], buffer[64];
*file_length = strlen(file_name);
/* We need to establish a connection to a remote server. Allocate the necessary
blocks and get ready to go. */
rdb = (RDB) ALLOC(type_rdb);
packet = &rdb->rdb_packet;
/* Pick up some user identification information */
user_id[0] = CNCT_user;
p = user_id + 2;
ISC_get_user(p, 0, 0, 0, 0, 0, 0);
user_id[1] = strlen(p);
2003-12-03 09:19:24 +01:00
for (; *p; p++) {
2001-05-23 15:26:42 +02:00
if (*p >= 'A' && *p <= 'Z')
*p = *p - 'A' + 'a';
2003-12-03 09:19:24 +01:00
}
2001-05-23 15:26:42 +02:00
*p++ = CNCT_host;
p++;
ISC_get_host(p, (USHORT) (user_id + sizeof(user_id) - p));
p[-1] = strlen(p);
2003-12-03 09:19:24 +01:00
for (; *p; p++) {
2001-05-23 15:26:42 +02:00
if (*p >= 'A' && *p <= 'Z')
*p = *p - 'A' + 'a';
2003-12-03 09:19:24 +01:00
}
2001-05-23 15:26:42 +02:00
if (uv_flag) {
*p++ = CNCT_user_verification;
*p++ = 0;
}
const SSHORT user_length = p - user_id;
2001-05-23 15:26:42 +02:00
/* Establish connection to server */
cnct = &packet->p_cnct;
packet->p_operation = op_connect;
cnct->p_cnct_operation = op_attach;
cnct->p_cnct_cversion = CONNECT_VERSION2;
cnct->p_cnct_client = ARCHITECTURE;
cnct->p_cnct_file.cstr_length = *file_length;
cnct->p_cnct_file.cstr_address = (UCHAR *) file_name;
/* Note: prior to V3.1E a recievers could not in truth handle more
then 5 protocol descriptions; however, the interprocess server
was created in 4.0 so this does not apply */
cnct->p_cnct_user_id.cstr_length = user_length;
cnct->p_cnct_user_id.cstr_address = (UCHAR*) user_id;
2001-05-23 15:26:42 +02:00
static const p_cnct::p_cnct_repeat protocols_to_try1[] =
{
REMOTE_PROTOCOL(PROTOCOL_VERSION7, ptype_rpc, MAX_PTYPE, 1),
REMOTE_PROTOCOL(PROTOCOL_VERSION8, ptype_rpc, MAX_PTYPE, 2),
REMOTE_PROTOCOL(PROTOCOL_VERSION10, ptype_rpc, MAX_PTYPE, 3)
2001-05-23 15:26:42 +02:00
#ifdef SCROLLABLE_CURSORS
,
REMOTE_PROTOCOL(PROTOCOL_SCROLLABLE_CURSORS, ptype_rpc, MAX_PTYPE, 4)
2001-05-23 15:26:42 +02:00
#endif
};
cnct->p_cnct_count = FB_NELEM(protocols_to_try1);
for (size_t i = 0; i < cnct->p_cnct_count; i++) {
cnct->p_cnct_versions[i] = protocols_to_try1[i];
}
2001-05-23 15:26:42 +02:00
/* If we can't talk to a server, punt. Let somebody else generate
an error. */
2001-05-23 15:26:42 +02:00
if (!(port = XNET_connect(node_name, packet, status_vector, FALSE))) {
ALLR_release((BLK) rdb);
return NULL;
}
/* Get response packet from server. */
rdb->rdb_port = port;
port->port_context = rdb;
port->receive(packet);
if (packet->p_operation == op_reject && !uv_flag) {
disconnect(port);
packet->p_operation = op_connect;
cnct->p_cnct_operation = op_attach;
cnct->p_cnct_cversion = CONNECT_VERSION2;
cnct->p_cnct_client = ARCHITECTURE;
cnct->p_cnct_file.cstr_length = *file_length;
cnct->p_cnct_file.cstr_address = (UCHAR *) file_name;
/* try again with next set of known protocols */
cnct->p_cnct_user_id.cstr_length = user_length;
cnct->p_cnct_user_id.cstr_address = (UCHAR*) user_id;
2001-05-23 15:26:42 +02:00
static const p_cnct::p_cnct_repeat protocols_to_try2[] =
{
REMOTE_PROTOCOL(PROTOCOL_VERSION4, ptype_rpc, ptype_batch_send, 1),
REMOTE_PROTOCOL(PROTOCOL_VERSION6, ptype_rpc, ptype_batch_send, 2),
};
cnct->p_cnct_count = FB_NELEM(protocols_to_try2);
2001-05-23 15:26:42 +02:00
for (size_t i = 0; i < cnct->p_cnct_count; i++) {
cnct->p_cnct_versions[i] = protocols_to_try2[i];
}
2001-05-23 15:26:42 +02:00
if (!(port = XNET_connect(node_name, packet, status_vector, FALSE))) {
ALLR_release((BLK) rdb);
return NULL;
}
/* Get response packet from server. */
rdb->rdb_port = port;
port->port_context = rdb;
port->receive(packet);
}
if (packet->p_operation == op_reject && !uv_flag) {
disconnect(port);
packet->p_operation = op_connect;
cnct->p_cnct_operation = op_attach;
cnct->p_cnct_cversion = CONNECT_VERSION2;
cnct->p_cnct_client = ARCHITECTURE;
cnct->p_cnct_file.cstr_length = *file_length;
cnct->p_cnct_file.cstr_address = (UCHAR *) file_name;
/* try again with next set of known protocols */
cnct->p_cnct_user_id.cstr_length = user_length;
cnct->p_cnct_user_id.cstr_address = (UCHAR*) user_id;
2001-05-23 15:26:42 +02:00
static const p_cnct::p_cnct_repeat protocols_to_try3[] =
{
REMOTE_PROTOCOL(PROTOCOL_VERSION3, ptype_rpc, ptype_batch_send, 1)
};
cnct->p_cnct_count = FB_NELEM(protocols_to_try3);
2001-05-23 15:26:42 +02:00
for (size_t i = 0; i < cnct->p_cnct_count; i++) {
cnct->p_cnct_versions[i] = protocols_to_try3[i];
}
2001-05-23 15:26:42 +02:00
if (!(port = XNET_connect(node_name, packet, status_vector, FALSE))) {
ALLR_release((BLK) rdb);
return NULL;
}
/* Get response packet from server. */
rdb->rdb_port = port;
port->port_context = rdb;
port->receive(packet);
}
if (packet->p_operation != op_accept) {
2003-11-08 17:40:17 +01:00
*status_vector++ = isc_arg_gds;
*status_vector++ = isc_connect_reject;
*status_vector++ = isc_arg_end;
2001-05-23 15:26:42 +02:00
disconnect(port);
return NULL;
}
port->port_protocol = packet->p_acpt.p_acpt_version;
/* once we've decided on a protocol, concatenate the version
string to reflect it... */
sprintf(buffer, "%s/P%d", port->port_version->str_data,
port->port_protocol);
ALLR_free((UCHAR *) port->port_version);
port->port_version = REMOTE_make_string(buffer);
if (packet->p_acpt.p_acpt_architecture == ARCHITECTURE)
port->port_flags |= PORT_symmetric;
if (packet->p_acpt.p_acpt_type == ptype_rpc)
port->port_flags |= PORT_rpc;
if (packet->p_acpt.p_acpt_type != ptype_out_of_band)
port->port_flags |= PORT_no_oob;
return port;
}
PORT XNET_connect(const TEXT* name, PACKET* packet,
ISC_STATUS* status_vector, USHORT flag)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* X N E T _ c o n n e c t
*
**************************************
*
* Functional description
* Establish half of a communication link.
2001-05-23 15:26:42 +02:00
*
**************************************/
if (xnet_shutdown)
return NULL;
// set up for unavailable server
2003-11-08 17:40:17 +01:00
status_vector[0] = isc_arg_gds;
status_vector[1] = isc_unavailable;
status_vector[2] = isc_arg_end;
#ifndef SUPERCLIENT
// We'll come here on handling op_service_attach packet on server.
// Server shouldn't do jumps.
return NULL;
#else
/*
LONG test_xnet_initialized;
InterlockedExchange((LPLONG) &test_xnet_initialized, xnet_initialized);
if (!test_xnet_initialized) {
InterlockedExchange((LPLONG) &xnet_initialized, TRUE);
THD_mutex_init(&xnet_mutex);
CurrentProcessId = GetCurrentProcessId();
gds__register_cleanup((FPTR_VOID_PTR) exit_handler, NULL);
InterlockedExchange((LPLONG) &xnet_mutex_ready, (LONG) TRUE);
}
else {
while (!xnet_mutex_ready)
Sleep(10);
}
*/
2003-12-03 09:19:24 +01:00
PORT port = NULL;
XCC xcc = NULL;
XPM xpm = NULL;
XPS xps = NULL;
XNET_RESPONSE response;
ULONG map_num, slot_num;
time_t timestamp;
TEXT name_buffer[128];
FILE_ID file_handle = 0;
CADDR_T mapped_address = 0;
UCHAR *start_ptr;
ULONG avail;
if (!xnet_initialized) {
xnet_initialized = TRUE;
2001-05-23 15:26:42 +02:00
THD_mutex_init(&xnet_mutex);
CurrentProcessId = GetCurrentProcessId();
gds__register_cleanup((FPTR_VOID_PTR) exit_handler, NULL);
}
XNET_LOCK;
if (!xnet_connect_init()) {
XNET_UNLOCK;
return NULL;
}
// waiting for xnet connect lock to release
if (WaitForSingleObject(xnet_connect_mutex, XNET_CONNECT_TIMEOUT) != WAIT_OBJECT_0) {
xnet_connect_fini();
XNET_UNLOCK;
return NULL;
2001-05-23 15:26:42 +02:00
}
/* writing connect request */
2001-05-23 15:26:42 +02:00
// mark connect area with XNET_INVALID_MAP_NUM to
// detect server faults on response
PXNET_RESPONSE(xnet_connect_map)->map_num = XNET_INVALID_MAP_NUM;
PXNET_RESPONSE(xnet_connect_map)->proc_id = CurrentProcessId;
2001-05-23 15:26:42 +02:00
SetEvent(xnet_connect_event);
2001-05-23 15:26:42 +02:00
// waiting for server response
if (WaitForSingleObject(xnet_response_event, XNET_CONNECT_TIMEOUT) != WAIT_OBJECT_0) {
ReleaseMutex(xnet_connect_mutex);
xnet_connect_fini();
XNET_UNLOCK;
return NULL;
}
2001-05-23 15:26:42 +02:00
memcpy(&response, xnet_connect_map, XNET_CONNECT_RESPONZE_SIZE);
ReleaseMutex(xnet_connect_mutex);
xnet_connect_fini();
2001-05-23 15:26:42 +02:00
XNET_UNLOCK;
2001-05-23 15:26:42 +02:00
if (response.map_num == XNET_INVALID_MAP_NUM) {
XNET_LOG_ERROR("server failed to response on connect request");
return NULL;
}
2001-05-23 15:26:42 +02:00
pages_per_slot = response.pages_per_slot;
slots_per_map = response.slots_per_map;
map_num = response.map_num;
slot_num = response.slot_num;
timestamp = response.timestamp;
2001-05-23 15:26:42 +02:00
try {
2001-05-23 15:26:42 +02:00
XNET_LOCK;
// see if area is already mapped for this client
for (xpm = client_maps; xpm; xpm = xpm->xpm_next) {
if (xpm->xpm_number == map_num &&
xpm->xpm_timestamp == timestamp &&
!(xpm->xpm_flags & XPMF_SERVER_SHUTDOWN))
{
break;
}
}
2001-05-23 15:26:42 +02:00
if (!xpm) {
// Area hasn't been mapped. Open new file mapping.
sprintf(name_buffer, XNET_MAPPED_FILE_NAME, XNET_PREFIX, map_num, (ULONG) timestamp);
2001-05-23 15:26:42 +02:00
file_handle = OpenFileMapping(FILE_MAP_WRITE, FALSE, name_buffer);
if (!file_handle) {
XNET_UNLOCK;
throw -1;
2001-05-23 15:26:42 +02:00
}
mapped_address = MapViewOfFile(file_handle, FILE_MAP_WRITE, 0L, 0L,
XPS_MAPPED_SIZE(slots_per_map, pages_per_slot));
2001-05-23 15:26:42 +02:00
if (!mapped_address) {
XNET_UNLOCK;
throw -1;
2001-05-23 15:26:42 +02:00
}
2001-05-23 15:26:42 +02:00
xpm = (XPM) ALLR_alloc(sizeof(struct xpm));
if (!xpm) {
XNET_UNLOCK;
throw -1;
2001-05-23 15:26:42 +02:00
}
2001-05-23 15:26:42 +02:00
xpm->xpm_next = client_maps;
client_maps = xpm;
xpm->xpm_count = 0;
xpm->xpm_number = map_num;
2001-05-23 15:26:42 +02:00
xpm->xpm_handle = file_handle;
xpm->xpm_address = mapped_address;
xpm->xpm_timestamp = timestamp;
2001-05-23 15:26:42 +02:00
xpm->xpm_flags = 0;
}
XNET_UNLOCK;
2001-05-23 15:26:42 +02:00
// there's no thread structure, so make one
2001-05-23 15:26:42 +02:00
xcc = (XCC) ALLR_alloc(sizeof(struct xcc));
if (!xcc) {
throw -1;
}
xcc->xcc_map_handle = xpm->xpm_handle;
xcc->xcc_mapped_addr =
(UCHAR *) xpm->xpm_address + XPS_SLOT_OFFSET(pages_per_slot, slot_num);
xcc->xcc_map_num = map_num;
xcc->xcc_slot = slot_num;
2001-05-23 15:26:42 +02:00
xcc->xcc_xpm = xpm;
xcc->xcc_flags = 0;
xcc->xcc_proc_h = 0;
2001-05-23 15:26:42 +02:00
xps = (XPS) xcc->xcc_mapped_addr;
// only speak if server has correct protocol
if (xps->xps_server_protocol != XPI_SERVER_PROTOCOL_VERSION) {
throw -1;
}
2001-05-23 15:26:42 +02:00
xps->xps_client_protocol = XPI_CLIENT_PROTOCOL_VERSION;
// open server process handle to watch server health during communication session
xcc->xcc_proc_h = OpenProcess(SYNCHRONIZE, 0, xps->xps_server_proc_id);
if (!xcc->xcc_proc_h) {
throw -1;
2001-05-23 15:26:42 +02:00
}
xpm->xpm_count++;
2001-05-23 15:26:42 +02:00
#ifdef WIN_NT
sprintf(name_buffer, XNET_E_C2S_DATA_CHAN_FILLED,
XNET_PREFIX, map_num, slot_num, (ULONG) timestamp);
xcc->xcc_event_send_channel_filled =
OpenEvent(EVENT_ALL_ACCESS, FALSE, name_buffer);
if (!xcc->xcc_event_send_channel_filled) {
throw -1;
}
sprintf(name_buffer, XNET_E_C2S_DATA_CHAN_EMPTED,
XNET_PREFIX, map_num, slot_num, (ULONG) timestamp);
xcc->xcc_event_send_channel_empted =
OpenEvent(EVENT_ALL_ACCESS, FALSE, name_buffer);
if (!xcc->xcc_event_send_channel_empted) {
throw -1;
}
sprintf(name_buffer, XNET_E_S2C_DATA_CHAN_FILLED,
XNET_PREFIX, map_num, slot_num, (ULONG) timestamp);
xcc->xcc_event_recv_channel_filled =
OpenEvent(EVENT_ALL_ACCESS, FALSE, name_buffer);
if (!xcc->xcc_event_recv_channel_filled) {
throw -1;
}
sprintf(name_buffer, XNET_E_S2C_DATA_CHAN_EMPTED,
XNET_PREFIX, map_num, slot_num, (ULONG) timestamp);
xcc->xcc_event_recv_channel_empted =
OpenEvent(EVENT_ALL_ACCESS, FALSE, name_buffer);
if (!xcc->xcc_event_recv_channel_empted) {
throw -1;
}
2001-05-23 15:26:42 +02:00
#else
// STUB : need to call event init for unix
2001-05-23 15:26:42 +02:00
#endif
/* added this here from the server side as this part is called by the client
and the server address need not be valid for the client -smistry 10/29/98 */
xcc->xcc_recv_channel = &xps->xps_channels[XPS_CHANNEL_S2C_DATA];
xcc->xcc_send_channel = &xps->xps_channels[XPS_CHANNEL_C2S_DATA];
2001-05-23 15:26:42 +02:00
/* we also need to add client side flags or channel pointer as they
differ from the server side */
avail = (ULONG) (XPS_USEFUL_SPACE(pages_per_slot) - (XNET_EVENT_SPACE * 2)) / 2;
start_ptr = (UCHAR*) xps + (sizeof(struct xps) + (XNET_EVENT_SPACE * 2));
2001-05-23 15:26:42 +02:00
/* send channel */
xps->xps_channels[XPS_CHANNEL_C2S_DATA].xch_client_ptr = start_ptr;
2001-05-23 15:26:42 +02:00
/* receive channel */
xps->xps_channels[XPS_CHANNEL_S2C_DATA].xch_client_ptr = (start_ptr + avail);
2001-05-23 15:26:42 +02:00
}
catch (...) {
2001-05-23 15:26:42 +02:00
#ifdef WIN_NT
if (file_handle) {
if (mapped_address) {
UnmapViewOfFile(mapped_address);
}
CloseHandle(file_handle);
}
if (xpm) {
ALLR_free(xpm);
}
if (xcc) {
if (xcc->xcc_event_send_channel_filled) {
CloseHandle(xcc->xcc_event_send_channel_filled);
}
if (xcc->xcc_event_send_channel_empted) {
CloseHandle(xcc->xcc_event_send_channel_empted);
}
if (xcc->xcc_event_recv_channel_filled) {
CloseHandle(xcc->xcc_event_recv_channel_filled);
}
if (xcc->xcc_event_recv_channel_empted) {
CloseHandle(xcc->xcc_event_recv_channel_empted);
}
ALLR_free(xcc);
}
2001-05-23 15:26:42 +02:00
#else
// Something for Unix ...
2001-05-23 15:26:42 +02:00
#endif
return NULL;
2001-05-23 15:26:42 +02:00
}
port = xnet_alloc_port(0, xcc->xcc_send_channel->xch_client_ptr,
xcc->xcc_send_channel->xch_size,
xcc->xcc_recv_channel->xch_client_ptr,
xcc->xcc_recv_channel->xch_size);
if (port) {
status_vector[1] = FB_SUCCESS;
port->port_status_vector = status_vector;
port->port_xcc = (void *) xcc;
gds__register_cleanup((FPTR_VOID_PTR) exit_handler, port);
send_full(port, packet);
}
2001-05-23 15:26:42 +02:00
return port;
#endif //SUPERCLIENT
2003-03-11 06:53:55 +01:00
}
2003-09-14 02:26:30 +02:00
#ifdef SUPERCLIENT
static bool_t xnet_connect_init()
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* x n e t _ c o n n e c t _ i n i t
2001-05-23 15:26:42 +02:00
*
**************************************
*
* Functional description
* Initialization of client side resources used
* when client performs connect to server
2001-05-23 15:26:42 +02:00
*
**************************************/
TEXT name_buffer[128];
2001-05-23 15:26:42 +02:00
xnet_connect_mutex = 0;
xnet_connect_map_h = 0;
xnet_connect_map = 0;
2001-05-23 15:26:42 +02:00
xnet_connect_event = 0;
xnet_response_event = 0;
2001-05-23 15:26:42 +02:00
try {
sprintf(name_buffer, XNET_MU_CONNECT_MUTEX, XNET_PREFIX);
xnet_connect_mutex = OpenMutex(MUTEX_ALL_ACCESS, TRUE, name_buffer);
if (!xnet_connect_mutex) {
throw -1;
}
2001-05-23 15:26:42 +02:00
sprintf(name_buffer, XNET_E_CONNECT_EVENT, XNET_PREFIX);
xnet_connect_event = OpenEvent(EVENT_ALL_ACCESS, FALSE, name_buffer);
if (!xnet_connect_event) {
throw -1;
}
2001-05-23 15:26:42 +02:00
sprintf(name_buffer, XNET_E_RESPONSE_EVENT, XNET_PREFIX);
xnet_response_event = OpenEvent(EVENT_ALL_ACCESS, FALSE, name_buffer);
if (!xnet_response_event) {
throw -1;
}
2001-05-23 15:26:42 +02:00
sprintf(name_buffer, XNET_MA_CONNECT_MAP, XNET_PREFIX);
xnet_connect_map_h = OpenFileMapping(FILE_MAP_WRITE, TRUE, name_buffer);
if (!xnet_connect_map_h) {
throw -1;
}
2001-05-23 15:26:42 +02:00
xnet_connect_map =
MapViewOfFile(xnet_connect_map_h, FILE_MAP_WRITE, 0, 0,
XNET_CONNECT_RESPONZE_SIZE);
if (!xnet_connect_map) {
throw -1;
}
2001-05-23 15:26:42 +02:00
return TRUE;
}
catch (...) {
xnet_connect_fini();
return FALSE;
2001-05-23 15:26:42 +02:00
}
2003-03-11 06:53:55 +01:00
2001-05-23 15:26:42 +02:00
}
2003-09-14 02:26:30 +02:00
#endif
2001-05-23 15:26:42 +02:00
static void xnet_connect_fini()
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* x n e t _ c o n n e c t _ f i n i
2001-05-23 15:26:42 +02:00
*
**************************************
*
* Functional description
* Release resources allocated in
* xnet_connect_init() / xnet_srv_init()
2001-05-23 15:26:42 +02:00
*
**************************************/
#ifdef WIN_NT
2001-05-23 15:26:42 +02:00
if (xnet_connect_mutex){
CloseHandle(xnet_connect_mutex);
xnet_connect_mutex = 0;
2001-05-23 15:26:42 +02:00
}
if (xnet_connect_event){
CloseHandle(xnet_connect_event);
xnet_connect_event = 0;
2001-05-23 15:26:42 +02:00
}
if (xnet_response_event){
CloseHandle(xnet_response_event);
xnet_response_event = 0;
}
2001-05-23 15:26:42 +02:00
if (xnet_connect_map){
UnmapViewOfFile(xnet_connect_map);
xnet_connect_map = 0;
}
2001-05-23 15:26:42 +02:00
if (xnet_connect_map_h){
CloseHandle(xnet_connect_map_h);
xnet_connect_map_h = 0;
2001-05-23 15:26:42 +02:00
}
#endif // WIN_NT
}
2001-05-23 15:26:42 +02:00
static int accept_connection(PORT port, P_CNCT * cnct)
{
/**************************************
*
* a c c e p t _ c o n n e c t i o n
*
**************************************
*
* Functional description
* Accept an incoming request for connection.
*
**************************************/
return TRUE;
}
2001-05-23 15:26:42 +02:00
static PORT xnet_alloc_port(PORT parent,
UCHAR * send_buffer,
ULONG send_length,
UCHAR * receive_buffer,
ULONG receive_length)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* x n e t _ a l l o c _ p o r t
2001-05-23 15:26:42 +02:00
*
**************************************
*
* Functional description
* Allocate a port block, link it in to parent (if there is a parent),
* and initialize input and output XDR streams.
*
**************************************/
PORT port;
TEXT buffer[64];
port = (PORT) ALLOCV(type_port, 0);
port->port_type = port_xnet;
port->port_state = state_pending;
ISC_get_host(buffer, sizeof(buffer));
port->port_host = REMOTE_make_string(buffer);
port->port_connection = REMOTE_make_string(buffer);
2003-01-19 13:18:24 +01:00
sprintf(buffer, "XNET Server (%s)", port->port_host->str_data);
2001-05-23 15:26:42 +02:00
port->port_version = REMOTE_make_string(buffer);
if (parent) {
port->port_parent = parent;
port->port_next = parent->port_clients;
parent->port_clients = parent->port_next = port;
port->port_handle = parent->port_handle;
port->port_server = parent->port_server;
port->port_server_flags = parent->port_server_flags;
if (port->port_connection)
ALLR_free((UCHAR *) port->port_connection);
port->port_connection =
REMOTE_make_string(parent->port_connection->str_data);
}
port->port_accept = accept_connection;
port->port_disconnect = disconnect;
port->port_receive_packet = receive;
port->port_send_packet = send_full;
port->port_send_partial = send_partial;
port->port_connect =
reinterpret_cast<PORT(*)(PORT, PACKET *, void (*)())>(aux_connect);
2001-05-23 15:26:42 +02:00
port->port_request = aux_request;
port->port_buff_size = send_length;
port->port_status_vector = NULL;
xdrxnet_create(&port->port_send, port, send_buffer, send_length, XDR_ENCODE);
2001-05-23 15:26:42 +02:00
xdrxnet_create(&port->port_receive, port, receive_buffer, 0, XDR_DECODE);
2001-05-23 15:26:42 +02:00
return port;
}
static PORT aux_connect(PORT port, PACKET * packet, XDR_INT(*ast) (void))
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* a u x _ c o n n e c t
*
**************************************
*
* Functional description
* Try to establish an alternative connection for handling events.
* Somebody has already done a successfull connect request.
* This uses the existing xcc for the parent port to more
* or less duplicate a new xcc for the new aux port pointing
* to the event stuff in the map.
2001-05-23 15:26:42 +02:00
*
**************************************/
if (port->port_server_flags) {
port->port_flags |= PORT_async;
return port;
}
PORT new_port = NULL;
XCC parent_xcc = NULL;
XCC xcc = NULL;
TEXT name_buffer[128];
XPS xps = NULL;
XPM xpm = NULL;
2001-05-23 15:26:42 +02:00
try {
2001-05-23 15:26:42 +02:00
// make a new xcc
parent_xcc = (XCC) port->port_xcc;
xps = (XPS) parent_xcc->xcc_mapped_addr;
2001-05-23 15:26:42 +02:00
xcc = (XCC) ALLR_alloc(sizeof(struct xcc));
if (!xcc) {
throw -1;
}
2001-05-23 15:26:42 +02:00
xpm = xcc->xcc_xpm = parent_xcc->xcc_xpm;
xcc->xcc_map_num = parent_xcc->xcc_map_num;
xcc->xcc_slot = parent_xcc->xcc_slot;
2001-05-23 15:26:42 +02:00
#ifdef WIN_NT
xcc->xcc_proc_h = parent_xcc->xcc_proc_h;
#endif
2001-05-23 15:26:42 +02:00
xcc->xcc_flags = 0;
xcc->xcc_map_handle = parent_xcc->xcc_map_handle;
xcc->xcc_mapped_addr = parent_xcc->xcc_mapped_addr;
xcc->xcc_xpm->xpm_count++;
sprintf(name_buffer, XNET_E_C2S_EVNT_CHAN_FILLED,
XNET_PREFIX, xcc->xcc_map_num, xcc->xcc_slot,
(ULONG) xpm->xpm_timestamp);
xcc->xcc_event_send_channel_filled =
OpenEvent(EVENT_ALL_ACCESS, FALSE, name_buffer);
if (!xcc->xcc_event_send_channel_filled) {
throw -1;
}
2001-05-23 15:26:42 +02:00
sprintf(name_buffer, XNET_E_C2S_EVNT_CHAN_EMPTED,
XNET_PREFIX, xcc->xcc_map_num, xcc->xcc_slot,
(ULONG) xpm->xpm_timestamp);
xcc->xcc_event_send_channel_empted =
OpenEvent(EVENT_ALL_ACCESS, FALSE, name_buffer);
if (!xcc->xcc_event_send_channel_empted) {
throw -1;
}
2001-05-23 15:26:42 +02:00
sprintf(name_buffer, XNET_E_S2C_EVNT_CHAN_FILLED,
XNET_PREFIX, xcc->xcc_map_num, xcc->xcc_slot,
(ULONG) xpm->xpm_timestamp);
xcc->xcc_event_recv_channel_filled =
OpenEvent(EVENT_ALL_ACCESS, FALSE, name_buffer);
if (!xcc->xcc_event_recv_channel_filled) {
throw -1;
}
2001-05-23 15:26:42 +02:00
sprintf(name_buffer, XNET_E_S2C_EVNT_CHAN_EMPTED,
XNET_PREFIX, xcc->xcc_map_num, xcc->xcc_slot,
(ULONG) xpm->xpm_timestamp);
xcc->xcc_event_recv_channel_empted =
OpenEvent(EVENT_ALL_ACCESS, FALSE, name_buffer);
if (!xcc->xcc_event_recv_channel_empted) {
throw -1;
}
2001-05-23 15:26:42 +02:00
// send events channel
xps->xps_channels[XPS_CHANNEL_C2S_EVENTS].xch_client_ptr =
((UCHAR *) xpm->xpm_address + sizeof(struct xps));
// receive events channel
xps->xps_channels[XPS_CHANNEL_S2C_EVENTS].xch_client_ptr =
((UCHAR *) xpm->xpm_address + sizeof(struct xps) + (XNET_EVENT_SPACE));
xcc->xcc_send_channel = &xps->xps_channels[XPS_CHANNEL_C2S_EVENTS];
xcc->xcc_recv_channel = &xps->xps_channels[XPS_CHANNEL_S2C_EVENTS];
// alloc new port and link xcc to it
new_port = xnet_alloc_port(NULL,
xcc->xcc_send_channel->xch_client_ptr,
xcc->xcc_send_channel->xch_size,
xcc->xcc_recv_channel->xch_client_ptr,
xcc->xcc_recv_channel->xch_size);
if (!new_port) {
throw -1;
}
2001-05-23 15:26:42 +02:00
port->port_async = new_port;
new_port->port_flags = port->port_flags & PORT_no_oob;
new_port->port_flags |= PORT_async;
new_port->port_xcc = (void *) xcc;
2001-05-23 15:26:42 +02:00
gds__register_cleanup((FPTR_VOID_PTR) exit_handler, new_port);
2001-05-23 15:26:42 +02:00
return new_port;
}
catch (...) {
2001-05-23 15:26:42 +02:00
XNET_LOG_ERROR("aux_connect() failed");
2001-05-23 15:26:42 +02:00
#ifdef WIN_NT
if (xcc) {
if (xcc->xcc_event_send_channel_filled) {
CloseHandle(xcc->xcc_event_send_channel_filled);
}
if (xcc->xcc_event_send_channel_empted) {
CloseHandle(xcc->xcc_event_send_channel_empted);
}
if (xcc->xcc_event_recv_channel_filled) {
CloseHandle(xcc->xcc_event_recv_channel_filled);
}
if (xcc->xcc_event_recv_channel_empted) {
CloseHandle(xcc->xcc_event_recv_channel_empted);
}
ALLR_free(xcc);
}
2001-05-23 15:26:42 +02:00
#else
// Something for Unix ...
2001-05-23 15:26:42 +02:00
#endif
return NULL;
}
2001-05-23 15:26:42 +02:00
}
static PORT aux_request(PORT port, PACKET * packet)
{
2001-05-23 15:26:42 +02:00
/**************************************
*
* a u x _ r e q u e s t
2001-05-23 15:26:42 +02:00
*
**************************************
*
* Functional description
* A remote interface has requested the server to
* prepare an auxiliary connection. This is done
* by allocating a new port and comm (xcc) structure,
* using the event stuff in the map rather than the
* normal database channels.
2001-05-23 15:26:42 +02:00
*
**************************************/
PORT new_port = NULL;
XCC parent_xcc = NULL;
XCC xcc = NULL;
TEXT name_buffer[128];
XPS xps = NULL;
XPM xpm = NULL;
2001-05-23 15:26:42 +02:00
try {
2001-05-23 15:26:42 +02:00
// make a new xcc
parent_xcc = (XCC) port->port_xcc;
xps = (XPS) parent_xcc->xcc_mapped_addr;
2001-05-23 15:26:42 +02:00
xcc = (XCC) ALLR_alloc(sizeof(struct xcc));
if (!xcc) {
throw -1;
2001-05-23 15:26:42 +02:00
}
xpm = xcc->xcc_xpm = parent_xcc->xcc_xpm;
xcc->xcc_map_num = parent_xcc->xcc_map_num;
xcc->xcc_slot = parent_xcc->xcc_slot;
2001-05-23 15:26:42 +02:00
#ifdef WIN_NT
xcc->xcc_proc_h = parent_xcc->xcc_proc_h;
#endif
2001-05-23 15:26:42 +02:00
xcc->xcc_flags = 0;
xcc->xcc_map_handle = parent_xcc->xcc_map_handle;
xcc->xcc_mapped_addr = parent_xcc->xcc_mapped_addr;
xcc->xcc_xpm->xpm_count++;
2001-05-23 15:26:42 +02:00
#ifdef WIN_NT
2001-05-23 15:26:42 +02:00
sprintf(name_buffer, XNET_E_C2S_EVNT_CHAN_FILLED,
XNET_PREFIX, xcc->xcc_map_num, xcc->xcc_slot,
(ULONG) xpm->xpm_timestamp);
xcc->xcc_event_recv_channel_filled =
CreateEvent(ISC_get_security_desc(), FALSE, FALSE, name_buffer);
if (!xcc->xcc_event_recv_channel_filled ||
(xcc->xcc_event_recv_channel_filled && ERRNO == ERROR_ALREADY_EXISTS)) {
throw -1;
}
2001-05-23 15:26:42 +02:00
sprintf(name_buffer, XNET_E_C2S_EVNT_CHAN_EMPTED,
XNET_PREFIX, xcc->xcc_map_num, xcc->xcc_slot,
(ULONG) xpm->xpm_timestamp);
xcc->xcc_event_recv_channel_empted =
CreateEvent(ISC_get_security_desc(), TRUE, TRUE, name_buffer);
if (!xcc->xcc_event_recv_channel_empted ||
(xcc->xcc_event_recv_channel_empted && ERRNO == ERROR_ALREADY_EXISTS)) {
throw -1;
2001-05-23 15:26:42 +02:00
}
sprintf(name_buffer, XNET_E_S2C_EVNT_CHAN_FILLED,
XNET_PREFIX, xcc->xcc_map_num, xcc->xcc_slot,
(ULONG) xpm->xpm_timestamp);
xcc->xcc_event_send_channel_filled =
CreateEvent(ISC_get_security_desc(), FALSE, FALSE, name_buffer);
if (!xcc->xcc_event_send_channel_filled ||
(xcc->xcc_event_send_channel_filled && ERRNO == ERROR_ALREADY_EXISTS)) {
throw -1;
}
2001-05-23 15:26:42 +02:00
sprintf(name_buffer, XNET_E_S2C_EVNT_CHAN_EMPTED,
XNET_PREFIX, xcc->xcc_map_num, xcc->xcc_slot,
(ULONG) xpm->xpm_timestamp);
xcc->xcc_event_send_channel_empted =
CreateEvent(ISC_get_security_desc(), TRUE, TRUE, name_buffer);
if (!xcc->xcc_event_send_channel_empted ||
(xcc->xcc_event_send_channel_empted && ERRNO == ERROR_ALREADY_EXISTS)) {
throw -1;
}
2001-05-23 15:26:42 +02:00
#else
// STUB : This should be event_init() calls ?
#endif
2001-05-23 15:26:42 +02:00
// send events channel
xps->xps_channels[XPS_CHANNEL_S2C_EVENTS].xch_client_ptr =
((UCHAR *) xpm->xpm_address + sizeof(struct xps) + (XNET_EVENT_SPACE));
// receive events channel
xps->xps_channels[XPS_CHANNEL_C2S_EVENTS].xch_client_ptr =
((UCHAR *) xpm->xpm_address + sizeof(struct xps));
xcc->xcc_send_channel = &xps->xps_channels[XPS_CHANNEL_S2C_EVENTS];
xcc->xcc_recv_channel = &xps->xps_channels[XPS_CHANNEL_C2S_EVENTS];
// alloc new port and link xcc to it
new_port = xnet_alloc_port(NULL,
xcc->xcc_send_channel->xch_client_ptr,
xcc->xcc_send_channel->xch_size,
xcc->xcc_recv_channel->xch_client_ptr,
xcc->xcc_recv_channel->xch_size);
if (!new_port) {
throw -1;
}
2001-05-23 15:26:42 +02:00
port->port_async = new_port;
new_port->port_xcc = (void *) xcc;
new_port->port_flags = port->port_flags & PORT_no_oob;
new_port->port_server_flags = port->port_server_flags;
2001-05-23 15:26:42 +02:00
return new_port;
2001-05-23 15:26:42 +02:00
}
catch (...) {
2001-05-23 15:26:42 +02:00
XNET_LOG_ERROR("aux_request() failed");
#ifdef WIN_NT
if (xcc) {
if (xcc->xcc_event_send_channel_filled) {
CloseHandle(xcc->xcc_event_send_channel_filled);
}
if (xcc->xcc_event_send_channel_empted) {
CloseHandle(xcc->xcc_event_send_channel_empted);
}
if (xcc->xcc_event_recv_channel_filled) {
CloseHandle(xcc->xcc_event_recv_channel_filled);
}
if (xcc->xcc_event_recv_channel_empted) {
CloseHandle(xcc->xcc_event_recv_channel_empted);
}
ALLR_free(xcc);
2001-05-23 15:26:42 +02:00
}
#else
// Something for Unix ...
#endif
return NULL;
2001-05-23 15:26:42 +02:00
}
}
static void xnet_cleanup_comm(XCC xcc)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* x n e t _ c l e a n u p _ c o m m
2001-05-23 15:26:42 +02:00
*
**************************************
*
* Functional description
* Clean up an xcc structure, close its handles,
* unmap its file, and free it.
2001-05-23 15:26:42 +02:00
*
**************************************/
XPM xpm;
XPM pxpm;
#ifdef WIN_NT
if (xcc->xcc_event_send_channel_filled) {
CloseHandle(xcc->xcc_event_send_channel_filled);
}
if (xcc->xcc_event_send_channel_empted) {
CloseHandle(xcc->xcc_event_send_channel_empted);
}
if (xcc->xcc_event_recv_channel_filled) {
CloseHandle(xcc->xcc_event_recv_channel_filled);
}
if (xcc->xcc_event_recv_channel_empted) {
CloseHandle(xcc->xcc_event_recv_channel_empted);
}
if (xcc->xcc_proc_h) {
CloseHandle(xcc->xcc_proc_h);
2001-05-23 15:26:42 +02:00
}
#endif // WIN_NT
2001-05-23 15:26:42 +02:00
xpm = xcc->xcc_xpm;
2001-05-23 15:26:42 +02:00
ALLR_free((UCHAR *) xcc);
2001-05-23 15:26:42 +02:00
// if this was the last area for this map, unmap it
if (xpm) {
xpm->xpm_count--;
2001-05-23 15:26:42 +02:00
if (!xpm->xpm_count && client_maps) {
UnmapViewOfFile(xpm->xpm_address);
CloseHandle(xpm->xpm_handle);
// find xpm in chain and release
if (xpm == client_maps) {
client_maps = xpm->xpm_next;
}
else {
for (pxpm = client_maps; pxpm->xpm_next; pxpm = pxpm->xpm_next) {
if (pxpm->xpm_next == xpm) {
pxpm->xpm_next = xpm->xpm_next;
break;
}
2001-05-23 15:26:42 +02:00
}
}
ALLR_free((UCHAR *) xpm);
2001-05-23 15:26:42 +02:00
}
}
}
static void xnet_cleanup_port(PORT port)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* c l e a n u p _ p o r t
2001-05-23 15:26:42 +02:00
*
**************************************
*
* Functional description
* Walk through the port structure freeing
* allocated memory and then free the port.
2001-05-23 15:26:42 +02:00
*
**************************************/
if (port->port_xcc) {
XNET_LOCK;
xnet_cleanup_comm((XCC) port->port_xcc);
XNET_UNLOCK;
}
if (port->port_version) {
2001-05-23 15:26:42 +02:00
ALLR_free((UCHAR *) port->port_version);
}
2001-05-23 15:26:42 +02:00
if (port->port_connection) {
2001-05-23 15:26:42 +02:00
ALLR_free((UCHAR *) port->port_connection);
}
2001-05-23 15:26:42 +02:00
if (port->port_user_name) {
2001-05-23 15:26:42 +02:00
ALLR_free((UCHAR *) port->port_user_name);
}
2001-05-23 15:26:42 +02:00
if (port->port_host) {
2001-05-23 15:26:42 +02:00
ALLR_free((UCHAR *) port->port_host);
}
2001-05-23 15:26:42 +02:00
if (port->port_object_vector) {
2001-05-23 15:26:42 +02:00
ALLR_free((UCHAR *) port->port_object_vector);
}
2001-05-23 15:26:42 +02:00
#ifdef SUPERSERVER
if (port->port_status_vector) {
ALLR_free(port->port_status_vector);
}
2001-05-23 15:26:42 +02:00
#endif
ALLR_free((BLK) port);
2001-05-23 15:26:42 +02:00
}
static void disconnect(PORT port)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* d i s c o n n e c t
*
**************************************
*
* Functional description
* Break a remote connection.
*
**************************************/
PORT parent, *ptr;
/* If this is a sub-port, unlink it from it's parent */
if ((parent = port->port_parent) != NULL) {
2001-05-23 15:26:42 +02:00
if (port->port_async) {
disconnect(port->port_async);
port->port_async = NULL;
}
for (ptr = &parent->port_clients; *ptr; ptr = &(*ptr)->port_next){
2001-05-23 15:26:42 +02:00
if (*ptr == port) {
*ptr = port->port_next;
if (ptr == &parent->port_clients)
parent->port_next = *ptr;
break;
}
}
2001-05-23 15:26:42 +02:00
}
else if (port->port_async) {
/* If we're MULTI_THREAD then we cannot free the port because another
* thread might be using it. If we're SUPERSERVER we must free the
* port to avoid a memory leak. What we really need to know is if we
* have multi-threaded events, but this is transport specific.
* -smistry 10/29/98 */
#if (defined (MULTI_THREAD) && !defined (SUPERSERVER))
2001-05-23 15:26:42 +02:00
port->port_async->port_flags |= PORT_disconnect;
#else
disconnect(port->port_async);
port->port_async = NULL;
#endif
}
gds__unregister_cleanup((FPTR_VOID_PTR)(exit_handler),port);
xnet_cleanup_port(port);
2001-05-23 15:26:42 +02:00
}
static void exit_handler(PORT main_port)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* e x i t _ h a n d l e r
*
**************************************
*
* Functional description
* Free port resources or everything
2001-05-23 15:26:42 +02:00
*
**************************************/
xnet_shutdown = TRUE;
if (main_port) {
disconnect(main_port);
}
else {
xnet_release_all();
}
2001-05-23 15:26:42 +02:00
}
static bool_t xnet_make_map(ULONG map_number, time_t timestamp,
FILE_ID* map_handle, CADDR_T* map_address)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* x n e t _ m a k e _ m a p
2001-05-23 15:26:42 +02:00
*
**************************************
*
* Functional description
* Create mamory map
2001-05-23 15:26:42 +02:00
*
**************************************/
TEXT name_buffer[128];
sprintf(name_buffer, XNET_MAPPED_FILE_NAME, XNET_PREFIX, map_number, (ULONG) timestamp);
*map_handle = CreateFileMapping((HANDLE) 0xFFFFFFFF,
ISC_get_security_desc(),
PAGE_READWRITE,
0L,
XPS_MAPPED_SIZE(slots_per_map, pages_per_slot),
name_buffer);
if (!(*map_handle) || (*map_handle && ERRNO == ERROR_ALREADY_EXISTS))
return FALSE;
2003-03-11 06:53:55 +01:00
*map_address = MapViewOfFile(*map_handle, FILE_MAP_WRITE, 0, 0,
XPS_MAPPED_SIZE(slots_per_map, pages_per_slot));
if (!(*map_address)) {
CloseHandle(*map_handle);
return FALSE;
2003-03-11 06:53:55 +01:00
}
2001-05-23 15:26:42 +02:00
return TRUE;
}
2003-03-11 06:53:55 +01:00
2001-05-23 15:26:42 +02:00
static XPM xnet_make_xpm(ULONG map_number, time_t timestamp)
{
/**************************************
*
* x n e t _ m a k e _ x p m
*
**************************************
*
* Functional description
* Create new xpm structure
*
**************************************/
XPM xpm = NULL;
FILE_ID map_handle = 0;
CADDR_T map_address = 0;
USHORT i;
2001-05-23 15:26:42 +02:00
if (!xnet_make_map(map_number, timestamp, &map_handle, &map_address))
return NULL;
2001-05-23 15:26:42 +02:00
/* allocate a structure and initialize it */
2001-05-23 15:26:42 +02:00
xpm = (XPM) ALLR_alloc(sizeof(struct xpm));
if (!xpm)
return NULL;
2001-05-23 15:26:42 +02:00
xpm->xpm_handle = map_handle;
xpm->xpm_address = map_address;
xpm->xpm_number = map_number;
xpm->xpm_count = 0;
xpm->xpm_timestamp = timestamp;
for (i = 0; i < slots_per_map; i++) {
xpm->xpm_ids[i] = XPM_FREE;
2003-03-11 06:53:55 +01:00
}
2001-05-23 15:26:42 +02:00
xpm->xpm_flags = 0;
xpm->xpm_next = client_maps;
client_maps = xpm;
2001-05-23 15:26:42 +02:00
return xpm;
}
static PORT receive( PORT main_port, PACKET * packet)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* r e c e i v e
2001-05-23 15:26:42 +02:00
*
**************************************
*
* Functional description
* Receive a message from a port.
2001-05-23 15:26:42 +02:00
*
**************************************/
if (!xdr_protocol(&main_port->port_receive, packet))
packet->p_operation = op_exit;
2001-05-23 15:26:42 +02:00
return main_port;
2001-05-23 15:26:42 +02:00
}
static int send_full( PORT port, PACKET * packet)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* s e n d _ f u l l
*
**************************************
*
* Functional description
* Send a packet across a port to another process.
* Flush data to remote interface
2001-05-23 15:26:42 +02:00
*
**************************************/
if (!xdr_protocol(&port->port_send, packet))
return FALSE;
if (xnet_write(&port->port_send))
return TRUE;
else{
XNET_ERROR(port, "SetEvent()", isc_net_write_err, ERRNO);
return FALSE;
}
2001-05-23 15:26:42 +02:00
}
static int send_partial( PORT port, PACKET * packet)
{
2001-05-23 15:26:42 +02:00
/**************************************
*
* s e n d _ p a r t i a l
*
**************************************
*
* Functional description
* Send a packet across a port to another process.
*
**************************************/
return xdr_protocol(&port->port_send, packet);
}
#ifdef SUPERCLIENT
#ifdef WIN_NT
static void xnet_on_server_shutdown(PORT port)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* s e r v e r _ s h u t d o w n
*
**************************************
*
* Functional description
* Server shutdown handler (client side only).
2001-05-23 15:26:42 +02:00
*
**************************************/
XCC xcc = (XCC)port->port_xcc;
XPM xpm = xcc->xcc_xpm;
2001-05-23 15:26:42 +02:00
XNET_LOG_ERROR("Server shutdown detected");
2001-05-23 15:26:42 +02:00
XNET_LOCK;
2001-05-23 15:26:42 +02:00
xcc->xcc_flags |= XCCF_SERVER_SHUTDOWN;
2001-05-23 15:26:42 +02:00
ULONG dead_proc_id = XPS(xpm->xpm_address)->xps_server_proc_id;
2001-05-23 15:26:42 +02:00
/* mark all mapped areas connected to server with dead_proc_id */
for (xpm = client_maps; xpm; xpm = xpm->xpm_next) {
if (XPS(xpm->xpm_address)->xps_server_proc_id == dead_proc_id){
xpm->xpm_flags |= XPMF_SERVER_SHUTDOWN;
xpm->xpm_handle = 0;
xpm->xpm_address = NULL;
2003-03-11 06:53:55 +01:00
}
2001-05-23 15:26:42 +02:00
}
XNET_UNLOCK;
2001-05-23 15:26:42 +02:00
}
2003-03-11 06:53:55 +01:00
#endif // WIN_NT
#endif // SUPERCLIENT
2001-05-23 15:26:42 +02:00
static int xdrxnet_create(XDR * xdrs, PORT port, UCHAR * buffer,
USHORT length, enum xdr_op x_op)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* x d r x n e t _ c r e a t e
2001-05-23 15:26:42 +02:00
*
**************************************
*
* Functional description
* Initialize an XDR stream.
2001-05-23 15:26:42 +02:00
*
**************************************/
xdrs->x_public = (caddr_t) port;
xdrs->x_private = (SCHAR *) buffer;
xdrs->x_base = xdrs->x_private;
xdrs->x_handy = length;
xdrs->x_ops = &xnet_ops;
xdrs->x_op = x_op;
return TRUE;
2001-05-23 15:26:42 +02:00
}
static int xnet_destroy( XDR * xdrs)
{
/**************************************
*
* x n e t _ d e s t r o y
*
**************************************
*
* Functional description
* Destroy a stream. A no-op.
*
**************************************/
2003-04-03 11:23:18 +02:00
return 0;
2001-05-23 15:26:42 +02:00
}
2003-04-10 12:31:28 +02:00
static void xnet_gen_error( PORT port, ISC_STATUS status, ...)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* x n e t _ g e n _ e r r o r
*
**************************************
*
* Functional description
* An error has occurred. Mark the port as broken.
* Format the status vector if there is one and
* save the status vector strings in a permanent place.
*
**************************************/
ISC_STATUS *status_vector = NULL;
2001-05-23 15:26:42 +02:00
port->port_flags |= PORT_broken;
port->port_state = state_broken;
2001-05-23 15:26:42 +02:00
if (port->port_context != NULL)
status_vector = port->port_context->rdb_status_vector;
if (status_vector == NULL)
status_vector = port->port_status_vector;
if (status_vector != NULL) {
STUFF_STATUS(status_vector, status)
REMOTE_save_status_strings(status_vector);
2001-05-23 15:26:42 +02:00
}
}
static int xnet_error(PORT port,TEXT * function, ISC_STATUS operation,
int status, ULONG source_line_num)
{
/**************************************
*
* x n e t _ e r r o r
*
**************************************
*
* Functional description
* An I/O error has occurred. If a status vector is present,
* generate an error return. In any case, return NULL, which
* is used to indicate and error.
*
**************************************/
xnet_log_error(source_line_num, function, status);
if (status)
xnet_gen_error(port, operation, SYS_ERR, status, 0);
else
xnet_gen_error(port, operation, 0);
return 0;
}
static bool_t xnet_getbytes(XDR * xdrs, SCHAR * buff, u_int count)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* x n e t _ g e t b y t e s
*
**************************************
*
* Functional description
* Fetch a bunch of bytes from remote interface.
2001-05-23 15:26:42 +02:00
*
**************************************/
2001-05-23 15:26:42 +02:00
SLONG bytecount = count;
SLONG to_copy;
PORT port = (PORT)xdrs->x_public;
XCC xcc = (XCC)port->port_xcc;
XCH xch = (XCH)xcc->xcc_recv_channel;
XPM xpm = xcc->xcc_xpm;
while (bytecount && !xnet_shutdown) {
#ifdef SUPERCLIENT
if (xpm->xpm_flags & XPMF_SERVER_SHUTDOWN) {
if (!(xcc->xcc_flags & XCCF_SERVER_SHUTDOWN)) {
xcc->xcc_flags |= XCCF_SERVER_SHUTDOWN;
XNET_ERROR(port, "connection lost: another side is dead",
isc_lost_db_connection, 0);
}
return FALSE;
}
#endif
2001-05-23 15:26:42 +02:00
if (xdrs->x_handy >= bytecount)
to_copy = bytecount;
else
to_copy = xdrs->x_handy;
if (xdrs->x_handy) {
if (to_copy == sizeof(SLONG))
*((SLONG*)buff) = *((SLONG*)xdrs->x_private);
else
memcpy(buff, xdrs->x_private,to_copy);
xdrs->x_handy -= to_copy;
xdrs->x_private += to_copy;
}
else {
THREAD_EXIT;
if (!xnet_read(xdrs)) {
THREAD_ENTER;
return FALSE;
};
THREAD_ENTER;
}
if (to_copy) {
bytecount -= to_copy;
buff += to_copy;
}
2001-05-23 15:26:42 +02:00
}
if (xnet_shutdown)
return FALSE;
else
return TRUE;
2001-05-23 15:26:42 +02:00
}
static bool_t xnet_getlong(XDR * xdrs, SLONG * lp)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* x n e t _ g e t l o n g
*
**************************************
*
* Functional description
* Fetch a longword from memory stream.
2001-05-23 15:26:42 +02:00
*
**************************************/
return (*xdrs->x_ops->x_getbytes) (xdrs, reinterpret_cast<SCHAR*>(lp), 4);
2001-05-23 15:26:42 +02:00
}
static u_int xnet_getpostn(XDR * xdrs)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* x n e t _ g e t p o s t n
*
**************************************
*
* Functional description
* Get the current position (which is also current length) from stream.
*
**************************************/
return (u_int) (xdrs->x_private - xdrs->x_base);
}
static caddr_t xnet_inline(XDR * xdrs, u_int bytecount)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* x n e t _ i n l i n e
*
**************************************
*
* Functional description
* Return a pointer to somewhere in the buffer.
*
**************************************/
if (bytecount > (u_int) xdrs->x_handy)
return FALSE;
2001-05-23 15:26:42 +02:00
return xdrs->x_base + bytecount;
}
static bool_t xnet_putbytes(XDR* xdrs, const SCHAR* buff, u_int count)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* x n e t _ p u t b y t e s
*
**************************************
*
* Functional description
* Put a bunch of bytes into a memory stream.
2001-05-23 15:26:42 +02:00
*
**************************************/
SLONG bytecount = count;
SLONG to_copy;
DWORD wait_result;
PORT port = (PORT)xdrs->x_public;
XCC xcc = (XCC)port->port_xcc;
XCH xch = (XCH)xcc->xcc_send_channel;
XPM xpm = xcc->xcc_xpm;
2001-05-23 15:26:42 +02:00
while (bytecount && !xnet_shutdown) {
#ifdef SUPERCLIENT
if (xpm->xpm_flags & XPMF_SERVER_SHUTDOWN) {
if (!(xcc->xcc_flags & XCCF_SERVER_SHUTDOWN)) {
xcc->xcc_flags |= XCCF_SERVER_SHUTDOWN;
XNET_ERROR(port, "connection lost: another side is dead",
isc_lost_db_connection, 0);
}
return FALSE;
}
#endif
2001-05-23 15:26:42 +02:00
if (xdrs->x_handy >= bytecount)
to_copy = bytecount;
else
to_copy = xdrs->x_handy;
if (xdrs->x_handy) {
2003-09-14 02:26:30 +02:00
if ((ULONG) xdrs->x_handy == xch->xch_size) {
THREAD_EXIT;
while(!xnet_shutdown) {
wait_result = WaitForSingleObject(xcc->xcc_event_send_channel_empted,
XNET_SEND_WAIT_TIMEOUT);
if (wait_result == WAIT_OBJECT_0)
break;
if (wait_result == WAIT_TIMEOUT) {
/* Check if another side is alive */
if (WaitForSingleObject(xcc->xcc_proc_h,1) == WAIT_TIMEOUT)
continue; /* Another side is alive */
else {
/* Another side is dead or somthing bad has happaned*/
#ifdef SUPERCLIENT
xnet_on_server_shutdown(port);
XNET_ERROR(port, "connection lost: another side is dead",
isc_lost_db_connection, 0);
2001-05-23 15:26:42 +02:00
#else
XNET_ERROR(port, "connection lost: another side is dead",
isc_conn_lost, 0);
2001-05-23 15:26:42 +02:00
#endif
THREAD_ENTER;
return FALSE;
}
}
else {
XNET_ERROR(port, "WaitForSingleObject()", isc_net_write_err, ERRNO);
THREAD_ENTER;
return FALSE; /* a non-timeout result is an error */
}
2001-05-23 15:26:42 +02:00
}
THREAD_ENTER;
2001-05-23 15:26:42 +02:00
}
if (to_copy == sizeof(SLONG))
*((SLONG*)xdrs->x_private) = *((SLONG*)buff);
else
memcpy(xdrs->x_private, buff, to_copy);
2001-05-23 15:26:42 +02:00
xdrs->x_handy -= to_copy;
xdrs->x_private += to_copy;
}
else {
if (!xnet_write(xdrs)) {
XNET_ERROR(port, "SetEvent()", isc_net_write_err, ERRNO);
return FALSE;
}
}
if (to_copy) {
bytecount -= to_copy;
buff += to_copy;
2001-05-23 15:26:42 +02:00
}
}
if (xnet_shutdown)
return FALSE;
else
return TRUE;
2001-05-23 15:26:42 +02:00
}
static bool_t xnet_putlong(XDR * xdrs, SLONG * lp)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* x n e t _ p u t l o n g
*
**************************************
*
* Functional description
* Fit a longword into a memory stream if it fits.
2001-05-23 15:26:42 +02:00
*
**************************************/
return (*xdrs->x_ops->x_putbytes) (xdrs, reinterpret_cast<SCHAR*>(AOF32L(*lp)), 4);
2001-05-23 15:26:42 +02:00
}
static bool_t xnet_read(XDR * xdrs)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* x n e t _ r e a d
*
**************************************
*
* Functional description
* Read a buffer full of data.
2001-05-23 15:26:42 +02:00
*
**************************************/
DWORD wait_result;
PORT port = (PORT)xdrs->x_public;
XCC xcc = (XCC)port->port_xcc;
XCH xch = (XCH)xcc->xcc_recv_channel;
XPM xpm = xcc->xcc_xpm;
2001-05-23 15:26:42 +02:00
if (xnet_shutdown)
2001-05-23 15:26:42 +02:00
return FALSE;
if (!SetEvent(xcc->xcc_event_recv_channel_empted)) {
XNET_ERROR(port, "SetEvent()", isc_net_read_err, ERRNO);
return FALSE;
}
while (!xnet_shutdown) {
#ifdef SUPERCLIENT
if (xpm->xpm_flags & XPMF_SERVER_SHUTDOWN) {
if (!(xcc->xcc_flags & XCCF_SERVER_SHUTDOWN)) {
xcc->xcc_flags |= XCCF_SERVER_SHUTDOWN;
XNET_ERROR(port, "connection lost: another side is dead",
isc_lost_db_connection, 0);
}
}
#endif
wait_result = WaitForSingleObject(xcc->xcc_event_recv_channel_filled,
XNET_RECV_WAIT_TIMEOUT);
if (wait_result == WAIT_OBJECT_0) {
/* Client wrote some data for us(for server) to read*/
xdrs->x_handy = xch->xch_length;
xdrs->x_private = xdrs->x_base;
return TRUE;
}
if (wait_result == WAIT_TIMEOUT) {
/* Check if another side is alive */
if (WaitForSingleObject(xcc->xcc_proc_h,1) == WAIT_TIMEOUT)
continue; /* Another side is alive */
else {
/* Another side is dead or somthing bad has happaned*/
#ifdef SUPERCLIENT
xnet_on_server_shutdown(port);
XNET_ERROR(port, "connection lost: another side is dead",
isc_lost_db_connection, 0);
#else
XNET_ERROR(port, "connection lost: another side is dead",
isc_conn_lost, 0);
#endif
return FALSE;
}
}
else {
XNET_ERROR(port, "WaitForSingleObject()", isc_net_read_err, ERRNO);
return FALSE; /* a non-timeout result is an error */
}
}
return FALSE;
2001-05-23 15:26:42 +02:00
}
static bool_t xnet_write(XDR * xdrs)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* x n e t _ w r i t e
2001-05-23 15:26:42 +02:00
*
**************************************
*
* Functional description
* Signal remote interface that memory stream is
* filled and ready for reading.
2001-05-23 15:26:42 +02:00
*
**************************************/
PORT port = (PORT)xdrs->x_public;
XCC xcc = (XCC)(port)->port_xcc;
XCH xch = (XCH)xcc->xcc_send_channel;
2001-05-23 15:26:42 +02:00
xch->xch_length = xdrs->x_private - xdrs->x_base;
if (SetEvent(xcc->xcc_event_send_channel_filled)) {
port->port_misc1 = (port->port_misc1 + 1) % MAX_SEQUENCE;
xdrs->x_private = xdrs->x_base;
xdrs->x_handy = xch->xch_size;
return TRUE;
}
else
2001-05-23 15:26:42 +02:00
return FALSE;
2001-05-23 15:26:42 +02:00
}
static bool_t xnet_setpostn(XDR * xdrs, u_int bytecount)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* x n e t _ s e t p o s t n
2001-05-23 15:26:42 +02:00
*
**************************************
*
* Functional description
* Set the current position (which is also current length) from stream.
2001-05-23 15:26:42 +02:00
*
**************************************/
if (bytecount > (u_int) xdrs->x_handy)
2001-05-23 15:26:42 +02:00
return FALSE;
xdrs->x_private = xdrs->x_base + bytecount;
2001-05-23 15:26:42 +02:00
return TRUE;
}
void xnet_release_all()
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* x n e t _ r e l e a s e _ a l l
2001-05-23 15:26:42 +02:00
*
**************************************
*
* Functional description
* Release all connections and dependant stuff.
*
**************************************/
if (!xnet_initialized)
2001-05-23 15:26:42 +02:00
return;
XPM xpm, nextxpm;
#ifndef SUPERCLIENT
xnet_connect_fini();
#endif
THD_mutex_lock(&xnet_mutex);
/* release all map stuf left not released by broken ports */
for (xpm = nextxpm = client_maps; nextxpm; xpm = nextxpm) {
nextxpm = nextxpm->xpm_next;
UnmapViewOfFile(xpm->xpm_address);
CloseHandle(xpm->xpm_handle);
ALLR_free((UCHAR *) xpm);
}
2001-05-23 15:26:42 +02:00
client_maps = NULL;
THD_mutex_unlock(&xnet_mutex);
#if defined(SUPERSERVER) || defined(SUPERCLIENT)
THD_mutex_destroy(&xnet_mutex);
#endif
xnet_initialized = FALSE;
}
/***********************************************************************/
/********************** ONLY SERVER CODE FROM HERE *********************/
/***********************************************************************/
#ifndef SUPERCLIENT
static bool_t xnet_srv_init()
{
/**************************************
*
* X N E T _ s r v _ i n i t
*
**************************************
*
* Functional description
* Initialization of server side resources used
* when clients perform connect to server
*
**************************************/
TEXT name_buffer[128];
// init the limits
#ifdef SUPERSERVER
slots_per_map = XPS_MAX_NUM_CLI;
pages_per_slot = XPS_MAX_PAGES_PER_CLI;
#else
// For classic server there is always only 1 connection and 1 slot
slots_per_map = 1;
pages_per_slot = XPS_MAX_PAGES_PER_CLI;
#endif
xnet_connect_mutex = 0;
xnet_connect_map_h = 0;
xnet_connect_map = 0;
xnet_connect_event = 0;
xnet_response_event = 0;
THD_mutex_init(&xnet_mutex);
try {
sprintf(name_buffer, XNET_MU_CONNECT_MUTEX, XNET_PREFIX);
xnet_connect_mutex =
CreateMutex(ISC_get_security_desc(), FALSE, name_buffer);
if (!xnet_connect_mutex || (xnet_connect_mutex && ERRNO == ERROR_ALREADY_EXISTS)) {
throw -1;
}
sprintf(name_buffer, XNET_E_CONNECT_EVENT, XNET_PREFIX);
xnet_connect_event =
CreateEvent(ISC_get_security_desc(), FALSE, FALSE, name_buffer);
if (!xnet_connect_event || (xnet_connect_event && ERRNO == ERROR_ALREADY_EXISTS)) {
throw -1;
}
sprintf(name_buffer, XNET_E_RESPONSE_EVENT, XNET_PREFIX);
xnet_response_event =
CreateEvent(ISC_get_security_desc(), FALSE, FALSE, name_buffer);
if (!xnet_response_event || (xnet_response_event && ERRNO == ERROR_ALREADY_EXISTS)) {
throw -1;
}
sprintf(name_buffer, XNET_MA_CONNECT_MAP, XNET_PREFIX);
xnet_connect_map_h = CreateFileMapping((HANDLE)0xFFFFFFFF,
ISC_get_security_desc(),
PAGE_READWRITE,
0,
XNET_CONNECT_RESPONZE_SIZE,
name_buffer);
if (!xnet_connect_map_h || (xnet_connect_map_h && ERRNO == ERROR_ALREADY_EXISTS)) {
throw -1;
}
xnet_connect_map = MapViewOfFile(xnet_connect_map_h, FILE_MAP_WRITE, 0L, 0L,
XNET_CONNECT_RESPONZE_SIZE);
if (!xnet_connect_map) {
throw -1;
}
return TRUE;
}
catch (...) {
xnet_connect_fini();
return FALSE;
2001-05-23 15:26:42 +02:00
}
}
#ifndef SUPERSERVER
static bool_t xnet_fork(ULONG client_pid, USHORT flag, ULONG* forken_pid)
{
/**************************************
*
* x n e t _ f o r k
*
**************************************
*
* Functional description
* Create child process to serve client connection
* It's for classic server only
*
**************************************/
STARTUPINFO start_crud;
PROCESS_INFORMATION pi;
bool_t cp_result;
if (!XNET_command_line[0]) {
#ifdef CMDLINE_VIA_SERVICE_MANAGER
SC_HANDLE manager, service;
if ((manager = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT)) &&
(service = OpenService(manager, REMOTE_SERVICE, SERVICE_QUERY_CONFIG))) {
LPQUERY_SERVICE_CONFIG config;
SCHAR buffer[1024];
DWORD config_len;
config = (LPQUERY_SERVICE_CONFIG) buffer;
THREAD_EXIT;
if (!QueryServiceConfig(service, config, sizeof(buffer), &config_len)) {
config = (LPQUERY_SERVICE_CONFIG) ALLR_alloc(config_len);
/* NOMEM: ALLR_alloc handled */
/* FREE: later in this block */
QueryServiceConfig(service, config, config_len, &config_len);
}
strcpy(XNET_command_line, config->lpBinaryPathName);
if ((SCHAR *) config != buffer) {
ALLR_free(config);
}
CloseServiceHandle(service);
THREAD_ENTER;
}
else {
strcpy(XNET_command_line, GetCommandLine());
}
CloseServiceHandle(manager);
#else
strcpy(XNET_command_line, GetCommandLine());
2001-05-23 15:26:42 +02:00
#endif
XNET_p = XNET_command_line + strlen(XNET_command_line);
}
2003-09-14 02:26:30 +02:00
sprintf(XNET_p, " -s -x -h %"ULONGFORMAT, (ULONG) client_pid);
start_crud.cb = sizeof(STARTUPINFO);
start_crud.lpReserved = NULL;
start_crud.lpReserved2 = NULL;
start_crud.cbReserved2 = 0;
start_crud.lpDesktop = NULL;
start_crud.lpTitle = NULL;
start_crud.dwFlags = STARTF_FORCEOFFFEEDBACK;
cp_result = CreateProcess(NULL,
XNET_command_line,
NULL,
NULL,
TRUE,
(flag & SRVR_high_priority ? HIGH_PRIORITY_CLASS : NORMAL_PRIORITY_CLASS)
|DETACHED_PROCESS | CREATE_SUSPENDED | STARTF_FORCEOFFFEEDBACK,
NULL, NULL, &start_crud, &pi);
// Child process ID (forken_pid) used as map number
if (cp_result) {
*forken_pid = pi.dwProcessId;
ResumeThread(pi.hThread);
CloseHandle(pi.hThread);
CloseHandle(pi.hProcess);
}
else
XNET_LOG_ERRORC("CreateProcess() failed");
return cp_result;
}
#endif // SUPERSERVER
#ifdef SUPERSERVER
static XPM xnet_get_free_slot(ULONG* map_num, ULONG* slot_num, time_t* timestamp)
{
/**************************************
*
* x n e t _ g e t _ f r e e _ s l o t
*
**************************************
*
* Functional description
* Search for free slot in map stuff
*
**************************************/
XPM xpm = NULL;
ULONG i = 0, j = 0;
/* go through list of maps */
for (xpm = client_maps; xpm; xpm = xpm->xpm_next) {
/* find an available unused comm area */
for (i = 0; i < slots_per_map; i++)
if (xpm->xpm_ids[i] == XPM_FREE)
break;
if (i < slots_per_map) {
xpm->xpm_count++;
xpm->xpm_ids[i] = XPM_BUSY;
j = xpm->xpm_number;
break;
}
j++;
}
/* if the mapped file structure has not yet been initialized,
make one now */
if (!xpm) {
/* allocate new map file and first slot */
2001-05-23 15:26:42 +02:00
xpm = xnet_make_xpm(j, *timestamp);
2001-05-23 15:26:42 +02:00
/* check for errors in creation of mapped file */
if (!xpm) {
XNET_UNLOCK;
return NULL;
2003-03-11 06:53:55 +01:00
}
i = 0;
xpm->xpm_ids[0] = XPM_BUSY;
xpm->xpm_count++;
2003-03-11 06:53:55 +01:00
}
else
*timestamp = xpm->xpm_timestamp;
2001-05-23 15:26:42 +02:00
*map_num = j;
*slot_num = i;
2001-05-23 15:26:42 +02:00
return xpm;
}
2001-05-23 15:26:42 +02:00
#endif // SUPERSERVER
static PORT xnet_get_srv_port(ULONG client_pid, XPM xpm,
ULONG map_num, ULONG slot_num,
time_t timestamp,
ISC_STATUS* status_vector)
{
/**************************************
*
* X N E T _ g e t s r v _ p o r t
*
**************************************
*
* Functional description
* Allocates new PORT for server side communication .
*
**************************************/
XCC xcc = NULL;
PORT port = NULL;
TEXT name_buffer[128];
UCHAR *p;
XPS xps;
ULONG avail;
// allocate a communications control structure and fill it in
if (!(xcc = (XCC) ALLR_alloc(sizeof(struct xcc))))
return NULL;
try {
p = (UCHAR *) xpm->xpm_address + XPS_SLOT_OFFSET(pages_per_slot, slot_num);
memset(p, (char) 0, XPS_MAPPED_PER_CLI(pages_per_slot));
xcc->xcc_next = NULL;
xcc->xcc_mapped_addr = p;
xcc->xcc_xpm = xpm;
xcc->xcc_slot = slot_num;
xcc->xcc_flags = 0;
// Open client process handle to watch clients health during communication session
xcc->xcc_proc_h = OpenProcess(SYNCHRONIZE, 0, client_pid);
if (!xcc->xcc_proc_h) {
throw -1;
}
xcc->xcc_map_num = map_num;
xps = (XPS) xcc->xcc_mapped_addr;
xps->xps_client_proc_id = client_pid;
#ifdef WIN_NT
xps->xps_server_proc_id = CurrentProcessId;
#else
// STUB : need something special for Solaris? I don't think so.
xps->xps_server_proc_id = getpid();
#endif
// make sure client knows what this server speaks
xps->xps_server_protocol = XPI_SERVER_PROTOCOL_VERSION;
xps->xps_client_protocol = 0L;
2001-05-23 15:26:42 +02:00
#ifdef WIN_NT
sprintf(name_buffer, XNET_E_C2S_DATA_CHAN_FILLED,
XNET_PREFIX, map_num, slot_num, (ULONG) timestamp);
xcc->xcc_event_recv_channel_filled =
CreateEvent(ISC_get_security_desc(), FALSE, FALSE, name_buffer);
if (!xcc->xcc_event_recv_channel_filled) {
throw -1;
2003-03-11 06:53:55 +01:00
}
sprintf(name_buffer, XNET_E_C2S_DATA_CHAN_EMPTED,
XNET_PREFIX, map_num, slot_num, (ULONG) timestamp);
xcc->xcc_event_recv_channel_empted =
CreateEvent(ISC_get_security_desc(), FALSE, FALSE, name_buffer);
if (!xcc->xcc_event_recv_channel_empted) {
throw -1;
2003-03-11 06:53:55 +01:00
}
sprintf(name_buffer, XNET_E_S2C_DATA_CHAN_FILLED,
XNET_PREFIX, map_num, slot_num, (ULONG) timestamp);
xcc->xcc_event_send_channel_filled =
CreateEvent(ISC_get_security_desc(), FALSE, FALSE, name_buffer);
if (!xcc->xcc_event_send_channel_filled) {
throw -1;
}
sprintf(name_buffer, XNET_E_S2C_DATA_CHAN_EMPTED,
XNET_PREFIX, map_num, slot_num, (ULONG) timestamp);
xcc->xcc_event_send_channel_empted =
CreateEvent(ISC_get_security_desc(), FALSE, FALSE, name_buffer);
if (!xcc->xcc_event_send_channel_empted) {
throw -1;
2003-03-11 06:53:55 +01:00
}
2001-05-23 15:26:42 +02:00
#else
// STUB : add create events here
2001-05-23 15:26:42 +02:00
#endif
// set up the channel structures
p += sizeof(struct xps);
avail = (USHORT) (XPS_USEFUL_SPACE(pages_per_slot) - (XNET_EVENT_SPACE * 2)) / 2;
xps->xps_channels[XPS_CHANNEL_C2S_EVENTS].xch_buffer = p; /* client to server events */
xps->xps_channels[XPS_CHANNEL_C2S_EVENTS].xch_size = XNET_EVENT_SPACE;
p += XNET_EVENT_SPACE;
xps->xps_channels[XPS_CHANNEL_S2C_EVENTS].xch_buffer = p; /* server to client events */
xps->xps_channels[XPS_CHANNEL_S2C_EVENTS].xch_size = XNET_EVENT_SPACE;
p += XNET_EVENT_SPACE;
xps->xps_channels[XPS_CHANNEL_C2S_DATA].xch_buffer = p; /* client to server data */
xps->xps_channels[XPS_CHANNEL_C2S_DATA].xch_size = avail;
p += avail;
xps->xps_channels[XPS_CHANNEL_S2C_DATA].xch_buffer = p; /* server to client data */
xps->xps_channels[XPS_CHANNEL_S2C_DATA].xch_size = avail;
xcc->xcc_recv_channel = &xps->xps_channels[XPS_CHANNEL_C2S_DATA];
xcc->xcc_send_channel = &xps->xps_channels[XPS_CHANNEL_S2C_DATA];
/* finally, allocate and set the port structure for this client */
port = xnet_alloc_port(0,
xcc->xcc_send_channel->xch_buffer,
xcc->xcc_send_channel->xch_size,
xcc->xcc_recv_channel->xch_buffer,
xcc->xcc_recv_channel->xch_size);
if (port) {
port->port_xcc = (void *) xcc;
port->port_server_flags |= SRVR_server;
2003-11-08 17:40:17 +01:00
status_vector[0] = isc_arg_gds;
status_vector[1] = FB_SUCCESS;
2003-11-08 17:40:17 +01:00
status_vector[2] = isc_arg_end;
port->port_status_vector = status_vector;
}
else {
throw -1;
}
gds__register_cleanup((FPTR_VOID_PTR) exit_handler, port);
}
catch (...) {
if (xcc) {
if (xcc->xcc_proc_h) {
CloseHandle(xcc->xcc_proc_h);
}
if (xcc->xcc_event_recv_channel_filled) {
CloseHandle(xcc->xcc_event_recv_channel_filled);
}
if (xcc->xcc_event_recv_channel_empted) {
CloseHandle(xcc->xcc_event_recv_channel_empted);
}
if (xcc->xcc_event_send_channel_filled) {
CloseHandle(xcc->xcc_event_send_channel_filled);
}
if (xcc->xcc_event_send_channel_empted) {
CloseHandle(xcc->xcc_event_send_channel_empted);
}
ALLR_free(xcc);
}
return NULL;
2001-05-23 15:26:42 +02:00
}
return port;
}
void XNET_srv(USHORT flag)
{
/**************************************
*
* X N E T _ s r v
*
**************************************
*
* Functional description
* XNET server main thread
*
**************************************/
2001-05-23 15:26:42 +02:00
#ifdef WIN_NT
#ifdef SUPERSERVER
PORT port;
ULONG map_num, slot_num;
XPM xpm;
ISC_STATUS* status_vector;
#endif
DWORD wait_res;
ULONG client_pid;
PXNET_RESPONSE presponse;
CurrentProcessId = GetCurrentProcessId();
XNET_command_line[0] = 0;
if (xnet_srv_init()) {
xnet_initialized = TRUE;
gds__register_cleanup((FPTR_VOID_PTR) exit_handler, NULL);
}
else {
XNET_LOG_ERROR("XNET server initialization failed");
return;
}
presponse = (PXNET_RESPONSE)xnet_connect_map;
while (!xnet_shutdown) {
// mark connect area as untouched
// presponse->proc_id = CurrentProcessId;
THREAD_EXIT;
wait_res = WaitForSingleObject(xnet_connect_event,INFINITE);
THREAD_ENTER;
if (wait_res != WAIT_OBJECT_0) {
XNET_LOG_ERRORC("WaitForSingleObject() failed");
break;
}
if (xnet_shutdown)
break;
// read client process id
if ((client_pid = presponse->proc_id) == CurrentProcessId)
continue; // dummy xnet_connect_event fire - no connect request
presponse->slots_per_map = slots_per_map;
presponse->pages_per_slot = pages_per_slot;
presponse->timestamp = time_t(0);
#ifdef SUPERSERVER
2003-10-08 10:42:48 +02:00
time_t timestamp = time(NULL);
// searhing for free slot
XNET_LOCK;
xpm = xnet_get_free_slot(&map_num, &slot_num, &timestamp);
XNET_UNLOCK;
// pack combined mapped area and number
if (xpm) {
presponse->proc_id = CurrentProcessId;
presponse->map_num = map_num;
presponse->slot_num = slot_num;
presponse->timestamp = timestamp;
status_vector = (ISC_STATUS*) ALLR_alloc(ISC_STATUS_LENGTH);
port = xnet_get_srv_port(client_pid, xpm, map_num, slot_num,
timestamp, status_vector);
}
else {
XNET_LOG_ERROR("xnet_get_free_slot() failed");
}
if (xpm && port) {
// start the thread for this client
gds__thread_start(reinterpret_cast<FPTR_INT_VOID_PTR>(process_connection_thread),
port, THREAD_medium, 0, 0);
}
else {
XNET_LOG_ERROR("failed to allocate server port for communication");
}
SetEvent(xnet_response_event);
#else // CS
// in case process we'll fail to start child process
presponse->slot_num = 0;
// child process ID (presponse->map_num) used as map number
if (!xnet_fork(client_pid, flag, &(presponse->map_num)))
SetEvent(xnet_response_event);// if xnet_fork successfully creats child process
// child process will call SetEvent(xnet_response_event)
// by itself
#endif //SUPERSERVER
}
2001-05-23 15:26:42 +02:00
#else
#endif // WIN_NT
}
PORT XNET_reconnect(ULONG client_pid, ISC_STATUS* status_vector)
{
/**************************************
*
* X N E T _ r e c o n n e c t
*
**************************************
*
* Functional description
* Classic server initialization code
*
**************************************/
PORT port = NULL;
XPM xpm = NULL;
TEXT name_buffer[128];
slots_per_map = 1;
pages_per_slot = XPS_MAX_PAGES_PER_CLI;
xnet_response_event = 0;
// CurrentProcessId used as map number
CurrentProcessId = GetCurrentProcessId();
try {
sprintf(name_buffer, XNET_E_RESPONSE_EVENT, XNET_PREFIX);
xnet_response_event = OpenEvent(EVENT_ALL_ACCESS, FALSE, name_buffer);
if (!xnet_response_event) {
throw -1;
2001-05-23 15:26:42 +02:00
}
xpm = xnet_make_xpm(CurrentProcessId, time_t(0));
if (!xpm) {
throw -1;
}
port = xnet_get_srv_port(client_pid, xpm, CurrentProcessId, 0, 0,status_vector);
if (!port) {
throw -1;
}
//make signal for client
SetEvent(xnet_response_event);
if (xnet_response_event) {
CloseHandle(xnet_response_event);
}
2001-05-23 15:26:42 +02:00
}
catch (...) {
XNET_LOG_ERROR("Unable to initialize child process");
status_vector[1] = isc_unavailable;
if (port) {
xnet_cleanup_port(port);
port = NULL;
}
if (xnet_response_event) {
SetEvent(xnet_response_event); // To prevent client blocking
CloseHandle(xnet_response_event);
}
}
return port;
2001-05-23 15:26:42 +02:00
}
#endif // SUPERCLIENT