/* * 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 #include #include #include #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 > UCharArrayAutoPtr; typedef struct Rdb : public Firebird::GlobalStorage, public TypedHandle { 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; } } *RDB; typedef struct Rtr : public Firebird::GlobalStorage, public TypedHandle { 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; } } *RTR; typedef struct Rbl : public Firebird::GlobalStorage, public TypedHandle { Firebird::HalfStaticArray 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; } } *RBL; typedef 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) { } } *RVNT; struct rem_str : public pool_alloc_rpt { 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 fmt_desc; public: 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: 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 typedef 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 ; } } *RPR; struct Rrq : public Firebird::GlobalStorage, public TypedHandle { 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_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: 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; } }; // remote SQL request typedef struct Rsr : public Firebird::GlobalStorage, public TypedHandle { 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; 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: 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_flags(0), rsr_fmt_length(0), rsr_rows_pending(0), rsr_msgs_waiting(0), rsr_reorder_level(0), rsr_batch_count(0) { } static ISC_STATUS badHandle() { return isc_bad_req_handle; } } *RSR; // 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: template R* get(R* r) { if (! r->checkHandle()) { Firebird::status_exception::raise(R::badHandle(), isc_arg_end); } return r; } public: 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; } public: 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() { return ptr.rdb == NULL; } void release() { ptr.rdb = 0; } }; // will be methods of remote statement class inline void stmt_save_exception(RSR statement, const ISC_STATUS* status, bool overwrite) { if (!statement->rsr_status) { statement->rsr_status = new Firebird::StatusHolder(); } if (overwrite || !statement->rsr_status->getError()) { statement->rsr_status->save(status); } } inline void stmt_clear_exception(RSR statement) { if (statement->rsr_status) statement->rsr_status->clear(); } inline ISC_STATUS stmt_have_exception(RSR statement) { return (statement->rsr_status ? statement->rsr_status->getError() : 0); } inline void stmt_raise_exception(RSR statement) { if (statement->rsr_status) statement->rsr_status->raise(); } inline void stmt_release_exception(RSR statement) { if (statement->rsr_status) { delete statement->rsr_status; statement->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 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 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 archiectures 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 */ class port_interface { public: virtual int accept_(rem_port* pPort, p_cnct* pConnection) = 0; }; //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 { /* 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 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 > port_queue; size_t port_qoffset; // current packet in the queue Firebird::RefMutex* const port_que_sync; #endif #ifdef TRUSTED_AUTH ServerAuth* port_trusted_auth; #endif Firebird::RefMutex* const port_sync; UCharArrayAutoPtr port_buffer; public: rem_port(rem_port_t t, size_t rpt) : 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), port_que_sync(FB_NEW(getPool()) Firebird::RefMutex()), #endif #ifdef TRUSTED_AUTH port_trusted_auth(0), #endif port_sync(FB_NEW(getPool()) Firebird::RefMutex()), port_buffer(FB_NEW(getPool()) UCHAR[rpt]) { memset (port_buffer, 0, rpt); port_sync->addRef(); #ifdef REM_SERVER port_que_sync->addRef(); #endif } ~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 REM_SERVER port_que_sync->release(); #endif #ifdef TRUSTED_AUTH delete port_trusted_auth; #endif port_sync->release(); } 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 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 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 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(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& 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); typedef 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) { } } *RMTQUE; #endif // REMOTE_REMOTE_H