mirror of
https://github.com/FirebirdSQL/firebird.git
synced 2025-01-27 05:23:02 +01:00
906 lines
25 KiB
C++
906 lines
25 KiB
C++
/*
|
|
* PROGRAM: JRD Remote Interface/Server
|
|
* MODULE: remote.h
|
|
* DESCRIPTION: Common descriptions
|
|
*
|
|
* 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.29 Sean Leyne - Removed obsolete "Netware" port
|
|
*
|
|
* 2002.10.30 Sean Leyne - Removed support for obsolete "PC_PLATFORM" define
|
|
*
|
|
*/
|
|
|
|
#ifndef REMOTE_REMOTE_H
|
|
#define REMOTE_REMOTE_H
|
|
|
|
#include "../jrd/common.h"
|
|
#include "gen/iberror.h"
|
|
#include "../remote/remote_def.h"
|
|
#include "../jrd/ThreadData.h"
|
|
#include "../jrd/ThreadStart.h"
|
|
#include "../common/thd.h"
|
|
#include "../common/classes/objects_array.h"
|
|
#include "../auth/trusted/AuthSspi.h"
|
|
#include "../common/classes/fb_string.h"
|
|
#include "../common/classes/ClumpletWriter.h"
|
|
#include "../common/classes/RefMutex.h"
|
|
#include "../common/StatusHolder.h"
|
|
|
|
#if !defined(SUPERCLIENT) && !defined(EMBEDDED)
|
|
#define REM_SERVER
|
|
#endif
|
|
|
|
// Include some apollo include files for tasking
|
|
|
|
#ifndef WIN_NT
|
|
#include <signal.h>
|
|
#include <fcntl.h>
|
|
#include <sys/socket.h>
|
|
#include <sys/ioctl.h>
|
|
#endif // !WIN_NT
|
|
|
|
|
|
// Uncomment this line if you need to trace module activity
|
|
//#define REMOTE_DEBUG
|
|
|
|
#ifdef REMOTE_DEBUG
|
|
DEFINE_TRACE_ROUTINE(remote_trace);
|
|
#define REMOTE_TRACE(args) remote_trace args
|
|
#else
|
|
#define REMOTE_TRACE(args) // nothing
|
|
#endif
|
|
|
|
#ifdef DEV_BUILD
|
|
// Debug packet/XDR memory allocation
|
|
|
|
// Temporarily disabling DEBUG_XDR_MEMORY
|
|
// #define DEBUG_XDR_MEMORY
|
|
|
|
#endif
|
|
|
|
const int BLOB_LENGTH = 16384;
|
|
|
|
#include "../remote/protocol.h"
|
|
#include "fb_blk.h"
|
|
|
|
|
|
// fwd. decl.
|
|
struct rem_port;
|
|
|
|
|
|
typedef Firebird::AutoPtr<UCHAR, Firebird::ArrayDelete<UCHAR> > UCharArrayAutoPtr;
|
|
|
|
|
|
struct Rdb : public Firebird::GlobalStorage, public TypedHandle<rem_type_rdb>
|
|
{
|
|
USHORT rdb_id;
|
|
USHORT rdb_flags;
|
|
FB_API_HANDLE rdb_handle; // database handle
|
|
rem_port* rdb_port; // communication port
|
|
struct Rtr* rdb_transactions; // linked list of transactions
|
|
struct Rrq* rdb_requests; // compiled requests
|
|
struct Rvnt* rdb_events; // known events
|
|
struct Rsr* rdb_sql_requests; // SQL requests
|
|
ISC_STATUS* rdb_status_vector;
|
|
PACKET rdb_packet; // Communication structure
|
|
|
|
public:
|
|
// Values for rdb_flags
|
|
enum {
|
|
SERVICE = 1
|
|
};
|
|
|
|
public:
|
|
Rdb() :
|
|
rdb_id(0), rdb_flags(0), rdb_handle(0),
|
|
rdb_port(0), rdb_transactions(0), rdb_requests(0),
|
|
rdb_events(0), rdb_sql_requests(0), rdb_status_vector(0)
|
|
{
|
|
}
|
|
|
|
static ISC_STATUS badHandle() { return isc_bad_db_handle; }
|
|
};
|
|
|
|
|
|
struct Rtr : public Firebird::GlobalStorage, public TypedHandle<rem_type_rtr>
|
|
{
|
|
Rdb* rtr_rdb;
|
|
Rtr* rtr_next;
|
|
struct Rbl* rtr_blobs;
|
|
FB_API_HANDLE rtr_handle;
|
|
USHORT rtr_id;
|
|
bool rtr_limbo;
|
|
|
|
public:
|
|
Rtr() :
|
|
rtr_rdb(0), rtr_next(0), rtr_blobs(0),
|
|
rtr_handle(0), rtr_id(0), rtr_limbo(0)
|
|
{ }
|
|
|
|
static ISC_STATUS badHandle() { return isc_bad_trans_handle; }
|
|
};
|
|
|
|
|
|
struct Rbl : public Firebird::GlobalStorage, public TypedHandle<rem_type_rbl>
|
|
{
|
|
Firebird::HalfStaticArray<UCHAR, BLOB_LENGTH> rbl_data;
|
|
Rdb* rbl_rdb;
|
|
Rtr* rbl_rtr;
|
|
Rbl* rbl_next;
|
|
UCHAR* rbl_buffer;
|
|
UCHAR* rbl_ptr;
|
|
FB_API_HANDLE rbl_handle;
|
|
SLONG rbl_offset; // Apparent (to user) offset in blob
|
|
USHORT rbl_id;
|
|
USHORT rbl_flags;
|
|
USHORT rbl_buffer_length;
|
|
USHORT rbl_length;
|
|
USHORT rbl_fragment_length;
|
|
USHORT rbl_source_interp; // source interp (for writing)
|
|
USHORT rbl_target_interp; // destination interp (for reading)
|
|
|
|
public:
|
|
// Values for rbl_flags
|
|
enum {
|
|
EOF_SET = 1,
|
|
SEGMENT = 2,
|
|
EOF_PENDING = 4,
|
|
CREATE = 8
|
|
};
|
|
|
|
public:
|
|
Rbl() :
|
|
rbl_data(getPool()), rbl_rdb(0), rbl_rtr(0), rbl_next(0),
|
|
rbl_buffer(rbl_data.getBuffer(BLOB_LENGTH)), rbl_ptr(rbl_buffer), rbl_handle(0),
|
|
rbl_offset(0), rbl_id(0), rbl_flags(0),
|
|
rbl_buffer_length(BLOB_LENGTH), rbl_length(0), rbl_fragment_length(0),
|
|
rbl_source_interp(0), rbl_target_interp(0)
|
|
{ }
|
|
|
|
static ISC_STATUS badHandle() { return isc_bad_segstr_handle; }
|
|
};
|
|
|
|
|
|
struct Rvnt : public Firebird::GlobalStorage
|
|
{
|
|
Rvnt* rvnt_next;
|
|
Rdb* rvnt_rdb;
|
|
FPTR_EVENT_CALLBACK rvnt_ast;
|
|
void* rvnt_arg;
|
|
SLONG rvnt_id;
|
|
SLONG rvnt_rid; // used by server to store client-side id
|
|
rem_port* rvnt_port; // used to id server from whence async came
|
|
const UCHAR* rvnt_items;
|
|
USHORT rvnt_length;
|
|
|
|
public:
|
|
Rvnt() :
|
|
rvnt_next(0), rvnt_rdb(0), rvnt_ast(0),
|
|
rvnt_arg(0), rvnt_id(0), rvnt_rid(0),
|
|
rvnt_port(0), rvnt_items(0), rvnt_length(0)
|
|
{ }
|
|
};
|
|
|
|
|
|
struct rem_str : public pool_alloc_rpt<SCHAR>
|
|
{
|
|
USHORT str_length;
|
|
SCHAR str_data[2];
|
|
};
|
|
|
|
|
|
// Include definition of descriptor
|
|
|
|
#include "../jrd/dsc.h"
|
|
|
|
|
|
struct rem_fmt : public Firebird::GlobalStorage
|
|
{
|
|
USHORT fmt_length;
|
|
USHORT fmt_net_length;
|
|
USHORT fmt_count;
|
|
USHORT fmt_version;
|
|
Firebird::Array<dsc> fmt_desc;
|
|
|
|
public:
|
|
explicit rem_fmt(size_t rpt) :
|
|
fmt_length(0), fmt_net_length(0), fmt_count(0),
|
|
fmt_version(0), fmt_desc(getPool(), rpt)
|
|
{
|
|
fmt_desc.grow(rpt);
|
|
}
|
|
};
|
|
|
|
// Windows declares a msg structure, so rename the structure
|
|
// to avoid overlap problems.
|
|
|
|
struct RMessage : public Firebird::GlobalStorage
|
|
{
|
|
RMessage* msg_next; // Next available message
|
|
USHORT msg_number; // Message number
|
|
UCHAR* msg_address; // Address of message
|
|
UCharArrayAutoPtr msg_buffer; // Allocated message
|
|
|
|
public:
|
|
explicit RMessage(size_t rpt) :
|
|
msg_next(0), msg_number(0), msg_address(0), msg_buffer(FB_NEW(getPool()) UCHAR[rpt])
|
|
{
|
|
memset(msg_buffer, 0, rpt);
|
|
}
|
|
};
|
|
|
|
|
|
// remote stored procedure request
|
|
struct Rpr : public Firebird::GlobalStorage
|
|
{
|
|
Rdb* rpr_rdb;
|
|
Rtr* rpr_rtr;
|
|
FB_API_HANDLE rpr_handle;
|
|
RMessage* rpr_in_msg; // input message
|
|
RMessage* rpr_out_msg; // output message
|
|
rem_fmt* rpr_in_format; // Format of input message
|
|
rem_fmt* rpr_out_format; // Format of output message
|
|
|
|
public:
|
|
Rpr() :
|
|
rpr_rdb(0), rpr_rtr(0), rpr_handle(0),
|
|
rpr_in_msg(0), rpr_out_msg(0), rpr_in_format(0), rpr_out_format(0)
|
|
{ }
|
|
};
|
|
|
|
struct Rrq : public Firebird::GlobalStorage, public TypedHandle<rem_type_rrq>
|
|
{
|
|
Rdb* rrq_rdb;
|
|
Rtr* rrq_rtr;
|
|
Rrq* rrq_next;
|
|
Rrq* rrq_levels; // RRQ block for next level
|
|
FB_API_HANDLE rrq_handle;
|
|
USHORT rrq_id;
|
|
USHORT rrq_max_msg;
|
|
USHORT rrq_level;
|
|
ISC_STATUS_ARRAY rrq_status_vector;
|
|
|
|
struct rrq_repeat
|
|
{
|
|
rem_fmt* rrq_format; // format for this message
|
|
RMessage* rrq_message; // beginning or end of cache, depending on whether it is client or server
|
|
RMessage* rrq_xdr; // point at which cache is read or written by xdr
|
|
USHORT rrq_msgs_waiting; // count of full rrq_messages
|
|
USHORT rrq_rows_pending; // How many rows in waiting
|
|
USHORT rrq_reorder_level; // Reorder when rows_pending < this level
|
|
USHORT rrq_batch_count; // Count of batches in pipeline
|
|
|
|
};
|
|
Firebird::Array<rrq_repeat> rrq_rpt;
|
|
|
|
public:
|
|
explicit Rrq(size_t rpt) :
|
|
rrq_rdb(0), rrq_rtr(0), rrq_next(0), rrq_levels(0),
|
|
rrq_handle(0), rrq_id(0), rrq_max_msg(0), rrq_level(0),
|
|
rrq_rpt(getPool(), rpt)
|
|
{
|
|
memset(rrq_status_vector, 0, sizeof rrq_status_vector);
|
|
rrq_rpt.grow(rpt);
|
|
}
|
|
|
|
Rrq* clone() const
|
|
{
|
|
Rrq* rc = new Rrq(rrq_rpt.getCount());
|
|
*rc = *this;
|
|
return rc;
|
|
}
|
|
|
|
static ISC_STATUS badHandle() { return isc_bad_req_handle; }
|
|
};
|
|
|
|
|
|
template <typename T>
|
|
class RFlags
|
|
{
|
|
public:
|
|
RFlags() :
|
|
m_flags(0)
|
|
{
|
|
// Require base flags field to be unsigned.
|
|
// This is a compile-time assertion; it won't build if you use a signed flags field.
|
|
typedef int dummy[T(-1) > 0];
|
|
}
|
|
explicit RFlags(const T flags) :
|
|
m_flags(flags)
|
|
{}
|
|
// At least one bit in the parameter is 1 in the object.
|
|
bool test(const T flags) const
|
|
{
|
|
return m_flags & flags;
|
|
}
|
|
// All bits received as parameter are 1 in the object.
|
|
bool testAll(const T flags) const
|
|
{
|
|
return (m_flags & flags) == flags;
|
|
}
|
|
void set(const T flags)
|
|
{
|
|
m_flags |= flags;
|
|
}
|
|
void clear(const T flags)
|
|
{
|
|
m_flags &= ~flags;
|
|
}
|
|
void reset()
|
|
{
|
|
m_flags = 0;
|
|
}
|
|
private:
|
|
T m_flags;
|
|
};
|
|
|
|
|
|
// remote SQL request
|
|
struct Rsr : public Firebird::GlobalStorage, public TypedHandle<rem_type_rsr>
|
|
{
|
|
Rsr* rsr_next;
|
|
Rdb* rsr_rdb;
|
|
Rtr* rsr_rtr;
|
|
FB_API_HANDLE rsr_handle;
|
|
rem_fmt* rsr_bind_format; // Format of bind message
|
|
rem_fmt* rsr_select_format; // Format of select message
|
|
rem_fmt* rsr_user_select_format; // Format of user's select message
|
|
rem_fmt* rsr_format; // Format of current message
|
|
RMessage* rsr_message; // Next message to process
|
|
RMessage* rsr_buffer; // Next buffer to use
|
|
Firebird::StatusHolder* rsr_status; // saved status for buffered errors
|
|
USHORT rsr_id;
|
|
RFlags<USHORT> rsr_flags;
|
|
USHORT rsr_fmt_length;
|
|
|
|
ULONG rsr_rows_pending; // How many rows are pending
|
|
USHORT rsr_msgs_waiting; // count of full rsr_messages
|
|
USHORT rsr_reorder_level; // Trigger pipelining at this level
|
|
USHORT rsr_batch_count; // Count of batches in pipeline
|
|
|
|
public:
|
|
// Values for rsr_flags.
|
|
enum {
|
|
FETCHED = 1, // Cleared by execute, set by fetch
|
|
EOF_SET = 2, // End-of-stream encountered
|
|
BLOB = 4, // Statement relates to blob op
|
|
NO_BATCH = 8, // Do not batch fetch rows
|
|
STREAM_ERR = 16, // There is an error pending in the batched rows
|
|
LAZY = 32, // To be allocated at the first reference
|
|
DEFER_EXECUTE = 64, // op_execute can be deferred
|
|
PAST_EOF = 128 // EOF was returned by fetch from this statement
|
|
};
|
|
|
|
public:
|
|
Rsr() :
|
|
rsr_next(0), rsr_rdb(0), rsr_rtr(0), rsr_handle(0),
|
|
rsr_bind_format(0), rsr_select_format(0), rsr_user_select_format(0),
|
|
rsr_format(0), rsr_message(0), rsr_buffer(0), rsr_status(0),
|
|
rsr_id(0), rsr_fmt_length(0),
|
|
rsr_rows_pending(0), rsr_msgs_waiting(0), rsr_reorder_level(0), rsr_batch_count(0)
|
|
{ }
|
|
|
|
void saveException(const ISC_STATUS* status, bool overwrite);
|
|
void clearException();
|
|
ISC_STATUS haveException();
|
|
void raiseException();
|
|
void releaseException();
|
|
|
|
static ISC_STATUS badHandle() { return isc_bad_req_handle; }
|
|
};
|
|
|
|
|
|
// Makes it possible to safely store all handles in single array
|
|
class RemoteObject
|
|
{
|
|
private:
|
|
union {
|
|
Rdb* rdb;
|
|
Rtr* rtr;
|
|
Rbl* rbl;
|
|
Rrq* rrq;
|
|
Rsr* rsr;
|
|
} ptr;
|
|
|
|
public:
|
|
RemoteObject() { ptr.rdb = 0; }
|
|
|
|
template <typename R>
|
|
R* get(R* r)
|
|
{
|
|
if (! r->checkHandle())
|
|
{
|
|
Firebird::status_exception::raise(Firebird::Arg::Gds(R::badHandle()));
|
|
}
|
|
return r;
|
|
}
|
|
|
|
void operator=(Rdb* v) { ptr.rdb = v; }
|
|
void operator=(Rtr* v) { ptr.rtr = v; }
|
|
void operator=(Rbl* v) { ptr.rbl = v; }
|
|
void operator=(Rrq* v) { ptr.rrq = v; }
|
|
void operator=(Rsr* v) { ptr.rsr = v; }
|
|
|
|
operator Rdb*() { return get(ptr.rdb); }
|
|
operator Rtr*() { return get(ptr.rtr); }
|
|
operator Rbl*() { return get(ptr.rbl); }
|
|
operator Rrq*() { return get(ptr.rrq); }
|
|
operator Rsr*() { return get(ptr.rsr); }
|
|
|
|
bool isMissing() const { return ptr.rdb == NULL; }
|
|
void release() { ptr.rdb = 0; }
|
|
};
|
|
|
|
|
|
|
|
inline void Rsr::saveException(const ISC_STATUS* status, bool overwrite)
|
|
{
|
|
if (!rsr_status) {
|
|
rsr_status = new Firebird::StatusHolder();
|
|
}
|
|
if (overwrite || !rsr_status->getError()) {
|
|
rsr_status->save(status);
|
|
}
|
|
}
|
|
|
|
inline void Rsr::clearException()
|
|
{
|
|
if (rsr_status)
|
|
rsr_status->clear();
|
|
}
|
|
|
|
inline ISC_STATUS Rsr::haveException()
|
|
{
|
|
return (rsr_status ? rsr_status->getError() : 0);
|
|
}
|
|
|
|
inline void Rsr::raiseException()
|
|
{
|
|
if (rsr_status)
|
|
rsr_status->raise();
|
|
}
|
|
|
|
inline void Rsr::releaseException()
|
|
{
|
|
delete rsr_status;
|
|
rsr_status = NULL;
|
|
}
|
|
|
|
#include "../remote/xdr.h"
|
|
|
|
|
|
// Generalized port definition.
|
|
|
|
#ifndef WIN_NT
|
|
typedef int SOCKET;
|
|
#endif
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////
|
|
// fwd. decl.
|
|
struct p_cnct;
|
|
struct rmtque;
|
|
struct xcc; // defined in xnet.h
|
|
|
|
// Queue of deferred packets
|
|
|
|
struct rem_que_packet
|
|
{
|
|
PACKET packet;
|
|
bool sent;
|
|
};
|
|
|
|
typedef Firebird::Array<rem_que_packet> PacketQueue;
|
|
|
|
#ifdef TRUSTED_AUTH
|
|
// delayed authentication block for trusted auth callback
|
|
class ServerAuth : public Firebird::GlobalStorage
|
|
{
|
|
public:
|
|
typedef void Part2(rem_port*, P_OP, const char* fName, int fLen, const UCHAR* pb, int pbLen, PACKET*);
|
|
Firebird::PathName fileName;
|
|
Firebird::HalfStaticArray<UCHAR, 128> clumplet;
|
|
AuthSspi* authSspi;
|
|
Part2* part2;
|
|
P_OP operation;
|
|
|
|
ServerAuth(const char* fName, int fLen, const Firebird::ClumpletWriter& pb, Part2* p2, P_OP op);
|
|
~ServerAuth();
|
|
};
|
|
#endif // TRUSTED_AUTH
|
|
|
|
|
|
// port_flags
|
|
const USHORT PORT_symmetric = 0x0001; // Server/client architectures are symmetic
|
|
const USHORT PORT_rpc = 0x0002; // Protocol is remote procedure call
|
|
const USHORT PORT_async = 0x0004; // Port is asynchronous channel for events
|
|
const USHORT PORT_no_oob = 0x0008; // Don't send out of band data
|
|
const USHORT PORT_disconnect = 0x0010; // Disconnect is in progress
|
|
// This is set only in inet.cpp but never tested
|
|
//const USHORT PORT_not_trusted = 0x0020; // Connection is from an untrusted node
|
|
const USHORT PORT_dummy_pckt_set= 0x0040; // A dummy packet interval is set
|
|
const USHORT PORT_partial_data = 0x0080; // Physical packet doesn't contain all API packet
|
|
const USHORT PORT_lazy = 0x0100; // Deferred operations are allowed
|
|
const USHORT PORT_server = 0x0200; // Server (not client) port
|
|
const USHORT PORT_detached = 0x0400; // op_detach, op_drop_database or op_service_detach was processed
|
|
|
|
// Port itself
|
|
|
|
typedef rem_port* (*t_port_connect)(rem_port*, PACKET*);
|
|
|
|
typedef Firebird::RefPtr<rem_port> RemPortPtr;
|
|
|
|
struct rem_port : public Firebird::GlobalStorage, public Firebird::RefCounted
|
|
{
|
|
#ifdef DEV_BUILD
|
|
static Firebird::AtomicCounter portCounter;
|
|
#endif
|
|
|
|
// sync objects
|
|
Firebird::RefPtr<Firebird::RefMutex> port_sync;
|
|
#ifdef REM_SERVER
|
|
Firebird::RefPtr<Firebird::RefMutex> port_que_sync;
|
|
#endif
|
|
Firebird::RefPtr<Firebird::RefMutex> port_write_sync;
|
|
|
|
// port function pointers (C "emulation" of virtual functions)
|
|
bool (*port_accept)(rem_port*, const p_cnct*);
|
|
void (*port_disconnect)(rem_port*);
|
|
void (*port_force_close)(rem_port*);
|
|
rem_port* (*port_receive_packet)(rem_port*, PACKET*);
|
|
XDR_INT (*port_send_packet)(rem_port*, PACKET*);
|
|
XDR_INT (*port_send_partial)(rem_port*, PACKET*);
|
|
t_port_connect port_connect; // Establish secondary connection
|
|
rem_port* (*port_request)(rem_port*, PACKET*); // Request to establish secondary connection
|
|
bool (*port_select_multi)(rem_port*, UCHAR*, SSHORT, SSHORT*, RemPortPtr&); // get packet from active port
|
|
|
|
enum rem_port_t {
|
|
INET, // Internet (TCP/IP)
|
|
PIPE, // Windows NT named pipe connection
|
|
XNET // Windows NT shared memory connection
|
|
} port_type;
|
|
enum state_t {
|
|
PENDING, // connection is pending
|
|
BROKEN, // connection is broken
|
|
DISCONNECTED // port is disconnected
|
|
} port_state;
|
|
|
|
//P_ARCH port_client_arch; // so we can tell arch of client
|
|
rem_port* port_clients; // client ports
|
|
rem_port* port_next; // next client port
|
|
rem_port* port_parent; // parent port (for client ports)
|
|
rem_port* port_async; // asynchronous sibling port
|
|
rem_port* port_async_receive; // async packets receiver
|
|
struct srvr* port_server; // server of port
|
|
USHORT port_server_flags; // TRUE if server
|
|
USHORT port_protocol; // protocol version number
|
|
USHORT port_buff_size; // port buffer size (approx)
|
|
USHORT port_flags; // Misc flags
|
|
SLONG port_connect_timeout; // Connection timeout value
|
|
SLONG port_dummy_packet_interval; // keep alive dummy packet interval
|
|
SLONG port_dummy_timeout; // time remaining until keepalive packet
|
|
ISC_STATUS* port_status_vector;
|
|
SOCKET port_handle; // handle for INET socket
|
|
int port_channel; // handle for connection (from by OS)
|
|
struct linger port_linger; // linger value as defined by SO_LINGER
|
|
Rdb* port_context;
|
|
ThreadHandle port_events_thread; // handle of thread, handling incoming events
|
|
void (*port_events_shutdown)(rem_port*); // hack - avoid changing API at beta stage
|
|
#ifdef WIN_NT
|
|
HANDLE port_pipe; // port pipe handle
|
|
HANDLE port_event; // event associated with a port
|
|
#endif
|
|
XDR port_receive;
|
|
XDR port_send;
|
|
#ifdef DEBUG_XDR_MEMORY
|
|
r e m _ v e c* port_packet_vector; // Vector of send/receive packets
|
|
#endif
|
|
Firebird::Array<RemoteObject> port_objects;
|
|
rem_str* port_version;
|
|
rem_str* port_host; // Our name
|
|
rem_str* port_connection; // Name of connection
|
|
rem_str* port_user_name;
|
|
rem_str* port_passwd;
|
|
rem_str* port_protocol_str; // String containing protocol name for this port
|
|
rem_str* port_address_str; // Protocol-specific address string for the port
|
|
Rpr* port_rpr; // port stored procedure reference
|
|
Rsr* port_statement; // Statement for execute immediate
|
|
rmtque* port_receive_rmtque; // for client, responses waiting
|
|
Firebird::AtomicCounter port_requests_queued; // requests currently queued
|
|
xcc* port_xcc; // interprocess structure
|
|
PacketQueue* port_deferred_packets; // queue of deferred packets
|
|
OBJCT port_last_object_id; // cached last id
|
|
#ifdef REM_SERVER
|
|
Firebird::ObjectsArray< Firebird::Array<char> > port_queue;
|
|
size_t port_qoffset; // current packet in the queue
|
|
#endif
|
|
#ifdef TRUSTED_AUTH
|
|
ServerAuth* port_trusted_auth;
|
|
#endif
|
|
UCharArrayAutoPtr port_buffer;
|
|
|
|
public:
|
|
rem_port(rem_port_t t, size_t rpt) :
|
|
port_sync(FB_NEW(getPool()) Firebird::RefMutex()),
|
|
#ifdef REM_SERVER
|
|
port_que_sync(FB_NEW(getPool()) Firebird::RefMutex()),
|
|
#endif
|
|
port_write_sync(FB_NEW(getPool()) Firebird::RefMutex()),
|
|
port_accept(0), port_disconnect(0), port_force_close(0), port_receive_packet(0), port_send_packet(0),
|
|
port_send_partial(0), port_connect(0), port_request(0), port_select_multi(0),
|
|
port_type(t), port_state(PENDING), //port_client_arch(arch_generic),
|
|
port_clients(0), port_next(0), port_parent(0), port_async(0), port_async_receive(0),
|
|
port_server(0), port_server_flags(0), port_protocol(0), port_buff_size(0),
|
|
port_flags(0), port_connect_timeout(0), port_dummy_packet_interval(0),
|
|
port_dummy_timeout(0), port_status_vector(0), port_handle(0), port_channel(0),
|
|
port_context(0), port_events_thread(0), port_events_shutdown(0),
|
|
#ifdef WIN_NT
|
|
port_pipe(INVALID_HANDLE_VALUE), port_event(INVALID_HANDLE_VALUE),
|
|
#endif
|
|
#ifdef DEBUG_XDR_MEMORY
|
|
port_packet_vector(0),
|
|
#endif
|
|
port_objects(getPool()), port_version(0), port_host(0),
|
|
port_connection(0), port_user_name(0), port_passwd(0), port_protocol_str(0),
|
|
port_address_str(0), port_rpr(0), port_statement(0), port_receive_rmtque(0),
|
|
port_requests_queued(0), port_xcc(0), port_deferred_packets(0), port_last_object_id(0),
|
|
#ifdef REM_SERVER
|
|
port_queue(getPool()), port_qoffset(0),
|
|
#endif
|
|
#ifdef TRUSTED_AUTH
|
|
port_trusted_auth(0),
|
|
#endif
|
|
port_buffer(FB_NEW(getPool()) UCHAR[rpt])
|
|
{
|
|
addRef();
|
|
memset (&port_linger, 0, sizeof port_linger);
|
|
memset (port_buffer, 0, rpt);
|
|
#ifdef DEV_BUILD
|
|
++portCounter;
|
|
#endif
|
|
}
|
|
|
|
private: // this is refCounted object
|
|
~rem_port();
|
|
|
|
public:
|
|
void linkParent(rem_port* const parent);
|
|
|
|
void unlinkParent();
|
|
|
|
template <typename T>
|
|
void getHandle(T*& blk, OBJCT id)
|
|
{
|
|
if ((port_flags & PORT_lazy) && (id == INVALID_OBJECT))
|
|
{
|
|
id = port_last_object_id;
|
|
}
|
|
if (id >= port_objects.getCount() || port_objects[id].isMissing())
|
|
{
|
|
Firebird::status_exception::raise(Firebird::Arg::Gds(T::badHandle()));
|
|
}
|
|
blk = port_objects[id];
|
|
}
|
|
|
|
template <typename T>
|
|
OBJCT setHandle(T* const object, const OBJCT id)
|
|
{
|
|
if (id >= port_objects.getCount())
|
|
{
|
|
// Prevent the creation of object handles that can't be
|
|
// transferred by the remote protocol.
|
|
if (id > MAX_OBJCT_HANDLES)
|
|
{
|
|
return (OBJCT) 0;
|
|
}
|
|
|
|
port_objects.grow(id + 1);
|
|
}
|
|
|
|
port_objects[id] = object;
|
|
return id;
|
|
}
|
|
|
|
// Allocate an object slot for an object.
|
|
template <typename T>
|
|
OBJCT get_id(T* object)
|
|
{
|
|
// Reserve slot 0 so we can distinguish something from nothing.
|
|
// NOTE: prior to server version 4.5.0 id==0 COULD be used - so
|
|
// only the server side can now depend on id==0 meaning "invalid id"
|
|
unsigned int i = 1;
|
|
for (; i < port_objects.getCount(); ++i)
|
|
{
|
|
if (port_objects[i].isMissing())
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
port_last_object_id = setHandle(object, static_cast<OBJCT>(i));
|
|
return port_last_object_id;
|
|
}
|
|
|
|
void releaseObject(OBJCT id)
|
|
{
|
|
if (id != INVALID_OBJECT)
|
|
{
|
|
port_objects[id].release();
|
|
}
|
|
}
|
|
|
|
|
|
public:
|
|
// TMN: Beginning of C++ port
|
|
// TMN: ugly, but at least a start
|
|
bool accept(p_cnct* cnct);
|
|
void disconnect();
|
|
void force_close();
|
|
rem_port* receive(PACKET* pckt);
|
|
XDR_INT send(PACKET* pckt);
|
|
XDR_INT send_partial(PACKET* pckt);
|
|
rem_port* connect(PACKET* pckt);
|
|
rem_port* request(PACKET* pckt);
|
|
bool select_multi(UCHAR* buffer, SSHORT bufsize, SSHORT* length, RemPortPtr& port);
|
|
|
|
#ifdef REM_SERVER
|
|
bool haveRecvData()
|
|
{
|
|
Firebird::RefMutexGuard queGuard(*port_que_sync);
|
|
return ((port_receive.x_handy > 0) || (port_qoffset < port_queue.getCount()));
|
|
}
|
|
|
|
void clearRecvQue()
|
|
{
|
|
Firebird::RefMutexGuard queGuard(*port_que_sync);
|
|
port_queue.clear();
|
|
port_qoffset = 0;
|
|
port_receive.x_private = port_receive.x_base;
|
|
}
|
|
|
|
class RecvQueState
|
|
{
|
|
public:
|
|
int save_handy;
|
|
size_t save_private;
|
|
size_t save_qoffset;
|
|
|
|
RecvQueState(const rem_port* port)
|
|
{
|
|
save_handy = port->port_receive.x_handy;
|
|
save_private = port->port_receive.x_private - port->port_receive.x_base;
|
|
save_qoffset = port->port_qoffset;
|
|
}
|
|
};
|
|
|
|
RecvQueState getRecvState() const
|
|
{
|
|
return RecvQueState(this);
|
|
}
|
|
|
|
void setRecvState(const RecvQueState& rs)
|
|
{
|
|
if (rs.save_qoffset > 0 && (rs.save_qoffset != port_qoffset))
|
|
{
|
|
Firebird::Array<char>& q = port_queue[rs.save_qoffset - 1];
|
|
memcpy(port_receive.x_base, q.begin(), q.getCount());
|
|
}
|
|
port_qoffset = rs.save_qoffset;
|
|
port_receive.x_private = port_receive.x_base + rs.save_private;
|
|
port_receive.x_handy = rs.save_handy;
|
|
}
|
|
#endif // REM_SERVER
|
|
|
|
// TMN: The following member functions are conceptually private
|
|
// to server.cpp and should be _made_ private in due time!
|
|
// That is, if we don't factor these method out.
|
|
|
|
ISC_STATUS compile(P_CMPL*, PACKET*);
|
|
ISC_STATUS ddl(P_DDL*, PACKET*);
|
|
void disconnect(PACKET*, PACKET*);
|
|
void drop_database(P_RLSE*, PACKET*);
|
|
|
|
ISC_STATUS end_blob(P_OP, P_RLSE*, PACKET*);
|
|
ISC_STATUS end_database(P_RLSE*, PACKET*);
|
|
ISC_STATUS end_request(P_RLSE*, PACKET*);
|
|
ISC_STATUS end_statement(P_SQLFREE*, PACKET*);
|
|
ISC_STATUS end_transaction(P_OP, P_RLSE*, PACKET*);
|
|
ISC_STATUS execute_immediate(P_OP, P_SQLST*, PACKET*);
|
|
ISC_STATUS execute_statement(P_OP, P_SQLDATA*, PACKET*);
|
|
ISC_STATUS fetch(P_SQLDATA*, PACKET*);
|
|
ISC_STATUS fetch_blob(P_SQLDATA*, PACKET*);
|
|
ISC_STATUS get_segment(P_SGMT*, PACKET*);
|
|
ISC_STATUS get_slice(P_SLC*, PACKET*);
|
|
ISC_STATUS info(P_OP, P_INFO*, PACKET*);
|
|
ISC_STATUS insert(P_SQLDATA*, PACKET*);
|
|
ISC_STATUS open_blob(P_OP, P_BLOB*, PACKET*);
|
|
ISC_STATUS prepare(P_PREP*, PACKET*);
|
|
ISC_STATUS prepare_statement(P_SQLST*, PACKET*);
|
|
ISC_STATUS put_segment(P_OP, P_SGMT*, PACKET*);
|
|
ISC_STATUS put_slice(P_SLC*, PACKET*);
|
|
ISC_STATUS que_events(P_EVENT*, PACKET*);
|
|
ISC_STATUS receive_after_start(P_DATA*, PACKET*, ISC_STATUS*);
|
|
ISC_STATUS receive_msg(P_DATA*, PACKET*);
|
|
ISC_STATUS seek_blob(P_SEEK*, PACKET*);
|
|
ISC_STATUS send_msg(P_DATA*, PACKET*);
|
|
ISC_STATUS send_response(PACKET*, OBJCT, USHORT, const ISC_STATUS*, bool);
|
|
ISC_STATUS service_attach(const char*, const USHORT, Firebird::ClumpletWriter&, PACKET*);
|
|
ISC_STATUS service_end(P_RLSE*, PACKET*);
|
|
ISC_STATUS service_start(P_INFO*, PACKET*);
|
|
ISC_STATUS set_cursor(P_SQLCUR*, PACKET*);
|
|
ISC_STATUS start(P_OP, P_DATA*, PACKET*);
|
|
ISC_STATUS start_and_send(P_OP, P_DATA*, PACKET*);
|
|
ISC_STATUS start_transaction(P_OP, P_STTR*, PACKET*);
|
|
ISC_STATUS transact_request(P_TRRQ *, PACKET*);
|
|
SSHORT asyncReceive(PACKET* asyncPacket, const UCHAR* buffer, SSHORT dataSize);
|
|
};
|
|
|
|
|
|
|
|
// Queuing structure for Client batch fetches
|
|
|
|
typedef bool (*t_rmtque_fn)(rem_port*, rmtque*, ISC_STATUS*, USHORT);
|
|
|
|
struct rmtque : public Firebird::GlobalStorage
|
|
{
|
|
rmtque* rmtque_next; // Next entry in queue
|
|
void* rmtque_parm; // What request has response in queue
|
|
Rrq::rrq_repeat* rmtque_message; // What message is pending
|
|
Rdb* rmtque_rdb; // What database has pending msg
|
|
|
|
// Fn that receives queued entry
|
|
t_rmtque_fn rmtque_function;
|
|
|
|
public:
|
|
rmtque() :
|
|
rmtque_next(0), rmtque_parm(0), rmtque_message(0), rmtque_rdb(0), rmtque_function(0)
|
|
{ }
|
|
};
|
|
|
|
|
|
// contains ports which must be closed at engine shutdown
|
|
class PortsCleanup
|
|
{
|
|
public:
|
|
PortsCleanup() :
|
|
m_ports(NULL),
|
|
m_mutex()
|
|
{}
|
|
|
|
explicit PortsCleanup(MemoryPool&) :
|
|
m_ports(NULL),
|
|
m_mutex()
|
|
{}
|
|
|
|
~PortsCleanup()
|
|
{}
|
|
|
|
void registerPort(rem_port*);
|
|
void unRegisterPort(rem_port*);
|
|
|
|
void closePorts();
|
|
|
|
private:
|
|
typedef Firebird::SortedArray<rem_port*> PortsArray;
|
|
PortsArray* m_ports;
|
|
Firebird::Mutex m_mutex;
|
|
};
|
|
|
|
#endif // REMOTE_REMOTE_H
|