-
-
Notifications
You must be signed in to change notification settings - Fork 268
Expand file tree
/
Copy pathremote.h
More file actions
1767 lines (1490 loc) · 50.8 KB
/
remote.h
File metadata and controls
1767 lines (1490 loc) · 50.8 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/*
* PROGRAM: JRD Remote Interface/Server
* MODULE: remote.h
* DESCRIPTION: Common descriptions
*
* The contents of this file are subject to the Interbase Public
* License Version 1.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy
* of the License at http://www.Inprise.com/IPL.html
*
* Software distributed under the License is distributed on an
* "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express
* or implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code was created by Inprise Corporation
* and its predecessors. Portions created by Inprise Corporation are
* Copyright (C) Inprise Corporation.
*
* All Rights Reserved.
* Contributor(s): ______________________________________.
*
* 2002.10.29 Sean Leyne - Removed obsolete "Netware" port
*
* 2002.10.30 Sean Leyne - Removed support for obsolete "PC_PLATFORM" define
*
*/
#ifndef REMOTE_REMOTE_H
#define REMOTE_REMOTE_H
#include "iberror.h"
#include "../remote/remote_def.h"
#include "../common/ThreadData.h"
#include "../common/ThreadStart.h"
#include "../common/Auth.h"
#include "../common/classes/objects_array.h"
#include "../common/classes/tree.h"
#include "../common/classes/fb_string.h"
#include "../common/classes/ClumpletWriter.h"
#include "../common/classes/RefMutex.h"
#include "../common/StatusHolder.h"
#include "../common/classes/RefCounted.h"
#include "../common/classes/GetPlugins.h"
#include "firebird/Interface.h"
#include <type_traits> // std::is_unsigned
#include <atomic>
#ifndef WIN_NT
#include <signal.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#ifndef INVALID_SOCKET
#define INVALID_SOCKET -1
#endif
#endif // !WIN_NT
#if defined(HAVE_ZLIB_H)
#define WIRE_COMPRESS_SUPPORT 1
//#define COMPRESS_DEBUG 1
#include "../common/classes/zip.h"
#endif
#define DEB_RBATCH(x) ((void) 0)
#define REM_SEND_OFFSET(bs) (0)
#define REM_RECV_OFFSET(bs) (bs)
// Uncomment this line if you need to trace module activity
//#define REMOTE_DEBUG
#ifdef REMOTE_DEBUG
DEFINE_TRACE_ROUTINE(remote_trace);
#define REMOTE_TRACE(args) remote_trace args
#else
#define REMOTE_TRACE(args) // nothing
#endif
#ifdef DEV_BUILD
// Debug packet/XDR memory allocation
// Temporarily disabling DEBUG_XDR_MEMORY
// #define DEBUG_XDR_MEMORY
#endif
constexpr int BLOB_LENGTH = 16384;
#include "../remote/protocol.h"
#include "fb_blk.h"
// Prefetch constants
constexpr ULONG MAX_PACKETS_PER_BATCH = 16;
constexpr ULONG MIN_ROWS_PER_BATCH = 10;
constexpr ULONG MAX_ROWS_PER_BATCH = 1000;
constexpr ULONG MAX_BATCH_CACHE_SIZE = 1024 * 1024; // 1 MB
constexpr ULONG DEFAULT_BLOBS_CACHE_SIZE = 10 * 1024 * 1024; // 10 MB
constexpr ULONG MAX_INLINE_BLOB_SIZE = MAX_USHORT;
constexpr ULONG DEFAULT_INLINE_BLOB_SIZE = MAX_USHORT;
// fwd. decl.
namespace Firebird {
class Exception;
class BatchCompletionState;
}
#ifdef WIN_NT
#include <WinSock2.h>
#else
typedef int SOCKET;
#endif
namespace os_utils
{
// force descriptor to have O_CLOEXEC set
SOCKET socket(int domain, int type, int protocol);
SOCKET accept(SOCKET sockfd, sockaddr *addr, socklen_t *addrlen);
}
struct rem_port;
typedef Firebird::AutoPtr<UCHAR, Firebird::ArrayDelete > UCharArrayAutoPtr;
typedef Firebird::RefPtr<Firebird::IAttachment> ServAttachment;
typedef Firebird::RefPtr<Firebird::IBlob> ServBlob;
typedef Firebird::RefPtr<Firebird::ITransaction> ServTransaction;
typedef Firebird::RefPtr<Firebird::IStatement> ServStatement;
typedef Firebird::RefPtr<Firebird::IResultSet> ServCursor;
typedef Firebird::RefPtr<Firebird::IBatch> ServBatch;
typedef Firebird::RefPtr<Firebird::IRequest> ServRequest;
typedef Firebird::RefPtr<Firebird::IEvents> ServEvents;
typedef Firebird::RefPtr<Firebird::IService> ServService;
// this set of parameters helps using same functions
// for both services and databases attachments
struct ParametersSet
{
UCHAR dummy_packet_interval, user_name, auth_block,
password, password_enc, trusted_auth,
plugin_name, plugin_list, specific_data,
address_path, process_id, process_name,
encrypt_key, client_version, remote_protocol,
host_name, os_user, config_text,
utf8_filename, map_attach;
};
extern const ParametersSet dpbParam, spbParam, connectParam;
struct Svc : public Firebird::GlobalStorage
{
ServService svc_iface; // service interface
Svc() :
svc_iface(NULL)
{ }
};
struct Rdb : public Firebird::GlobalStorage, public TypedHandle<rem_type_rdb>
{
ServAttachment rdb_iface; // attachment interface
rem_port* rdb_port; // communication port
Firebird::AutoPtr<Svc> rdb_svc; // service-specific block
struct Rtr* rdb_transactions; // linked list of transactions
struct Rrq* rdb_requests; // compiled requests
struct Rvnt* rdb_events; // known events
struct Rsr* rdb_sql_requests; // SQL requests
PACKET rdb_packet; // Communication structure
USHORT rdb_id;
private:
ThreadId rdb_async_thread_id; // Id of async thread (when active)
public:
std::atomic<int> rdb_async_lock; // Atomic to avoid >1 async calls at once
ULONG rdb_inline_blob_size; // default max size of blob that can be transferred inline
ULONG rdb_blob_cache_size; // limit on cached blobs size
ULONG rdb_cached_blobs_size; // actual size of cached blobs
ULONG rdb_cached_blobs_count; // actual count of cached blobs
public:
Rdb() :
rdb_iface(NULL), rdb_port(0),
rdb_transactions(0), rdb_requests(0), rdb_events(0), rdb_sql_requests(0),
rdb_id(0), rdb_async_thread_id(0), rdb_async_lock(0),
rdb_inline_blob_size(DEFAULT_INLINE_BLOB_SIZE), rdb_blob_cache_size(DEFAULT_BLOBS_CACHE_SIZE),
rdb_cached_blobs_size(0), rdb_cached_blobs_count(0)
{
}
static ISC_STATUS badHandle() { return isc_bad_db_handle; }
// Increment blob cache usage.
// Return false if blob cache have not enough space for a blob of given size.
bool incBlobCache(ULONG size)
{
if (rdb_cached_blobs_size + size > rdb_blob_cache_size)
return false;
rdb_cached_blobs_size += size;
rdb_cached_blobs_count++;
return true;
}
// Decrement blob cache usage.
void decBlobCache(ULONG size)
{
fb_assert(rdb_cached_blobs_size >= size);
fb_assert(rdb_cached_blobs_count > 0);
rdb_cached_blobs_size -= size;
rdb_cached_blobs_count--;
}
};
struct Rtr : public Firebird::GlobalStorage, public TypedHandle<rem_type_rtr>
{
using BlobsTree = Firebird::BePlusTree<struct Rbl*, SQUAD, struct Rbl>;
Rdb* rtr_rdb;
Rtr* rtr_next;
BlobsTree rtr_blobs;
ServTransaction rtr_iface;
USHORT rtr_id;
bool rtr_limbo;
Firebird::Array<Rsr*> rtr_cursors;
Rtr** rtr_self;
Rbl* rtr_inline_blob;
public:
Rtr() :
rtr_rdb(0), rtr_next(0), rtr_blobs(getPool()),
rtr_iface(NULL), rtr_id(0), rtr_limbo(0),
rtr_cursors(getPool()), rtr_self(NULL),
rtr_inline_blob(NULL)
{ }
~Rtr()
{
if (rtr_self && *rtr_self == this)
*rtr_self = NULL;
}
static ISC_STATUS badHandle() { return isc_bad_trans_handle; }
Rbl* createInlineBlob();
void setupInlineBlob(P_INLINE_BLOB* p_blob);
};
struct RBlobInfo
{
bool valid;
UCHAR blob_type;
ULONG num_segments;
ULONG max_segment;
FB_UINT64 total_length;
RBlobInfo()
{
memset(this, 0, sizeof(*this));
}
// parse into response into m_info, assume buffer contains all known info items
void parseInfo(unsigned int bufferLength, const unsigned char* buffer);
// returns false if there is no valid local info or if unknown item encountered
bool getLocalInfo(unsigned int itemsLength, const unsigned char* items,
unsigned int bufferLength, unsigned char* buffer);
};
// Used in XDR
class RemBlobBuffer : public Firebird::Array<UCHAR>
{
using Firebird::Array<UCHAR>::Array;
};
struct Rbl : public Firebird::GlobalStorage, public TypedHandle<rem_type_rbl>
{
RemBlobBuffer rbl_data;
Rdb* rbl_rdb;
Rtr* rbl_rtr;
UCHAR* rbl_buffer;
UCHAR* rbl_ptr;
ServBlob rbl_iface;
SQUAD rbl_blob_id;
SLONG rbl_offset; // Apparent (to user) offset in blob
USHORT rbl_id;
USHORT rbl_flags;
USHORT rbl_buffer_length;
USHORT rbl_length;
USHORT rbl_fragment_length;
USHORT rbl_source_interp; // source interp (for writing)
USHORT rbl_target_interp; // destination interp (for reading)
Rbl** rbl_self;
RBlobInfo rbl_info;
public:
// Values for rbl_flags
enum {
EOF_SET = 0x01,
SEGMENT = 0x02,
EOF_PENDING = 0x04,
CREATE = 0x08,
CACHED = 0x10
};
public:
Rbl(unsigned int initialSize) :
rbl_data(getPool()), rbl_rdb(0), rbl_rtr(0),
rbl_buffer(rbl_data.getBuffer(initialSize)), rbl_ptr(rbl_buffer), rbl_iface(NULL),
rbl_blob_id(NULL_BLOB), rbl_offset(0), rbl_id(0), rbl_flags(0),
rbl_buffer_length(initialSize), rbl_length(0), rbl_fragment_length(0),
rbl_source_interp(0), rbl_target_interp(0), rbl_self(NULL)
{ }
~Rbl()
{
if (rbl_self && *rbl_self == this)
*rbl_self = NULL;
if (rbl_iface)
rbl_iface->release();
}
static ISC_STATUS badHandle() { return isc_bad_segstr_handle; }
bool isCached() const { return rbl_flags & CACHED; }
unsigned getCachedSize() const { return sizeof(Rbl) + rbl_data.getCapacity(); }
static const SQUAD& generate(const void*, const Rbl* item) { return item->rbl_blob_id; }
};
struct Rvnt : public Firebird::GlobalStorage, public TypedHandle<rem_type_rev>
{
Rvnt* rvnt_next;
Rdb* rvnt_rdb;
Firebird::RefPtr<Firebird::IEventCallback> rvnt_callback;
ServEvents rvnt_iface;
rem_port* rvnt_port; // used to id server from whence async came
SLONG rvnt_id; // used to store client-side id
USHORT rvnt_length;
Rvnt** rvnt_self;
Firebird::AtomicCounter rvnt_destroyed;
public:
Rvnt() :
rvnt_next(NULL), rvnt_rdb(NULL), rvnt_callback(NULL), rvnt_iface(NULL),
rvnt_port(NULL), rvnt_id(0), rvnt_length(0), rvnt_self(NULL)
{ }
~Rvnt()
{
if (rvnt_self && *rvnt_self == this)
*rvnt_self = NULL;
}
};
struct rem_str : public pool_alloc_rpt<SCHAR>
{
USHORT str_length;
SCHAR str_data[2];
};
// Include definition of descriptor
#include "../common/dsc.h"
// Note, currently the only routine that created and changed rem_fmt is
// parse_format() in parse.cpp
struct rem_fmt : public Firebird::GlobalStorage
{
ULONG fmt_length;
ULONG fmt_net_length;
Firebird::Array<dsc> fmt_desc;
Firebird::HalfStaticArray<unsigned short, 4> fmt_blob_idx; // indices of blob's in fmt_desc
public:
explicit rem_fmt(FB_SIZE_T rpt) :
fmt_length(0), fmt_net_length(0),
fmt_desc(getPool(), rpt),
fmt_blob_idx(getPool())
{
fmt_desc.grow(rpt);
}
bool haveBlobs() const
{
return fmt_blob_idx.hasData();
}
};
// Windows declares a msg structure, so rename the structure
// to avoid overlap problems.
struct RMessage : public Firebird::GlobalStorage
{
RMessage* msg_next; // Next available message
USHORT msg_number; // Message number
UCHAR* msg_address; // Address of message
UCharArrayAutoPtr msg_buffer; // Allocated message
public:
explicit RMessage(size_t rpt) :
msg_next(0), msg_number(0), msg_address(0), msg_buffer(FB_NEW_POOL(getPool()) UCHAR[rpt])
{
memset(msg_buffer, 0, rpt);
}
};
// remote stored procedure request
struct Rpr : public Firebird::GlobalStorage
{
Rdb* rpr_rdb;
Rtr* rpr_rtr;
RMessage* rpr_in_msg; // input message
RMessage* rpr_out_msg; // output message
rem_fmt* rpr_in_format; // Format of input message
rem_fmt* rpr_out_format; // Format of output message
public:
Rpr() :
rpr_rdb(0), rpr_rtr(0),
rpr_in_msg(0), rpr_out_msg(0), rpr_in_format(0), rpr_out_format(0)
{ }
};
struct Rrq : public Firebird::GlobalStorage, public TypedHandle<rem_type_rrq>
{
Rdb* rrq_rdb;
Rtr* rrq_rtr;
Rrq* rrq_next;
Rrq* rrq_levels; // RRQ block for next level
ServRequest rrq_iface;
USHORT rrq_id;
USHORT rrq_max_msg;
USHORT rrq_level;
Firebird::StatusHolder rrqStatus;
struct rrq_repeat
{
rem_fmt* rrq_format; // format for this message
RMessage* rrq_message; // beginning or end of cache, depending on whether it is client or server
RMessage* rrq_xdr; // point at which cache is read or written by xdr
USHORT rrq_msgs_waiting; // count of full rrq_messages
USHORT rrq_rows_pending; // How many rows in waiting
USHORT rrq_reorder_level; // Reorder when rows_pending < this level
USHORT rrq_batch_count; // Count of batches in pipeline
};
Firebird::Array<rrq_repeat> rrq_rpt;
Rrq** rrq_self;
public:
explicit Rrq(FB_SIZE_T rpt) :
rrq_rdb(0), rrq_rtr(0), rrq_next(0), rrq_levels(0),
rrq_iface(NULL), rrq_id(0), rrq_max_msg(0), rrq_level(0),
rrq_rpt(getPool(), rpt), rrq_self(NULL)
{
//memset(rrq_status_vector, 0, sizeof rrq_status_vector);
rrq_rpt.grow(rpt);
}
~Rrq()
{
if (rrq_self && *rrq_self == this)
*rrq_self = NULL;
if (rrq_iface)
rrq_iface->release();
}
Rrq* clone() const
{
Rrq* rc = FB_NEW Rrq(rrq_rpt.getCount());
*rc = *this;
rc->rrq_self = NULL;
return rc;
}
static ISC_STATUS badHandle() { return isc_bad_req_handle; }
void saveStatus(const Firebird::Exception& ex) noexcept;
void saveStatus(Firebird::IStatus* ex) noexcept;
};
template <typename T>
class RFlags
{
public:
RFlags() :
m_flags(0)
{
// Require base flags field to be unsigned.
static_assert(std::is_unsigned<T>::value, "T must be unsigned");
}
explicit RFlags(const T flags) :
m_flags(flags)
{}
// At least one bit in the parameter is 1 in the object.
bool test(const T flags) const
{
return m_flags & flags;
}
// All bits received as parameter are 1 in the object.
bool testAll(const T flags) const
{
return (m_flags & flags) == flags;
}
void set(const T flags)
{
m_flags |= flags;
}
void clear(const T flags)
{
m_flags &= ~flags;
}
void reset()
{
m_flags = 0;
}
private:
T m_flags;
};
// remote SQL request
struct Rsr : public Firebird::GlobalStorage, public TypedHandle<rem_type_rsr>
{
Rsr* rsr_next;
Rdb* rsr_rdb;
Rtr* rsr_rtr;
ServStatement rsr_iface;
ServCursor rsr_cursor;
ServBatch rsr_batch;
rem_fmt* rsr_bind_format; // Format of bind message
rem_fmt* rsr_select_format; // Format of select message
rem_fmt* rsr_user_select_format; // Format of user's select message
rem_fmt* rsr_format; // Format of current message
RMessage* rsr_message; // Next message to process
RMessage* rsr_buffer; // Next buffer to use
Firebird::StatusHolder* rsr_status; // saved status for buffered errors
USHORT rsr_id;
RFlags<USHORT> rsr_flags;
ULONG rsr_fmt_length;
ULONG rsr_rows_pending; // How many rows are pending
USHORT rsr_msgs_waiting; // count of full rsr_messages
USHORT rsr_reorder_level; // Trigger pipelining at this level
USHORT rsr_batch_count; // Count of batches in pipeline
Firebird::string rsr_cursor_name; // Name for cursor to be set on open
bool rsr_delayed_format; // Out format was delayed on execute, set it on fetch
unsigned int rsr_timeout; // Statement timeout to be set on open\execute
Rsr** rsr_self;
ULONG rsr_batch_size; // Aligned message size for IBatch operations
ULONG rsr_batch_flags; // Flags for batch processing
union // BatchCS passed to XDR protocol
{
Firebird::IBatchCompletionState* rsr_batch_ics; // server
Firebird::BatchCompletionState* rsr_batch_cs; // client
};
P_FETCH rsr_fetch_operation; // Last performed fetch operation
SLONG rsr_fetch_position; // and position
unsigned int rsr_inline_blob_size; // max size of blob that can be transferred inline
struct BatchStream
{
BatchStream()
: curBpb(*getDefaultMemoryPool()), hdrPrevious(0), segmented(false)
{ }
static constexpr ULONG SIZEOF_BLOB_HEAD = sizeof(ISC_QUAD) + 2 * sizeof(ULONG);
typedef Firebird::HalfStaticArray<UCHAR, 64> Bpb;
Bpb curBpb;
UCHAR hdr[SIZEOF_BLOB_HEAD];
ULONG blobRemaining; // Remaining to transfer size of blob data
ULONG bpbRemaining; // Remaining to transfer size of BPB
ULONG segRemaining; // Remaining to transfer size of segment data
USHORT alignment; // Alignment in BLOB stream
USHORT hdrPrevious; // Header data left from previous block (in hdr)
bool segmented; // Current blob kind
void saveData(const UCHAR* data, ULONG size)
{
fb_assert(size + hdrPrevious <= SIZEOF_BLOB_HEAD);
memcpy(&hdr[hdrPrevious], data, size);
hdrPrevious += size;
}
};
BatchStream rsr_batch_stream;
public:
// Values for rsr_flags.
enum : USHORT {
FETCHED = 1, // Cleared by execute, set by fetch
EOF_SET = 2, // End-of-stream encountered
NO_BATCH = 4, // Do not batch fetch rows
STREAM_ERR = 8, // There is an error pending in the batched rows
LAZY = 16, // To be allocated at the first reference
DEFER_EXECUTE = 32, // op_execute can be deferred
PAST_EOF = 64, // EOF was returned by fetch from this statement
BOF_SET = 128, // Beginning-of-stream
PAST_BOF = 256 // BOF was returned by fetch from this statement
};
static constexpr auto STREAM_END = (BOF_SET | EOF_SET);
static constexpr auto PAST_END = (PAST_BOF | PAST_EOF);
public:
Rsr() :
rsr_next(0), rsr_rdb(0), rsr_rtr(0), rsr_iface(NULL), rsr_cursor(NULL), rsr_batch(NULL),
rsr_bind_format(0), rsr_select_format(0), rsr_user_select_format(0),
rsr_format(0), rsr_message(0), rsr_buffer(0), rsr_status(0),
rsr_id(0), rsr_fmt_length(0),
rsr_rows_pending(0), rsr_msgs_waiting(0), rsr_reorder_level(0), rsr_batch_count(0),
rsr_cursor_name(getPool()), rsr_delayed_format(false), rsr_timeout(0), rsr_self(NULL),
rsr_batch_size(0), rsr_batch_flags(0), rsr_batch_ics(NULL),
rsr_fetch_operation(fetch_next), rsr_fetch_position(0), rsr_inline_blob_size(0)
{ }
~Rsr()
{
if (rsr_self && *rsr_self == this)
*rsr_self = NULL;
if (rsr_cursor)
rsr_cursor->release();
if (rsr_batch)
rsr_batch->release();
if (rsr_iface)
rsr_iface->release();
delete rsr_status;
}
void saveException(Firebird::IStatus* status, bool overwrite);
void saveException(const Firebird::Exception& ex, bool overwrite);
void clearException();
ISC_STATUS haveException();
void raiseException();
void releaseException();
static ISC_STATUS badHandle() { return isc_bad_req_handle; }
void checkIface(ISC_STATUS code = isc_unprepared_stmt);
void checkCursor();
void checkBatch();
// return true if select format have blobs
bool haveBlobs() const
{
return rsr_select_format && rsr_select_format->haveBlobs();
}
SLONG getCursorAdjustment() const
{
if (rsr_fetch_operation != fetch_next && rsr_fetch_operation != fetch_prior)
return 0;
const bool isEnd = rsr_flags.test(Rsr::STREAM_END) && !rsr_flags.test(Rsr::PAST_END);
const SLONG offset = rsr_msgs_waiting + (isEnd ? 1 : 0);
const bool isAhead = (rsr_fetch_operation == fetch_next);
return isAhead ? -offset : offset;
}
};
// Makes it possible to safely store all handles in single array
class RemoteObject
{
private:
union {
Rdb* rdb;
Rtr* rtr;
Rbl* rbl;
Rrq* rrq;
Rsr* rsr;
} ptr;
public:
RemoteObject() { ptr.rdb = 0; }
template <typename R>
R* get(R* r)
{
if (!r || !r->checkHandle())
{
Firebird::status_exception::raise(Firebird::Arg::Gds(R::badHandle()));
}
return r;
}
void operator=(Rdb* v) { ptr.rdb = v; }
void operator=(Rtr* v) { ptr.rtr = v; }
void operator=(Rbl* v) { ptr.rbl = v; }
void operator=(Rrq* v) { ptr.rrq = v; }
void operator=(Rsr* v) { ptr.rsr = v; }
operator Rdb*() { return get(ptr.rdb); }
operator Rtr*() { return get(ptr.rtr); }
operator Rbl*() { return get(ptr.rbl); }
operator Rrq*() { return get(ptr.rrq); }
operator Rsr*() { return get(ptr.rsr); }
bool isMissing() const { return ptr.rdb == NULL; }
void release() { ptr.rdb = 0; }
};
inline void Rsr::saveException(Firebird::IStatus* status, bool overwrite)
{
if (!rsr_status) {
rsr_status = FB_NEW Firebird::StatusHolder();
}
if (overwrite || !rsr_status->getError()) {
rsr_status->save(status);
}
}
inline void Rsr::clearException()
{
if (rsr_status)
rsr_status->clear();
}
inline ISC_STATUS Rsr::haveException()
{
return (rsr_status ? rsr_status->getError() : 0);
}
inline void Rsr::raiseException()
{
if (rsr_status)
rsr_status->raise();
}
inline void Rsr::releaseException()
{
delete rsr_status;
rsr_status = NULL;
}
#include "../remote/remot_proto.h"
// Generalized port definition.
//////////////////////////////////////////////////////////////////
// fwd. decl.
struct p_cnct;
struct rmtque;
struct xcc; // defined in xnet.h
// Queue of deferred packets
struct rem_que_packet
{
PACKET packet;
bool sent;
};
typedef Firebird::Array<rem_que_packet> PacketQueue;
class ServerAuthBase
{
public:
static constexpr unsigned AUTH_CONTINUE = 0x01;
static constexpr unsigned AUTH_COND_ACCEPT = 0x02;
virtual ~ServerAuthBase();
virtual bool authenticate(PACKET* send, unsigned flags = 0) = 0;
};
class ServerCallbackBase
{
public:
virtual ~ServerCallbackBase();
virtual void wakeup(unsigned int length, const void* data) = 0;
virtual Firebird::ICryptKeyCallback* getInterface() = 0;
virtual void stop() = 0;
virtual void destroy() = 0;
};
// CryptKey implementation
class InternalCryptKey final :
public Firebird::VersionedIface<Firebird::ICryptKeyImpl<InternalCryptKey, Firebird::CheckStatusWrapper> >,
public Firebird::GlobalStorage
{
public:
InternalCryptKey()
: keyName(getPool())
{ }
// ICryptKey implementation
void setSymmetric(Firebird::CheckStatusWrapper* status, const char* type, unsigned keyLength, const void* key);
void setAsymmetric(Firebird::CheckStatusWrapper* status, const char* type, unsigned encryptKeyLength,
const void* encryptKey, unsigned decryptKeyLength, const void* decryptKey);
const void* getEncryptKey(unsigned* length);
const void* getDecryptKey(unsigned* length);
class Key : public Firebird::UCharBuffer
{
public:
Key()
: Firebird::UCharBuffer(getPool())
{ }
void set(unsigned keyLength, const void* key)
{
assign(static_cast<const UCHAR*>(key), keyLength);
}
const void* get(unsigned* length) const
{
if (getCount() > 0)
{
if (length)
*length = getCount();
return begin();
}
return NULL;
}
};
Key encrypt, decrypt;
Firebird::PathName keyName;
};
// Type of known by server key, received from it by client
class KnownServerKey : public Firebird::AutoStorage
{
public:
Firebird::PathName type, plugins;
typedef Firebird::Pair<Firebird::Full<Firebird::PathName, Firebird::UCharBuffer> > PluginSpecific;
Firebird::ObjectsArray<PluginSpecific> specificData;
KnownServerKey()
: Firebird::AutoStorage(), type(getPool()), plugins(getPool()), specificData(getPool())
{ }
explicit KnownServerKey(Firebird::MemoryPool& p)
: Firebird::AutoStorage(p), type(getPool()), plugins(getPool()), specificData(getPool())
{ }
KnownServerKey(Firebird::MemoryPool& p, const KnownServerKey& v)
: Firebird::AutoStorage(p), type(getPool(), v.type), plugins(getPool(), v.plugins),
specificData(getPool(), v.specificData)
{ }
void addSpecificData(const Firebird::PathName& plugin, unsigned len, const void* data)
{
PluginSpecific& p = specificData.add();
p.first = plugin;
memcpy(p.second.getBuffer(len), data, len);
}
const Firebird::UCharBuffer* findSpecificData(const Firebird::PathName& plugin) const
{
for (unsigned i = 0; i < specificData.getCount(); ++i)
{
//KnownServerKey::PluginSpecific& p = specificData[i];
auto& p = specificData[i];
if (p.first == plugin)
return &p.second;
}
return nullptr;
}
private:
KnownServerKey(const KnownServerKey&);
KnownServerKey& operator=(const KnownServerKey&);
};
// Tags for clumplets, passed from server to client
constexpr UCHAR TAG_KEY_TYPE = 0;
constexpr UCHAR TAG_KEY_PLUGINS = 1;
constexpr UCHAR TAG_KNOWN_PLUGINS = 2;
constexpr UCHAR TAG_PLUGIN_SPECIFIC = 3;
typedef Firebird::GetPlugins<Firebird::IClient> AuthClientPlugins;
// Representation of authentication data, visible for plugin
// Transferred in format, depending upon type of the packet (phase of handshake)
class RmtAuthBlock final :
public Firebird::VersionedIface<Firebird::IAuthBlockImpl<RmtAuthBlock, Firebird::CheckStatusWrapper> >
{
public:
RmtAuthBlock(const Firebird::AuthReader::AuthBlock& aBlock);
// Firebird::IAuthBlock implementation
const char* getType();
const char* getName();
const char* getPlugin();
const char* getSecurityDb();
const char* getOriginalPlugin();
FB_BOOLEAN next(Firebird::CheckStatusWrapper* status);
FB_BOOLEAN first(Firebird::CheckStatusWrapper* status);
private:
Firebird::AuthReader::AuthBlock buffer;
Firebird::AuthReader rdr;
Firebird::AuthReader::Info info;
FB_BOOLEAN loadInfo();
};
class ClntAuthBlock final :
public Firebird::RefCntIface<Firebird::IClientBlockImpl<ClntAuthBlock, Firebird::CheckStatusWrapper> >
{
private:
Firebird::PathName pluginList; // To be passed to server
Firebird::PathName serverPluginList; // Received from server
Firebird::string cliUserName, cliPassword; // Used by plugin, taken from DPB
Firebird::string cliOrigUserName; // Original user name, passed to server
// These two are legacy encrypted password, trusted auth data and so on - what plugin needs
Firebird::UCharBuffer dataForPlugin, dataFromPlugin;
Firebird::HalfStaticArray<InternalCryptKey*, 1> cryptKeys; // Wire crypt keys that came from plugin(s) last time
Firebird::string dpbConfig; // User's configuration parameters
Firebird::PathName dpbPlugins; // User's plugin list
Firebird::RefPtr<const Firebird::Config> clntConfig; // Used to get plugins list and pass to port
Firebird::AutoPtr<RmtAuthBlock> remAuthBlock; //Authentication block if present
unsigned nextKey; // First key to be analyzed
class ClientCrypt final :
public Firebird::VersionedIface<Firebird::ICryptKeyCallbackImpl<ClientCrypt, Firebird::CheckStatusWrapper> >,
public Firebird::GlobalStorage
{
public:
ClientCrypt()
: pluginItr(Firebird::IPluginManager::TYPE_KEY_HOLDER, "NoDefault"),
currentIface(nullptr), afterIface(nullptr),
triedPlugins(getPool())
{ }
~ClientCrypt()
{
dispose();
}
Firebird::ICryptKeyCallback* create(const Firebird::Config* conf);
// Firebird::ICryptKeyCallback implementation
unsigned callback(unsigned dataLength, const void* data, unsigned bufferLength, void* buffer) override;
unsigned afterAttach(Firebird::CheckStatusWrapper* st, const char* dbName, const Firebird::IStatus* attStatus) override;
void dispose() override;
int getHashLength(Firebird::CheckStatusWrapper* status) override;
void getHashData(Firebird::CheckStatusWrapper* status, void* hash) override;
private:
typedef Firebird::GetPlugins<Firebird::IKeyHolderPlugin> KeyHolderItr;
KeyHolderItr pluginItr;
Firebird::ICryptKeyCallback* currentIface;
Firebird::ICryptKeyCallback* afterIface;
class TriedPlugins
{
typedef Firebird::Pair<Firebird::Left<Firebird::PathName, Firebird::IKeyHolderPlugin*> > TriedPlugin;
Firebird::ObjectsArray<TriedPlugin> data;
public:
TriedPlugins(MemoryPool& p)
: data(p)
{ }
void add(KeyHolderItr& itr)
{
for (auto& p : data)
{
if (p.first == itr.name())
return;
}