8
0
mirror of https://github.com/FirebirdSQL/firebird.git synced 2025-01-27 20:03:03 +01:00
firebird-mirror/src/remote/remote.h
robocop b2e8da134f Trying to fix the interface again.
Sorry for going back and forth with constness, but in some cases it was impossible to ensure that input params aren't overwritten, thus I took const away to avoid making promises that can't be met (see the case of fetch that uses a supposedly input-only param to return data). Overwriting memory that was declared const initially is a serious error in C++ with undefined outcome so we better do not lie.
2008-04-03 10:17:24 +00:00

912 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)
{ }
//ISC_STATUS badHandle() { return ; }
};
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);
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
// port function pointers (C "emulation" of virtual functions)
int (*port_accept)(rem_port*, 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 */
rem_port* (*port_select_multi)(rem_port*, UCHAR*, SSHORT, SSHORT*); // 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 */
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_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_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_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);
rem_port* select_multi(UCHAR* buffer, SSHORT bufsize, SSHORT* length);
#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*);
};
/* 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