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

5434 lines
136 KiB
C++
Raw Normal View History

2001-05-23 15:26:42 +02:00
/*
* PROGRAM: JRD Remote Server
* MODULE: server.cpp
2001-05-23 15:26:42 +02:00
* DESCRIPTION: Remote server
*
* 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-06-29 10:49:39 +02:00
*
* 2002.02.27 Claudio Valderrama: Fix SF Bug #509995.
*
2002-10-30 07:40:58 +01:00
* 2002.10.29 Sean Leyne - Removed obsolete "Netware" port
*
* 2002.10.30 Sean Leyne - Removed support for obsolete "PC_PLATFORM" define
*
2001-05-23 15:26:42 +02:00
*/
#include "firebird.h"
2004-03-22 12:38:23 +01:00
#include "../jrd/common.h"
2004-04-29 00:36:29 +02:00
#include <stdio.h>
2001-05-23 15:26:42 +02:00
#include <string.h>
2003-11-08 17:40:17 +01:00
#include "../jrd/ibase.h"
2001-05-23 15:26:42 +02:00
#include "../jrd/gdsassert.h"
#include "../remote/remote.h"
2008-01-16 08:55:28 +01:00
#include "../jrd/ThreadStart.h"
2001-05-23 15:26:42 +02:00
#include "../jrd/license.h"
#include "../common/classes/timestamp.h"
2001-05-23 15:26:42 +02:00
#include "../remote/merge_proto.h"
#include "../remote/parse_proto.h"
#include "../remote/remot_proto.h"
#include "../remote/serve_proto.h"
#include "../remote/xdr_proto.h"
2001-05-23 15:26:42 +02:00
#ifdef WIN_NT
#include "../remote/os/win32/cntl_proto.h"
2001-05-23 15:26:42 +02:00
#include <stdlib.h>
#endif
#include "../jrd/gds_proto.h"
#include "../jrd/isc_proto.h"
#include "../jrd/isc_s_proto.h"
#include "../jrd/thread_proto.h"
2001-05-23 15:26:42 +02:00
#include "../jrd/why_proto.h"
#include "../jrd/constants.h"
#include "../common/classes/init.h"
#include "../common/classes/semaphore.h"
#include "../common/classes/ClumpletWriter.h"
#include "../common/config/config.h"
#ifdef DEBUG
#include "gen/iberror.h"
#endif
#include "../jrd/os/isc_i_proto.h"
2001-05-23 15:26:42 +02:00
#include "../remote/proto_proto.h" // xdr_protocol_overhead()
2008-01-16 08:55:28 +01:00
#include "../jrd/scroll_cursors.h"
2001-05-23 15:26:42 +02:00
typedef struct server_req_t : public Firebird::GlobalStorage
2001-05-23 15:26:42 +02:00
{
server_req_t* req_next;
server_req_t* req_chain;
RemPortPtr req_port;
2001-05-23 15:26:42 +02:00
PACKET req_send;
PACKET req_receive;
public:
server_req_t() : req_next(0), req_chain(0) { }
2004-06-09 20:23:27 +02:00
} *SERVER_REQ;
2001-05-23 15:26:42 +02:00
typedef struct srvr : public Firebird::GlobalStorage
2001-05-23 15:26:42 +02:00
{
struct srvr* srvr_next;
rem_port* srvr_parent_port;
rem_port::rem_port_t srvr_port_type;
2001-05-23 15:26:42 +02:00
USHORT srvr_flags;
public:
srvr(srvr* servers, rem_port* port, USHORT flags) :
2008-12-02 08:09:49 +01:00
srvr_next(servers), srvr_parent_port(port),
srvr_port_type(port->port_type), srvr_flags(flags)
{ }
2004-06-09 20:23:27 +02:00
} *SRVR;
2001-05-23 15:26:42 +02:00
namespace {
// this sets of parameters help use same functions
// for both services and databases attachments
2008-04-19 13:33:37 +02:00
struct ParametersSet
{
UCHAR address_path;
};
const ParametersSet dpbParam = {isc_dpb_address_path};
const ParametersSet spbParam = {isc_spb_address_path};
}
2007-04-03 10:18:11 +02:00
static void free_request(SERVER_REQ);
2006-03-03 17:20:42 +01:00
static SERVER_REQ alloc_request();
static bool link_request(rem_port*, SERVER_REQ);
2006-03-03 17:20:42 +01:00
2007-04-03 10:18:11 +02:00
static bool accept_connection(rem_port*, P_CNCT*, PACKET*);
static ISC_STATUS allocate_statement(rem_port*, P_RLSE*, PACKET*);
2008-03-15 11:28:25 +01:00
static void append_request_chain(SERVER_REQ, SERVER_REQ*);
static void append_request_next(SERVER_REQ, SERVER_REQ*);
2006-12-08 19:38:15 +01:00
static void attach_database(rem_port*, P_OP, P_ATCH*, PACKET*);
static void attach_service(rem_port*, P_ATCH*, PACKET*);
2008-12-02 08:09:49 +01:00
static void attach_database2(rem_port*, P_OP, const char*, int,
2006-12-08 19:38:15 +01:00
const UCHAR*, int, PACKET*);
2008-12-02 08:09:49 +01:00
static void attach_service2(rem_port*, P_OP, const char*, int,
2006-12-08 19:38:15 +01:00
const UCHAR*, int, PACKET*);
#ifdef TRUSTED_AUTH
2008-04-15 11:31:35 +02:00
static void trusted_auth(rem_port*, const P_TRAU*, PACKET*);
2008-01-16 08:55:28 +01:00
static bool canUseTrusted();
2006-12-08 19:38:15 +01:00
#endif
2004-03-14 06:51:54 +01:00
#ifdef NOT_USED_OR_REPLACED
static void aux_connect(rem_port*, P_REQ*, PACKET*);
2004-03-14 06:51:54 +01:00
#endif
static void aux_request(rem_port*, P_REQ*, PACKET*);
static ISC_STATUS cancel_events(rem_port*, P_EVENT*, PACKET*);
static void addClumplets(Firebird::ClumpletWriter&, const ParametersSet&, const rem_port*);
2001-05-23 15:26:42 +02:00
static void cancel_operation(rem_port*, USHORT);
2001-05-23 15:26:42 +02:00
static bool check_request(Rrq*, USHORT, USHORT);
2008-03-30 11:37:57 +02:00
static USHORT check_statement_type(Rsr*);
2001-05-23 15:26:42 +02:00
#ifdef SCROLLABLE_CURSORS
static REM_MSG dump_cache(Rrq::rrq_repeat*);
2001-05-23 15:26:42 +02:00
#endif
static bool get_next_msg_no(Rrq*, USHORT, USHORT*);
static Rtr* make_transaction(Rdb*, FB_API_HANDLE);
2008-01-16 08:55:28 +01:00
static bool process_packet(rem_port* port,
PACKET* sendL,
PACKET* receive,
rem_port** result);
static void release_blob(Rbl*);
static void release_event(Rvnt*);
static void release_request(Rrq*);
2008-03-30 11:37:57 +02:00
static void release_statement(Rsr**);
static void release_sql_request(Rsr*);
static void release_transaction(Rtr*);
2001-05-23 15:26:42 +02:00
#ifdef SCROLLABLE_CURSORS
static REM_MSG scroll_cache(Rrq::rrq_repeat*, USHORT *, ULONG *);
2001-05-23 15:26:42 +02:00
#endif
2007-04-03 10:18:11 +02:00
static void server_ast(void*, USHORT, const UCHAR*);
2008-01-16 08:55:28 +01:00
static void set_server(rem_port*, USHORT);
static void success(ISC_STATUS*);
static int shut_server(const int, const int, void*);
static THREAD_ENTRY_DECLARE loopThread(THREAD_ENTRY_PARAM);
2003-09-11 20:59:34 +02:00
static void zap_packet(PACKET*, bool);
2001-05-23 15:26:42 +02:00
static bool bad_port_context(ISC_STATUS*, Rdb*, const ISC_LONG);
2007-04-03 10:18:11 +02:00
inline bool bad_db(ISC_STATUS* status_vector, Rdb* rdb)
{
return bad_port_context(status_vector, rdb, isc_bad_db_handle);
}
inline bool bad_service(ISC_STATUS* status_vector, Rdb* rdb)
{
return bad_port_context(status_vector, rdb, isc_bad_svc_handle);
}
2001-05-23 15:26:42 +02:00
class Worker
{
public:
static const int MAX_THREADS = 127; // With 128 gdb shows -128. gcc/gdb bug?
static const int IDLE_TIMEOUT = 60;
Worker();
~Worker();
bool wait(int timeout = IDLE_TIMEOUT); // true is success, false if timeout
2008-03-14 03:50:40 +01:00
static bool wakeUp();
2008-03-13 11:41:38 +01:00
void setState(const bool active);
static void start(USHORT flags);
2008-12-02 08:09:49 +01:00
static int getCount() { return m_cntAll; }
2008-12-02 08:09:49 +01:00
static bool isShuttingDown() { return shutting_down; }
static void shutdown();
private:
Worker* m_next;
Worker* m_prev;
Firebird::Semaphore m_sem;
bool m_active;
2008-03-13 11:41:38 +01:00
#ifdef DEV_BUILD
FB_THREAD_ID m_tid;
2008-03-13 11:41:38 +01:00
#endif
void remove();
2008-03-13 11:41:38 +01:00
void insert(const bool active);
static void wakeUpAll();
static Worker* m_activeWorkers;
static Worker* m_idleWorkers;
static Firebird::GlobalPtr<Firebird::Mutex> m_mutex;
static int m_cntAll;
static int m_cntIdle;
static bool shutting_down;
};
Worker* Worker::m_activeWorkers = NULL;
Worker* Worker::m_idleWorkers = NULL;
Firebird::GlobalPtr<Firebird::Mutex> Worker::m_mutex;
int Worker::m_cntAll = 0;
int Worker::m_cntIdle = 0;
bool Worker::shutting_down = false;
static Firebird::GlobalPtr<Firebird::Mutex> request_que_mutex;
2001-05-23 15:26:42 +02:00
static SERVER_REQ request_que = NULL;
static SERVER_REQ free_requests = NULL;
static SERVER_REQ active_requests = NULL;
static Firebird::GlobalPtr<Firebird::Mutex> servers_mutex;
static SRVR servers;
static Firebird::AtomicCounter cntServers;
static bool server_shutdown = false;
2001-05-23 15:26:42 +02:00
2003-02-13 10:33:26 +01:00
static const UCHAR request_info[] =
2001-05-23 15:26:42 +02:00
{
2003-11-08 17:40:17 +01:00
isc_info_state,
isc_info_message_number,
isc_info_end
2001-05-23 15:26:42 +02:00
};
2003-02-13 10:33:26 +01:00
static const UCHAR sql_info[] =
2001-05-23 15:26:42 +02:00
{
2003-11-08 17:40:17 +01:00
isc_info_sql_stmt_type,
2001-05-23 15:26:42 +02:00
isc_info_sql_batch_fetch
};
#define GDS_DSQL_ALLOCATE isc_dsql_allocate_statement
#define GDS_DSQL_EXECUTE isc_dsql_execute2_m
#define GDS_DSQL_EXECUTE_IMMED isc_dsql_exec_immed3_m
#define GDS_DSQL_FETCH isc_dsql_fetch_m
#define GDS_DSQL_FREE isc_dsql_free_statement
#define GDS_DSQL_INSERT isc_dsql_insert_m
#define GDS_DSQL_PREPARE isc_dsql_prepare_m
#define GDS_DSQL_SET_CURSOR isc_dsql_set_cursor_name
#define GDS_DSQL_SQL_INFO isc_dsql_sql_info
void SRVR_main(rem_port* main_port, USHORT flags)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* S R V R _ m a i n
*
**************************************
*
* Functional description
* Main entrypoint of server.
*
**************************************/
ISC_enter(); /* Setup floating point exception handler once and for all. */
2001-05-23 15:26:42 +02:00
// Setup context pool for main thread
Firebird::ContextPoolHolder mainThreadContext(getDefaultMemoryPool());
PACKET send, receive;
2003-09-11 20:59:34 +02:00
zap_packet(&receive, true);
zap_packet(&send, true);
2001-05-23 15:26:42 +02:00
set_server(main_port, flags);
2003-09-11 20:59:34 +02:00
while (true)
2001-05-23 15:26:42 +02:00
{
//
// Note: The following is cloned in server other SRVR_main instances.
//
ISC_STATUS_ARRAY status = {0};
main_port->port_status_vector = status;
rem_port* port = main_port->receive(&receive);
2001-05-23 15:26:42 +02:00
if (!port) {
break;
}
if (!process_packet(port, &send, &receive, &port)) {
2001-05-23 15:26:42 +02:00
break;
2003-03-11 06:53:55 +01:00
}
2001-05-23 15:26:42 +02:00
}
}
2006-03-03 17:20:42 +01:00
static void free_request(SERVER_REQ request)
{
/**************************************
*
* f r e e _ r e q u e s t
*
**************************************
*
* Functional description
*
**************************************/
Firebird::MutexLockGuard queGuard(request_que_mutex);
request->req_port = 0;
2006-03-03 17:20:42 +01:00
request->req_next = free_requests;
free_requests = request;
}
static SERVER_REQ alloc_request()
{
/**************************************
*
* a l l o c _ r e q u e s t
*
**************************************
*
* Functional description
* Get request block from the free blocks list,
* if empty - allocate the new one.
*
**************************************/
Firebird::MutexEnsureUnlock queGuard(request_que_mutex);
queGuard.enter();
2006-03-03 17:20:42 +01:00
SERVER_REQ request = free_requests;
#if defined(DEV_BUILD) && defined(DEBUG)
int request_count = 0;
#endif
2008-01-27 00:23:15 +01:00
2006-03-03 17:20:42 +01:00
/* Allocate a memory block to store the request in */
if (request)
{
free_requests = request->req_next;
}
else
{
/* No block on the free list - allocate some new memory */
2008-03-30 22:43:36 +02:00
for (;;)
2006-03-03 17:20:42 +01:00
{
try
{
request = new server_req_t;
break;
}
catch (const Firebird::BadAlloc&)
{ }
2006-03-03 17:20:42 +01:00
#if defined(DEV_BUILD) && defined(DEBUG)
if (request_count++ > 4)
Firebird::BadAlloc::raise();
2006-03-03 17:20:42 +01:00
#endif
/* System is out of memory, let's delay processing this
request and hope another thread will free memory or
request blocks that we can then use. */
queGuard.leave();
2006-03-03 17:20:42 +01:00
THREAD_SLEEP(1 * 1000);
queGuard.enter();
2006-03-03 17:20:42 +01:00
}
zap_packet(&request->req_send, true);
zap_packet(&request->req_receive, true);
#ifdef DEBUG_REMOTE_MEMORY
printf("alloc_request allocate request %x\n", request);
#endif
}
2008-01-27 00:23:15 +01:00
2006-03-03 17:20:42 +01:00
request->req_next = NULL;
request->req_chain = NULL;
return request;
}
static bool link_request(rem_port* port, SERVER_REQ request)
2006-03-03 17:20:42 +01:00
{
/**************************************
*
* l i n k _ r e q u e s t
*
**************************************
*
* Functional description
2008-12-02 08:09:49 +01:00
* Search for a port in a queue,
2006-03-03 17:20:42 +01:00
* if found - append new request to it.
*
**************************************/
const P_OP operation = request->req_receive.p_operation;
SERVER_REQ queue;
2008-03-14 03:50:40 +01:00
{ // request_que_mutex scope
Firebird::MutexLockGuard queGuard(request_que_mutex);
bool active = true;
queue = active_requests;
2008-03-14 03:50:40 +01:00
while (true)
2006-03-03 17:20:42 +01:00
{
2008-12-02 08:09:49 +01:00
for (; queue; queue = queue->req_next)
{
2008-12-02 08:09:49 +01:00
if (queue->req_port == port)
{
// Don't queue a dummy keepalive packet if there is a request on this port
if (operation == op_dummy) {
free_request(request);
return true;
}
2008-12-02 08:09:49 +01:00
append_request_chain(request, &queue->req_chain);
2006-03-03 17:20:42 +01:00
#ifdef DEBUG_REMOTE_MEMORY
2008-12-02 08:09:49 +01:00
printf("link_request %s request_queued %d\n",
active ? "ACTIVE" : "PENDING", port->port_requests_queued);
fflush(stdout);
2006-03-03 17:20:42 +01:00
#endif
break;
}
}
2008-03-14 03:50:40 +01:00
if (queue || !active)
break;
2008-03-14 03:50:40 +01:00
queue = request_que;
active = false;
}
if (!queue) {
append_request_next(request, &request_que);
}
} // request_que_mutex scope
port->port_requests_queued++;
if (queue)
{
if (operation == op_exit || operation == op_disconnect)
cancel_operation(port, fb_cancel_raise);
return true;
2006-03-03 17:20:42 +01:00
}
return false;
}
void SRVR_multi_thread( rem_port* main_port, USHORT flags)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* S R V R _ m u l t i _ t h r e a d
*
**************************************
*
* Functional description
* Multi-threaded flavor of server.
*
**************************************/
2008-01-16 08:55:28 +01:00
SERVER_REQ request = NULL;
RemPortPtr port; // Was volatile PORT port = NULL;
// hold reference on main_port to free asyncPacket before deletion of port
RemPortPtr mainPortRef(main_port);
PACKET asyncPacket;
2001-05-23 15:26:42 +02:00
zap_packet(&asyncPacket, true);
++cntServers;
2001-05-23 15:26:42 +02:00
2001-12-24 03:51:06 +01:00
try {
2001-05-23 15:26:42 +02:00
2006-03-03 17:20:42 +01:00
set_server(main_port, flags);
2001-05-23 15:26:42 +02:00
/* We need to have this error handler as there is so much underlaying code
* that is depending on it being there. The expected failure
* that can occur in the call paths from here is out-of-memory
* and it is unknown if other failures can get us here
* Failures can occur from set_server as well as RECEIVE
*
* Note that if a failure DOES occur, we reenter the loop and try to continue
* operations. This is important as this is the main receive loop for
* new incoming requests, if we exit here no new requests can come to the
* server.
*/
2006-03-03 17:20:42 +01:00
try {
2001-05-23 15:26:42 +02:00
2008-03-18 13:58:21 +01:00
const size_t MAX_PACKET_SIZE = MAX_SSHORT;
const SSHORT bufSize = MIN(main_port->port_buff_size, MAX_PACKET_SIZE);
2008-03-18 13:58:21 +01:00
Firebird::UCharBuffer packet_buffer;
UCHAR* const buffer = packet_buffer.getBuffer(bufSize);
2008-03-18 13:58:21 +01:00
2006-03-03 17:20:42 +01:00
// When this loop exits, the server will no longer receive requests
while (true)
2001-05-23 15:26:42 +02:00
{
SSHORT dataSize;
2006-03-03 17:20:42 +01:00
// We have a request block - now get some information to stick into it
2008-04-20 16:02:51 +02:00
const bool ok = main_port->select_multi(buffer, bufSize, &dataSize, port);
if (!port)
2006-03-03 17:20:42 +01:00
{
2008-11-06 01:23:21 +01:00
if ((main_port->port_server_flags & SRVR_multi_client) && !server_shutdown)
{
gds__log("SRVR_multi_thread/RECEIVE: error on main_port, shutting down");
}
break;
2001-05-23 15:26:42 +02:00
}
if (dataSize)
2006-03-03 17:20:42 +01:00
{
2008-05-14 11:24:14 +02:00
const SSHORT asyncSize = port->asyncReceive(&asyncPacket, buffer, dataSize);
if (asyncSize == dataSize)
{
2008-04-18 03:37:44 +02:00
port = NULL;
continue;
}
dataSize -= asyncSize;
Firebird::RefMutexGuard queGuard(*port->port_que_sync);
memcpy(port->port_queue.add().getBuffer(dataSize), buffer + asyncSize, dataSize);
2006-03-03 17:20:42 +01:00
}
2008-04-20 16:02:51 +02:00
Firebird::RefMutexEnsureUnlock portGuard(*port->port_sync);
2008-03-15 14:46:28 +01:00
const bool portLocked = portGuard.tryEnter();
if (portLocked || !dataSize)
{
// Allocate a memory block to store the request in
request = alloc_request();
2008-12-02 08:09:49 +01:00
if (dataSize)
2006-03-03 17:20:42 +01:00
{
fb_assert(portLocked);
Firebird::RefMutexGuard queGuard(*port->port_que_sync);
2007-04-03 10:18:11 +02:00
const rem_port::RecvQueState recvState = port->getRecvState();
port->receive(&request->req_receive);
if (request->req_receive.p_operation == op_partial)
{
port->setRecvState(recvState);
2008-03-15 14:46:28 +01:00
portGuard.leave();
free_request(request);
request = 0;
port = 0;
continue;
}
if (!port->haveRecvData())
{
port->clearRecvQue();
}
2006-03-03 17:20:42 +01:00
}
else
{
2008-04-20 16:02:51 +02:00
request->req_receive.p_operation = ok ? op_dummy : op_exit;
}
2001-05-23 15:26:42 +02:00
request->req_port = port;
2008-12-02 08:09:49 +01:00
if (portLocked)
{
2008-03-15 14:46:28 +01:00
portGuard.leave();
}
if (!link_request(port, request))
{
/* No port to assign request to, add it to the waiting queue and wake up a
2008-12-02 08:09:49 +01:00
* thread to handle it
*/
REMOTE_TRACE(("Enqueue request %p", request));
request = 0;
#ifdef DEBUG_REMOTE_MEMORY
printf("SRVR_multi_thread APPEND_PENDING request_queued %d\n",
port->port_requests_queued);
fflush(stdout);
2001-05-23 15:26:42 +02:00
#endif
Worker::start(flags);
}
request = 0;
2006-03-03 17:20:42 +01:00
}
port = 0;
2001-05-23 15:26:42 +02:00
}
Worker::shutdown();
// All worker threads are stopped and will never run any more
// Disconnect remaining ports gracefully
rem_port* run_port = main_port;
while (run_port)
{
rem_port* current_port = run_port; // important order of operations
run_port = run_port->port_next; // disconnect() can modify linked list of ports
if (!(current_port->port_flags & PORT_disconnect))
current_port->disconnect(NULL, NULL);
}
2001-05-23 15:26:42 +02:00
}
catch (const Firebird::Exception& e)
2001-12-24 03:51:06 +01:00
{
gds__log("SRVR_multi_thread: shutting down due to unhandled exception");
2008-03-28 15:17:21 +01:00
ISC_STATUS_ARRAY status_vector;
Firebird::stuff_exception(status_vector, e);
gds__log_status(0, status_vector);
2006-03-03 17:20:42 +01:00
/* If we got as far as having a port allocated before the error, disconnect it
* gracefully.
*/
if (port)
2006-03-03 17:20:42 +01:00
{
/*
2006-03-03 17:20:42 +01:00
#if defined(DEV_BUILD) && defined(DEBUG)
2001-12-24 03:51:06 +01:00
ConsolePrintf("%%ISERVER-F-NOPORT, no port in a storm\r\n");
2008-12-02 08:09:49 +01:00
#endif
*/
2006-03-03 17:20:42 +01:00
gds__log("SRVR_multi_thread: forcefully disconnecting a port");
/* To handle recursion within the error handler */
try {
2006-03-03 17:20:42 +01:00
/* If we have a port, request really should be non-null, but just in case ... */
if (request != NULL) {
/* Send client a real status indication of why we disconnected them */
/* Note that send_response() can post errors that wind up in this same handler */
/*
2006-03-03 17:20:42 +01:00
#if defined(DEV_BUILD) && defined(DEBUG)
ConsolePrintf
("%%ISERVER-F-NOMEM, virtual memory exhausted\r\n");
2008-12-02 08:09:49 +01:00
#endif
*/
2008-12-02 08:09:49 +01:00
port->send_response(&request->req_send, 0, 0, status_vector, false);
2006-03-03 17:20:42 +01:00
port->disconnect(&request->req_send, &request->req_receive);
}
else {
/* Can't tell the client much, just make 'em go away. Their side should detect
* a network error
*/
port->disconnect(NULL, NULL);
}
port = NULL;
} // try
catch (const Firebird::Exception&) {
2001-12-24 03:51:06 +01:00
port->disconnect(NULL, NULL);
2006-03-03 17:20:42 +01:00
port = NULL;
2001-12-24 03:51:06 +01:00
}
2006-03-03 17:20:42 +01:00
}
2001-12-24 03:51:06 +01:00
2006-03-03 17:20:42 +01:00
/* There was an error in the processing of the request, if we have allocated
* a request, free it up and continue.
*/
2008-12-02 08:09:49 +01:00
if (request != NULL)
{
free_request(request);
2006-03-03 17:20:42 +01:00
request = NULL;
2001-12-24 03:51:06 +01:00
}
}
if (main_port->port_async_receive)
{
REMOTE_free_packet(main_port->port_async_receive, &asyncPacket);
}
2001-12-24 03:51:06 +01:00
}
catch (const Firebird::Exception&) {
2001-12-24 03:51:06 +01:00
/* Some kind of unhandled error occured during server setup. In lieu
* of anything we CAN do, log something (and we might be so hosed
* we can't log anything) and give up.
* The likely error here is out-of-memory.
*/
gds__log("SRVR_multi_thread: error during startup, shutting down");
}
--cntServers;
2001-05-23 15:26:42 +02:00
}
static bool accept_connection(rem_port* port,
2003-09-11 20:59:34 +02:00
P_CNCT * connect,
PACKET* send)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* a c c e p t _ c o n n e c t i o n
*
**************************************
*
* Functional description
* Process a connect packet.
*
**************************************/
2006-12-10 01:16:00 +01:00
// Accept the physical connection
2001-05-23 15:26:42 +02:00
send->p_operation = op_reject;
P_ACPT* accept = &send->p_acpt;
2001-05-23 15:26:42 +02:00
if (!port->accept(connect)) {
port->send(send);
2003-09-11 20:59:34 +02:00
return false;
2001-05-23 15:26:42 +02:00
}
2006-12-10 01:16:00 +01:00
// Select the most appropriate protocol (this will get smarter)
2006-12-08 19:38:15 +01:00
P_ARCH architecture = arch_generic;
USHORT version = 0;
USHORT type = 0;
bool accepted = false;
USHORT weight = 0;
const p_cnct::p_cnct_repeat* protocol = connect->p_cnct_versions;
2001-05-23 15:26:42 +02:00
for (const p_cnct::p_cnct_repeat* const end = protocol + connect->p_cnct_count;
protocol < end; protocol++)
{
2001-05-23 15:26:42 +02:00
if ((protocol->p_cnct_version == PROTOCOL_VERSION3 ||
protocol->p_cnct_version == PROTOCOL_VERSION4 ||
protocol->p_cnct_version == PROTOCOL_VERSION5 ||
protocol->p_cnct_version == PROTOCOL_VERSION6 ||
protocol->p_cnct_version == PROTOCOL_VERSION7 ||
protocol->p_cnct_version == PROTOCOL_VERSION8 ||
protocol->p_cnct_version == PROTOCOL_VERSION9 ||
2006-12-08 19:38:15 +01:00
protocol->p_cnct_version == PROTOCOL_VERSION10 ||
protocol->p_cnct_version == PROTOCOL_VERSION11 ||
protocol->p_cnct_version == PROTOCOL_VERSION12
2001-05-23 15:26:42 +02:00
#ifdef SCROLLABLE_CURSORS
|| protocol->p_cnct_version == PROTOCOL_SCROLLABLE_CURSORS
#endif
) &&
(protocol->p_cnct_architecture == arch_generic ||
protocol->p_cnct_architecture == ARCHITECTURE) &&
2003-11-03 01:37:11 +01:00
protocol->p_cnct_weight >= weight)
{
2004-08-27 01:27:46 +02:00
accepted = true;
2001-05-23 15:26:42 +02:00
weight = protocol->p_cnct_weight;
version = protocol->p_cnct_version;
architecture = protocol->p_cnct_architecture;
type = MIN(protocol->p_cnct_max_type, ptype_lazy_send);
2001-05-23 15:26:42 +02:00
send->p_operation = op_accept;
}
}
2001-05-23 15:26:42 +02:00
/* Send off out gracious acceptance or flag rejection */
2004-08-27 01:27:46 +02:00
if (!accepted) {
port->send(send);
2004-08-27 01:27:46 +02:00
return false;
}
2001-05-23 15:26:42 +02:00
accept->p_acpt_version = port->port_protocol = version;
accept->p_acpt_architecture = architecture;
accept->p_acpt_type = type;
/* and modify the version string to reflect the chosen protocol */
2006-12-08 19:38:15 +01:00
Firebird::string buffer;
buffer.printf("%s/P%d", port->port_version->str_data,
port->port_protocol & FB_PROTOCOL_MASK);
delete port->port_version;
2006-12-08 19:38:15 +01:00
port->port_version = REMOTE_make_string(buffer.c_str());
2001-05-23 15:26:42 +02:00
if (architecture == ARCHITECTURE)
port->port_flags |= PORT_symmetric;
if (type == ptype_rpc)
port->port_flags |= PORT_rpc;
if (type != ptype_out_of_band)
port->port_flags |= PORT_no_oob;
if (type == ptype_lazy_send)
port->port_flags |= PORT_lazy;
2001-05-23 15:26:42 +02:00
port->send(send);
2003-09-11 20:59:34 +02:00
return true;
2001-05-23 15:26:42 +02:00
}
static ISC_STATUS allocate_statement( rem_port* port, P_RLSE * allocate, PACKET* send)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* a l l o c a t e _ s t a t e m e n t
*
**************************************
*
* Functional description
* Allocate a statement handle.
*
**************************************/
2003-04-16 12:18:51 +02:00
ISC_STATUS_ARRAY status_vector;
2001-05-23 15:26:42 +02:00
Rdb* rdb = port->port_context;
2008-12-02 08:09:49 +01:00
if (bad_db(status_vector, rdb))
{
return port->send_response(send, 0, 0, status_vector, true);
}
2008-12-02 08:09:49 +01:00
2004-05-03 01:06:37 +02:00
FB_API_HANDLE handle = 0;
2001-05-23 15:26:42 +02:00
2003-11-03 01:37:11 +01:00
GDS_DSQL_ALLOCATE(status_vector, &rdb->rdb_handle, &handle);
2001-05-23 15:26:42 +02:00
OBJCT object;
2001-05-23 15:26:42 +02:00
if (status_vector[1])
object = 0;
else {
/* Allocate SQL request block */
2008-03-30 11:37:57 +02:00
Rsr* statement = new Rsr;
2001-05-23 15:26:42 +02:00
statement->rsr_rdb = rdb;
statement->rsr_handle = handle;
if (statement->rsr_id = port->get_id(statement))
2001-05-23 15:26:42 +02:00
{
object = statement->rsr_id;
statement->rsr_next = rdb->rdb_sql_requests;
rdb->rdb_sql_requests = statement;
}
else {
object = 0;
2003-08-30 03:43:08 +02:00
GDS_DSQL_FREE(status_vector, &statement->rsr_handle, DSQL_drop);
delete statement;
2001-05-23 15:26:42 +02:00
status_vector[0] = isc_arg_gds;
status_vector[1] = isc_too_many_handles;
status_vector[2] = isc_arg_end;
}
}
return port->send_response(send, object, 0, status_vector, true);
2001-05-23 15:26:42 +02:00
}
2008-03-15 11:28:25 +01:00
static void append_request_chain(SERVER_REQ request, SERVER_REQ* que_inst)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* a p p e n d _ r e q u e s t _ c h a i n
*
**************************************
*
* Functional description
2008-12-02 08:09:49 +01:00
* Traverse using req_chain ptr and append
2001-05-23 15:26:42 +02:00
* a request at the end of a que.
* Return count of pending requests.
*
**************************************/
Firebird::MutexLockGuard queGuard(request_que_mutex);
2001-05-23 15:26:42 +02:00
2008-03-15 11:28:25 +01:00
while (*que_inst)
que_inst = &(*que_inst)->req_chain;
2001-05-23 15:26:42 +02:00
*que_inst = request;
2001-05-23 15:26:42 +02:00
}
2006-12-17 10:09:39 +01:00
2008-03-15 11:28:25 +01:00
static void append_request_next(SERVER_REQ request, SERVER_REQ* que_inst)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* a p p e n d _ r e q u e s t _ n e x t
*
**************************************
*
* Functional description
2008-12-02 08:09:49 +01:00
* Traverse using req_next ptr and append
2001-05-23 15:26:42 +02:00
* a request at the end of a que.
* Return count of pending requests.
*
**************************************/
Firebird::MutexLockGuard queGuard(request_que_mutex);
2001-05-23 15:26:42 +02:00
2008-03-15 11:28:25 +01:00
while (*que_inst)
que_inst = &(*que_inst)->req_next;
2001-05-23 15:26:42 +02:00
*que_inst = request;
2001-05-23 15:26:42 +02:00
}
2006-12-17 10:09:39 +01:00
2008-12-02 08:09:49 +01:00
static void addClumplets(Firebird::ClumpletWriter& dpb_buffer,
const ParametersSet& par,
const rem_port* port)
{
/**************************************
*
* a d d C l u m p l e t s
*
**************************************
*
* Functional description
* Insert remote endpoint data into DPB address stack
*
**************************************/
Firebird::ClumpletWriter address_stack_buffer(Firebird::ClumpletReader::UnTagged, MAX_UCHAR - 2);
if (dpb_buffer.find(par.address_path)) {
address_stack_buffer.reset(dpb_buffer.getBytes(), dpb_buffer.getClumpLength());
dpb_buffer.deleteClumplet();
}
Firebird::ClumpletWriter address_record(Firebird::ClumpletReader::UnTagged, MAX_UCHAR - 2);
if (port->port_protocol_str)
2008-12-02 08:09:49 +01:00
address_record.insertString(isc_dpb_addr_protocol,
port->port_protocol_str->str_data, port->port_protocol_str->str_length);
if (port->port_address_str)
2008-12-02 08:09:49 +01:00
address_record.insertString(isc_dpb_addr_endpoint,
port->port_address_str->str_data, port->port_address_str->str_length);
// We always insert remote address descriptor as a first element
// of appropriate clumplet so user cannot fake it and engine may somewhat trust it.
fb_assert(address_stack_buffer.getCurOffset() == 0);
2008-12-02 08:09:49 +01:00
address_stack_buffer.insertBytes(isc_dpb_address,
address_record.getBuffer(), address_record.getBufferLength());
2008-12-02 08:09:49 +01:00
dpb_buffer.insertBytes(par.address_path, address_stack_buffer.getBuffer(),
address_stack_buffer.getBufferLength());
2008-12-02 08:09:49 +01:00
// Remove all remaining isc_*pb_address_path clumplets.
// This is the security feature to prevent user from faking remote address
// by passing multiple address_path clumplets. Engine assumes that
2008-12-02 08:09:49 +01:00
// dpb contains no more than one address_path clumplet and for
// clients coming via remote interface it can trust the first address from
// address stack. Clients acessing database directly can do whatever they
// want with the engine including faking the source address, not much we
// can do about it.
while (!dpb_buffer.isEof()) {
if (dpb_buffer.getClumpTag() == par.address_path)
dpb_buffer.deleteClumplet();
else
dpb_buffer.moveNext();
}
}
2001-05-23 15:26:42 +02:00
2006-12-17 10:09:39 +01:00
2006-12-08 19:38:15 +01:00
static void attach_database(rem_port* port,
2008-12-02 08:09:49 +01:00
P_OP operation,
P_ATCH * attach,
2006-12-08 19:38:15 +01:00
PACKET* send)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* a t t a c h _ d a t a b a s e
*
**************************************
*
* Functional description
* Process an attach or create packet.
*
**************************************/
const char* file = reinterpret_cast<const char*>(attach->p_atch_file.cstr_address);
const USHORT l = attach->p_atch_file.cstr_length;
const UCHAR* dpb = attach->p_atch_dpb.cstr_address;
const USHORT dl = attach->p_atch_dpb.cstr_length;
2001-05-23 15:26:42 +02:00
Firebird::ClumpletWriter dpb_buffer(Firebird::ClumpletReader::Tagged, MAX_SSHORT);
2001-05-23 15:26:42 +02:00
if (dl)
dpb_buffer.reset(dpb, dl);
else
dpb_buffer.reset(isc_dpb_version1);
2008-01-16 08:55:28 +01:00
// remove trusted role if present (security measure)
dpb_buffer.deleteWithTag(isc_dpb_trusted_role);
2006-12-08 19:38:15 +01:00
#ifdef TRUSTED_AUTH
// Do we need trusted authentication?
if (dpb_buffer.find(isc_dpb_trusted_auth))
2006-12-08 19:38:15 +01:00
{
2008-12-02 08:09:49 +01:00
try
2006-12-08 19:38:15 +01:00
{
// extract trusted authentication data from dpb
AuthSspi::DataHolder data;
2008-12-02 08:09:49 +01:00
memcpy(data.getBuffer(dpb_buffer.getClumpLength()),
2006-12-08 19:38:15 +01:00
dpb_buffer.getBytes(), dpb_buffer.getClumpLength());
dpb_buffer.deleteClumplet();
2008-01-16 08:55:28 +01:00
// remove extra trusted auth if present (security measure)
dpb_buffer.deleteWithTag(isc_dpb_trusted_auth);
2008-01-16 08:55:28 +01:00
if (canUseTrusted() && port->port_protocol >= PROTOCOL_VERSION11)
2006-12-08 19:38:15 +01:00
{
2008-12-02 08:09:49 +01:00
port->port_trusted_auth =
new ServerAuth(file, l, dpb_buffer, attach_database2, operation);
AuthSspi* authSspi = port->port_trusted_auth->authSspi;
if (authSspi->accept(data) && authSspi->isActive())
{
send->p_operation = op_trusted_auth;
cstring& s = send->p_trau.p_trau_data;
s.cstr_allocated = 0;
s.cstr_length = data.getCount();
s.cstr_address = data.begin();
port->send(send);
return;
}
2006-12-08 19:38:15 +01:00
}
}
catch (const Firebird::status_exception& e)
2006-12-08 19:38:15 +01:00
{
ISC_STATUS_ARRAY status_vector;
Firebird::stuff_exception(status_vector, e);
delete port->port_trusted_auth;
port->port_trusted_auth = 0;
2006-12-08 19:38:15 +01:00
port->send_response(send, 0, 0, status_vector, false);
return;
}
}
2008-01-16 08:55:28 +01:00
#else
// remove trusted auth if present (security measure)
dpb_buffer.deleteWithTag(isc_dpb_trusted_auth);
2006-12-08 19:38:15 +01:00
#endif //TRUSTED_AUTH
2008-01-16 08:55:28 +01:00
2008-12-02 08:09:49 +01:00
attach_database2(port, operation, file, l, dpb_buffer.getBuffer(),
2006-12-08 19:38:15 +01:00
dpb_buffer.getBufferLength(), send);
}
2006-12-17 10:09:39 +01:00
2006-12-08 19:38:15 +01:00
static void attach_database2(rem_port* port,
P_OP operation,
2008-12-02 08:09:49 +01:00
const char* file,
int l,
const UCHAR* dpb,
int dl,
2006-12-08 19:38:15 +01:00
PACKET* send)
{
send->p_operation = op_accept;
FB_API_HANDLE handle = 0;
Firebird::ClumpletWriter dpb_buffer(Firebird::ClumpletReader::Tagged, MAX_SSHORT);
if (dl)
dpb_buffer.reset(dpb, dl);
else
dpb_buffer.reset(isc_dpb_version1);
#ifdef TRUSTED_AUTH
// If we have trusted authentication, append it to database parameter block
if (port->port_trusted_auth)
{
AuthSspi* authSspi = port->port_trusted_auth->authSspi;
Firebird::string trustedUserName;
2008-01-16 08:55:28 +01:00
bool wheel = false;
if (authSspi->getLogin(trustedUserName, wheel))
2006-12-08 19:38:15 +01:00
{
dpb_buffer.insertString(isc_dpb_trusted_auth, trustedUserName);
2008-01-16 08:55:28 +01:00
if (wheel && !dpb_buffer.find(isc_dpb_sql_role_name))
{
dpb_buffer.insertString(isc_dpb_trusted_role, ADMIN_ROLE, strlen(ADMIN_ROLE));
}
2006-12-08 19:38:15 +01:00
}
}
#endif //TRUSTED_AUTH
// If we have user identification, append it to database parameter block
rem_str* string = port->port_user_name;
if (string) {
dpb_buffer.setCurOffset(dpb_buffer.getBufferLength());
dpb_buffer.insertString(isc_dpb_sys_user_name, string->str_data, string->str_length);
}
// Now insert additional clumplets into dpb
addClumplets(dpb_buffer, dpbParam, port);
2008-12-02 08:09:49 +01:00
/* Disable remote gsec attachments */
dpb_buffer.deleteWithTag(isc_dpb_gsec_attach);
dpb_buffer.deleteWithTag(isc_dpb_sec_attach);
2001-05-23 15:26:42 +02:00
/* See if user has specified parameters relevant to the connection,
2001-05-23 15:26:42 +02:00
they will be stuffed in the DPB if so. */
REMOTE_get_timeout_params(port, &dpb_buffer);
dpb = dpb_buffer.getBuffer();
dl = dpb_buffer.getBufferLength();
2001-05-23 15:26:42 +02:00
2008-03-28 15:17:21 +01:00
ISC_STATUS_ARRAY status_vector;
2001-05-23 15:26:42 +02:00
if (operation == op_attach)
{
isc_attach_database(status_vector, l, file,
&handle, dl, reinterpret_cast<const char*>(dpb));
2001-05-23 15:26:42 +02:00
}
else
{
isc_create_database(status_vector, l, file,
&handle, dl, reinterpret_cast<const char*>(dpb), 0);
2001-05-23 15:26:42 +02:00
}
if (!status_vector[1])
{
Rdb* rdb = new Rdb;
if (rdb)
{
port->port_context = rdb;
#ifdef DEBUG_REMOTE_MEMORY
printf("attach_databases(server) allocate rdb %x\n", rdb);
2001-05-23 15:26:42 +02:00
#endif
rdb->rdb_port = port;
rdb->rdb_handle = handle;
}
else
{
status_vector[0] = isc_arg_gds;
status_vector[1] = isc_virmemexh;
status_vector[2] = isc_arg_end;
}
2001-05-23 15:26:42 +02:00
}
2006-12-08 19:38:15 +01:00
port->send_response(send, 0, 0, status_vector, false);
#ifdef TRUSTED_AUTH
delete port->port_trusted_auth;
port->port_trusted_auth = 0;
#endif
2001-05-23 15:26:42 +02:00
}
2004-03-14 06:51:54 +01:00
#ifdef NOT_USED_OR_REPLACED
static void aux_connect( rem_port* port, P_REQ * request, PACKET* send)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* a u x _ c o n n e c t
*
**************************************
*
* Functional description
* We're receive a auxiliary connection on the main communications
* channel. Accept connection and reply politely.
*
2004-03-14 06:51:54 +01:00
* 13-Mar-2004, Nickolay Samofatov
* This code is 64-bit unsafe, unused and also has a security hole, thus I disable it for now
*
2001-05-23 15:26:42 +02:00
**************************************/
port->connect(0, 0);
rem_port* partner = (rem_port*) request->p_req_partner;
2001-05-23 15:26:42 +02:00
partner->port_async = port;
}
2004-03-14 06:51:54 +01:00
#endif
2001-05-23 15:26:42 +02:00
static void aux_request( rem_port* port, P_REQ * request, PACKET* send)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* a u x _ r e q u e s t
*
**************************************
*
* Functional description
* Other guy wants to establish a secondary connection.
* Humor him.
*
**************************************/
2003-04-16 12:18:51 +02:00
ISC_STATUS_ARRAY status_vector;
2001-05-23 15:26:42 +02:00
/* save the port status vector */
ISC_STATUS* const save_status = port->port_status_vector;
2001-05-23 15:26:42 +02:00
port->port_status_vector = status_vector;
success(status_vector);
// This buffer is used by INET and WNET transports
// to return the server identification string
UCHAR buffer[BUFFER_TINY];
send->p_resp.p_resp_data.cstr_address = buffer;
rem_port* aux_port = port->request(send);
Rdb* rdb = port->port_context;
if (bad_db(status_vector, rdb))
{
// who has any idea what else to do with such attempt
return;
}
2008-12-02 08:09:49 +01:00
2001-05-23 15:26:42 +02:00
port->send_response(send, rdb->rdb_id,
2008-12-02 08:09:49 +01:00
send->p_resp.p_resp_data.cstr_length,
status_vector, false);
2001-05-23 15:26:42 +02:00
if (status_vector[1]) {
/* restore the port status vector */
port->port_status_vector = save_status;
return;
}
if (aux_port) {
aux_port->connect(send, 0);
aux_port->port_context = rdb;
}
/* restore the port status vector */
port->port_status_vector = save_status;
}
static ISC_STATUS cancel_events( rem_port* port, P_EVENT * stuff, PACKET* send)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* c a n c e l _ e v e n t s
*
**************************************
*
* Functional description
* Cancel events.
*
**************************************/
ISC_STATUS_ARRAY status_vector;
2008-12-02 08:09:49 +01:00
2001-05-23 15:26:42 +02:00
/* Which database ? */
Rdb* rdb = port->port_context;
if (bad_db(status_vector, rdb))
{
return port->send_response(send, 0, 0, status_vector, false);
}
2001-05-23 15:26:42 +02:00
/* Find the event */
Rvnt* event;
2001-05-23 15:26:42 +02:00
for (event = rdb->rdb_events; event; event = event->rvnt_next)
2008-01-16 08:55:28 +01:00
{
2001-05-23 15:26:42 +02:00
if (event->rvnt_rid == stuff->p_event_rid)
break;
2008-01-16 08:55:28 +01:00
}
2001-05-23 15:26:42 +02:00
/* If no event found, pretend it was cancelled */
if (!event)
return port->send_response(send, 0, 0, status_vector, false);
2001-05-23 15:26:42 +02:00
/* cancel the event */
if (event->rvnt_id) {
2003-08-30 03:43:08 +02:00
isc_cancel_events(status_vector, &rdb->rdb_handle, &event->rvnt_id);
2001-05-23 15:26:42 +02:00
}
/* zero event info */
event->rvnt_id = 0L;
event->rvnt_rid = 0L;
2003-12-22 11:00:59 +01:00
event->rvnt_ast = 0;
2001-05-23 15:26:42 +02:00
/* return response */
return port->send_response(send, 0, 0, status_vector, false);
2001-05-23 15:26:42 +02:00
}
static void cancel_operation( rem_port* port, USHORT kind)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* c a n c e l _ o p e r a t i o n
*
**************************************
*
* Functional description
* Flag a running operation for cancel.
* Service operations are not currently
* able to be canceled.
*
**************************************/
Rdb* rdb;
if ((port->port_flags & (PORT_async | PORT_disconnect)) || !(rdb = port->port_context))
2003-03-11 06:53:55 +01:00
{
return;
}
2001-05-23 15:26:42 +02:00
if (rdb->rdb_handle)
2003-03-11 06:53:55 +01:00
{
if (!(rdb->rdb_flags & Rdb::SERVICE))
2003-03-11 06:53:55 +01:00
{
ISC_STATUS_ARRAY status_vector;
fb_cancel_operation(status_vector, &rdb->rdb_handle, kind);
2001-05-23 15:26:42 +02:00
}
2003-03-11 06:53:55 +01:00
}
2001-05-23 15:26:42 +02:00
}
static bool check_request(Rrq* request,
2003-09-11 20:59:34 +02:00
USHORT incarnation,
USHORT msg_number)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* c h e c k _ r e q u e s t
*
**************************************
*
* Functional description
* Check to see if a request is ready to send us a particular
* message. If so, return TRUE, otherwise FALSE.
*
**************************************/
USHORT n;
if (!get_next_msg_no(request, incarnation, &n))
2003-09-11 20:59:34 +02:00
return false;
2001-05-23 15:26:42 +02:00
2003-09-11 20:59:34 +02:00
return (msg_number == n);
2001-05-23 15:26:42 +02:00
}
2008-03-30 11:37:57 +02:00
static USHORT check_statement_type( Rsr* statement)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* c h e c k _ s t a t e m e n t _ t y p e
*
**************************************
*
* Functional description
* Return the type of SQL statement.
*
**************************************/
UCHAR buffer[16];
2003-04-16 12:18:51 +02:00
ISC_STATUS_ARRAY local_status;
USHORT ret = 0;
2003-09-11 20:59:34 +02:00
bool done = false;
2001-05-23 15:26:42 +02:00
2003-09-11 20:59:34 +02:00
if (!GDS_DSQL_SQL_INFO(local_status, &statement->rsr_handle,
sizeof(sql_info), (const SCHAR*) sql_info,
2003-09-11 20:59:34 +02:00
sizeof(buffer), reinterpret_cast<char*>(buffer)))
2001-05-23 15:26:42 +02:00
{
for (const UCHAR* info = buffer; (*info != isc_info_end) && !done;)
2001-05-23 15:26:42 +02:00
{
const USHORT l = (USHORT) gds__vax_integer(info + 1, 2);
const USHORT type = (USHORT) gds__vax_integer(info + 3, l);
2001-05-23 15:26:42 +02:00
switch (*info)
{
2003-11-08 17:40:17 +01:00
case isc_info_sql_stmt_type:
2008-01-16 08:55:28 +01:00
switch (type)
2001-05-23 15:26:42 +02:00
{
2008-01-16 08:55:28 +01:00
case isc_info_sql_stmt_get_segment:
case isc_info_sql_stmt_put_segment:
ret |= STMT_BLOB;
2008-01-16 08:55:28 +01:00
break;
case isc_info_sql_stmt_select:
case isc_info_sql_stmt_select_for_upd:
ret |= STMT_DEFER_EXECUTE;
2008-01-16 08:55:28 +01:00
break;
2001-05-23 15:26:42 +02:00
}
break;
case isc_info_sql_batch_fetch:
2003-09-11 20:59:34 +02:00
if (type == 0)
ret |= STMT_NO_BATCH;
2001-05-23 15:26:42 +02:00
break;
case isc_info_error:
case isc_info_truncated:
2003-09-11 20:59:34 +02:00
done = true;
2001-05-23 15:26:42 +02:00
break;
}
info += 3 + l;
}
}
return ret;
}
2004-05-12 21:39:17 +02:00
ISC_STATUS rem_port::compile(P_CMPL* compileL, PACKET* sendL)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* c o m p i l e
*
**************************************
*
* Functional description
* Compile and request.
*
**************************************/
2003-04-16 12:18:51 +02:00
ISC_STATUS_ARRAY status_vector;
2001-05-23 15:26:42 +02:00
Rdb* rdb = this->port_context;
if (bad_db(status_vector, rdb))
{
return this->send_response(sendL, 0, 0, status_vector, false);
}
2004-05-03 01:06:37 +02:00
FB_API_HANDLE handle = 0;
2004-05-12 21:39:17 +02:00
const UCHAR* blr = compileL->p_cmpl_blr.cstr_address;
USHORT blr_length = compileL->p_cmpl_blr.cstr_length;
2001-05-23 15:26:42 +02:00
2003-08-30 03:43:08 +02:00
isc_compile_request(status_vector, &rdb->rdb_handle, &handle, blr_length,
reinterpret_cast<const char*>(blr));
2001-05-23 15:26:42 +02:00
if (status_vector[1])
return this->send_response(sendL, 0, 0, status_vector, false);
2001-05-23 15:26:42 +02:00
/* Parse the request to find the messages */
REM_MSG message = PARSE_messages(blr, blr_length);
USHORT max_msg = 0;
2001-05-23 15:26:42 +02:00
REM_MSG next;
2001-05-23 15:26:42 +02:00
for (next = message; next; next = next->msg_next)
max_msg = MAX(max_msg, next->msg_number);
/* Allocate block and merge into data structures */
Rrq* requestL = new Rrq(max_msg + 1);
#ifdef DEBUG_REMOTE_MEMORY
2004-04-29 00:36:29 +02:00
printf("compile(server) allocate request %x\n", request);
2001-05-23 15:26:42 +02:00
#endif
2004-05-12 21:39:17 +02:00
requestL->rrq_handle = handle;
requestL->rrq_rdb = rdb;
requestL->rrq_max_msg = max_msg;
OBJCT object = 0;
2008-12-02 08:09:49 +01:00
if (requestL->rrq_id = this->get_id(requestL))
2001-05-23 15:26:42 +02:00
{
2004-05-12 21:39:17 +02:00
object = requestL->rrq_id;
requestL->rrq_next = rdb->rdb_requests;
rdb->rdb_requests = requestL;
2001-05-23 15:26:42 +02:00
}
else {
2004-05-12 21:39:17 +02:00
isc_release_request(status_vector, &requestL->rrq_handle);
delete requestL;
2001-05-23 15:26:42 +02:00
status_vector[0] = isc_arg_gds;
status_vector[1] = isc_too_many_handles;
status_vector[2] = isc_arg_end;
return this->send_response(sendL, 0, 0, status_vector, false);
2001-05-23 15:26:42 +02:00
}
while (message) {
next = message->msg_next;
message->msg_next = message;
#ifdef SCROLLABLE_CURSORS
message->msg_prior = message;
#endif
Rrq::rrq_repeat* tail = &requestL->rrq_rpt[message->msg_number];
2001-05-23 15:26:42 +02:00
tail->rrq_message = message;
tail->rrq_xdr = message;
tail->rrq_format = (rem_fmt*) message->msg_address;
2001-05-23 15:26:42 +02:00
message->msg_address = NULL;
message = next;
}
return this->send_response(sendL, object, 0, status_vector, false);
2001-05-23 15:26:42 +02:00
}
2004-05-12 21:39:17 +02:00
ISC_STATUS rem_port::ddl(P_DDL* ddlL, PACKET* sendL)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* d d l
*
**************************************
*
* Functional description
* Execute isc_ddl call.
*
**************************************/
2003-04-16 12:18:51 +02:00
ISC_STATUS_ARRAY status_vector;
Rtr* transaction;
2001-05-23 15:26:42 +02:00
getHandle(transaction, ddlL->p_ddl_transaction);
2001-05-23 15:26:42 +02:00
Rdb* rdb = this->port_context;
if (bad_db(status_vector, rdb))
{
return this->send_response(sendL, 0, 0, status_vector, false);
}
2004-05-12 21:39:17 +02:00
const UCHAR* blr = ddlL->p_ddl_blr.cstr_address;
const USHORT blr_length = ddlL->p_ddl_blr.cstr_length;
2001-05-23 15:26:42 +02:00
2003-08-30 03:43:08 +02:00
isc_ddl(status_vector, &rdb->rdb_handle, &transaction->rtr_handle,
blr_length, reinterpret_cast<const char*>(blr));
2001-05-23 15:26:42 +02:00
return this->send_response(sendL, 0, 0, status_vector, false);
2001-05-23 15:26:42 +02:00
}
2004-05-12 21:39:17 +02:00
void rem_port::disconnect(PACKET* sendL, PACKET* receiveL)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* d i s c o n n e c t
*
**************************************
*
* Functional description
* We've lost the connection to the parent. Stop everything.
*
**************************************/
Rdb* rdb = this->port_context;
2001-05-23 15:26:42 +02:00
if (this->port_flags & PORT_async)
{
if (rdb && rdb->rdb_port && !(rdb->rdb_port->port_flags & PORT_disconnect))
{
PACKET *packet = &rdb->rdb_packet;
packet->p_operation = op_dummy;
rdb->rdb_port->send(packet);
}
2001-05-23 15:26:42 +02:00
return;
}
2001-05-23 15:26:42 +02:00
this->port_flags |= PORT_disconnect;
if (!rdb) {
2004-05-12 21:39:17 +02:00
REMOTE_free_packet(this, sendL);
REMOTE_free_packet(this, receiveL);
2001-05-23 15:26:42 +02:00
this->disconnect();
return;
}
/* For WNET and XNET we should send dummy op_disconnect packet
to wakeup async port handling events on client side.
For INET it's not necessary because INET client's async port
wakes up while server performs shutdown(socket) call on its async port.
See interface.cpp - event_thread(). */
PACKET *packet = &rdb->rdb_packet;
if (this->port_async)
{
if ((this->port_type == rem_port::XNET) || (this->port_type == rem_port::PIPE))
{
packet->p_operation = op_disconnect;
this->port_async->send(packet);
}
this->port_async->port_flags |= PORT_disconnect;
}
2001-05-23 15:26:42 +02:00
if (rdb->rdb_handle)
2008-03-28 15:17:21 +01:00
{
ISC_STATUS_ARRAY status_vector;
2008-12-02 08:09:49 +01:00
if (!(rdb->rdb_flags & Rdb::SERVICE)) {
2001-05-23 15:26:42 +02:00
/* Prevent a pending or spurious cancel from aborting
a good, clean detach from the database. */
fb_cancel_operation(status_vector, &rdb->rdb_handle, fb_cancel_disable);
2001-05-23 15:26:42 +02:00
while (rdb->rdb_requests)
release_request(rdb->rdb_requests);
while (rdb->rdb_sql_requests)
release_sql_request(rdb->rdb_sql_requests);
Rtr* transaction;
2001-05-23 15:26:42 +02:00
while (transaction = rdb->rdb_transactions) {
2008-01-16 08:55:28 +01:00
if (!transaction->rtr_limbo)
isc_rollback_transaction(status_vector, &transaction->rtr_handle);
2001-05-23 15:26:42 +02:00
#ifdef SUPERSERVER
/* The underlying JRD subsystem will release all
memory resources related to a limbo transaction
as a side-effect of the database detach call below.
However, the y-valve handle must be released. */
2001-05-23 15:26:42 +02:00
else
fb_disconnect_transaction(status_vector, &transaction->rtr_handle);
2001-05-23 15:26:42 +02:00
#endif
release_transaction(rdb->rdb_transactions);
}
2003-08-30 03:43:08 +02:00
isc_detach_database(status_vector, &rdb->rdb_handle);
2001-05-23 15:26:42 +02:00
while (rdb->rdb_events) {
release_event(rdb->rdb_events);
}
if (this->port_statement) {
release_statement(&this->port_statement);
}
}
else
{
2003-08-30 03:43:08 +02:00
isc_service_detach(status_vector, &rdb->rdb_handle);
2001-05-23 15:26:42 +02:00
}
2008-03-28 15:17:21 +01:00
}
2001-05-23 15:26:42 +02:00
2004-05-12 21:39:17 +02:00
REMOTE_free_packet(this, sendL);
REMOTE_free_packet(this, receiveL);
2001-05-23 15:26:42 +02:00
#ifdef DEBUG_REMOTE_MEMORY
2004-04-29 00:36:29 +02:00
printf("disconnect(server) free rdb %x\n", rdb);
2001-05-23 15:26:42 +02:00
#endif
this->port_context = NULL;
2007-09-14 08:55:15 +02:00
if (this->port_async)
this->port_async->port_context = NULL;
delete rdb;
2001-05-23 15:26:42 +02:00
if (this->port_connection)
{
#ifdef DEBUG_REMOTE_MEMORY
printf("disconnect(server) free string %x\n", this->port_connection);
2001-05-23 15:26:42 +02:00
#endif
delete this->port_connection;
2001-05-23 15:26:42 +02:00
this->port_connection = NULL;
}
if (this->port_version)
{
#ifdef DEBUG_REMOTE_MEMORY
printf("disconnect(server) free string %x\n", this->port_version);
2001-05-23 15:26:42 +02:00
#endif
delete this->port_version;
2001-05-23 15:26:42 +02:00
this->port_version = NULL;
}
if (this->port_passwd)
{
#ifdef DEBUG_REMOTE_MEMORY
printf("disconnect(server) free string %x\n", this->port_passwd);
2001-05-23 15:26:42 +02:00
#endif
delete this->port_passwd;
2001-05-23 15:26:42 +02:00
this->port_passwd = NULL;
}
if (this->port_user_name)
{
#ifdef DEBUG_REMOTE_MEMORY
printf("disconnect(server) free string %x\n", this->port_user_name);
2001-05-23 15:26:42 +02:00
#endif
delete this->port_user_name;
2001-05-23 15:26:42 +02:00
this->port_user_name = NULL;
}
if (this->port_host)
{
#ifdef DEBUG_REMOTE_MEMORY
printf("disconnect(server) free string %x\n", this->port_host);
2001-05-23 15:26:42 +02:00
#endif
delete this->port_host;
2001-05-23 15:26:42 +02:00
this->port_host = NULL;
}
this->disconnect();
}
2004-05-12 21:39:17 +02:00
void rem_port::drop_database(P_RLSE* release, PACKET* sendL)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* d r o p _ d a t a b a s e
*
**************************************
*
* Functional description
* End a request.
*
**************************************/
2003-04-16 12:18:51 +02:00
ISC_STATUS_ARRAY status_vector;
2001-05-23 15:26:42 +02:00
Rdb* rdb = this->port_context;
if (bad_db(status_vector, rdb))
{
this->send_response(sendL, 0, 0, status_vector, false);
return;
}
2001-05-23 15:26:42 +02:00
2003-08-30 03:43:08 +02:00
isc_drop_database(status_vector, &rdb->rdb_handle);
2001-05-23 15:26:42 +02:00
2008-03-27 03:27:56 +01:00
if (status_vector[1] && (status_vector[1] != isc_drdb_completed_with_errs))
{
this->send_response(sendL, 0, 0, status_vector, false);
2001-05-23 15:26:42 +02:00
return;
}
2001-05-23 15:26:42 +02:00
port_flags |= PORT_detached;
2001-05-23 15:26:42 +02:00
while (rdb->rdb_events)
release_event(rdb->rdb_events);
while (rdb->rdb_requests)
release_request(rdb->rdb_requests);
while (rdb->rdb_sql_requests)
release_sql_request(rdb->rdb_sql_requests);
while (rdb->rdb_transactions)
release_transaction(rdb->rdb_transactions);
if (this->port_statement)
release_statement(&this->port_statement);
this->send_response(sendL, 0, 0, status_vector, false);
2001-05-23 15:26:42 +02:00
}
#ifdef SCROLLABLE_CURSORS
static REM_MSG dump_cache( Rrq::rrq_repeat* tail)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* d u m p _ c a c h e
*
**************************************
*
* Functional description
2008-12-02 08:09:49 +01:00
* We have encountered a situation where what's in
* cache is not useful, so empty the cache in
* preparation for refilling it.
2001-05-23 15:26:42 +02:00
*
**************************************/
REM_MSG message = tail->rrq_xdr;
2003-09-11 20:59:34 +02:00
while (true) {
2001-05-23 15:26:42 +02:00
message->msg_address = NULL;
message = message->msg_next;
if (message == tail->rrq_xdr)
break;
}
tail->rrq_message = message;
return message;
}
#endif
2004-05-12 21:39:17 +02:00
ISC_STATUS rem_port::end_blob(P_OP operation, P_RLSE * release, PACKET* sendL)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* e n d _ b l o b
*
**************************************
*
* Functional description
* End a blob.
*
**************************************/
Rbl* blob;
2003-04-16 12:18:51 +02:00
ISC_STATUS_ARRAY status_vector;
2001-05-23 15:26:42 +02:00
getHandle(blob, release->p_rlse_object);
2001-05-23 15:26:42 +02:00
if (operation == op_close_blob)
2003-08-30 03:43:08 +02:00
isc_close_blob(status_vector, &blob->rbl_handle);
2001-05-23 15:26:42 +02:00
else
2003-08-30 03:43:08 +02:00
isc_cancel_blob(status_vector, &blob->rbl_handle);
2001-05-23 15:26:42 +02:00
if (!status_vector[1]) {
release_blob(blob);
}
return this->send_response(sendL, 0, 0, status_vector, false);
2001-05-23 15:26:42 +02:00
}
2004-05-12 21:39:17 +02:00
ISC_STATUS rem_port::end_database(P_RLSE * release, PACKET* sendL)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* e n d _ d a t a b a s e
*
**************************************
*
* Functional description
* End a request.
*
**************************************/
2003-04-16 12:18:51 +02:00
ISC_STATUS_ARRAY status_vector;
2001-05-23 15:26:42 +02:00
Rdb* rdb = this->port_context;
if (bad_db(status_vector, rdb))
{
return this->send_response(sendL, 0, 0, status_vector, false);
}
2001-05-23 15:26:42 +02:00
2004-11-24 10:22:07 +01:00
isc_detach_database(status_vector, &rdb->rdb_handle);
2001-05-23 15:26:42 +02:00
if (status_vector[1])
return this->send_response(sendL, 0, 0, status_vector, false);
2001-05-23 15:26:42 +02:00
port_flags |= PORT_detached;
2001-05-23 15:26:42 +02:00
while (rdb->rdb_events)
release_event(rdb->rdb_events);
while (rdb->rdb_requests)
release_request(rdb->rdb_requests);
while (rdb->rdb_sql_requests)
release_sql_request(rdb->rdb_sql_requests);
while (rdb->rdb_transactions)
release_transaction(rdb->rdb_transactions);
if (this->port_statement)
release_statement(&this->port_statement);
return this->send_response(sendL, 0, 0, status_vector, false);
2001-05-23 15:26:42 +02:00
}
2004-05-12 21:39:17 +02:00
ISC_STATUS rem_port::end_request(P_RLSE * release, PACKET* sendL)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* e n d _ r e q u e s t
*
**************************************
*
* Functional description
* End a request.
*
**************************************/
Rrq* requestL;
2003-04-16 12:18:51 +02:00
ISC_STATUS_ARRAY status_vector;
2001-05-23 15:26:42 +02:00
getHandle(requestL, release->p_rlse_object);
2001-05-23 15:26:42 +02:00
2004-05-12 21:39:17 +02:00
isc_release_request(status_vector, &requestL->rrq_handle);
2001-05-23 15:26:42 +02:00
if (!status_vector[1])
2004-05-12 21:39:17 +02:00
release_request(requestL);
2001-05-23 15:26:42 +02:00
return this->send_response(sendL, 0, 0, status_vector, true);
2001-05-23 15:26:42 +02:00
}
2004-05-12 21:39:17 +02:00
ISC_STATUS rem_port::end_statement(P_SQLFREE* free_stmt, PACKET* sendL)
2001-05-23 15:26:42 +02:00
{
/*****************************************
*
* e n d _ s t a t e m e n t
*
*****************************************
*
* Functional description
* Free a statement.
*
*****************************************/
2008-03-30 11:37:57 +02:00
Rsr* statement;
2003-04-16 12:18:51 +02:00
ISC_STATUS_ARRAY status_vector;
2001-05-23 15:26:42 +02:00
getHandle(statement, free_stmt->p_sqlfree_statement);
2001-05-23 15:26:42 +02:00
GDS_DSQL_FREE(status_vector, &statement->rsr_handle, free_stmt->p_sqlfree_option);
2001-05-23 15:26:42 +02:00
if (status_vector[1])
return this->send_response(sendL, 0, 0, status_vector, true);
2001-05-23 15:26:42 +02:00
if (!statement->rsr_handle) {
release_sql_request(statement);
statement = NULL;
}
else {
statement->rsr_flags.clear(Rsr::FETCHED);
2001-05-23 15:26:42 +02:00
statement->rsr_rtr = NULL;
REMOTE_reset_statement(statement);
statement->rsr_message = statement->rsr_buffer;
}
2006-02-04 11:37:15 +01:00
const USHORT object = (statement) ? statement->rsr_id : INVALID_OBJECT;
2001-05-23 15:26:42 +02:00
return this->send_response(sendL, object, 0, status_vector, true);
2001-05-23 15:26:42 +02:00
}
2004-05-12 21:39:17 +02:00
ISC_STATUS rem_port::end_transaction(P_OP operation, P_RLSE * release, PACKET* sendL)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* e n d _ t r a n s a c t i o n
*
**************************************
*
* Functional description
* End a transaction.
*
**************************************/
Rtr* transaction;
2003-04-16 12:18:51 +02:00
ISC_STATUS_ARRAY status_vector;
2001-05-23 15:26:42 +02:00
getHandle(transaction, release->p_rlse_object);
2001-05-23 15:26:42 +02:00
switch (operation)
{
case op_commit:
2003-08-30 03:43:08 +02:00
isc_commit_transaction(status_vector, &transaction->rtr_handle);
2001-05-23 15:26:42 +02:00
break;
case op_rollback:
2003-08-30 03:43:08 +02:00
isc_rollback_transaction(status_vector, &transaction->rtr_handle);
2001-05-23 15:26:42 +02:00
break;
case op_rollback_retaining:
2003-08-30 03:43:08 +02:00
isc_rollback_retaining(status_vector, &transaction->rtr_handle);
2001-05-23 15:26:42 +02:00
break;
case op_commit_retaining:
2003-08-30 03:43:08 +02:00
isc_commit_retaining(status_vector, &transaction->rtr_handle);
2001-05-23 15:26:42 +02:00
break;
case op_prepare:
2003-08-30 03:43:08 +02:00
if (!isc_prepare_transaction(status_vector, &transaction->rtr_handle))
2008-01-16 08:55:28 +01:00
transaction->rtr_limbo = true;
2001-05-23 15:26:42 +02:00
break;
}
if (!status_vector[1])
if (operation == op_commit || operation == op_rollback) {
REMOTE_cleanup_transaction(transaction);
release_transaction(transaction);
}
return this->send_response(sendL, 0, 0, status_vector, false);
2001-05-23 15:26:42 +02:00
}
2004-05-12 21:39:17 +02:00
ISC_STATUS rem_port::execute_immediate(P_OP op, P_SQLST * exnow, PACKET* sendL)
2001-05-23 15:26:42 +02:00
{
/*****************************************
*
* e x e c u t e _ i m m e d i a t e
*
*****************************************
*
* Functional description
* process an execute immediate DSQL packet
*
*****************************************/
Rtr* transaction = NULL;
USHORT in_blr_length, in_msg_type, parser_version,
out_blr_length, out_msg_type;
2003-04-16 12:18:51 +02:00
ISC_STATUS_ARRAY status_vector;
2001-05-23 15:26:42 +02:00
Rdb* rdb = this->port_context;
if (bad_db(status_vector, rdb))
{
return this->send_response(sendL, 0, 0, status_vector, false);
}
2001-05-23 15:26:42 +02:00
/** Do not call CHECK_HANDLE if this is the start of a transaction **/
if (exnow->p_sqlst_transaction) {
getHandle(transaction, exnow->p_sqlst_transaction);
2001-05-23 15:26:42 +02:00
}
USHORT in_msg_length = 0, out_msg_length = 0;
2008-03-30 11:37:57 +02:00
const UCHAR* in_msg = NULL;
UCHAR* out_msg = NULL;
UCHAR* in_blr;
UCHAR* out_blr;
2001-05-23 15:26:42 +02:00
if (op == op_exec_immediate2)
{
in_blr_length = exnow->p_sqlst_blr.cstr_length;
in_blr = exnow->p_sqlst_blr.cstr_address;
in_msg_type = exnow->p_sqlst_message_number;
if (this->port_statement->rsr_bind_format)
{
in_msg_length = this->port_statement->rsr_bind_format->fmt_length;
in_msg = this->port_statement->rsr_message->msg_address;
}
out_blr_length = exnow->p_sqlst_out_blr.cstr_length;
out_blr = exnow->p_sqlst_out_blr.cstr_address;
out_msg_type = exnow->p_sqlst_out_message_number;
if (this->port_statement->rsr_select_format)
{
2008-03-30 11:37:57 +02:00
out_msg_length = this->port_statement->rsr_select_format->fmt_length;
2001-05-23 15:26:42 +02:00
if (!this->port_statement->rsr_message->msg_address)
{
/* TMN: Obvious bugfix. Please look at your compilers warnings. */
/* They are not enemies, they're friends! */
/* port->port_statement->rsr_message->msg_address = &port->port_statement->rsr_message->msg_buffer; */
this->port_statement->rsr_message->msg_address =
this->port_statement->rsr_message->msg_buffer;
}
out_msg = this->port_statement->rsr_message->msg_address;
}
}
else
{
in_blr_length = out_blr_length = 0;
in_blr = out_blr = NULL;
in_msg_type = out_msg_type = 0;
}
2004-05-03 01:06:37 +02:00
FB_API_HANDLE handle = (transaction) ? transaction->rtr_handle : 0;
2001-05-23 15:26:42 +02:00
/* Since the API to GDS_DSQL_EXECUTE_IMMED is public and can not be changed, there needs to
* be a way to send the parser version to DSQL so that the parser can compare the keyword
* version to the parser version. To accomplish this, the parser version is combined with
* the client dialect and sent across that way. In dsql8_execute_immediate, the parser version
* and client dialect are separated and passed on to their final desintations. The information
* is combined as follows:
* Dialect * 10 + parser_version
*
* and is extracted in dsql8_execute_immediate as follows:
2004-09-05 15:53:56 +02:00
* parser_version = ((dialect * 10) + parser_version) % 10
* client_dialect = ((dialect * 10) + parser_version) / 10
2001-05-23 15:26:42 +02:00
*
* For example, parser_version = 1 and client dialect = 1
*
* combined = (1 * 10) + 1 == 11
*
2004-09-05 15:53:56 +02:00
* parser = (combined) % 10 == 1
* dialect = (combined) / 10 == 1
2001-05-23 15:26:42 +02:00
*/
parser_version = (this->port_protocol < PROTOCOL_VERSION10) ? 1 : 2;
GDS_DSQL_EXECUTE_IMMED(status_vector,
&rdb->rdb_handle,
&handle,
2001-05-23 15:26:42 +02:00
exnow->p_sqlst_SQL_str.cstr_length,
2008-03-30 11:37:57 +02:00
reinterpret_cast<const char*>(exnow->p_sqlst_SQL_str.cstr_address),
(USHORT) ((exnow->p_sqlst_SQL_dialect * 10) + parser_version),
2001-05-23 15:26:42 +02:00
in_blr_length,
reinterpret_cast<char*>(in_blr),
2001-05-23 15:26:42 +02:00
in_msg_type,
in_msg_length,
2008-03-30 11:37:57 +02:00
reinterpret_cast<const char*>(in_msg),
2001-05-23 15:26:42 +02:00
out_blr_length,
reinterpret_cast<char*>(out_blr),
out_msg_type,
out_msg_length,
reinterpret_cast<char*>(out_msg));
if (op == op_exec_immediate2)
{
this->port_statement->rsr_format = this->port_statement->rsr_select_format;
2001-05-23 15:26:42 +02:00
2004-05-12 21:39:17 +02:00
sendL->p_operation = op_sql_response;
sendL->p_sqldata.p_sqldata_messages = (status_vector[1] || !out_msg) ? 0 : 1;
2004-05-12 21:39:17 +02:00
this->send_partial(sendL);
2001-05-23 15:26:42 +02:00
}
if (!status_vector[1]) {
if (transaction && !handle) {
REMOTE_cleanup_transaction(transaction);
release_transaction(transaction);
transaction = NULL;
}
else if (!transaction && handle) {
if (!(transaction = make_transaction(rdb, handle))) {
status_vector[0] = isc_arg_gds;
status_vector[1] = isc_too_many_handles;
status_vector[2] = isc_arg_end;
}
}
}
2004-05-12 21:39:17 +02:00
return this->send_response( sendL,
2001-05-23 15:26:42 +02:00
(OBJCT) (transaction ? transaction->rtr_id : 0),
0,
2008-12-02 08:09:49 +01:00
status_vector,
false);
2001-05-23 15:26:42 +02:00
}
2004-05-12 21:39:17 +02:00
ISC_STATUS rem_port::execute_statement(P_OP op, P_SQLDATA* sqldata, PACKET* sendL)
2001-05-23 15:26:42 +02:00
{
/*****************************************
*
* e x e c u t e _ s t a t e m e n t
*
*****************************************
*
* Functional description
* Execute a non-SELECT dynamic SQL statement.
*
*****************************************/
Rtr* transaction = NULL;
2001-05-23 15:26:42 +02:00
/** Do not call CHECK_HANDLE if this is the start of a transaction **/
if (sqldata->p_sqldata_transaction)
{
getHandle(transaction, sqldata->p_sqldata_transaction);
2001-05-23 15:26:42 +02:00
}
2008-03-30 11:37:57 +02:00
Rsr* statement;
getHandle(statement, sqldata->p_sqldata_statement);
2001-05-23 15:26:42 +02:00
USHORT in_msg_length = 0, out_msg_length = 0;
UCHAR* in_msg = NULL;
UCHAR* out_msg = NULL;
USHORT out_msg_type, out_blr_length;
UCHAR* out_blr;
2001-05-23 15:26:42 +02:00
if (statement->rsr_format)
{
in_msg_length = statement->rsr_format->fmt_length;
in_msg = statement->rsr_message->msg_address;
}
if (op == op_execute2)
{
out_blr_length = sqldata->p_sqldata_out_blr.cstr_length;
out_blr = sqldata->p_sqldata_out_blr.cstr_address;
out_msg_type = sqldata->p_sqldata_out_message_number;
if (this->port_statement->rsr_select_format)
{
out_msg_length = this->port_statement->rsr_select_format->fmt_length;
2001-05-23 15:26:42 +02:00
out_msg = this->port_statement->rsr_message->msg_buffer;
}
}
else
{
out_blr_length = 0;
out_msg_type = 0;
out_blr = NULL;
}
statement->rsr_flags.clear(Rsr::FETCHED);
2001-05-23 15:26:42 +02:00
2004-05-03 01:06:37 +02:00
FB_API_HANDLE handle = (transaction) ? transaction->rtr_handle : 0;
2001-05-23 15:26:42 +02:00
2008-03-28 15:17:21 +01:00
ISC_STATUS_ARRAY status_vector;
2008-12-02 08:09:49 +01:00
2001-05-23 15:26:42 +02:00
GDS_DSQL_EXECUTE(status_vector,
&handle,
&statement->rsr_handle,
2001-05-23 15:26:42 +02:00
sqldata->p_sqldata_blr.cstr_length,
2008-03-30 11:37:57 +02:00
reinterpret_cast<const char*>(sqldata->p_sqldata_blr.cstr_address),
2001-05-23 15:26:42 +02:00
sqldata->p_sqldata_message_number,
in_msg_length,
reinterpret_cast<char*>(in_msg),
2001-05-23 15:26:42 +02:00
out_blr_length,
reinterpret_cast<char*>(out_blr),
out_msg_type,
out_msg_length,
reinterpret_cast<char*>(out_msg));
if (op == op_execute2)
{
this->port_statement->rsr_format = this->port_statement->rsr_select_format;
2001-05-23 15:26:42 +02:00
2004-05-12 21:39:17 +02:00
sendL->p_operation = op_sql_response;
sendL->p_sqldata.p_sqldata_messages = (status_vector[1] || !out_msg) ? 0 : 1;
2004-05-12 21:39:17 +02:00
this->send_partial(sendL);
2001-05-23 15:26:42 +02:00
}
if (!status_vector[1]) {
if (transaction && !handle) {
REMOTE_cleanup_transaction(transaction);
release_transaction(transaction);
transaction = NULL;
}
else if (!transaction && handle) {
if (!(transaction = make_transaction(statement->rsr_rdb, handle))) {
status_vector[0] = isc_arg_gds;
status_vector[1] = isc_too_many_handles;
status_vector[2] = isc_arg_end;
}
}
statement->rsr_rtr = transaction;
}
const bool defer = this->haveRecvData();
2004-05-12 21:39:17 +02:00
return this->send_response( sendL,
2001-05-23 15:26:42 +02:00
(OBJCT) (transaction ? transaction->rtr_id : 0),
0,
2008-12-02 08:09:49 +01:00
status_vector,
defer);
2001-05-23 15:26:42 +02:00
}
2004-05-12 21:39:17 +02:00
ISC_STATUS rem_port::fetch(P_SQLDATA * sqldata, PACKET* sendL)
2001-05-23 15:26:42 +02:00
{
/*****************************************
*
* f e t c h
*
*****************************************
*
* Functional description
* Fetch next record from a dynamic SQL cursor.
*
*****************************************/
2008-03-30 11:37:57 +02:00
Rsr* statement;
2001-05-23 15:26:42 +02:00
getHandle(statement, sqldata->p_sqldata_statement);
2001-05-23 15:26:42 +02:00
if (statement->rsr_flags.test(Rsr::BLOB)) {
2004-05-12 21:39:17 +02:00
return this->fetch_blob(sqldata, sendL);
2001-05-23 15:26:42 +02:00
}
USHORT msg_length;
2001-05-23 15:26:42 +02:00
if (statement->rsr_format) {
msg_length = statement->rsr_format->fmt_length;
}
else {
2001-05-23 15:26:42 +02:00
msg_length = 0;
}
USHORT count = ((this->port_flags & PORT_rpc) || statement->rsr_flags.test(Rsr::NO_BATCH)) ?
1 : sqldata->p_sqldata_messages;
USHORT count2 = statement->rsr_flags.test(Rsr::NO_BATCH) ? 0 : count;
2001-05-23 15:26:42 +02:00
2008-03-28 15:17:21 +01:00
// On first fetch, clear the end-of-stream flag & reset the message buffers
2001-05-23 15:26:42 +02:00
if (!statement->rsr_flags.test(Rsr::FETCHED)) {
statement->rsr_flags.clear(Rsr::EOF_SET | Rsr::STREAM_ERR);
statement->clearException();
REM_MSG message = statement->rsr_message;
if (message != NULL) {
2001-05-23 15:26:42 +02:00
statement->rsr_buffer = message;
2003-09-11 20:59:34 +02:00
while (true) {
2001-05-23 15:26:42 +02:00
message->msg_address = NULL;
message = message->msg_next;
if (message == statement->rsr_message)
break;
}
}
}
2008-03-28 15:17:21 +01:00
// Get ready to ship the data out
2001-05-23 15:26:42 +02:00
2004-05-12 21:39:17 +02:00
P_SQLDATA* response = &sendL->p_sqldata;
sendL->p_operation = op_fetch_response;
2001-05-23 15:26:42 +02:00
response->p_sqldata_statement = sqldata->p_sqldata_statement;
response->p_sqldata_status = 0;
response->p_sqldata_messages = 1;
ISC_STATUS s = 0;
REM_MSG message = NULL;
2001-05-23 15:26:42 +02:00
2008-03-28 15:17:21 +01:00
// Check to see if any messages are already sitting around
ISC_STATUS_ARRAY status_vector;
2001-05-23 15:26:42 +02:00
2003-09-11 20:59:34 +02:00
while (true) {
2001-05-23 15:26:42 +02:00
/* Have we exhausted the cache & reached cursor EOF? */
if (statement->rsr_flags.test(Rsr::EOF_SET) && !statement->rsr_msgs_waiting) {
statement->rsr_flags.clear(Rsr::EOF_SET);
2001-05-23 15:26:42 +02:00
s = 100;
count2 = 0;
break;
}
/* Have we exhausted the cache & have a pending error? */
if (statement->rsr_flags.test(Rsr::STREAM_ERR) && !statement->rsr_msgs_waiting)
{
fb_assert(statement->rsr_status);
statement->rsr_flags.clear(Rsr::STREAM_ERR);
2004-05-12 21:39:17 +02:00
return this->send_response(sendL, 0, 0,
statement->rsr_status->value(),
false);
2001-05-23 15:26:42 +02:00
}
message = statement->rsr_buffer;
/* Make sure message can be de referenced, if not then return false */
if (message == NULL)
return FALSE;
/* If we don't have a message cached, get one from the
access method. */
if (!message->msg_address) {
2003-11-04 00:59:24 +01:00
fb_assert(statement->rsr_msgs_waiting == 0);
2001-05-23 15:26:42 +02:00
s = GDS_DSQL_FETCH(status_vector,
&statement->rsr_handle,
2001-05-23 15:26:42 +02:00
sqldata->p_sqldata_blr.cstr_length,
reinterpret_cast<char*>(sqldata->p_sqldata_blr.cstr_address),
2001-05-23 15:26:42 +02:00
sqldata->p_sqldata_message_number,
msg_length,
reinterpret_cast<char*>(message->msg_buffer.operator UCHAR*()));
2001-05-23 15:26:42 +02:00
statement->rsr_flags.set(Rsr::FETCHED);
2001-05-23 15:26:42 +02:00
if (s) {
2008-01-16 08:55:28 +01:00
if (s == 100 || s == 101)
{
2001-05-23 15:26:42 +02:00
count2 = 0;
break;
}
2008-01-16 08:55:28 +01:00
return this->send_response(sendL, 0, 0, status_vector, false);
2001-05-23 15:26:42 +02:00
}
message->msg_address = message->msg_buffer;
}
else {
/* Take a message from the outqoing queue */
2003-11-04 00:59:24 +01:00
fb_assert(statement->rsr_msgs_waiting >= 1);
2001-05-23 15:26:42 +02:00
statement->rsr_msgs_waiting--;
}
/* For compatibility with Protocol 7, we must break out of the
loop before sending the last record. */
count--;
if (this->port_protocol <= PROTOCOL_VERSION7 && count <= 0) {
break;
}
/* There's a buffer waiting -- send it */
2004-05-12 21:39:17 +02:00
if (!this->send_partial(sendL)) {
2001-05-23 15:26:42 +02:00
return FALSE;
}
message->msg_address = NULL;
/* If we've sent the requested amount, break out of loop */
if (count <= 0)
break;
}
response->p_sqldata_status = s;
response->p_sqldata_messages = 0;
// hvlad: message->msg_address not used in xdr_protocol because of
// response->p_sqldata_messages set to zero above.
2008-12-02 08:09:49 +01:00
// It is important to not zero message->msg_address after send because
// during thread context switch in send we can receive packet with
// op_free and op_execute (lazy port feature allow this) which itself
// set message->msg_address to some useful information
2006-12-29 09:48:28 +01:00
// This fix must be re-thought when real multithreading will be implemented
2001-05-23 15:26:42 +02:00
if (message) {
message->msg_address = NULL;
}
this->send(sendL);
2001-05-23 15:26:42 +02:00
/* Since we have a little time on our hands while this packet is sent
and processed, get the next batch of records. Start by finding the
next free buffer. */
message = statement->rsr_buffer;
REM_MSG next = NULL;
2001-05-23 15:26:42 +02:00
while (message->msg_address && message->msg_next != statement->rsr_buffer)
message = message->msg_next;
for (; count2; --count2) {
if (message->msg_address) {
if (!next)
2008-01-16 08:55:28 +01:00
{
next = statement->rsr_buffer;
while (next->msg_next != message)
next = next->msg_next;
}
message = new Message(statement->rsr_fmt_length);
2001-05-23 15:26:42 +02:00
message->msg_number = next->msg_number;
message->msg_next = next->msg_next;
next->msg_next = message;
next = message;
}
s = GDS_DSQL_FETCH(status_vector,
&statement->rsr_handle,
2001-05-23 15:26:42 +02:00
sqldata->p_sqldata_blr.cstr_length,
reinterpret_cast<char*>(sqldata->p_sqldata_blr.cstr_address),
2001-05-23 15:26:42 +02:00
sqldata->p_sqldata_message_number,
msg_length,
reinterpret_cast<char*>(message->msg_buffer.operator UCHAR*()));
2001-05-23 15:26:42 +02:00
if (s) {
if (status_vector[1]) {
/* If already have an error queued, don't overwrite it */
if (!statement->rsr_flags.test(Rsr::STREAM_ERR)) {
statement->rsr_flags.set(Rsr::STREAM_ERR);
statement->saveException(status_vector, true);
2001-05-23 15:26:42 +02:00
}
}
if (s == 100)
statement->rsr_flags.set(Rsr::EOF_SET);
2001-05-23 15:26:42 +02:00
break;
}
message->msg_address = message->msg_buffer;
message = message->msg_next;
statement->rsr_msgs_waiting++;
}
2003-09-13 11:15:06 +02:00
return TRUE;
2001-05-23 15:26:42 +02:00
}
2004-05-12 21:39:17 +02:00
ISC_STATUS rem_port::fetch_blob(P_SQLDATA * sqldata, PACKET* sendL)
2001-05-23 15:26:42 +02:00
{
/*****************************************
*
* f e t c h _ b l o b
*
*****************************************
*
* Functional description
* Fetch next record from a dynamic SQL cursor.
*
*****************************************/
2008-03-30 11:37:57 +02:00
Rsr* statement;
2001-05-23 15:26:42 +02:00
getHandle(statement, sqldata->p_sqldata_statement);
2001-05-23 15:26:42 +02:00
USHORT msg_length;
2001-05-23 15:26:42 +02:00
if (statement->rsr_format)
msg_length = statement->rsr_format->fmt_length;
else
msg_length = 0;
REM_MSG message = statement->rsr_message;
if (message != NULL)
2001-05-23 15:26:42 +02:00
statement->rsr_buffer = message;
/* Get ready to ship the data out */
2004-05-12 21:39:17 +02:00
P_SQLDATA* response = &sendL->p_sqldata;
sendL->p_operation = op_fetch_response;
2001-05-23 15:26:42 +02:00
response->p_sqldata_statement = sqldata->p_sqldata_statement;
response->p_sqldata_status = 0;
response->p_sqldata_messages = 1;
ISC_STATUS s = 0;
2001-05-23 15:26:42 +02:00
message = statement->rsr_buffer;
2008-03-28 15:17:21 +01:00
ISC_STATUS_ARRAY status_vector;
2001-05-23 15:26:42 +02:00
s = GDS_DSQL_FETCH(status_vector,
&statement->rsr_handle,
2001-05-23 15:26:42 +02:00
sqldata->p_sqldata_blr.cstr_length,
reinterpret_cast<char*>(sqldata->p_sqldata_blr.cstr_address),
2001-05-23 15:26:42 +02:00
sqldata->p_sqldata_message_number,
msg_length,
reinterpret_cast<char*>(message->msg_buffer.operator UCHAR*()));
2001-05-23 15:26:42 +02:00
if (!status_vector[1] || status_vector[1] != isc_segment || status_vector[1] != isc_segstr_eof)
{
2001-05-23 15:26:42 +02:00
message->msg_address = message->msg_buffer;
response->p_sqldata_status = s;
response->p_sqldata_messages = (status_vector[1] == isc_segstr_eof) ? 0 : 1;
2004-05-12 21:39:17 +02:00
this->send_partial(sendL);
2001-05-23 15:26:42 +02:00
message->msg_address = NULL;
}
return this->send_response(sendL, 0, 0, status_vector, false);
2001-05-23 15:26:42 +02:00
}
static bool get_next_msg_no(Rrq* request,
2003-09-11 20:59:34 +02:00
USHORT incarnation,
USHORT * msg_number)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* g e t _ n e x t _ m s g _ n o
*
**************************************
*
* Functional description
* Return the number of the next message
* in the request.
*
**************************************/
2003-04-16 12:18:51 +02:00
ISC_STATUS_ARRAY status_vector;
UCHAR info_buffer[128];
2001-05-23 15:26:42 +02:00
2003-08-30 03:43:08 +02:00
isc_request_info(status_vector, &request->rrq_handle, incarnation,
sizeof(request_info), reinterpret_cast<const SCHAR*>(request_info),
2003-08-30 03:43:08 +02:00
sizeof(info_buffer), reinterpret_cast<char*>(info_buffer));
2001-05-23 15:26:42 +02:00
if (status_vector[1])
2003-09-11 20:59:34 +02:00
return false;
2001-05-23 15:26:42 +02:00
2003-09-11 20:59:34 +02:00
bool result = false;
for (const UCHAR* info = info_buffer; *info != isc_info_end;)
{
const USHORT l = (USHORT) gds__vax_integer(info + 1, 2);
const USHORT n = (USHORT) gds__vax_integer(info + 3, l);
2001-05-23 15:26:42 +02:00
switch (*info) {
2003-11-08 17:40:17 +01:00
case isc_info_state:
if (n != isc_info_req_send)
2003-09-11 20:59:34 +02:00
return false;
2001-05-23 15:26:42 +02:00
break;
2003-11-08 17:40:17 +01:00
case isc_info_message_number:
2001-05-23 15:26:42 +02:00
*msg_number = n;
2003-09-11 20:59:34 +02:00
result = true;
2001-05-23 15:26:42 +02:00
break;
default:
2003-09-11 20:59:34 +02:00
return false;
2001-05-23 15:26:42 +02:00
}
info += 3 + l;
}
return result;
}
2004-05-12 21:39:17 +02:00
ISC_STATUS rem_port::get_segment(P_SGMT* segment, PACKET* sendL)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* g e t _ s e g m e n t
*
**************************************
*
* Functional description
* Get a single blob segment.
*
**************************************/
Rbl* blob;
2001-05-23 15:26:42 +02:00
getHandle(blob, segment->p_sgmt_blob);
2001-05-23 15:26:42 +02:00
UCHAR temp_buffer[BLOB_LENGTH];
USHORT buffer_length = segment->p_sgmt_length;
UCHAR* buffer;
2001-05-23 15:26:42 +02:00
if (buffer_length <= sizeof(temp_buffer))
buffer = temp_buffer;
else
{
if (buffer_length > blob->rbl_buffer_length) {
blob->rbl_buffer = blob->rbl_data.getBuffer(buffer_length);
2001-05-23 15:26:42 +02:00
blob->rbl_buffer_length = buffer_length;
}
buffer = blob->rbl_buffer;
}
#ifdef DEBUG_REMOTE_MEMORY
2004-04-29 00:36:29 +02:00
printf("get_segment(server) allocate buffer %x\n", buffer);
2001-05-23 15:26:42 +02:00
#endif
2004-05-12 21:39:17 +02:00
sendL->p_resp.p_resp_data.cstr_address = buffer;
2001-05-23 15:26:42 +02:00
/* Be backwards compatible */
2008-03-28 15:17:21 +01:00
ISC_STATUS_ARRAY status_vector;
USHORT length;
2001-05-23 15:26:42 +02:00
if (this->port_flags & PORT_rpc)
{
length = 0;
2003-08-30 03:43:08 +02:00
isc_get_segment(status_vector, &blob->rbl_handle, &length,
2001-05-23 15:26:42 +02:00
segment->p_sgmt_length,
2003-08-30 03:43:08 +02:00
reinterpret_cast<char*>(buffer));
const ISC_STATUS status =
this->send_response(sendL, blob->rbl_id, length, status_vector, false);
#ifdef DEBUG_REMOTE_MEMORY
2004-04-29 00:36:29 +02:00
printf("get_segment(server) free buffer %x\n", buffer);
2001-05-23 15:26:42 +02:00
#endif
return status;
}
/* Gobble up a buffer's worth of segments */
UCHAR* p = buffer;
ISC_STATUS state = 0;
2001-05-23 15:26:42 +02:00
while (buffer_length > 2) {
buffer_length -= 2;
p += 2;
2003-08-30 03:43:08 +02:00
isc_get_segment(status_vector, &blob->rbl_handle, &length,
buffer_length, reinterpret_cast<char*>(p));
2003-11-08 17:40:17 +01:00
if (status_vector[1] == isc_segstr_eof)
2001-05-23 15:26:42 +02:00
{
state = 2;
success(status_vector);
p -= 2;
break;
}
2003-11-08 17:40:17 +01:00
if (status_vector[1] && (status_vector[1] != isc_segment))
2001-05-23 15:26:42 +02:00
{
p -= 2;
break;
}
p[-2] = (UCHAR) length;
p[-1] = (UCHAR) (length >> 8);
p += length;
buffer_length -= length;
2003-11-08 17:40:17 +01:00
if (status_vector[1] == isc_segment) {
2001-05-23 15:26:42 +02:00
state = 1;
success(status_vector);
break;
}
}
2004-05-12 21:39:17 +02:00
const ISC_STATUS status = this->send_response(sendL,
2001-05-23 15:26:42 +02:00
(OBJCT)state,
(USHORT) (p - buffer),
2008-12-02 08:09:49 +01:00
status_vector,
false);
2001-05-23 15:26:42 +02:00
#ifdef DEBUG_REMOTE_MEMORY
2004-04-29 00:36:29 +02:00
printf("get_segment(server) free buffer %x\n", buffer);
2001-05-23 15:26:42 +02:00
#endif
return status;
}
2004-05-12 21:39:17 +02:00
ISC_STATUS rem_port::get_slice(P_SLC * stuff, PACKET* sendL)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* g e t _ s l i c e
*
**************************************
*
* Functional description
* Get an array slice.
*
**************************************/
Rtr* transaction;
2003-04-16 12:18:51 +02:00
ISC_STATUS_ARRAY status_vector;
2001-05-23 15:26:42 +02:00
Rdb* rdb = this->port_context;
if (bad_db(status_vector, rdb))
{
return this->send_response(sendL, 0, 0, status_vector, false);
}
getHandle(transaction, stuff->p_slc_transaction);
2001-05-23 15:26:42 +02:00
Firebird::HalfStaticArray<UCHAR, 4096> temp_buffer;
UCHAR* slice = 0;
2008-03-27 03:27:56 +01:00
if (stuff->p_slc_length) {
slice = temp_buffer.getBuffer(stuff->p_slc_length);
2001-05-23 15:26:42 +02:00
memset(slice, 0, stuff->p_slc_length);
#ifdef DEBUG_REMOTE_MEMORY
2004-04-29 00:36:29 +02:00
printf("get_slice(server) allocate buffer %x\n", slice);
2001-05-23 15:26:42 +02:00
#endif
}
2004-05-12 21:39:17 +02:00
P_SLR* response = &sendL->p_slr;
2001-05-23 15:26:42 +02:00
2003-08-30 03:43:08 +02:00
isc_get_slice(status_vector, &rdb->rdb_handle, &transaction->rtr_handle,
(ISC_QUAD*) &stuff->p_slc_id, stuff->p_slc_sdl.cstr_length,
2003-12-03 09:19:24 +01:00
reinterpret_cast<const char*>(stuff->p_slc_sdl.cstr_address),
2001-05-23 15:26:42 +02:00
stuff->p_slc_parameters.cstr_length,
2003-12-03 09:19:24 +01:00
(const ISC_LONG*) stuff->p_slc_parameters.cstr_address,
2003-08-30 03:43:08 +02:00
stuff->p_slc_length, slice,
reinterpret_cast<SLONG*>(&response->p_slr_length));
2001-05-23 15:26:42 +02:00
ISC_STATUS status;
2001-05-23 15:26:42 +02:00
if (status_vector[1])
status = this->send_response(sendL, 0, 0, status_vector, false);
2001-05-23 15:26:42 +02:00
else {
2004-05-12 21:39:17 +02:00
sendL->p_operation = op_slice;
2001-05-23 15:26:42 +02:00
response->p_slr_slice.lstr_address = slice;
response->p_slr_slice.lstr_length = response->p_slr_length;
2003-08-15 12:23:46 +02:00
response->p_slr_sdl = stuff->p_slc_sdl.cstr_address;
2001-05-23 15:26:42 +02:00
response->p_slr_sdl_length = stuff->p_slc_sdl.cstr_length;
2004-05-12 21:39:17 +02:00
this->send(sendL);
2001-05-23 15:26:42 +02:00
response->p_slr_sdl = 0;
status = FB_SUCCESS;
2001-05-23 15:26:42 +02:00
}
return status;
}
ISC_STATUS rem_port::info(P_OP op, P_INFO* stuff, PACKET* sendL)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* i n f o
*
**************************************
*
* Functional description
* Get info for a blob, database, request, service,
* statement, or transaction.
*
**************************************/
2003-04-16 12:18:51 +02:00
ISC_STATUS_ARRAY status_vector;
2001-05-23 15:26:42 +02:00
Rdb* rdb = this->port_context;
if (bad_db(status_vector, rdb))
{
return this->send_response(sendL, 0, 0, status_vector, false);
}
2001-05-23 15:26:42 +02:00
/* Make sure there is a suitable temporary blob buffer */
Firebird::Array<UCHAR> buf;
UCHAR* const buffer = buf.getBuffer(stuff->p_info_buffer_length);
2001-05-23 15:26:42 +02:00
memset(buffer, 0, stuff->p_info_buffer_length);
Firebird::HalfStaticArray<SCHAR, 1024> info;
SCHAR* info_buffer = 0;
2007-04-11 18:05:40 +02:00
USHORT info_len;
Firebird::HalfStaticArray<UCHAR, 1024> temp;
UCHAR* temp_buffer = 0;
if (op == op_info_database)
{
info_len = 0;
info_buffer = 0;
temp_buffer = temp.getBuffer(stuff->p_info_buffer_length);
2002-06-29 10:49:39 +02:00
}
else
{
// stuff isc_info_length in front of info items buffer
CSTRING_CONST* info_string = (op == op_service_info) ?
&stuff->p_info_recv_items : &stuff->p_info_items;
info_len = 1 + info_string->cstr_length;
info_buffer = info.getBuffer(info_len);
2002-06-29 10:49:39 +02:00
*info_buffer = isc_info_length;
memmove(info_buffer + 1, info_string->cstr_address, info_len - 1);
}
Rbl* blob;
Rtr* transaction;
Rsr* statement;
USHORT info_db_len = 0;
2001-05-23 15:26:42 +02:00
switch (op) {
case op_info_blob:
getHandle(blob, stuff->p_info_object);
2003-08-30 03:43:08 +02:00
isc_blob_info(status_vector, &blob->rbl_handle,
info_len,
info_buffer,
2001-05-23 15:26:42 +02:00
stuff->p_info_buffer_length,
2003-08-30 03:43:08 +02:00
reinterpret_cast<char*>(buffer));
2001-05-23 15:26:42 +02:00
break;
case op_info_database:
2003-08-30 03:43:08 +02:00
isc_database_info(status_vector, &rdb->rdb_handle,
2001-05-23 15:26:42 +02:00
stuff->p_info_items.cstr_length,
reinterpret_cast<const char*>(stuff->p_info_items.cstr_address),
2002-06-29 10:49:39 +02:00
stuff->p_info_buffer_length /*sizeof (temp)*/,
reinterpret_cast<char*>(temp_buffer) /*temp*/);
2001-05-23 15:26:42 +02:00
if (!status_vector[1]) {
Firebird::string version;
version.printf("%s/%s", GDS_VERSION, this->port_version->str_data);
2008-12-02 08:09:49 +01:00
info_db_len = MERGE_database_info(temp_buffer /*temp*/,
buffer, stuff->p_info_buffer_length,
2001-05-23 15:26:42 +02:00
IMPLEMENTATION, 4, 1,
reinterpret_cast<const UCHAR*>(version.c_str()),
2008-03-10 09:44:07 +01:00
reinterpret_cast<const UCHAR*>(this->port_host->str_data),
2001-05-23 15:26:42 +02:00
0);
}
break;
case op_info_request:
{
Rrq* requestL;
getHandle(requestL, stuff->p_info_object);
2004-05-12 23:47:36 +02:00
isc_request_info(status_vector, &requestL->rrq_handle,
2001-05-23 15:26:42 +02:00
stuff->p_info_incarnation,
info_len,
info_buffer,
2001-05-23 15:26:42 +02:00
stuff->p_info_buffer_length,
reinterpret_cast<char*>(buffer));
2001-05-23 15:26:42 +02:00
break;
}
2001-05-23 15:26:42 +02:00
case op_info_transaction:
getHandle(transaction, stuff->p_info_object);
2003-08-30 03:43:08 +02:00
isc_transaction_info(status_vector, &transaction->rtr_handle,
info_len,
info_buffer,
2001-05-23 15:26:42 +02:00
stuff->p_info_buffer_length,
reinterpret_cast<char*>(buffer));
2001-05-23 15:26:42 +02:00
break;
case op_service_info:
isc_service_query(status_vector,
&rdb->rdb_handle,
2001-05-23 15:26:42 +02:00
NULL,
stuff->p_info_items.cstr_length,
reinterpret_cast<const char*>(stuff->p_info_items.cstr_address),
info_len,
info_buffer,
2001-05-23 15:26:42 +02:00
stuff->p_info_buffer_length,
reinterpret_cast<char*>(buffer));
2001-05-23 15:26:42 +02:00
break;
case op_info_sql:
getHandle(statement, stuff->p_info_object);
2001-05-23 15:26:42 +02:00
GDS_DSQL_SQL_INFO(status_vector,
&statement->rsr_handle,
info_len,
info_buffer,
2001-05-23 15:26:42 +02:00
stuff->p_info_buffer_length,
reinterpret_cast<char*>(buffer));
2001-05-23 15:26:42 +02:00
break;
}
/* Send a response that includes the segment. */
USHORT response_len = info_db_len ? info_db_len : stuff->p_info_buffer_length;
SSHORT skip_len = 0;
if (*buffer == isc_info_length)
{
skip_len = gds__vax_integer(buffer + 1, 2);
SLONG val = gds__vax_integer(buffer + 3, skip_len);
skip_len += 3;
if (val && val <= response_len) {
response_len = val;
}
}
sendL->p_resp.p_resp_data.cstr_address = buffer + skip_len;
2008-12-02 08:09:49 +01:00
const ISC_STATUS status = this->send_response(sendL, stuff->p_info_object,
response_len, status_vector, false);
2001-05-23 15:26:42 +02:00
return status;
}
2004-05-12 21:39:17 +02:00
ISC_STATUS rem_port::insert(P_SQLDATA * sqldata, PACKET* sendL)
2001-05-23 15:26:42 +02:00
{
/*****************************************
*
* i n s e r t
*
*****************************************
*
* Functional description
* Insert next record into a dynamic SQL cursor.
*
*****************************************/
2008-03-30 11:37:57 +02:00
Rsr* statement;
2001-05-23 15:26:42 +02:00
getHandle(statement, sqldata->p_sqldata_statement);
2001-05-23 15:26:42 +02:00
USHORT msg_length;
const UCHAR* msg;
2001-05-23 15:26:42 +02:00
if (statement->rsr_format)
{
msg_length = statement->rsr_format->fmt_length;
msg = statement->rsr_message->msg_address;
}
else
{
msg_length = 0;
msg = NULL;
}
2008-03-28 15:17:21 +01:00
ISC_STATUS_ARRAY status_vector;
2008-12-02 08:09:49 +01:00
2001-05-23 15:26:42 +02:00
GDS_DSQL_INSERT(status_vector,
&statement->rsr_handle,
2001-05-23 15:26:42 +02:00
sqldata->p_sqldata_blr.cstr_length,
reinterpret_cast<const char*>(sqldata->p_sqldata_blr.cstr_address),
2001-05-23 15:26:42 +02:00
sqldata->p_sqldata_message_number, msg_length,
reinterpret_cast<const char*>(msg));
2001-05-23 15:26:42 +02:00
return this->send_response(sendL, 0, 0, status_vector, false);
2001-05-23 15:26:42 +02:00
}
static Rtr* make_transaction (Rdb* rdb, FB_API_HANDLE handle)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* m a k e _ t r a n s a c t i o n
*
**************************************
*
* Functional description
* Create a local transaction handle.
*
**************************************/
Rtr* transaction = new Rtr;
2001-05-23 15:26:42 +02:00
transaction->rtr_rdb = rdb;
transaction->rtr_handle = handle;
if (transaction->rtr_id = rdb->rdb_port->get_id(transaction))
2001-05-23 15:26:42 +02:00
{
transaction->rtr_next = rdb->rdb_transactions;
rdb->rdb_transactions = transaction;
}
else {
delete transaction;
transaction = NULL;
2001-05-23 15:26:42 +02:00
}
return transaction;
}
2004-05-12 21:39:17 +02:00
ISC_STATUS rem_port::open_blob(P_OP op, P_BLOB* stuff, PACKET* sendL)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* o p e n _ b l o b
*
**************************************
*
* Functional description
* Open or create a new blob.
*
**************************************/
Rtr* transaction;
2003-04-16 12:18:51 +02:00
ISC_STATUS_ARRAY status_vector;
2001-05-23 15:26:42 +02:00
getHandle(transaction, stuff->p_blob_transaction);
2001-05-23 15:26:42 +02:00
Rdb* rdb = this->port_context;
if (bad_db(status_vector, rdb))
{
return this->send_response(sendL, 0, 0, status_vector, false);
}
2004-05-03 01:06:37 +02:00
FB_API_HANDLE handle = 0;
USHORT bpb_length = 0;
const UCHAR* bpb = NULL;
2001-05-23 15:26:42 +02:00
if (op == op_open_blob2 || op == op_create_blob2) {
bpb_length = stuff->p_blob_bpb.cstr_length;
bpb = stuff->p_blob_bpb.cstr_address;
}
if (op == op_open_blob || op == op_open_blob2)
2008-12-02 08:09:49 +01:00
isc_open_blob2(status_vector, &rdb->rdb_handle,
2003-08-30 03:43:08 +02:00
&transaction->rtr_handle, &handle,
(ISC_QUAD*) &stuff->p_blob_id, bpb_length, bpb);
2001-05-23 15:26:42 +02:00
else
2003-08-30 03:43:08 +02:00
isc_create_blob2(status_vector, &rdb->rdb_handle, &transaction->rtr_handle,
2004-05-12 21:39:17 +02:00
&handle, (ISC_QUAD*) &sendL->p_resp.p_resp_blob_id,
bpb_length, reinterpret_cast<const char*>(bpb));
2001-05-23 15:26:42 +02:00
USHORT object;
2001-05-23 15:26:42 +02:00
if (status_vector[1])
object = 0;
else {
Rbl* blob = new Rbl;
#ifdef DEBUG_REMOTE_MEMORY
2004-04-29 00:36:29 +02:00
printf("open_blob(server) allocate blob %x\n", blob);
2001-05-23 15:26:42 +02:00
#endif
blob->rbl_handle = handle;
blob->rbl_rdb = rdb;
if (blob->rbl_id = this->get_id(blob))
2001-05-23 15:26:42 +02:00
{
object = blob->rbl_id;
blob->rbl_rtr = transaction;
blob->rbl_next = transaction->rtr_blobs;
transaction->rtr_blobs = blob;
}
else
{
object = 0;
2003-08-30 03:43:08 +02:00
isc_cancel_blob(status_vector, &blob->rbl_handle);
delete blob;
2001-05-23 15:26:42 +02:00
status_vector[0] = isc_arg_gds;
status_vector[1] = isc_too_many_handles;
status_vector[2] = isc_arg_end;
}
}
return this->send_response(sendL, object, 0, status_vector, false);
2001-05-23 15:26:42 +02:00
}
2004-05-12 21:39:17 +02:00
ISC_STATUS rem_port::prepare(P_PREP * stuff, PACKET* sendL)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* p r e p a r e
*
**************************************
*
* Functional description
* End a transaction.
*
**************************************/
Rtr* transaction;
2003-04-16 12:18:51 +02:00
ISC_STATUS_ARRAY status_vector;
2001-05-23 15:26:42 +02:00
getHandle(transaction, stuff->p_prep_transaction);
2001-05-23 15:26:42 +02:00
2003-08-30 03:43:08 +02:00
if (!isc_prepare_transaction2(status_vector, &transaction->rtr_handle,
2001-05-23 15:26:42 +02:00
stuff->p_prep_data.cstr_length,
2003-08-30 03:43:08 +02:00
stuff->p_prep_data.cstr_address))
2001-05-23 15:26:42 +02:00
{
2008-01-16 08:55:28 +01:00
transaction->rtr_limbo = true;
2001-05-23 15:26:42 +02:00
}
return this->send_response(sendL, 0, 0, status_vector, false);
2001-05-23 15:26:42 +02:00
}
2004-05-12 23:47:36 +02:00
ISC_STATUS rem_port::prepare_statement(P_SQLST * prepareL, PACKET* sendL)
2001-05-23 15:26:42 +02:00
{
/*****************************************
*
2006-02-04 11:37:15 +01:00
* p r e p a r e _ s t a t e m e n t
2001-05-23 15:26:42 +02:00
*
*****************************************
*
* Functional description
* Prepare a dynamic SQL statement for execution.
*
*****************************************/
Rtr* transaction = NULL;
2008-03-30 11:37:57 +02:00
Rsr* statement;
2001-05-23 15:26:42 +02:00
/** Do not call CHECK_HANDLE if this is the start of a transaction **/
2004-05-12 23:47:36 +02:00
if (prepareL->p_sqlst_transaction)
2001-05-23 15:26:42 +02:00
{
getHandle(transaction, prepareL->p_sqlst_transaction);
}
getHandle(statement, prepareL->p_sqlst_statement);
Firebird::HalfStaticArray<UCHAR, 1024> local_buffer, info_buffer;
UCHAR* const info = info_buffer.getBuffer(prepareL->p_sqlst_items.cstr_length + 1);
UCHAR* const buffer = local_buffer.getBuffer(prepareL->p_sqlst_buffer_length);
2001-05-23 15:26:42 +02:00
// stuff isc_info_length in front of info items buffer
*info = isc_info_length;
memmove(info + 1, prepareL->p_sqlst_items.cstr_address, prepareL->p_sqlst_items.cstr_length);
2004-05-03 01:06:37 +02:00
FB_API_HANDLE handle = (transaction) ? transaction->rtr_handle : 0;
2001-05-23 15:26:42 +02:00
/* Since the API to GDS_DSQL_PREPARE is public and can not be changed, there needs to
* be a way to send the parser version to DSQL so that the parser can compare the keyword
* version to the parser version. To accomplish this, the parser version is combined with
* the client dialect and sent across that way. In dsql8_prepare_statement, the parser version
* and client dialect are separated and passed on to their final desintations. The information
* is combined as follows:
* Dialect * 10 + parser_version
*
* and is extracted in dsql8_prepare_statement as follows:
2004-09-05 15:53:56 +02:00
* parser_version = ((dialect * 10) + parser_version) % 10
* client_dialect = ((dialect * 10) + parser_version) / 10
2001-05-23 15:26:42 +02:00
*
* For example, parser_version = 1 and client dialect = 1
*
* combined = (1 * 10) + 1 == 11
*
2004-09-05 15:53:56 +02:00
* parser = (combined) % 10 == 1
* dialect = (combined) / 10 == 1
2001-05-23 15:26:42 +02:00
*/
const USHORT parser_version = (this->port_protocol < PROTOCOL_VERSION10) ? 1 : 2;
2001-05-23 15:26:42 +02:00
2008-03-28 15:17:21 +01:00
ISC_STATUS_ARRAY status_vector;
2001-05-23 15:26:42 +02:00
GDS_DSQL_PREPARE(status_vector,
&handle,
&statement->rsr_handle,
2004-05-12 23:47:36 +02:00
prepareL->p_sqlst_SQL_str.cstr_length,
reinterpret_cast<const char*>(prepareL->p_sqlst_SQL_str.cstr_address),
(USHORT) ((prepareL->p_sqlst_SQL_dialect * 10) + parser_version),
prepareL->p_sqlst_items.cstr_length + 1,
reinterpret_cast<const char*> (info),
2004-05-12 23:47:36 +02:00
prepareL->p_sqlst_buffer_length,
reinterpret_cast<char*>(buffer));
2001-05-23 15:26:42 +02:00
if (status_vector[1]) {
return this->send_response(sendL, 0, 0, status_vector, false);
2001-05-23 15:26:42 +02:00
}
REMOTE_reset_statement(statement);
statement->rsr_flags.clear(Rsr::BLOB | Rsr::NO_BATCH | Rsr::DEFER_EXECUTE);
USHORT state = check_statement_type(statement);
if (state & STMT_BLOB) {
statement->rsr_flags.set(Rsr::BLOB);
}
if (state & STMT_NO_BATCH) {
statement->rsr_flags.set(Rsr::NO_BATCH);
}
if ((state & STMT_DEFER_EXECUTE) && (port_flags & PORT_lazy)) {
statement->rsr_flags.set(Rsr::DEFER_EXECUTE);
}
if (!(port_flags & PORT_lazy)) {
state = (state & STMT_BLOB) ? 1 : 0;
}
2001-05-23 15:26:42 +02:00
/* Send a response that includes the info requested. */
USHORT response_len = prepareL->p_sqlst_buffer_length;
SSHORT skip_len = 0;
if (*buffer == isc_info_length)
{
skip_len = gds__vax_integer(buffer + 1, 2);
SLONG val = gds__vax_integer(buffer + 3, skip_len);
skip_len += 3;
if (val && val <= response_len) {
response_len = val;
}
}
sendL->p_resp.p_resp_data.cstr_address = buffer + skip_len;
2001-05-23 15:26:42 +02:00
const ISC_STATUS status = this->send_response(sendL, state, response_len, status_vector, false);
2001-05-23 15:26:42 +02:00
return status;
}
2007-04-03 10:18:11 +02:00
// Declared in serve_proto.h
2008-01-16 08:55:28 +01:00
static bool process_packet(rem_port* port,
PACKET* sendL,
PACKET* receive,
rem_port** result)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
2008-01-16 08:55:28 +01:00
* p r o c e s s _ p a c k e t
2001-05-23 15:26:42 +02:00
*
**************************************
*
* Functional description
* Given an packet received from client, process it a packet ready to be
* sent.
*
**************************************/
Firebird::RefMutexGuard portGuard(*port->port_sync);
2001-05-23 15:26:42 +02:00
2001-12-24 03:51:06 +01:00
try {
P_OP op = receive->p_operation;
switch (op)
2002-03-31 01:40:08 +01:00
{
case op_connect:
2004-05-12 21:39:17 +02:00
if (!accept_connection(port, &receive->p_cnct, sendL)) {
rem_str* string = port->port_user_name;
if (string) {
gds__log("SERVER/process_packet: connection rejected for %*.*s",
2002-03-31 01:40:08 +01:00
string->str_length, string->str_length,
string->str_data);
}
2002-10-31 12:58:41 +01:00
if (port->port_server->srvr_flags & SRVR_multi_client) {
port->port_state = rem_port::BROKEN;
2002-10-31 12:58:41 +01:00
}
2002-03-31 01:40:08 +01:00
else {
gds__log("SERVER/process_packet: connect reject, server exiting");
2008-01-16 08:55:28 +01:00
port->disconnect(sendL, receive);
2003-09-11 20:59:34 +02:00
return false;
2002-03-31 01:40:08 +01:00
}
2001-05-23 15:26:42 +02:00
}
2002-03-31 01:40:08 +01:00
break;
2001-05-23 15:26:42 +02:00
2002-03-31 01:40:08 +01:00
case op_compile:
2004-05-12 21:39:17 +02:00
port->compile(&receive->p_cmpl, sendL);
2002-03-31 01:40:08 +01:00
break;
2001-05-23 15:26:42 +02:00
2002-03-31 01:40:08 +01:00
case op_attach:
case op_create:
2004-05-12 21:39:17 +02:00
attach_database(port, op, &receive->p_atch, sendL);
2002-03-31 01:40:08 +01:00
break;
2001-05-23 15:26:42 +02:00
2002-03-31 01:40:08 +01:00
case op_service_attach:
2006-12-08 19:38:15 +01:00
attach_service(port, &receive->p_atch, sendL);
break;
case op_trusted_auth:
#ifdef TRUSTED_AUTH
trusted_auth(port, &receive->p_trau, sendL);
break;
2008-12-02 08:09:49 +01:00
//else
2006-12-08 19:38:15 +01:00
// fall down ...
#endif
case op_update_account_info:
case op_authenticate_user:
{
ISC_STATUS_ARRAY status_vector;
status_vector[0] = isc_arg_gds;
status_vector[1] = isc_wish_list;
status_vector[2] = isc_arg_end;
port->send_response(sendL, 0, 0, status_vector, false);
}
2002-03-31 01:40:08 +01:00
break;
2001-05-23 15:26:42 +02:00
2002-03-31 01:40:08 +01:00
case op_service_start:
2004-05-12 21:39:17 +02:00
port->service_start(&receive->p_info, sendL);
2001-05-23 15:26:42 +02:00
break;
2002-03-31 01:40:08 +01:00
case op_disconnect:
case op_exit:
{
SRVR server = port->port_server;
if (!server)
break;
2008-01-16 08:55:28 +01:00
if ((server->srvr_flags & SRVR_multi_client) && port != server->srvr_parent_port)
{
2004-05-12 21:39:17 +02:00
port->disconnect(sendL, receive);
port = NULL;
break;
}
2008-01-16 08:55:28 +01:00
if ((server->srvr_flags & SRVR_multi_client) && port == server->srvr_parent_port)
2008-01-16 08:55:28 +01:00
{
gds__log("SERVER/process_packet: Multi-client server shutdown");
}
2008-01-16 08:55:28 +01:00
port->disconnect(sendL, receive);
return false;
2001-05-23 15:26:42 +02:00
}
2002-03-31 01:40:08 +01:00
case op_receive:
2004-05-12 21:39:17 +02:00
port->receive_msg(&receive->p_data, sendL);
2002-03-31 01:40:08 +01:00
break;
2001-05-23 15:26:42 +02:00
2002-03-31 01:40:08 +01:00
case op_send:
2004-05-12 21:39:17 +02:00
port->send_msg(&receive->p_data, sendL);
2002-03-31 01:40:08 +01:00
break;
2001-05-23 15:26:42 +02:00
2002-03-31 01:40:08 +01:00
case op_start:
case op_start_and_receive:
2004-05-12 21:39:17 +02:00
port->start(op, &receive->p_data, sendL);
2002-03-31 01:40:08 +01:00
break;
2001-05-23 15:26:42 +02:00
2002-03-31 01:40:08 +01:00
case op_start_and_send:
case op_start_send_and_receive:
2004-05-12 21:39:17 +02:00
port->start_and_send(op, &receive->p_data, sendL);
2002-03-31 01:40:08 +01:00
break;
2001-05-23 15:26:42 +02:00
2002-03-31 01:40:08 +01:00
case op_transact:
2004-05-12 21:39:17 +02:00
port->transact_request(&receive->p_trrq, sendL);
2002-03-31 01:40:08 +01:00
break;
2001-05-23 15:26:42 +02:00
2002-03-31 01:40:08 +01:00
case op_reconnect:
case op_transaction:
2004-05-12 21:39:17 +02:00
port->start_transaction(op, &receive->p_sttr, sendL);
2002-03-31 01:40:08 +01:00
break;
2001-05-23 15:26:42 +02:00
2002-03-31 01:40:08 +01:00
case op_prepare:
case op_rollback:
case op_rollback_retaining:
case op_commit:
case op_commit_retaining:
2004-05-12 21:39:17 +02:00
port->end_transaction(op, &receive->p_rlse, sendL);
2002-03-31 01:40:08 +01:00
break;
2001-05-23 15:26:42 +02:00
2002-03-31 01:40:08 +01:00
case op_detach:
2004-05-12 21:39:17 +02:00
port->end_database(&receive->p_rlse, sendL);
2002-03-31 01:40:08 +01:00
break;
2001-05-23 15:26:42 +02:00
2002-03-31 01:40:08 +01:00
case op_service_detach:
2004-05-12 21:39:17 +02:00
port->service_end(&receive->p_rlse, sendL);
2002-03-31 01:40:08 +01:00
break;
2001-05-23 15:26:42 +02:00
2002-03-31 01:40:08 +01:00
case op_drop_database:
2004-05-12 21:39:17 +02:00
port->drop_database(&receive->p_rlse, sendL);
2002-03-31 01:40:08 +01:00
break;
2001-05-23 15:26:42 +02:00
2002-03-31 01:40:08 +01:00
case op_create_blob:
case op_open_blob:
case op_create_blob2:
case op_open_blob2:
2004-05-12 21:39:17 +02:00
port->open_blob(op, &receive->p_blob, sendL);
2002-03-31 01:40:08 +01:00
break;
2001-05-23 15:26:42 +02:00
2002-03-31 01:40:08 +01:00
case op_batch_segments:
case op_put_segment:
2004-05-12 21:39:17 +02:00
port->put_segment(op, &receive->p_sgmt, sendL);
2002-03-31 01:40:08 +01:00
break;
2001-05-23 15:26:42 +02:00
2002-03-31 01:40:08 +01:00
case op_get_segment:
2004-05-12 21:39:17 +02:00
port->get_segment(&receive->p_sgmt, sendL);
2002-03-31 01:40:08 +01:00
break;
2001-05-23 15:26:42 +02:00
2002-03-31 01:40:08 +01:00
case op_seek_blob:
2004-05-12 21:39:17 +02:00
port->seek_blob(&receive->p_seek, sendL);
2002-03-31 01:40:08 +01:00
break;
2001-05-23 15:26:42 +02:00
2002-03-31 01:40:08 +01:00
case op_cancel_blob:
case op_close_blob:
2004-05-12 21:39:17 +02:00
port->end_blob(op, &receive->p_rlse, sendL);
2002-03-31 01:40:08 +01:00
break;
2001-05-23 15:26:42 +02:00
2002-03-31 01:40:08 +01:00
case op_prepare2:
2004-05-12 21:39:17 +02:00
port->prepare(&receive->p_prep, sendL);
2002-03-31 01:40:08 +01:00
break;
2001-05-23 15:26:42 +02:00
2002-03-31 01:40:08 +01:00
case op_release:
2004-05-12 21:39:17 +02:00
port->end_request(&receive->p_rlse, sendL);
2002-03-31 01:40:08 +01:00
break;
2001-05-23 15:26:42 +02:00
2002-03-31 01:40:08 +01:00
case op_info_blob:
case op_info_database:
case op_info_request:
case op_info_transaction:
case op_service_info:
case op_info_sql:
2004-05-12 21:39:17 +02:00
port->info(op, &receive->p_info, sendL);
2002-03-31 01:40:08 +01:00
break;
2001-05-23 15:26:42 +02:00
2002-03-31 01:40:08 +01:00
case op_que_events:
2004-05-12 21:39:17 +02:00
port->que_events(&receive->p_event, sendL);
2002-03-31 01:40:08 +01:00
break;
2001-05-23 15:26:42 +02:00
2002-03-31 01:40:08 +01:00
case op_cancel_events:
2004-05-12 21:39:17 +02:00
cancel_events(port, &receive->p_event, sendL);
2002-03-31 01:40:08 +01:00
break;
2001-05-23 15:26:42 +02:00
2002-03-31 01:40:08 +01:00
case op_connect_request:
2004-05-12 21:39:17 +02:00
aux_request(port, &receive->p_req, sendL);
2002-03-31 01:40:08 +01:00
break;
2001-05-23 15:26:42 +02:00
2004-03-14 06:51:54 +01:00
#ifdef NOT_USED_OR_REPLACED
2002-03-31 01:40:08 +01:00
case op_aux_connect:
2004-05-12 21:39:17 +02:00
aux_connect(port, &receive->p_req, sendL);
2002-03-31 01:40:08 +01:00
break;
2004-03-14 06:51:54 +01:00
#endif
2001-05-23 15:26:42 +02:00
2002-03-31 01:40:08 +01:00
case op_ddl:
2004-05-12 21:39:17 +02:00
port->ddl(&receive->p_ddl, sendL);
2002-03-31 01:40:08 +01:00
break;
2001-05-23 15:26:42 +02:00
2002-03-31 01:40:08 +01:00
case op_get_slice:
2004-05-12 21:39:17 +02:00
port->get_slice(&receive->p_slc, sendL);
2002-03-31 01:40:08 +01:00
break;
2001-05-23 15:26:42 +02:00
2002-03-31 01:40:08 +01:00
case op_put_slice:
2004-05-12 21:39:17 +02:00
port->put_slice(&receive->p_slc, sendL);
2002-03-31 01:40:08 +01:00
break;
2001-05-23 15:26:42 +02:00
2002-03-31 01:40:08 +01:00
case op_allocate_statement:
2004-05-12 21:39:17 +02:00
allocate_statement(port, &receive->p_rlse, sendL);
2002-03-31 01:40:08 +01:00
break;
2001-05-23 15:26:42 +02:00
2002-03-31 01:40:08 +01:00
case op_execute:
case op_execute2:
2004-05-12 21:39:17 +02:00
port->execute_statement(op, &receive->p_sqldata, sendL);
2002-03-31 01:40:08 +01:00
break;
2001-05-23 15:26:42 +02:00
2002-03-31 01:40:08 +01:00
case op_exec_immediate:
case op_exec_immediate2:
2004-05-12 21:39:17 +02:00
port->execute_immediate(op, &receive->p_sqlst, sendL);
2002-03-31 01:40:08 +01:00
break;
2001-05-23 15:26:42 +02:00
2002-03-31 01:40:08 +01:00
case op_fetch:
2004-05-12 21:39:17 +02:00
port->fetch(&receive->p_sqldata, sendL);
2002-03-31 01:40:08 +01:00
break;
2001-05-23 15:26:42 +02:00
2002-03-31 01:40:08 +01:00
case op_free_statement:
2004-05-12 21:39:17 +02:00
port->end_statement(&receive->p_sqlfree, sendL);
2002-03-31 01:40:08 +01:00
break;
2001-05-23 15:26:42 +02:00
2002-03-31 01:40:08 +01:00
case op_insert:
2004-05-12 21:39:17 +02:00
port->insert(&receive->p_sqldata, sendL);
2002-03-31 01:40:08 +01:00
break;
2001-05-23 15:26:42 +02:00
2002-03-31 01:40:08 +01:00
case op_prepare_statement:
2004-05-12 21:39:17 +02:00
port->prepare_statement(&receive->p_sqlst, sendL);
2002-03-31 01:40:08 +01:00
break;
2001-05-23 15:26:42 +02:00
2002-03-31 01:40:08 +01:00
case op_set_cursor:
2004-05-12 21:39:17 +02:00
port->set_cursor(&receive->p_sqlcur, sendL);
2002-03-31 01:40:08 +01:00
break;
2001-05-23 15:26:42 +02:00
2002-03-31 01:40:08 +01:00
case op_dummy:
2004-05-12 21:39:17 +02:00
sendL->p_operation = op_dummy;
port->send(sendL);
2002-03-31 01:40:08 +01:00
break;
2001-05-23 15:26:42 +02:00
case op_cancel:
cancel_operation(port, receive->p_cancel_op.p_co_kind);
break;
2002-03-31 01:40:08 +01:00
default:
gds__log("SERVER/process_packet: don't understand packet type %d",
2002-03-31 01:40:08 +01:00
receive->p_operation);
port->port_state = rem_port::BROKEN;
2002-03-31 01:40:08 +01:00
break;
}
2001-05-23 15:26:42 +02:00
if (port && port->port_state == rem_port::BROKEN) {
2002-03-31 01:40:08 +01:00
if (!port->port_parent) {
if (!Worker::isShuttingDown())
gds__log("SERVER/process_packet: broken port, server exiting");
port->disconnect(sendL, receive);
2003-09-11 20:59:34 +02:00
return false;
2002-03-31 01:40:08 +01:00
}
2004-05-12 21:39:17 +02:00
port->disconnect(sendL, receive);
2002-03-31 01:40:08 +01:00
port = NULL;
2001-05-23 15:26:42 +02:00
}
2002-03-31 01:40:08 +01:00
if (result)
*result = port;
2001-05-23 15:26:42 +02:00
2001-12-24 03:51:06 +01:00
} // try
catch (const Firebird::status_exception& ex) {
// typical case like bad handle passed
ISC_STATUS_ARRAY local_status;
memset(local_status, 0, sizeof(local_status));
Firebird::stuff_exception(local_status, ex);
// Send it to the user
port->send_response(sendL, 0, 0, local_status, false);
return false;
}
catch (const Firebird::Exception& ex) {
// something more serious happened
ISC_STATUS_ARRAY local_status;
memset(local_status, 0, sizeof(local_status));
2008-01-16 08:55:28 +01:00
Firebird::stuff_exception(local_status, ex);
gds__log_status(0, local_status);
2001-12-24 03:51:06 +01:00
// It would be nice to log an error to the user, instead of just terminating them!
2008-01-16 08:55:28 +01:00
port->send_response(sendL, 0, 0, local_status, false);
port->disconnect(sendL, receive); // Well, how about this...
2001-12-24 03:51:06 +01:00
2003-09-11 20:59:34 +02:00
return false;
2001-12-24 03:51:06 +01:00
}
2001-05-23 15:26:42 +02:00
2003-09-11 20:59:34 +02:00
return true;
2001-05-23 15:26:42 +02:00
}
2006-12-08 19:38:15 +01:00
#ifdef TRUSTED_AUTH
2008-04-15 11:31:35 +02:00
static void trusted_auth(rem_port* port, const P_TRAU* p_trau, PACKET* send)
2006-12-08 19:38:15 +01:00
{
2008-01-16 08:55:28 +01:00
/**************************************
*
* t r u s t e d _ a u t h
*
**************************************
*
* Functional description
* Server side of trusted auth handshake.
*
**************************************/
2006-12-08 19:38:15 +01:00
ISC_STATUS_ARRAY status_vector;
2006-12-10 01:16:00 +01:00
ServerAuth* sa = port->port_trusted_auth;
2006-12-08 19:38:15 +01:00
if (! sa)
{
status_vector[0] = isc_arg_gds;
status_vector[1] = isc_unavailable;
status_vector[2] = isc_arg_end;
port->send_response(send, 0, 0, status_vector, false);
}
2008-12-02 08:09:49 +01:00
try
2006-12-08 19:38:15 +01:00
{
AuthSspi::DataHolder data;
memcpy(data.getBuffer(p_trau->p_trau_data.cstr_length),
p_trau->p_trau_data.cstr_address, p_trau->p_trau_data.cstr_length);
AuthSspi* authSspi = sa->authSspi;
if (authSspi->accept(data) && authSspi->isActive())
{
send->p_operation = op_trusted_auth;
cstring& s = send->p_trau.p_trau_data;
s.cstr_allocated = 0;
s.cstr_length = data.getCount();
s.cstr_address = data.begin();
port->send(send);
return;
}
}
catch (const Firebird::status_exception& e)
2006-12-08 19:38:15 +01:00
{
2008-03-28 15:17:21 +01:00
// ISC_STATUS_ARRAY status_vector; It exists in the outer scope.
2006-12-08 19:38:15 +01:00
Firebird::stuff_exception(status_vector, e);
port->send_response(send, 0, 0, status_vector, false);
return;
}
2008-12-02 08:09:49 +01:00
sa->part2(port, sa->operation, sa->fileName.c_str(), sa->fileName.length(),
2006-12-08 19:38:15 +01:00
sa->clumplet.begin(), sa->clumplet.getCount(), send);
}
2008-01-16 08:55:28 +01:00
static bool canUseTrusted()
{
/**************************************
*
* c a n U s e T r u s t e d
*
**************************************
*
* Functional description
* Cache config setting for trusted auth.
*
**************************************/
static AmCache useTrusted = AM_UNKNOWN;
if (useTrusted == AM_UNKNOWN)
{
Firebird::PathName authMethod(Config::getAuthMethod());
useTrusted = (authMethod == AmTrusted || authMethod == AmMixed) ? AM_ENABLED : AM_DISABLED;
}
return useTrusted == AM_ENABLED;
}
2006-12-10 01:16:00 +01:00
#endif // TRUSTED_AUTH
2006-12-08 19:38:15 +01:00
2004-05-12 21:39:17 +02:00
ISC_STATUS rem_port::put_segment(P_OP op, P_SGMT * segment, PACKET* sendL)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* p u t _ s e g m e n t
*
**************************************
*
* Functional description
* Write a single blob segment.
*
**************************************/
Rbl* blob;
2001-05-23 15:26:42 +02:00
getHandle(blob, segment->p_sgmt_blob);
2001-05-23 15:26:42 +02:00
const UCHAR* p = segment->p_sgmt_segment.cstr_address;
USHORT length = segment->p_sgmt_segment.cstr_length;
2001-05-23 15:26:42 +02:00
/* Do the signal segment version. If it failed, just pass on the
bad news. */
2008-03-28 15:17:21 +01:00
ISC_STATUS_ARRAY status_vector;
2001-05-23 15:26:42 +02:00
if (op == op_put_segment) {
isc_put_segment(status_vector, &blob->rbl_handle, length, reinterpret_cast<const char*>(p));
return this->send_response(sendL, 0, 0, status_vector, false);
2001-05-23 15:26:42 +02:00
}
/* We've got a batch of segments. This is only slightly more complicated */
const UCHAR* const end = p + length;
2001-05-23 15:26:42 +02:00
while (p < end) {
length = *p++;
length += *p++ << 8;
isc_put_segment(status_vector, &blob->rbl_handle, length, reinterpret_cast<const char*>(p));
2001-05-23 15:26:42 +02:00
if (status_vector[1])
return this->send_response(sendL, 0, 0, status_vector, false);
2001-05-23 15:26:42 +02:00
p += length;
}
return this->send_response(sendL, 0, 0, status_vector, false);
2001-05-23 15:26:42 +02:00
}
2004-05-12 21:39:17 +02:00
ISC_STATUS rem_port::put_slice(P_SLC * stuff, PACKET* sendL)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* p u t _ s l i c e
*
**************************************
*
* Functional description
* Put an array slice.
*
**************************************/
Rtr* transaction;
2003-04-16 12:18:51 +02:00
ISC_STATUS_ARRAY status_vector;
2001-05-23 15:26:42 +02:00
getHandle(transaction, stuff->p_slc_transaction);
2001-05-23 15:26:42 +02:00
Rdb* rdb = this->port_context;
if (bad_db(status_vector, rdb))
{
return this->send_response(sendL, 0, 0, status_vector, false);
}
2001-05-23 15:26:42 +02:00
2004-05-12 21:39:17 +02:00
sendL->p_resp.p_resp_blob_id = stuff->p_slc_id;
2003-08-30 03:43:08 +02:00
isc_put_slice(status_vector, &rdb->rdb_handle, &transaction->rtr_handle,
2004-05-12 21:39:17 +02:00
(ISC_QUAD*) &sendL->p_resp.p_resp_blob_id,
2001-05-23 15:26:42 +02:00
stuff->p_slc_sdl.cstr_length,
reinterpret_cast<const char*>(stuff->p_slc_sdl.cstr_address),
2001-05-23 15:26:42 +02:00
stuff->p_slc_parameters.cstr_length,
(const ISC_LONG*) stuff->p_slc_parameters.cstr_address,
2001-05-23 15:26:42 +02:00
stuff->p_slc_slice.lstr_length,
2003-08-30 03:43:08 +02:00
stuff->p_slc_slice.lstr_address);
2001-05-23 15:26:42 +02:00
return this->send_response(sendL, 0, 0, status_vector, false);
2001-05-23 15:26:42 +02:00
}
2004-05-12 21:39:17 +02:00
ISC_STATUS rem_port::que_events(P_EVENT * stuff, PACKET* sendL)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* q u e _ e v e n t s
*
**************************************
*
* Functional description
*
**************************************/
ISC_STATUS_ARRAY status_vector;
Rdb* rdb = this->port_context;
if (bad_db(status_vector, rdb))
{
return this->send_response(sendL, 0, 0, status_vector, false);
}
2001-05-23 15:26:42 +02:00
/* Find unused event block or, if necessary, a new one */
Rvnt* event;
2001-05-23 15:26:42 +02:00
for (event = rdb->rdb_events; event; event = event->rvnt_next) {
if (!event->rvnt_id) {
break;
}
}
if (!event)
{
event = new Rvnt;
#ifdef DEBUG_REMOTE_MEMORY
2004-04-29 00:36:29 +02:00
printf("que_events(server) allocate event %x\n", event);
2001-05-23 15:26:42 +02:00
#endif
event->rvnt_next = rdb->rdb_events;
rdb->rdb_events = event;
}
2003-12-22 11:00:59 +01:00
event->rvnt_ast = stuff->p_event_ast;
2008-12-02 08:09:49 +01:00
2003-12-22 11:00:59 +01:00
// CVC: Going from SLONG to void*, problems when sizeof(void*) > 4
2004-03-14 06:51:54 +01:00
// Nickolay Samofatov. No problem actually. Event argument returned by server
2008-12-02 08:09:49 +01:00
// on event firing is not used by the client. Client looks up argument via
2004-03-14 06:51:54 +01:00
// seaching client-side event table and remote event ID passed by server on
2008-12-02 08:09:49 +01:00
// event registration. As a result we may use this argument value for
2004-03-14 06:51:54 +01:00
// server-side debugging only.
event->rvnt_arg = (void*)(IPTR) stuff->p_event_arg;
2008-12-02 08:09:49 +01:00
2001-05-23 15:26:42 +02:00
event->rvnt_rid = stuff->p_event_rid;
event->rvnt_rdb = rdb;
2003-08-30 03:43:08 +02:00
isc_que_events(status_vector, &rdb->rdb_handle, &event->rvnt_id,
2001-05-23 15:26:42 +02:00
stuff->p_event_items.cstr_length,
stuff->p_event_items.cstr_address,
2003-12-22 11:00:59 +01:00
server_ast,
2003-08-30 03:43:08 +02:00
event);
2001-05-23 15:26:42 +02:00
const SLONG id = event->rvnt_id;
2001-05-23 15:26:42 +02:00
if (status_vector[1]) {
event->rvnt_id = 0;
}
return this->send_response(sendL, (OBJCT) id, 0, status_vector, false);
2001-05-23 15:26:42 +02:00
}
ISC_STATUS rem_port::receive_after_start( P_DATA* data,
2004-05-12 21:39:17 +02:00
PACKET* sendL,
2003-04-10 12:31:28 +02:00
ISC_STATUS* status_vector)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* r e c e i v e _ a f t e r _ s t a r t
*
**************************************
*
* Functional description
* Receive a message.
*
**************************************/
Rrq* requestL;
2001-05-23 15:26:42 +02:00
getHandle(requestL, data->p_data_request);
2001-05-23 15:26:42 +02:00
const USHORT level = data->p_data_incarnation;
2004-05-12 23:47:36 +02:00
requestL = REMOTE_find_request(requestL, level);
2001-05-23 15:26:42 +02:00
/* Figure out the number of the message that we're stalled on. */
USHORT msg_number;
2004-05-12 23:47:36 +02:00
if (!get_next_msg_no(requestL, level, &msg_number)) {
return this->send_response(sendL, 0, 0, status_vector, false);
2001-05-23 15:26:42 +02:00
}
2004-05-12 21:39:17 +02:00
sendL->p_operation = op_response_piggyback;
P_RESP* response = &sendL->p_resp;
2001-05-23 15:26:42 +02:00
response->p_resp_object = msg_number;
response->p_resp_status_vector = status_vector;
response->p_resp_data.cstr_length = 0;
2004-05-12 21:39:17 +02:00
this->send_partial(sendL);
2001-05-23 15:26:42 +02:00
/* Fill in packet to fool receive into thinking that it has been
called directly by the client. */
const Rrq::rrq_repeat* tail = &requestL->rrq_rpt[msg_number];
const rem_fmt* format = tail->rrq_format;
2001-05-23 15:26:42 +02:00
data->p_data_message_number = msg_number;
if (this->port_flags & PORT_rpc)
{
data->p_data_messages = 1;
}
else
{
data->p_data_messages =
(USHORT) REMOTE_compute_batch_size(this,
(USHORT) xdr_protocol_overhead(op_response_piggyback),
op_send,
format);
2001-05-23 15:26:42 +02:00
}
2004-05-12 21:39:17 +02:00
return this->receive_msg(data, sendL);
2001-05-23 15:26:42 +02:00
}
2004-05-12 21:39:17 +02:00
ISC_STATUS rem_port::receive_msg(P_DATA * data, PACKET* sendL)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* r e c e i v e _ m s g
*
**************************************
*
* Functional description
* Receive a message.
*
**************************************/
/* Find the database, request, message number, and the number of
2001-05-23 15:26:42 +02:00
messages the client is willing to cope with. Then locate the
message control block for the request and message type. */
2008-12-02 08:09:49 +01:00
Rrq* requestL;
getHandle(requestL, data->p_data_request);
2001-05-23 15:26:42 +02:00
const USHORT level = data->p_data_incarnation;
2004-05-12 23:47:36 +02:00
requestL = REMOTE_find_request(requestL, level);
const USHORT msg_number = data->p_data_message_number;
USHORT count, count2;
2008-03-28 15:17:21 +01:00
count2 = count = (this->port_flags & PORT_rpc) ? 1 : data->p_data_messages;
2008-12-02 08:09:49 +01:00
2008-03-28 15:17:21 +01:00
ISC_STATUS_ARRAY status_vector;
2008-12-02 08:09:49 +01:00
if (msg_number > requestL->rrq_max_msg)
{
status_vector[0] = isc_arg_gds;
status_vector[1] = isc_badmsgnum;
status_vector[2] = isc_arg_end;
return this->send_response(sendL, 0, 0, status_vector, false);
}
Rrq::rrq_repeat* tail = &requestL->rrq_rpt[msg_number];
const rem_fmt* format = tail->rrq_format;
2001-05-23 15:26:42 +02:00
/* Get ready to ship the data out */
2004-05-12 21:39:17 +02:00
sendL->p_operation = op_send;
sendL->p_data.p_data_request = data->p_data_request;
sendL->p_data.p_data_message_number = msg_number;
sendL->p_data.p_data_incarnation = level;
sendL->p_data.p_data_messages = 1;
2001-05-23 15:26:42 +02:00
#ifdef SCROLLABLE_CURSORS
2008-12-02 08:09:49 +01:00
/* check the direction and offset for possible redirection; if the user
scrolls in a direction other than we were going or an offset other
than 1, then we need to resynchronize:
if the direction is the same as the lookahead cache, scroll forward
through the cache to see if we find the record; otherwise scroll the
next layer down backward by an amount equal to the number of records
2001-05-23 15:26:42 +02:00
in the cache, plus the amount asked for by the next level up */
USHORT direction;
ULONG offset;
2001-05-23 15:26:42 +02:00
if (this->port_protocol < PROTOCOL_SCROLLABLE_CURSORS)
{
direction = blr_forward;
offset = 1;
}
else
{
direction = data->p_data_direction;
offset = data->p_data_offset;
tail->rrq_xdr = scroll_cache(tail, &direction, &offset);
}
#endif
/* Check to see if any messages are already sitting around */
REM_MSG message = 0;
2003-09-11 20:59:34 +02:00
while (true) {
2001-05-23 15:26:42 +02:00
message = tail->rrq_xdr;
/* If we don't have a message cached, get one from the next layer down. */
if (!message->msg_address) {
/* If we have an error queued for delivery, send it now */
2004-05-12 23:47:36 +02:00
if (requestL->rrq_status_vector[1]) {
const ISC_STATUS res =
this->send_response(sendL, 0, 0, requestL->rrq_status_vector, false);
memset(requestL->rrq_status_vector, 0, sizeof(requestL->rrq_status_vector));
2001-05-23 15:26:42 +02:00
return res;
}
#ifdef SCROLLABLE_CURSORS
2008-12-02 08:09:49 +01:00
isc_receive2(status_vector, &requestL->rrq_handle, msg_number,
format->fmt_length, message->msg_buffer, level,
2003-08-30 03:43:08 +02:00
direction, offset);
2001-05-23 15:26:42 +02:00
#else
2004-05-12 23:47:36 +02:00
isc_receive(status_vector, &requestL->rrq_handle, msg_number,
2003-08-30 03:43:08 +02:00
format->fmt_length, message->msg_buffer, level);
2001-05-23 15:26:42 +02:00
#endif
if (status_vector[1])
return this->send_response(sendL, 0, 0, status_vector, false);
2001-05-23 15:26:42 +02:00
#ifdef SCROLLABLE_CURSORS
2008-12-02 08:09:49 +01:00
/* set the appropriate flags according to the way we just scrolled
the next layer down, and calculate the offset from the beginning
2001-05-23 15:26:42 +02:00
of the result set */
switch (direction) {
case blr_forward:
tail->rrq_flags &= ~Rrq::BACKWARD;
tail->rrq_absolute += (tail->rrq_flags & Rrq::ABSOLUTE_BACKWARD) ? -offset : offset;
2001-05-23 15:26:42 +02:00
break;
case blr_backward:
tail->rrq_flags |= Rrq::BACKWARD;
tail->rrq_absolute += (tail->rrq_flags & Rrq::ABSOLUTE_BACKWARD) ? offset : -offset;
2001-05-23 15:26:42 +02:00
break;
case blr_bof_forward:
tail->rrq_flags &= ~Rrq::BACKWARD;
tail->rrq_flags &= ~Rrq::ABSOLUTE_BACKWARD;
2001-05-23 15:26:42 +02:00
tail->rrq_absolute = offset;
direction = blr_forward;
break;
case blr_eof_backward:
tail->rrq_flags |= Rrq::BACKWARD;
tail->rrq_flags |= Rrq::ABSOLUTE_BACKWARD;
2001-05-23 15:26:42 +02:00
tail->rrq_absolute = offset;
direction = blr_backward;
break;
}
message->msg_absolute = tail->rrq_absolute;
2008-12-02 08:09:49 +01:00
/* if we have already scrolled to the location indicated,
2001-05-23 15:26:42 +02:00
then we just want to continue one by one in that direction */
offset = 1;
#endif
message->msg_address = message->msg_buffer;
}
/* If there aren't any buffers remaining, break out of loop */
if (--count <= 0)
break;
/* There's a buffer waiting -- see if the request is ready to send */
REM_MSG next = message->msg_next;
2001-05-23 15:26:42 +02:00
if ((next == message || !next->msg_address) &&
2004-05-12 23:47:36 +02:00
!check_request(requestL, data->p_data_incarnation, msg_number))
{
2001-05-23 15:26:42 +02:00
/* We've reached the end of the RSE - don't prefetch and flush
everything we've buffered so far */
count2 = 0;
break;
}
2004-05-12 21:39:17 +02:00
if (!this->send_partial(sendL))
2001-05-23 15:26:42 +02:00
return FALSE;
message->msg_address = NULL;
}
2004-05-12 21:39:17 +02:00
sendL->p_data.p_data_messages = 0;
this->send(sendL);
2001-05-23 15:26:42 +02:00
message->msg_address = NULL;
2008-12-02 08:09:49 +01:00
/* Bump up the message pointer to resync with rrq_xdr (rrq_xdr
2001-05-23 15:26:42 +02:00
was incremented by xdr_request in the SEND call). */
tail->rrq_message = message->msg_next;
/* Since we have a little time on our hands while this packet is sent
and processed, get the next batch of records. Start by finding the
next free buffer. */
message = tail->rrq_xdr;
REM_MSG prior = NULL;
2001-05-23 15:26:42 +02:00
while (message->msg_address && message->msg_next != tail->rrq_xdr)
message = message->msg_next;
for (; count2 && check_request(requestL, data->p_data_incarnation, msg_number); --count2)
{
2001-05-23 15:26:42 +02:00
if (message->msg_address) {
if (!prior)
#ifdef SCROLLABLE_CURSORS
prior = message->msg_prior;
#else
2008-01-16 08:55:28 +01:00
prior = tail->rrq_xdr;
while (prior->msg_next != message)
prior = prior->msg_next;
2001-05-23 15:26:42 +02:00
#endif
/* allocate a new message block and put it in the cache */
message = new Message(format->fmt_length);
#ifdef DEBUG_REMOTE_MEMORY
2004-04-29 00:36:29 +02:00
printf("receive_msg(server) allocate message %x\n",
2001-05-23 15:26:42 +02:00
message);
#endif
message->msg_number = prior->msg_number;
message->msg_next = prior->msg_next;
#ifdef SCROLLABLE_CURSORS
message->msg_prior = prior;
#endif
prior->msg_next = message;
prior = message;
}
2008-12-02 08:09:49 +01:00
/* fetch the next record into cache; even for scrollable cursors, we are
just doing a simple lookahead continuing on in the last direction specified,
2001-05-23 15:26:42 +02:00
so there is no reason to do an isc_receive2() */
2004-05-12 23:47:36 +02:00
isc_receive(status_vector, &requestL->rrq_handle, msg_number,
2001-05-23 15:26:42 +02:00
format->fmt_length,
message->msg_buffer, data->p_data_incarnation);
/* Did we have an error? If so, save it for later delivery */
if (status_vector[1]) {
/* If already have an error queued, don't overwrite it */
2004-05-12 23:47:36 +02:00
if (!requestL->rrq_status_vector[1]) {
memcpy(requestL->rrq_status_vector, status_vector,
sizeof(requestL->rrq_status_vector));
2001-05-23 15:26:42 +02:00
}
break;
}
#ifdef SCROLLABLE_CURSORS
2008-12-02 08:09:49 +01:00
/* if we have already scrolled to the location indicated,
2001-05-23 15:26:42 +02:00
then we just want to continue on in that direction */
switch (direction)
{
case blr_forward:
tail->rrq_absolute += (tail->rrq_flags & Rrq::ABSOLUTE_BACKWARD) ? -offset : offset;
2001-05-23 15:26:42 +02:00
break;
case blr_backward:
tail->rrq_absolute += (tail->rrq_flags & Rrq::ABSOLUTE_BACKWARD) ? offset : -offset;
2001-05-23 15:26:42 +02:00
break;
}
message->msg_absolute = tail->rrq_absolute;
#endif
message->msg_address = message->msg_buffer;
message = message->msg_next;
}
return TRUE;
}
static void release_blob(Rbl* blob)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* r e l e a s e _ b l o b
*
**************************************
*
* Functional description
* Release a blob block and friends.
*
**************************************/
Rdb* rdb = blob->rbl_rdb;
Rtr* transaction = blob->rbl_rtr;
2001-05-23 15:26:42 +02:00
rdb->rdb_port->releaseObject(blob->rbl_id);
2001-05-23 15:26:42 +02:00
for (Rbl** p = &transaction->rtr_blobs; *p; p = &(*p)->rbl_next) {
2001-05-23 15:26:42 +02:00
if (*p == blob) {
*p = blob->rbl_next;
break;
}
}
#ifdef DEBUG_REMOTE_MEMORY
2004-04-29 00:36:29 +02:00
printf("release_blob(server) free blob %x\n", blob);
2001-05-23 15:26:42 +02:00
#endif
delete blob;
2001-05-23 15:26:42 +02:00
}
static void release_event( Rvnt* event)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* r e l e a s e _ e v e n t
*
**************************************
*
* Functional description
* Release an event block.
*
**************************************/
Rdb* rdb = event->rvnt_rdb;
2001-05-23 15:26:42 +02:00
for (Rvnt** p = &rdb->rdb_events; *p; p = &(*p)->rvnt_next)
2008-01-16 08:55:28 +01:00
{
2001-05-23 15:26:42 +02:00
if (*p == event) {
*p = event->rvnt_next;
break;
}
2008-01-16 08:55:28 +01:00
}
2001-05-23 15:26:42 +02:00
delete event;
2001-05-23 15:26:42 +02:00
}
static void release_request( Rrq* request)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* r e l e a s e _ r e q u e s t
*
**************************************
*
* Functional description
* Release a request block.
*
**************************************/
Rdb* rdb = request->rrq_rdb;
rdb->rdb_port->releaseObject(request->rrq_id);
2001-05-23 15:26:42 +02:00
REMOTE_release_request(request);
}
2008-03-30 11:37:57 +02:00
static void release_statement( Rsr** statement)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* r e l e a s e _ s t a t e m e n t
*
**************************************
*
* Functional description
* Release a GDML or SQL statement?
*
**************************************/
delete (*statement)->rsr_select_format;
delete (*statement)->rsr_bind_format;
(*statement)->releaseException();
2001-05-23 15:26:42 +02:00
REMOTE_release_messages((*statement)->rsr_message);
delete *statement;
2001-05-23 15:26:42 +02:00
*statement = NULL;
}
2008-03-30 11:37:57 +02:00
static void release_sql_request( Rsr* statement)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* r e l e a s e _ s q l _ r e q u e s t
*
**************************************
*
* Functional description
* Release an SQL request block.
*
**************************************/
Rdb* rdb = statement->rsr_rdb;
rdb->rdb_port->releaseObject(statement->rsr_id);
2001-05-23 15:26:42 +02:00
2008-03-30 11:37:57 +02:00
for (Rsr** p = &rdb->rdb_sql_requests; *p; p = &(*p)->rsr_next)
2008-01-16 08:55:28 +01:00
{
2001-05-23 15:26:42 +02:00
if (*p == statement) {
*p = statement->rsr_next;
break;
}
2008-01-16 08:55:28 +01:00
}
2001-05-23 15:26:42 +02:00
release_statement(&statement);
}
static void release_transaction( Rtr* transaction)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* r e l e a s e _ t r a n s a c t i o n
*
**************************************
*
* Functional description
* Release a transaction block and friends.
*
**************************************/
Rdb* rdb = transaction->rtr_rdb;
rdb->rdb_port->releaseObject(transaction->rtr_id);
2001-05-23 15:26:42 +02:00
while (transaction->rtr_blobs)
release_blob(transaction->rtr_blobs);
for (Rtr** p = &rdb->rdb_transactions; *p; p = &(*p)->rtr_next)
2008-01-16 08:55:28 +01:00
{
2001-05-23 15:26:42 +02:00
if (*p == transaction) {
*p = transaction->rtr_next;
break;
}
2008-01-16 08:55:28 +01:00
}
2001-05-23 15:26:42 +02:00
#ifdef DEBUG_REMOTE_MEMORY
2004-04-29 00:36:29 +02:00
printf("release_transact(server) free transaction %x\n", transaction);
2001-05-23 15:26:42 +02:00
#endif
delete transaction;
2001-05-23 15:26:42 +02:00
}
#ifdef SCROLLABLE_CURSORS
2002-11-19 13:40:54 +01:00
static REM_MSG scroll_cache(
Rrq::rrq_repeat* tail,
2001-05-23 15:26:42 +02:00
USHORT * direction, ULONG * offset)
{
/**************************************
*
* s c r o l l _ c a c h e
*
**************************************
*
* Functional description
*
2008-12-02 08:09:49 +01:00
* Try to fetch the requested record from cache, if possible. This algorithm depends
* on all scrollable cursors being INSENSITIVE to database changes, so that absolute
* record numbers within the result set will remain constant.
*
* 1. BOF Forward or EOF Backward: Retain the record number of the offset from the
* beginning or end of the result set. If we can figure out the relative offset
* from the absolute, then scroll to it. If it's in cache, great, otherwise dump
* the cache and have the server scroll the correct number of records.
2001-05-23 15:26:42 +02:00
*
2008-12-02 08:09:49 +01:00
* 2. Forward or Backward: Try to scroll the desired offset in cache. If we
* scroll off the end of the cache, dump the cache and ask the server for a
* packetful of records.
2001-05-23 15:26:42 +02:00
*
2008-12-02 08:09:49 +01:00
* This routine differs from the corresponding routine on the client in that
* we are using only a lookahead cache. There is no point in caching records backward,
* in that the client already has them and would not request them from us.
2001-05-23 15:26:42 +02:00
*
**************************************/
2008-12-02 08:09:49 +01:00
/* if we are to continue in the current direction, set direction to
the last direction scrolled; then depending on the direction asked
2001-05-23 15:26:42 +02:00
for, save the last direction asked for by the next layer above */
if (*direction == blr_continue) {
if (tail->rrq_flags & Rrq::LAST_BACKWARD)
2001-05-23 15:26:42 +02:00
*direction = blr_backward;
else
*direction = blr_forward;
}
if (*direction == blr_forward || *direction == blr_bof_forward)
tail->rrq_flags &= ~Rrq::LAST_BACKWARD;
2001-05-23 15:26:42 +02:00
else
tail->rrq_flags |= Rrq::LAST_BACKWARD;
2001-05-23 15:26:42 +02:00
2008-12-02 08:09:49 +01:00
/* set to the first message; if it has no record, this means the cache is
2001-05-23 15:26:42 +02:00
empty and there is no point in trying to find the record here */
REM_MSG message = tail->rrq_xdr;
2001-05-23 15:26:42 +02:00
if (!message->msg_address)
return message;
2008-12-02 08:09:49 +01:00
/* if we are scrolling from BOF and the cache was started from EOF (or vice
2001-05-23 15:26:42 +02:00
versa), the cache is unusable. */
if ((*direction == blr_bof_forward && (tail->rrq_flags & Rrq::ABSOLUTE_BACKWARD)) ||
(*direction == blr_eof_backward && !(tail->rrq_flags & Rrq::ABSOLUTE_BACKWARD)))
{
return dump_cache(tail);
}
2001-05-23 15:26:42 +02:00
2008-12-02 08:09:49 +01:00
/* if we are going to an absolute position, see if we can find that position
2001-05-23 15:26:42 +02:00
in cache, otherwise change to a relative seek from our former position */
if (*direction == blr_bof_forward || *direction == blr_eof_backward) {
2008-12-02 08:09:49 +01:00
/* If offset is before our current position, just dump the cache because
the server cache is purely a lookahead cache--we don't bother to cache
back records because the client will cache those records, making it
2001-05-23 15:26:42 +02:00
unlikely the client would be asking us for a record which is in our cache. */
if (*offset < message->msg_absolute)
return dump_cache(tail);
/* convert the absolute to relative, and prepare to scroll forward to look for the record */
*offset -= message->msg_absolute;
if (*direction == blr_bof_forward)
*direction = blr_forward;
else
*direction = blr_backward;
}
if ((*direction == blr_forward && (tail->rrq_flags & Rrq::BACKWARD)) ||
(*direction == blr_backward && !(tail->rrq_flags & Rrq::BACKWARD)))
{
2008-12-02 08:09:49 +01:00
/* lookahead cache was in opposite direction from the scroll direction,
so increase the scroll amount by the amount we looked ahead, then
2001-05-23 15:26:42 +02:00
dump the cache */
for (message = tail->rrq_xdr; message->msg_address;) {
(*offset)++;
message = message->msg_next;
if (message == tail->rrq_message)
break;
}
return dump_cache(tail);
}
2008-01-16 08:55:28 +01:00
/* lookahead cache is in same direction we want to scroll, so scroll
forward through the cache, decrementing the offset */
for (message = tail->rrq_xdr; message->msg_address;) {
if (*offset == 1)
break;
(*offset)--;
message = message->msg_next;
if (message == tail->rrq_message)
break;
2001-05-23 15:26:42 +02:00
}
return message;
}
#endif
ISC_STATUS rem_port::seek_blob(P_SEEK* seek, PACKET* sendL)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* s e e k _ b l o b
*
**************************************
*
* Functional description
* Execute a blob seek operation.
*
**************************************/
Rbl* blob;
2001-05-23 15:26:42 +02:00
getHandle(blob, seek->p_seek_blob);
2001-05-23 15:26:42 +02:00
const SSHORT mode = seek->p_seek_mode;
const SLONG offset = seek->p_seek_offset;
2001-05-23 15:26:42 +02:00
2008-03-28 15:17:21 +01:00
ISC_STATUS_ARRAY status_vector;
SLONG result;
2003-08-30 03:43:08 +02:00
isc_seek_blob(status_vector, &blob->rbl_handle, mode, offset, &result);
2001-05-23 15:26:42 +02:00
sendL->p_resp.p_resp_blob_id.bid_quad_low = result;
2001-05-23 15:26:42 +02:00
return this->send_response(sendL, 0, 0, status_vector, false);
2001-05-23 15:26:42 +02:00
}
2004-05-12 21:39:17 +02:00
ISC_STATUS rem_port::send_msg(P_DATA * data, PACKET* sendL)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* s e n d _ m s g
*
**************************************
*
* Functional description
* Handle a isc_send operation.
*
**************************************/
2003-04-16 12:18:51 +02:00
ISC_STATUS_ARRAY status_vector;
2001-05-23 15:26:42 +02:00
Rrq* requestL;
getHandle(requestL, data->p_data_request);
2001-05-23 15:26:42 +02:00
const USHORT number = data->p_data_message_number;
2004-05-12 23:47:36 +02:00
requestL = REMOTE_find_request(requestL, data->p_data_incarnation);
if (number > requestL->rrq_max_msg)
{
status_vector[0] = isc_arg_gds;
status_vector[1] = isc_badmsgnum;
status_vector[2] = isc_arg_end;
return this->send_response(sendL, 0, 0, status_vector, false);
}
2004-05-12 23:47:36 +02:00
REM_MSG message = requestL->rrq_rpt[number].rrq_message;
const rem_fmt* format = requestL->rrq_rpt[number].rrq_format;
2001-05-23 15:26:42 +02:00
2004-05-12 23:47:36 +02:00
isc_send(status_vector, &requestL->rrq_handle, number, format->fmt_length,
2003-08-30 03:43:08 +02:00
message->msg_address, data->p_data_incarnation);
2001-05-23 15:26:42 +02:00
message->msg_address = NULL;
return this->send_response(sendL, 0, 0, status_vector, false);
2001-05-23 15:26:42 +02:00
}
2004-05-12 21:39:17 +02:00
ISC_STATUS rem_port::send_response( PACKET* sendL,
2001-05-23 15:26:42 +02:00
OBJCT object,
USHORT length,
const ISC_STATUS* status_vector,
bool defer_flag)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* s e n d _ r e s p o n s e
*
**************************************
*
* Functional description
* Send a response packet.
*
**************************************/
/* Start by translating the status vector into "generic" form */
ISC_STATUS_ARRAY new_vector;
ISC_STATUS* v = new_vector;
TEXT buffer[1024];
const char* const bufferEnd = buffer + sizeof(buffer);
TEXT* p = buffer;
const ISC_STATUS exit_code = status_vector[1];
2001-05-23 15:26:42 +02:00
for (bool sw = true; *status_vector && sw;)
2001-05-23 15:26:42 +02:00
{
switch (*status_vector)
2001-05-23 15:26:42 +02:00
{
case isc_arg_warning:
2003-11-08 17:40:17 +01:00
case isc_arg_gds:
2008-07-29 12:36:36 +02:00
// When talking with older (pre 6.0) clients, do not send warnings
if (*status_vector == isc_arg_warning && this->port_protocol < PROTOCOL_VERSION10)
2001-05-23 15:26:42 +02:00
{
sw = false;
continue;
}
2001-05-23 15:26:42 +02:00
*v++ = *status_vector++;
2001-05-23 15:26:42 +02:00
/* The status codes are converted to their offsets so that they
* were compatible with the RDB implementation. This was fine
* when status codes were restricted to a single facility. Now
* that the facility is part of the status code we need to know
* this on the client side, thus when talking with 6.0 and newer
* clients, do not decode the status code, just send it to the
* client. The same check is made in interface.cpp::check_response
*/
2001-05-23 15:26:42 +02:00
if (this->port_protocol < PROTOCOL_VERSION10) {
USHORT fac = 0, code_class = 0;
*v++ = gds__decode(*status_vector++, &fac, &code_class);
}
else {
*v++ = *status_vector++;
}
for (;;)
{
switch (*status_vector)
{
case isc_arg_string:
case isc_arg_number:
*v++ = *status_vector++;
*v++ = *status_vector++;
continue;
2001-05-23 15:26:42 +02:00
case isc_arg_cstring:
++status_vector;
*v++ = isc_arg_string;
if (p < bufferEnd) // CVC: Avoid B.O.
{
TEXT** sp = (TEXT**) v;
*sp++ = p;
v = (ISC_STATUS*) sp;
SLONG l = *status_vector++;
const TEXT* q = (TEXT*) *status_vector++;
while (l-- > 0 && (p < bufferEnd - 1))
*p++ = *q++;
*p++ = 0;
2001-05-23 15:26:42 +02:00
}
else
{
// See if we can honor zero length strings, else use an error msg
TEXT** sp = (TEXT**) v;
if (!*status_vector) // this is the length
*sp++ = const_cast<char*>("");
else
*sp++ = const_cast<char*>("Not enough buffer for message");
2008-12-02 08:09:49 +01:00
v = (ISC_STATUS*) sp;
status_vector += 2;
}
continue;
} // switch
break;
} // for (;;)
2001-05-23 15:26:42 +02:00
continue;
2003-11-08 17:40:17 +01:00
case isc_arg_interpreted:
case isc_arg_sql_state:
2001-05-23 15:26:42 +02:00
*v++ = *status_vector++;
*v++ = *status_vector++;
continue;
}
2008-12-02 08:09:49 +01:00
2006-04-07 04:55:34 +02:00
const int l = (p < bufferEnd) ? fb_interpret(p, bufferEnd - p, &status_vector) : 0;
2001-05-23 15:26:42 +02:00
if (l == 0)
break;
2003-11-08 17:40:17 +01:00
*v++ = isc_arg_interpreted;
TEXT** sp = (TEXT**) v;
2001-05-23 15:26:42 +02:00
*sp++ = p;
2003-04-10 12:31:28 +02:00
v = (ISC_STATUS *) sp;
2001-05-23 15:26:42 +02:00
p += l;
sw = false;
2001-05-23 15:26:42 +02:00
}
2003-11-08 17:40:17 +01:00
*v = isc_arg_end;
2001-05-23 15:26:42 +02:00
2008-07-29 12:36:36 +02:00
// Format and send response. Note: the blob_id and data address fields
// of the response packet may contain valid data. Don't trash them.
2001-05-23 15:26:42 +02:00
2004-05-12 21:39:17 +02:00
sendL->p_operation = op_response;
2004-05-12 21:39:17 +02:00
P_RESP* response = &sendL->p_resp;
2001-05-23 15:26:42 +02:00
response->p_resp_object = object;
response->p_resp_status_vector = new_vector;
response->p_resp_data.cstr_length = length;
if ((this->port_flags & PORT_lazy) && defer_flag) {
this->send_partial(sendL);
}
else {
this->send(sendL);
}
2001-05-23 15:26:42 +02:00
// If database or attachment has been shut down,
// there's no point in keeping the connection open
if (exit_code == isc_shutdown || exit_code == isc_att_shutdown)
{
this->port_state = rem_port::BROKEN;
}
2001-05-23 15:26:42 +02:00
return exit_code;
}
2003-12-22 11:00:59 +01:00
static void server_ast(void* event_void, USHORT length, const UCHAR* items)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* s e r v e r _ a s t
*
**************************************
*
* Functional description
2003-01-15 13:15:07 +01:00
* Send an asynchrous event packet back to client.
2001-05-23 15:26:42 +02:00
*
**************************************/
Rvnt* event = static_cast<Rvnt*>(event_void);
2001-05-23 15:26:42 +02:00
event->rvnt_id = 0;
Rdb* rdb = event->rvnt_rdb;
2001-05-23 15:26:42 +02:00
rem_port* port = rdb->rdb_port->port_async;
if (!port) {
2001-05-23 15:26:42 +02:00
return;
}
Firebird::RefMutexGuard portGuard(*port->port_sync);
PACKET packet;
2001-05-23 15:26:42 +02:00
packet.p_operation = op_event;
P_EVENT* p_event = &packet.p_event;
2001-05-23 15:26:42 +02:00
p_event->p_event_database = rdb->rdb_id;
p_event->p_event_items.cstr_length = length;
p_event->p_event_items.cstr_address = items;
2008-12-02 08:09:49 +01:00
// Nickolay Samofatov: We keep these values and even pass them to the client
// (as 32-bit values) when event is fired, but client ignores them.
2003-12-22 11:00:59 +01:00
p_event->p_event_ast = event->rvnt_ast;
p_event->p_event_arg = (SLONG)(IPTR) event->rvnt_arg;
2008-12-02 08:09:49 +01:00
2001-05-23 15:26:42 +02:00
p_event->p_event_rid = event->rvnt_rid;
port->send(&packet);
}
2006-12-08 19:38:15 +01:00
static void attach_service(rem_port* port, P_ATCH* attach, PACKET* sendL)
{
const char* service_name = reinterpret_cast<const char*>(attach->p_atch_file.cstr_address);
2006-12-08 19:38:15 +01:00
const USHORT service_length = attach->p_atch_file.cstr_length;
2008-12-02 08:09:49 +01:00
Firebird::ClumpletWriter spb(Firebird::ClumpletReader::SpbAttach, MAX_DPB_SIZE,
2006-12-08 19:38:15 +01:00
attach->p_atch_dpb.cstr_address, attach->p_atch_dpb.cstr_length, isc_spb_current_version);
2008-01-16 08:55:28 +01:00
// remove trusted role if present (security measure)
spb.deleteWithTag(isc_spb_trusted_role);
2006-12-08 19:38:15 +01:00
#ifdef TRUSTED_AUTH
// Do we can & need trusted authentication?
if (spb.find(isc_spb_trusted_auth))
2006-12-08 19:38:15 +01:00
{
2008-12-02 08:09:49 +01:00
try
2006-12-08 19:38:15 +01:00
{
// extract trusted authentication data from spb
AuthSspi::DataHolder data;
memcpy(data.getBuffer(spb.getClumpLength()), spb.getBytes(), spb.getClumpLength());
2006-12-08 19:38:15 +01:00
spb.deleteClumplet();
2008-01-16 08:55:28 +01:00
// remove extra trusted auth if present (security measure)
spb.deleteWithTag(isc_spb_trusted_auth);
2008-01-16 08:55:28 +01:00
if (canUseTrusted() && port->port_protocol >= PROTOCOL_VERSION11)
2006-12-08 19:38:15 +01:00
{
2008-12-02 08:09:49 +01:00
port->port_trusted_auth =
new ServerAuth(service_name, service_length, spb, attach_service2, op_trusted_auth);
AuthSspi* authSspi = port->port_trusted_auth->authSspi;
if (authSspi->accept(data) && authSspi->isActive())
{
sendL->p_operation = op_trusted_auth;
cstring& s = sendL->p_trau.p_trau_data;
s.cstr_allocated = 0;
s.cstr_length = data.getCount();
s.cstr_address = data.begin();
port->send(sendL);
return;
}
2006-12-08 19:38:15 +01:00
}
}
catch (const Firebird::status_exception& e)
2006-12-08 19:38:15 +01:00
{
ISC_STATUS_ARRAY status_vector;
Firebird::stuff_exception(status_vector, e);
delete port->port_trusted_auth;
port->port_trusted_auth = 0;
2006-12-08 19:38:15 +01:00
port->send_response(sendL, 0, 0, status_vector, false);
return;
}
}
2008-01-16 08:55:28 +01:00
#else // TRUSTED_AUTH
// remove trusted auth if present (security measure)
spb.deleteWithTag(isc_spb_trusted_auth);
2006-12-10 01:16:00 +01:00
#endif // TRUSTED_AUTH
2008-12-02 08:09:49 +01:00
attach_service2(port, op_trusted_auth, service_name, service_length,
2006-12-08 19:38:15 +01:00
spb.getBuffer(), spb.getBufferLength(), sendL);
}
static void attach_service2(rem_port* port,
P_OP,
2008-12-02 08:09:49 +01:00
const char* service_name,
int service_length,
const UCHAR* spb,
int sl,
2006-12-08 19:38:15 +01:00
PACKET* sendL)
{
2008-12-02 08:09:49 +01:00
Firebird::ClumpletWriter tmp(Firebird::ClumpletReader::SpbAttach, MAX_DPB_SIZE,
spb, sl, isc_spb_current_version);
port->service_attach(service_name, service_length, tmp, sendL);
2006-12-08 19:38:15 +01:00
#ifdef TRUSTED_AUTH
delete port->port_trusted_auth;
port->port_trusted_auth = 0;
#endif
}
2006-12-17 10:09:39 +01:00
2008-12-02 08:09:49 +01:00
ISC_STATUS rem_port::service_attach(const char* service_name,
2006-12-08 19:38:15 +01:00
const USHORT service_length,
2008-12-02 08:09:49 +01:00
Firebird::ClumpletWriter& spb,
2006-12-08 19:38:15 +01:00
PACKET* sendL)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
2008-12-02 08:09:49 +01:00
* s e r v i c e _ a t t a c h
2001-05-23 15:26:42 +02:00
*
**************************************
*
* Functional description
* Connect to a Firebird service.
2001-05-23 15:26:42 +02:00
*
**************************************/
2004-05-12 21:39:17 +02:00
sendL->p_operation = op_accept;
2004-05-03 01:06:37 +02:00
FB_API_HANDLE handle = 0;
2001-05-23 15:26:42 +02:00
2006-12-08 19:38:15 +01:00
#ifdef TRUSTED_AUTH
// If we have trusted authentication, append it to database parameter block
if (port_trusted_auth)
{
AuthSspi* authSspi = port_trusted_auth->authSspi;
Firebird::string trustedUserName;
2008-01-16 08:55:28 +01:00
bool wheel = false;
if (authSspi->getLogin(trustedUserName, wheel))
2006-12-08 19:38:15 +01:00
{
spb.insertString(isc_spb_trusted_auth, trustedUserName);
2008-01-16 08:55:28 +01:00
if (wheel && !spb.find(isc_spb_sql_role_name))
{
spb.insertString(isc_spb_trusted_role, ADMIN_ROLE, strlen(ADMIN_ROLE));
}
2006-12-08 19:38:15 +01:00
}
}
2006-12-10 01:16:00 +01:00
#endif // TRUSTED_AUTH
2001-05-23 15:26:42 +02:00
// If we have user identification, append it to database parameter block
const rem_str* string = port_user_name;
if (string) {
spb.setCurOffset(spb.getBufferLength());
spb.insertString(isc_spb_sys_user_name, string->str_data, string->str_length);
2001-05-23 15:26:42 +02:00
}
// Now insert additional clumplets into spb
addClumplets(spb, spbParam, this);
2008-12-02 08:09:49 +01:00
/* See if user has specified parameters relevent to the connection,
they will be stuffed in the SPB if so. */
REMOTE_get_timeout_params(this, &spb);
2001-05-23 15:26:42 +02:00
ISC_STATUS_ARRAY status_vector;
2001-05-23 15:26:42 +02:00
isc_service_attach(status_vector,
service_length,
2006-12-08 19:38:15 +01:00
service_name,
&handle,
spb.getBufferLength(),
reinterpret_cast<const char*>(spb.getBuffer()));
2001-05-23 15:26:42 +02:00
if (!status_vector[1]) {
Rdb* rdb = new Rdb;
2006-12-08 19:38:15 +01:00
if (rdb)
{
this->port_context = rdb;
#ifdef DEBUG_REMOTE_MEMORY
2006-12-08 19:38:15 +01:00
printf("attach_service(server) allocate rdb %x\n", rdb);
2001-05-23 15:26:42 +02:00
#endif
2006-12-08 19:38:15 +01:00
rdb->rdb_port = this;
rdb->rdb_handle = handle;
rdb->rdb_flags |= Rdb::SERVICE;
2006-12-08 19:38:15 +01:00
}
else
{
status_vector[0] = isc_arg_gds;
status_vector[1] = isc_virmemexh;
2006-12-08 19:38:15 +01:00
status_vector[2] = isc_arg_end;
}
2001-05-23 15:26:42 +02:00
}
return this->send_response(sendL, 0, 0, status_vector, false);
2001-05-23 15:26:42 +02:00
}
2004-05-12 21:39:17 +02:00
ISC_STATUS rem_port::service_end(P_RLSE * release, PACKET* sendL)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* s e r v i c e _ e n d
*
**************************************
*
* Functional description
* Close down a service.
*
**************************************/
ISC_STATUS_ARRAY status_vector;
2008-12-02 08:09:49 +01:00
Rdb* rdb = this->port_context;
if (bad_service(status_vector, rdb))
{
return this->send_response(sendL, 0, 0, status_vector, false);
}
2001-05-23 15:26:42 +02:00
2003-08-30 03:43:08 +02:00
isc_service_detach(status_vector, &rdb->rdb_handle);
2001-05-23 15:26:42 +02:00
if (status_vector[1] == 0) {
port_flags |= PORT_detached;
}
return this->send_response(sendL, 0, 0, status_vector, false);
2001-05-23 15:26:42 +02:00
}
2004-05-12 21:39:17 +02:00
ISC_STATUS rem_port::service_start(P_INFO * stuff, PACKET* sendL)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* s e r v i c e _ s t a r t
*
**************************************
*
* Functional description
* Start a service on the server
*
**************************************/
ISC_STATUS_ARRAY status_vector;
2008-12-02 08:09:49 +01:00
Rdb* rdb = this->port_context;
if (bad_service(status_vector, rdb))
{
return this->send_response(sendL, 0, 0, status_vector, false);
}
2008-12-02 08:09:49 +01:00
SLONG* reserved = 0; // reserved for future use
2001-05-23 15:26:42 +02:00
isc_service_start(status_vector,
&rdb->rdb_handle,
reserved,
2001-05-23 15:26:42 +02:00
stuff->p_info_items.cstr_length,
reinterpret_cast<const char*>(stuff->p_info_items.cstr_address));
2001-05-23 15:26:42 +02:00
return this->send_response(sendL, 0, 0, status_vector, false);
2001-05-23 15:26:42 +02:00
}
2004-05-12 21:39:17 +02:00
ISC_STATUS rem_port::set_cursor(P_SQLCUR * sqlcur, PACKET* sendL)
2001-05-23 15:26:42 +02:00
{
/*****************************************
*
* s e t _ c u r s o r
*
*****************************************
*
* Functional description
* Set a cursor name for a dynamic request.
*
*****************************************/
2008-03-30 11:37:57 +02:00
Rsr* statement;
2003-04-16 12:18:51 +02:00
ISC_STATUS_ARRAY status_vector;
2001-05-23 15:26:42 +02:00
getHandle(statement, sqlcur->p_sqlcur_statement);
2001-05-23 15:26:42 +02:00
GDS_DSQL_SET_CURSOR(status_vector,
&statement->rsr_handle,
reinterpret_cast<const char*>(sqlcur->p_sqlcur_cursor_name.cstr_address),
2001-05-23 15:26:42 +02:00
sqlcur->p_sqlcur_type);
return this->send_response(sendL, 0, 0, status_vector, false);
2001-05-23 15:26:42 +02:00
}
void set_server( rem_port* port, USHORT flags)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* s e t _ s e r v e r
*
**************************************
*
* Functional description
* Look up the server for this type
* of port. If one doesn't exist,
* create it.
*
**************************************/
Firebird::MutexLockGuard srvrGuard(servers_mutex);
2001-05-23 15:26:42 +02:00
SRVR server;
for (server = servers; server; server = server->srvr_next) {
if (port->port_type == server->srvr_port_type) {
break;
}
}
2008-12-02 08:09:49 +01:00
if (!server)
{
servers = server = new srvr(servers, port, flags);
fb_shutdown_callback(0, shut_server, fb_shut_postproviders, 0);
2001-05-23 15:26:42 +02:00
}
port->port_server = server;
}
2004-05-12 21:39:17 +02:00
ISC_STATUS rem_port::start(P_OP operation, P_DATA * data, PACKET* sendL)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* s t a r t
*
**************************************
*
* Functional description
*
**************************************/
Rtr* transaction;
2001-05-23 15:26:42 +02:00
getHandle(transaction, data->p_data_transaction);
2001-05-23 15:26:42 +02:00
Rrq* requestL;
getHandle(requestL, data->p_data_request);
2001-05-23 15:26:42 +02:00
2004-05-12 23:47:36 +02:00
requestL = REMOTE_find_request(requestL, data->p_data_incarnation);
REMOTE_reset_request(requestL, 0);
2001-05-23 15:26:42 +02:00
2008-03-28 15:17:21 +01:00
ISC_STATUS_ARRAY status_vector;
2004-05-12 23:47:36 +02:00
isc_start_request(status_vector, &requestL->rrq_handle,
2003-08-30 03:43:08 +02:00
&transaction->rtr_handle, data->p_data_incarnation);
2001-05-23 15:26:42 +02:00
if (!status_vector[1]) {
2004-05-12 23:47:36 +02:00
requestL->rrq_rtr = transaction;
2001-05-23 15:26:42 +02:00
if (operation == op_start_and_receive)
2004-05-12 21:39:17 +02:00
return this->receive_after_start(data, sendL, status_vector);
2001-05-23 15:26:42 +02:00
}
return this->send_response(sendL, 0, 0, status_vector, false);
2001-05-23 15:26:42 +02:00
}
ISC_STATUS rem_port::start_and_send(P_OP operation,
2001-05-23 15:26:42 +02:00
P_DATA* data,
2004-05-12 21:39:17 +02:00
PACKET* sendL)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* s t a r t _ a n d _ s e n d
*
**************************************
*
* Functional description
*
**************************************/
ISC_STATUS_ARRAY status_vector;
Rtr* transaction;
getHandle(transaction, data->p_data_transaction);
Rrq* requestL;
getHandle(requestL, data->p_data_request);
2001-05-23 15:26:42 +02:00
2004-05-12 23:47:36 +02:00
requestL = REMOTE_find_request(requestL, data->p_data_incarnation);
const USHORT number = data->p_data_message_number;
if (number > requestL->rrq_max_msg)
{
status_vector[0] = isc_arg_gds;
status_vector[1] = isc_badmsgnum;
status_vector[2] = isc_arg_end;
return this->send_response(sendL, 0, 0, status_vector, false);
}
2004-05-12 23:47:36 +02:00
REM_MSG message = requestL->rrq_rpt[number].rrq_message;
const rem_fmt* format = requestL->rrq_rpt[number].rrq_format;
REMOTE_reset_request(requestL, message);
2001-05-23 15:26:42 +02:00
2004-05-12 23:47:36 +02:00
isc_start_and_send(status_vector, &requestL->rrq_handle,
2003-08-30 03:43:08 +02:00
&transaction->rtr_handle, number,
format->fmt_length, message->msg_address,
2001-05-23 15:26:42 +02:00
data->p_data_incarnation);
if (!status_vector[1]) {
2004-05-12 23:47:36 +02:00
requestL->rrq_rtr = transaction;
2001-05-23 15:26:42 +02:00
if (operation == op_start_send_and_receive) {
2004-05-12 21:39:17 +02:00
return this->receive_after_start(data, sendL, status_vector);
2001-05-23 15:26:42 +02:00
}
}
return this->send_response(sendL, 0, 0, status_vector, false);
2001-05-23 15:26:42 +02:00
}
2004-05-12 21:39:17 +02:00
ISC_STATUS rem_port::start_transaction(P_OP operation, P_STTR * stuff, PACKET* sendL)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* s t a r t _ t r a n s a c t i o n
*
**************************************
*
* Functional description
* Start a transaction.
*
**************************************/
2003-04-16 12:18:51 +02:00
ISC_STATUS_ARRAY status_vector;
2001-05-23 15:26:42 +02:00
Rdb* rdb = this->port_context;
if (bad_db(status_vector, rdb))
{
return this->send_response(sendL, 0, 0, status_vector, false);
}
2008-12-02 08:09:49 +01:00
2004-05-03 01:06:37 +02:00
FB_API_HANDLE handle = 0;
2001-05-23 15:26:42 +02:00
if (operation == op_reconnect)
2003-08-30 03:43:08 +02:00
isc_reconnect_transaction(status_vector, &rdb->rdb_handle, &handle,
2001-05-23 15:26:42 +02:00
stuff->p_sttr_tpb.cstr_length,
reinterpret_cast<const char*>(stuff->p_sttr_tpb.cstr_address));
2001-05-23 15:26:42 +02:00
else
2003-08-30 03:43:08 +02:00
isc_start_transaction(status_vector, &handle, (SSHORT) 1, &rdb->rdb_handle,
2001-05-23 15:26:42 +02:00
stuff->p_sttr_tpb.cstr_length,
2003-08-30 03:43:08 +02:00
stuff->p_sttr_tpb.cstr_address);
2001-05-23 15:26:42 +02:00
OBJCT object;
2001-05-23 15:26:42 +02:00
if (status_vector[1])
{
object = 0;
}
else
{
Rtr* transaction = make_transaction(rdb, handle);
if (transaction)
2001-05-23 15:26:42 +02:00
{
object = transaction->rtr_id;
if (operation == op_reconnect)
2008-01-16 08:55:28 +01:00
transaction->rtr_limbo = true;
#ifdef DEBUG_REMOTE_MEMORY
2004-04-29 00:36:29 +02:00
printf("start_transaction(server) allocate trans %x\n",
2001-05-23 15:26:42 +02:00
transaction);
#endif
}
else {
object = 0;
if (operation != op_reconnect)
2003-08-30 03:43:08 +02:00
isc_rollback_transaction(status_vector, &handle);
2001-05-23 15:26:42 +02:00
#ifdef SUPERSERVER
/* Note that there is an underlying transaction pool
that won't be released until this connection is
detached. At least release the y-valve handle. */
else
fb_disconnect_transaction(status_vector, &handle);
2001-05-23 15:26:42 +02:00
#endif
status_vector[0] = isc_arg_gds;
status_vector[1] = isc_too_many_handles;
status_vector[2] = isc_arg_end;
}
}
return this->send_response(sendL, object, 0, status_vector, false);
2001-05-23 15:26:42 +02:00
}
2008-03-28 15:17:21 +01:00
static void success( ISC_STATUS* status_vector)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* s u c c e s s
*
**************************************
*
* Functional description
* Set status vector to indicate success.
*
**************************************/
2003-11-08 17:40:17 +01:00
status_vector[0] = isc_arg_gds;
status_vector[1] = FB_SUCCESS;
2003-11-08 17:40:17 +01:00
status_vector[2] = isc_arg_end;
2001-05-23 15:26:42 +02:00
}
static THREAD_ENTRY_DECLARE loopThread(THREAD_ENTRY_PARAM)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* t h r e a d
*
**************************************
*
* Functional description
* Execute requests in a happy loop.
*
**************************************/
ISC_enter(); /* Setup floating point exception handler once and for all. */
2001-05-23 15:26:42 +02:00
Worker worker;
2008-10-04 19:46:31 +02:00
rem_port* port = NULL;
while (!Worker::isShuttingDown())
2002-03-31 01:40:08 +01:00
{
Firebird::MutexEnsureUnlock reqQueGuard(request_que_mutex);
reqQueGuard.enter();
SERVER_REQ request = request_que;
if (request)
2002-03-31 01:40:08 +01:00
{
worker.setState(true);
REMOTE_TRACE(("Dequeue request %p", request_que));
2001-05-23 15:26:42 +02:00
request_que = request->req_next;
reqQueGuard.leave();
2002-03-31 01:40:08 +01:00
while (request)
{
2001-05-23 15:26:42 +02:00
/* Bind a thread to a port. */
2002-03-31 01:40:08 +01:00
if (request->req_port->port_server_flags & SRVR_thread_per_port)
{
2001-05-23 15:26:42 +02:00
port = request->req_port;
free_request(request);
2001-05-23 15:26:42 +02:00
SRVR_main(port, port->port_server_flags);
request = 0;
continue;
}
/* Splice request into list of active requests, execute request,
and unsplice */
{ // scope
Firebird::MutexLockGuard queGuard(request_que_mutex);
request->req_next = active_requests;
active_requests = request;
}
2001-05-23 15:26:42 +02:00
/* Validate port. If it looks ok, process request */
2008-03-15 14:46:28 +01:00
Firebird::RefMutexEnsureUnlock portQueGuard(*request->req_port->port_que_sync);
{ // port_sync scope
Firebird::RefMutexGuard portGuard(*request->req_port->port_sync);
if (request->req_port->port_state != rem_port::DISCONNECTED)
2004-03-24 21:12:35 +01:00
{
process_packet(request->req_port, &request->req_send, &request->req_receive, &port);
2002-03-31 01:40:08 +01:00
}
else
{
port = NULL;
}
// With lazy port feature enabled we can have more received and
// not handled data in receive queue. Handle it now if it contains
// whole request packet. If it contain partial packet don't clear
// request queue, restore receive buffer state to state before
// reading packet and wait until rest of data arrives
if (port)
{
fb_assert(port == request->req_port);
// It is very important to not release port_que_sync before
// port_sync, else we can miss data arrived at time between
// releasing locks and will never handle it. Therefore we
// can't ise MutexLockGuard here
2008-03-15 14:46:28 +01:00
portQueGuard.enter();
if (port->haveRecvData())
{
SERVER_REQ new_request = alloc_request();
const rem_port::RecvQueState recvState = port->getRecvState();
port->receive(&new_request->req_receive);
if (new_request->req_receive.p_operation == op_partial)
{
// gds__log("Partial");
free_request(new_request);
port->setRecvState(recvState);
}
else
{
if (!port->haveRecvData())
port->clearRecvQue();
new_request->req_port = port;
2001-05-23 15:26:42 +02:00
2008-12-02 08:09:49 +01:00
const bool ok = link_request(port, new_request);
fb_assert(ok);
}
}
2001-05-23 15:26:42 +02:00
}
} // port_sync scope
if (port) {
2008-03-15 14:46:28 +01:00
portQueGuard.leave();
2002-03-31 01:40:08 +01:00
}
2001-05-23 15:26:42 +02:00
{ // request_que_mutex scope
Firebird::MutexLockGuard queGuard(request_que_mutex);
2001-05-23 15:26:42 +02:00
/* Take request out of list of active requests */
2008-12-02 08:09:49 +01:00
for (SERVER_REQ* req_ptr = &active_requests; *req_ptr;
req_ptr = &(*req_ptr)->req_next)
{
if (*req_ptr == request) {
*req_ptr = request->req_next;
break;
}
2001-05-23 15:26:42 +02:00
}
2008-12-02 08:09:49 +01:00
/* If this is a explicit or implicit disconnect, get rid of
any chained requests */
2008-12-02 08:09:49 +01:00
if (!port)
{
SERVER_REQ next;
while (next = request->req_chain) {
request->req_chain = next->req_chain;
free_request(next);
}
if (request->req_send.p_operation == op_void &&
request->req_receive.p_operation == op_void)
{
delete request;
request = 0;
}
2001-05-23 15:26:42 +02:00
}
else {
port->port_requests_queued--;
#ifdef DEBUG_REMOTE_MEMORY
printf("thread ACTIVE request_queued %d\n",
port->port_requests_queued);
fflush(stdout);
2001-05-23 15:26:42 +02:00
#endif
}
2001-05-23 15:26:42 +02:00
/* Pick up any remaining chained request, and free current request */
2008-12-02 08:09:49 +01:00
if (request) {
SERVER_REQ next = request->req_chain;
free_request(request);
//request = next;
2008-12-02 08:09:49 +01:00
// Try to be fair - put new request at the end of waiting
// requests queue and take request to work on from the
// head of the queue
2008-12-02 08:09:49 +01:00
if (next)
{
append_request_next(next, &request_que);
request = request_que;
request_que = request->req_next;
}
else {
request = NULL;
}
}
} // request_que_mutex scope
} // while (request)
2001-05-23 15:26:42 +02:00
}
2008-12-02 08:09:49 +01:00
else
{
reqQueGuard.leave();
worker.setState(false);
2001-05-23 15:26:42 +02:00
if (Worker::isShuttingDown())
break;
2008-12-02 08:09:49 +01:00
if (!worker.wait())
break;
2001-05-23 15:26:42 +02:00
}
}
return 0;
}
SSHORT rem_port::asyncReceive(PACKET* asyncPacket, const UCHAR* buffer, SSHORT dataSize)
{
/**************************************
*
* a s y n c R e c e i v e
*
**************************************
*
* Functional description
* If possible, accept incoming data asynchronously
*
**************************************/
if (! port_async_receive)
{
return 0;
}
if (haveRecvData())
{
// We have no reliable way to distinguish network packet that start
// from the beginning of XDR packet or in the middle of it.
// Therefore try to process asynchronously only if there is no data
2008-12-02 08:09:49 +01:00
// waiting in port queue. This can lead to fallback to synchronous
// processing of async command (i.e. with some delay), but reliably
// protects from spurious protocol breakage.
return 0;
}
2008-12-02 08:09:49 +01:00
switch (getOperation(buffer, dataSize))
{
case op_cancel:
break;
default:
return 0;
}
{ // scope for guard
static Firebird::GlobalPtr<Firebird::Mutex> mutex;
Firebird::MutexLockGuard guard(mutex);
port_async_receive->clearRecvQue();
port_async_receive->port_receive.x_handy = 0;
memcpy(port_async_receive->port_queue.add().getBuffer(dataSize), buffer, dataSize);
// It's required, that async packets follow simple rule:
// xdr packet fits into network packet.
port_async_receive->receive(asyncPacket);
}
2008-05-13 03:29:38 +02:00
2008-05-14 11:24:14 +02:00
const SSHORT asyncSize = dataSize - port_async_receive->port_receive.x_handy;
fb_assert(asyncSize >= 0);
2008-05-15 03:27:23 +02:00
switch (asyncPacket->p_operation)
{
case op_cancel:
cancel_operation(this, asyncPacket->p_cancel_op.p_co_kind);
break;
default:
return 0;
}
return asyncSize;
}
2004-05-12 21:39:17 +02:00
ISC_STATUS rem_port::transact_request(P_TRRQ* trrq, PACKET* sendL)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* t r a n s a c t _ r e q u e s t
*
**************************************
*
* Functional description
*
**************************************/
2003-04-16 12:18:51 +02:00
ISC_STATUS_ARRAY status_vector;
Rtr* transaction;
2001-05-23 15:26:42 +02:00
getHandle(transaction, trrq->p_trrq_transaction);
2001-05-23 15:26:42 +02:00
Rdb* rdb = this->port_context;
if (bad_db(status_vector, rdb))
{
return this->send_response(sendL, 0, 0, status_vector, false);
}
2008-12-02 08:09:49 +01:00
UCHAR* blr = trrq->p_trrq_blr.cstr_address;
const USHORT blr_length = trrq->p_trrq_blr.cstr_length;
Rpr* procedure = this->port_rpr;
UCHAR* in_msg = (procedure->rpr_in_msg) ? procedure->rpr_in_msg->msg_address : NULL;
const USHORT in_msg_length =
2001-05-23 15:26:42 +02:00
(procedure->rpr_in_format) ? procedure->rpr_in_format->fmt_length : 0;
UCHAR* out_msg = (procedure->rpr_out_msg) ? procedure->rpr_out_msg->msg_address : NULL;
const USHORT out_msg_length =
2004-12-16 04:03:13 +01:00
(procedure->rpr_out_format) ? procedure->rpr_out_format->fmt_length : 0;
2001-05-23 15:26:42 +02:00
isc_transact_request(status_vector,
&rdb->rdb_handle,
&transaction->rtr_handle,
2001-05-23 15:26:42 +02:00
blr_length,
reinterpret_cast<char*>(blr),
2001-05-23 15:26:42 +02:00
in_msg_length,
reinterpret_cast<char*>(in_msg),
2001-05-23 15:26:42 +02:00
out_msg_length,
reinterpret_cast<char*>(out_msg));
if (status_vector[1])
return this->send_response(sendL, 0, 0, status_vector, false);
2001-05-23 15:26:42 +02:00
2004-05-12 21:39:17 +02:00
P_DATA* data = &sendL->p_data;
sendL->p_operation = op_transact_response;
2001-05-23 15:26:42 +02:00
data->p_data_messages = 1;
2004-05-12 21:39:17 +02:00
this->send(sendL);
2001-05-23 15:26:42 +02:00
return FB_SUCCESS;
2001-05-23 15:26:42 +02:00
}
2003-09-11 20:59:34 +02:00
static void zap_packet(PACKET* packet,
bool new_packet)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* z a p _ p a c k e t
*
**************************************
*
* Functional description
* Zero out a packet block.
*
**************************************/
if (new_packet)
2001-05-23 15:26:42 +02:00
memset(packet, 0, sizeof(PACKET));
else {
2001-05-23 15:26:42 +02:00
#ifdef DEBUG_XDR_MEMORY
/* Don't trash debug xdr memory allocation table of recycled packets. */
memset(&packet->p_operation, 0, sizeof(PACKET) - OFFSET(PACKET*, p_operation));
2001-05-23 15:26:42 +02:00
#else
memset(packet, 0, sizeof(PACKET));
#endif
}
2001-05-23 15:26:42 +02:00
}
2008-12-02 08:09:49 +01:00
static bool bad_port_context(ISC_STATUS* status_vector,
Rdb* rdb,
const ISC_LONG error)
{
/**************************************
*
* b a d _ p o r t _ c o n t e x t
*
**************************************
*
* Functional description
* Check rdb pointer, in case of error create status vector
*
**************************************/
if (rdb)
{
return false;
}
status_vector[0] = isc_arg_gds;
2006-04-07 04:55:34 +02:00
status_vector[1] = error;
status_vector[2] = isc_arg_end;
return true;
}
Worker::Worker()
{
m_active = false;
m_next = m_prev = NULL;
2008-03-13 11:41:38 +01:00
#ifdef DEV_BUILD
m_tid = getThreadId();
2008-03-13 11:41:38 +01:00
#endif
Firebird::MutexLockGuard guard(m_mutex);
insert(m_active);
}
Worker::~Worker()
{
Firebird::MutexLockGuard guard(m_mutex);
remove();
--m_cntAll;
}
2008-03-14 03:50:40 +01:00
bool Worker::wait(int timeout)
{
return m_sem.tryEnter(timeout);
}
2008-03-13 11:41:38 +01:00
void Worker::setState(const bool active)
{
if (m_active == active)
return;
Firebird::MutexLockGuard guard(m_mutex);
remove();
insert(active);
}
2008-03-14 03:50:40 +01:00
bool Worker::wakeUp()
{
Firebird::MutexLockGuard guard(m_mutex);
if (m_idleWorkers)
{
m_idleWorkers->m_sem.release();
return true;
}
return (m_cntAll >= MAX_THREADS);
}
2008-03-14 03:50:40 +01:00
void Worker::wakeUpAll()
{
Firebird::MutexLockGuard guard(m_mutex);
2008-03-13 11:41:38 +01:00
for (Worker* thd = m_idleWorkers; thd; thd = thd->m_next)
thd->m_sem.release();
}
void Worker::remove()
{
if (!m_active) {
m_cntIdle--;
}
if (m_idleWorkers == this) {
m_idleWorkers = this->m_next;
}
if (m_activeWorkers == this) {
m_activeWorkers = this->m_next;
}
if (m_next) {
m_next->m_prev = this->m_prev;
}
if (m_prev) {
m_prev->m_next = this->m_next;
}
m_prev = m_next = NULL;
}
2008-03-13 11:41:38 +01:00
void Worker::insert(const bool active)
{
fb_assert(!m_next);
fb_assert(!m_prev);
fb_assert(m_idleWorkers != this);
fb_assert(m_activeWorkers != this);
2008-03-14 03:50:40 +01:00
Worker** list = active ? &m_activeWorkers : &m_idleWorkers;
m_next = *list;
if (*list) {
(*list)->m_prev = this;
}
*list = this;
m_active = active;
2008-12-02 08:09:49 +01:00
if (!m_active)
{
m_cntIdle++;
fb_assert(m_idleWorkers == this);
}
else
fb_assert(m_activeWorkers == this);
}
void Worker::start(USHORT flags)
{
Firebird::MutexLockGuard guard(m_mutex);
if (!isShuttingDown() && !wakeUp())
{
if (gds__thread_start(loopThread, (void*)(IPTR) flags, THREAD_medium, 0, 0) == 0)
{
++m_cntAll;
}
}
}
void Worker::shutdown()
{
Firebird::MutexLockGuard guard(m_mutex);
if (shutting_down)
{
return;
}
shutting_down = true;
2008-12-02 08:09:49 +01:00
while (getCount())
{
wakeUpAll();
m_mutex->leave(); // we need CheckoutGuard here
try
{
THREAD_SLEEP(100);
}
2008-10-09 02:59:56 +02:00
catch (const Firebird::Exception&)
{
m_mutex->enter();
throw;
}
m_mutex->enter();
}
}
static int shut_server(const int, const int, void*)
{
server_shutdown = true;
return 0;
}