mirror of
https://github.com/FirebirdSQL/firebird.git
synced 2025-01-24 21:23:04 +01:00
919 lines
25 KiB
C++
919 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 "../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/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:
|
|
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:
|
|
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;
|
|
SSHORT 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. */
|
|
|
|
typedef struct Message : public Firebird::GlobalStorage
|
|
{
|
|
Message* msg_next; /* Next available message */
|
|
#ifdef SCROLLABLE_CURSORS
|
|
Message* msg_prior; /* Next available message */
|
|
ULONG msg_absolute; /* Absolute record number in cursor result set */
|
|
#endif
|
|
USHORT msg_number; /* Message number */
|
|
UCHAR* msg_address; /* Address of message */
|
|
UCharArrayAutoPtr msg_buffer; /* Allocated message */
|
|
|
|
public:
|
|
explicit Message(size_t rpt) :
|
|
msg_next(0),
|
|
#ifdef SCROLLABLE_CURSORS
|
|
msg_prior(0), msg_absolute(0),
|
|
#endif
|
|
msg_number(0), msg_address(0), msg_buffer(FB_NEW(getPool()) UCHAR[rpt])
|
|
{
|
|
memset(msg_buffer, 0, rpt);
|
|
}
|
|
} *REM_MSG;
|
|
|
|
|
|
// remote stored procedure request
|
|
struct Rpr : public Firebird::GlobalStorage
|
|
{
|
|
Rdb* rpr_rdb;
|
|
Rtr* rpr_rtr;
|
|
FB_API_HANDLE rpr_handle;
|
|
Message* rpr_in_msg; /* input message */
|
|
Message* 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 */
|
|
Message* rrq_message; /* beginning or end of cache, depending on whether it is client or server */
|
|
Message* rrq_xdr; /* point at which cache is read or written by xdr */
|
|
#ifdef SCROLLABLE_CURSORS
|
|
Message* rrq_last; /* last message returned */
|
|
ULONG rrq_absolute; /* current offset in result set for record being read into cache */
|
|
USHORT rrq_flags;
|
|
#endif
|
|
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:
|
|
#ifdef SCROLLABLE_CURSORS
|
|
enum {
|
|
BACKWARD = 1, /* the cache was created in the backward direction */
|
|
ABSOLUTE_BACKWARD = 2, /* rrq_absolute is measured from the end of the stream */
|
|
LAST_BACKWARD = 4 /* last time, the next level up asked for us to scroll in the backward direction */
|
|
};
|
|
#endif
|
|
|
|
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 */
|
|
Message* rsr_message; /* Next message to process */
|
|
Message* 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(R::badHandle(), isc_arg_end);
|
|
}
|
|
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 HANDLE;
|
|
#endif /* WIN_NT */
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////
|
|
// fwd. decl.
|
|
struct p_cnct;
|
|
struct rmtque;
|
|
|
|
/* 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
|
|
|
|
/* Port itself */
|
|
|
|
//typedef XDR_INT (*t_event_ast)();
|
|
typedef void (*t_event_ast)(rem_port*);
|
|
typedef rem_port* (*t_port_connect)(rem_port*, PACKET*, t_event_ast);
|
|
|
|
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::RefMutex* const port_sync;
|
|
Firebird::Reference port_sync_reference;
|
|
#ifdef REM_SERVER
|
|
Firebird::RefMutex* const port_que_sync;
|
|
Firebird::Reference port_que_reference;
|
|
#endif
|
|
Firebird::RefMutex* const port_write_sync;
|
|
Firebird::Reference port_write_reference;
|
|
|
|
// port function pointers (C "emulation" of virtual functions)
|
|
int (*port_accept)(rem_port*, const p_cnct*);
|
|
void (*port_disconnect)(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 {
|
|
CLOSED, /* no connection */
|
|
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;
|
|
HANDLE port_handle; /* handle for connection (from by OS) */
|
|
int port_channel; /* handle for connection (from by OS) */
|
|
struct linger port_linger; /* linger value as defined by SO_LINGER */
|
|
Rdb* port_context;
|
|
t_event_ast port_ast; /* AST for events */
|
|
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 */
|
|
USHORT port_requests_queued; /* requests currently queued */
|
|
void* 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()),
|
|
port_sync_reference(*port_sync),
|
|
#ifdef REM_SERVER
|
|
port_que_sync(FB_NEW(getPool()) Firebird::RefMutex()),
|
|
port_que_reference(*port_que_sync),
|
|
#endif
|
|
port_write_sync(FB_NEW(getPool()) Firebird::RefMutex()),
|
|
port_write_reference(*port_write_sync),
|
|
port_accept(0), port_disconnect(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_ast(0),
|
|
#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()
|
|
{
|
|
delete port_version;
|
|
delete port_connection;
|
|
delete port_user_name;
|
|
delete port_host;
|
|
delete port_protocol_str;
|
|
delete port_address_str;
|
|
|
|
#ifdef DEBUG_XDR_MEMORY
|
|
delete port_packet_vector;
|
|
#endif
|
|
|
|
#ifdef TRUSTED_AUTH
|
|
delete port_trusted_auth;
|
|
#endif
|
|
|
|
#ifdef DEV_BUILD
|
|
--portCounter;
|
|
#endif
|
|
}
|
|
|
|
public:
|
|
void linkParent(rem_port* parent)
|
|
{
|
|
port_parent = parent;
|
|
port_next = parent->port_clients;
|
|
port_handle = parent->port_handle;
|
|
port_server = parent->port_server;
|
|
port_server_flags = parent->port_server_flags;
|
|
|
|
parent->port_clients = parent->port_next = this;
|
|
}
|
|
|
|
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(T::badHandle(), isc_arg_end);
|
|
}
|
|
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 */
|
|
int accept(p_cnct* cnct);
|
|
void disconnect();
|
|
rem_port* receive(PACKET* pckt);
|
|
XDR_INT send(PACKET* pckt);
|
|
XDR_INT send_partial(PACKET* pckt);
|
|
rem_port* connect(PACKET* pckt, t_event_ast);
|
|
rem_port* request(PACKET* pckt);
|
|
bool select_multi(UCHAR* buffer, SSHORT bufsize, SSHORT* length, RemPortPtr& port);
|
|
|
|
#ifdef REM_SERVER
|
|
bool haveRecvData() const
|
|
{
|
|
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*);
|
|
bool 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)
|
|
{ }
|
|
};
|
|
|
|
#endif // REMOTE_REMOTE_H
|