[go: up one dir, main page]

Menu

[r999]: / trunk / VTS3 / VTSDB.cpp  Maximize  Restore  History

Download this file

812 lines (646 with data), 18.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
// VTSDB.cpp: implementation of the VTSDB class.
//
//////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "VTS.h"
//MAD_DB #include "JConfig.hpp"
#include "VTSDB.h"
//MAD_DB #include "VTSValue.h"
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif
/* MAD_DB Moved to VTSPort
const char *gVTSPortTypes[6] =
{ "Null"
, "IP"
, "Ethernet"
, "ARCNET"
, "MS/TP"
, "PTP"
};
*/
//
// VTSPacketHeader::VTSPacketHeader
//
// The packet header contains information about the packet: where it
// came from, where it was going, how to interpret the contents, etc.
// It is stored in the packet list array in the database, while the
// packet contents (which vary in length) are stored in JDBOctetStr
// objects.
//
VTSPacketHeader::VTSPacketHeader( void )
//MAD_DB : packetPortID(0) // port identifier
: packetProtocolID(0) // protocol identifier for decoding
, packetFlags(0) // protocol specific flags
, packetType(txData) // not really transmit
, packetSource(nullAddr) // source address
, packetDestination(nullAddr) // destination address
//MAD_DB , packetDataID(0) // no assigned data (yet)
{
::GetSystemTimeAsFileTime( &packetTime ); // gets current time
memset(m_szPortName, 0, sizeof(m_szPortName));
}
//
// VTSPacket::VTSPacket
//
// If the packet is constructed with known data (the length is non-zero
// and the data is not null) then the packet just uses that information
// rather than make a copy of it. The idea is to keep the amount of
// buffer creation and memory copies to a minimum.
//
// In the ReadPacket function, the packet is created without data, then
// new data is provided once the information is available from the database.
// Because the database object is released, it is important to make a copy.
// The application may use the same packet object in multiple reads (like
// in a search loop).
//
VTSPacket::VTSPacket( int len, BACnetOctetPtr data )
: packetHdr() // empty header
, ownData(false) // packet does not own data
, packetLen(0) // number of octets in data
, packetData(0) // pointer to data
{
// make a reference to the data
if (len != 0) {
packetLen = len;
packetData = data;
}
}
//
// VTSPacket::~VTSPacket
//
// If the packet owns its data pointer, delete it.
//
VTSPacket::~VTSPacket( void )
{
// toss current data iff owned
if (ownData && packetData)
delete[] packetData;
}
//
// VTSPacket::NewData
//
// This function is called when the packet contents should reflect a new
// record from the database.
//
void VTSPacket::NewData( BACnetOctetPtr data, int len )
{
// toss current data iff owned
if (ownData && packetData)
delete[] packetData;
// take ownership of the pointer
ownData = true;
// make a copy of the data
packetLen = len;
packetData = new BACnetOctet[ len ];
memcpy( packetData, data, len );
}
/*
VTSPort * VTSPacket::GetPortLink(void)
{
VTSDoc * pdoc = (VTSDoc *) ((VTSApp *) AfxGetApp())->GetWorkspace();
if ( pdoc )
return pdoc->GetPorts()->Find(packetHdr.m_szPortName);
return NULL;
}
*/
//
// VTSPacket::NewDataRef
//
// This function is called when the packet contents should reflect new data
// and the application knows that the packet will be destroyed at the time
// the packet goes away (no dangling pointers).
//
void VTSPacket::NewDataRef( BACnetOctetPtr data, int len, bool fOwned /* = false */ )
{
// toss current data iff owned
if (ownData && packetData)
delete[] packetData;
// this is not owned data
ownData = fOwned; // MAD_DB
// refer to the new data
packetLen = len;
packetData = data;
}
void VTSPacket::operator =( const VTSPacket& pkt)
{
memcpy(&packetHdr, &pkt.packetHdr, sizeof(packetHdr));
NewData(pkt.packetData, pkt.packetLen);
}
//
// VTSDB::VTSDB
//
//VTSDB::VTSDB( void ) MAD_DB
VTSDB::VTSDB( LPCTSTR lpszFileName )
//MAD_DB : pObjMgr(0), pArrayMgr(0), pListMgr(0),
// : m_pfilePackets(NULL), m_strPacketFileName(lpszFileName)
{
m_pfilePackets = NULL;
m_strPacketFileName = lpszFileName;
}
//
// VTSDB::~VTSDB
//
VTSDB::~VTSDB( void )
{
// MAD_DB
if ( m_pfilePackets != NULL )
delete m_pfilePackets;
m_pfilePackets = NULL;
}
//
// VTSDB::Init
//
/*MAD_DB
void VTSDB::Init( void )
{
int stat
;
// let the database set itself up
JDB::Init();
// set the version
fileDesc->majorVersion = kVTSDBMajorVersion;
fileDesc->minorVersion = kVTSDBMinorVersion;
// build some managers for objects and arrays
pObjMgr = new JDBObjMgr( this );
pArrayMgr = new JDBArrayMgr( pObjMgr );
pListMgr = new JDBListMgr( pObjMgr );
// allocate a descriptor
dbDesc = (VTSDescObjPtr)AllocDesc( kVTSDescSig, kVTSDescObjSize );
// create the port list
if ((stat = pListMgr->NewList( dbPortList, kObjIdSize )) != 0) {
return;
}
// save the list ID in the descriptor
dbDesc->portListID = dbPortList.objID;
// create the name list
if ((stat = pListMgr->NewList( dbNameList, kVTSNameDescSize )) != 0) {
return;
}
// save the list ID in the descriptor
dbDesc->nameListID = dbNameList.objID;
// create the packet list
if ((stat = pArrayMgr->NewArray( dbPacketList, kVTSPacketHeaderSize, 4096 / kVTSPacketHeaderSize )) != 0) {
return;
}
// save the packet list ID in the descriptor
dbDesc->packetListID = dbPacketList.objID;
// create the device list
if ((stat = pListMgr->NewList( dbDeviceList, kObjIdSize )) != 0) {
return;
}
// save the list ID in the descriptor
dbDesc->deviceListID = dbDeviceList.objID;
// MAD_DB
// Don't care about results here until we remove the DB
Open(m_strPacketFileName);
}
//
// VTSDB::Open
//
void VTSDB::Open( void )
{
int stat
;
char errMsg[80]
;
// open the database
JDB::Open();
// make sure the versions are compatible
if ((fileDesc->majorVersion != kVTSDBMajorVersion) || (fileDesc->minorVersion > kVTSDBMinorVersion)) {
sprintf( errMsg, "Version %d.%d incompatible with this release (Version %d.%d expected)"
, fileDesc->majorVersion, fileDesc->minorVersion
, kVTSDBMajorVersion, kVTSDBMinorVersion
);
// it opened, so close it
CloseFile();
throw errMsg;
}
// build some managers for objects and arrays
pObjMgr = new JDBObjMgr( this );
pArrayMgr = new JDBArrayMgr( pObjMgr );
pListMgr = new JDBListMgr( pObjMgr );
// update if we need to
if (fileDesc->minorVersion < kVTSDBMinorVersion) {
// it probably grew bigger
ResizeDesc( kVTSDescSig, kVTSDescObjSize );
}
// get a pointer to our descriptor
dbDesc = (VTSDescObjPtr)GetDesc( kVTSDescSig );
// load the port list
if ((stat = pListMgr->GetList( dbPortList, dbDesc->portListID )) != 0)
return;
// load the name list
if ((stat = pListMgr->GetList( dbNameList, dbDesc->nameListID )) != 0)
return;
// load the packet array
if ((stat = pArrayMgr->GetArray( dbPacketList, dbDesc->packetListID )) != 0)
return;
if (fileDesc->minorVersion == 0) {
// create the device list
if ((stat = pListMgr->NewList( dbDeviceList, kObjIdSize )) != 0) {
return;
}
// save the list ID in the descriptor
dbDesc->deviceListID = dbDeviceList.objID;
} else {
// load the device list
if ((stat = pListMgr->GetList( dbDeviceList, dbDesc->deviceListID )) != 0)
return;
}
if (fileDesc->minorVersion < kVTSDBMinorVersion) {
objId devDescID
;
VTSDeviceDesc devDesc
;
// loop through the device list
for (int i = 0; i < dbDeviceList.Length(); i++) {
// get the port descriptor ID's
stat = dbDeviceList.ReadElem( i, &devDescID );
// read the current descriptor
stat = pObjMgr->ReadObject( devDescID, &devDesc );
// make sure there is an initialized object list
if (devDesc.objSize < kVTSDeviceDescSize) {
// create a new object and property list
JDBListPtr lp = new JDBList();
stat = pListMgr->NewList( *lp, kVTSObjPropValueSize );
devDesc.deviceObjPropValueListID = lp->objID;
delete lp;
// update the object size
devDesc.objSize = kVTSDeviceDescSize;
// save the updated descriptor
stat = pObjMgr->WriteObject( devDescID, &devDesc );
}
}
}
// updated to current version
fileDesc->minorVersion = kVTSDBMinorVersion;
// MAD_DB
// Don't care about results here until we remove the DB
Open(m_strPacketFileName);
}
*/
bool VTSDB::Open( LPCTSTR lpszFileName )
{
// Close the file if previously open... should not be
if ( m_pfilePackets != NULL )
delete m_pfilePackets;
m_pfilePackets = new CFile();
if ( m_pfilePackets == NULL )
return false;
CFileException e;
if ( !m_pfilePackets->Open( lpszFileName, CFile::modeCreate | CFile::modeNoTruncate | CFile::modeReadWrite | CFile::shareExclusive, &e ) )
{
TCHAR szCause[255];
CString strError;
e.GetErrorMessage(szCause, 255);
strError.Format(IDS_ERR_FILEPKTOPEN, lpszFileName);
strError += szCause;
AfxMessageBox(strError);
ClosePackets();
return false;
}
return true;
}
//
// VTSDB::Close
//
void VTSDB::Close( void )
{
/* MAD_DB
// all done with the managers
if (pObjMgr)
delete pObjMgr;
if (pArrayMgr)
delete pArrayMgr;
if (pListMgr)
delete pListMgr;
// pass it along
JDB::Close();
*/
// MAD_DB
ClosePackets();
}
void VTSDB::ClosePackets()
{
if ( m_pfilePackets != NULL )
{
if ( m_pfilePackets->m_hFile != (UINT)CFile::hFileNull )
{
try
{
m_pfilePackets->Flush();
m_pfilePackets->Close();
}
catch (CFileException e )
{}
}
delete m_pfilePackets;
m_pfilePackets = NULL;
}
}
//
// VTSDB::GetPacketCount
//
// This simple function returns the number of packets in the database. Unlike the
// ReadPacket and WritePacket functions, no changes are made, and the array object
// is really bound into the database. So just to make sure that things like the
// cache don't get modified by another thread, lock the writeLock.
//
/* MAD_DB
int VTSDB::GetPacketCount( void )
{
int count
;
CSingleLock lock( &writeLock )
;
lock.Lock();
count = dbPacketList.Count();
lock.Unlock();
return count;
}
*/
//
// VTSDB::DeletePackets
//
void VTSDB::DeletePackets( void )
{
/* MAD_DB
int stat, i
;
VTSDBTransaction trans( this ) // build a transaction wrapper
;
VTSPacketHeader hdr
;
// delete all of the packet data objects
for (i = 0; i < dbPacketList.Count(); i++) {
// read the header
if ((stat = dbPacketList.ReadElem( i, &hdr )) != 0)
throw stat;
// if there is a JDBOctetStringObj there, delete it
if (hdr.packetDataID != 0)
pObjMgr->DeleteObject( hdr.packetDataID );
}
// now delete the array
if ((stat = pArrayMgr->DeleteArray( dbPacketList.objID )) != 0) {
return;
}
// create a new packet list
if ((stat = pArrayMgr->NewArray( dbPacketList, kVTSPacketHeaderSize, 4096 / kVTSPacketHeaderSize )) != 0) {
return;
}
// save the packet list ID in the descriptor
dbDesc->packetListID = dbPacketList.objID;
// finished with update
trans.CompleteTransaction();
*/
// We're messing with file pointers so lock out other threads before this write
CSingleLock lock( &writeLock );
lock.Lock();
try
{
m_pfilePackets->SetLength(0);
m_pfilePackets->Flush();
m_pfilePackets->SeekToEnd();
}
catch (CFileException e)
{
}
lock.Unlock();
}
//
// VTSDB::ReadPacket
//
// Read a packet from the database. Because the cache may move around and change
// some pointers, lock it first. There is no reason to create a transaction because
// no modifications will be made.
//
/* MAD_DB
void VTSDB::ReadPacket( int indx, VTSPacket& pkt )
{
int stat
;
CSingleLock lock( &writeLock )
;
// make sure no other threads are mucking around
lock.Lock();
// read the packet header from the array
if ((stat = dbPacketList.ReadElem( indx, &pkt.packetHdr )) != 0)
throw stat;
// if there's data copy it from the octet string
if (pkt.packetHdr.packetDataID != 0) {
// load up the packet data
JDBOctetStringPtr osp = new JDBOctetString( pObjMgr, pkt.packetHdr.packetDataID )
;
// copy it to the pkt
pkt.NewData( osp->GetDataPtr(), osp->GetLength() );
// finished with object
delete osp;
} else
pkt.NewDataRef( 0, 0 );
// be nice and release it before returning
lock.Unlock();
}
*/
// returns -1 if file problem or no more records
ULONGLONG VTSDB::ReadNextPacket(VTSPacket& pkt, ULONGUONG lPosition )
{
ASSERT(m_pfilePackets != NULL && m_pfilePackets->m_hFile != CFile::hFileNull );
if ( m_pfilePackets == NULL || m_pfilePackets->m_hFile == CFile::hFileNull )
return -1;
CSingleLock lock( &writeLock );
// make sure no other threads are mucking around
lock.Lock();
// If caller specified a position to read from, go there first...
// otherwise, use the current position
try
{
// Get current position to restore if read problem
ULONGULONG nCurrentPosition = m_pfilePackets->Seek(0, CFile::current);
BACnetOctetPtr pbuffer = NULL;
ULONGULONG nNewPosition;
m_pfilePackets->Seek(lPosition, CFile::begin);
// Attempt to read the packet header... throw exception if header isn't there
if ( m_pfilePackets->Read(&pkt.packetHdr, sizeof(pkt.packetHdr)) != sizeof(pkt.packetHdr) )
AfxThrowFileException(CFileException::endOfFile);
// Attempt to read the size of the octets... throw exception if size isn't there
if ( m_pfilePackets->Read(&pkt.packetLen, sizeof(int)) != sizeof(int) )
AfxThrowFileException(CFileException::endOfFile);
// OK... See if there is any octet data. If not, buffer will already be NULL
// and length will be zero.
if ( pkt.packetLen != 0 )
{
// Yep. Allocate size for data and pull it from the file
pbuffer = new BACnetOctet[pkt.packetLen]; // ought to be enough
if ( pbuffer == NULL )
AfxThrowFileException(CFileException::none);
if ( m_pfilePackets->Read(pbuffer, pkt.packetLen) != (UINT) pkt.packetLen )
AfxThrowFileException(CFileException::endOfFile);
}
// pull off remaining number of bytes read
// Doesn't matter if blows here
int nBogus;
m_pfilePackets->Read(&nBogus, sizeof(int));
nNewPosition = m_pfilePackets->Seek(0, CFile::current);
// Point to new octet buffer and make the packet own the stuff so it kills it later
// Don't assign it until all file operations have completed (so we don't have to undo the assignment).
pkt.NewDataRef(pbuffer, pkt.packetLen, true);
}
catch(...)
{
// A problem ocurred while reading the file... Try to clean up
if ( pbuffer != NULL )
{
pkt.packetLen = 0;
delete pbuffer;
}
// reset file pointer and return read error or end of file (-1)
m_pfilePackets->Seek(nCurrentPosition, CFile::begin);
}
// be nice and release it before returning
lock.Unlock();
return nNewPosition;
}
//
// VTSDB::WritePacket
//
LONG VTSDB::WritePacket( VTSPacket& pkt )
{
//MAD_DB
/*
int stat, rnum
;
VTSDBTransaction trans( this ) // build a transaction wrapper
;
// is this updating an existing record?
if (indx >= 0) {
VTSPacketHeader oldHdr
;
// read the old header
if ((stat = dbPacketList.ReadElem( indx, &oldHdr )) != 0)
throw stat;
// if there is a JDBOctetStringObj there, delete it
if (oldHdr.packetDataID != 0)
pObjMgr->DeleteObject( oldHdr.packetDataID );
}
// create a new object with the packet contents
JDBOctetStringPtr osp = new JDBOctetString( pObjMgr, pkt.packetData, pkt.packetLen )
;
// save the object ID into the packet header
pkt.packetHdr.packetDataID = osp->objID;
// finished saving contents (already saved when it was created)
delete osp;
// madanner 3/03, attempt to catch write error and report... close transaction
try
{
// write back if this is an update, otherwise append
if (indx >= 0) {
if ((stat = dbPacketList.WriteElem( indx, &pkt.packetHdr )) != 0)
throw stat;
} else {
if ((stat = dbPacketList.NewElem( &rnum, &pkt.packetHdr )) != 0)
throw stat;
}
}
catch(...)
{
TRACE0("PROBLEM WRITING TO DB !!! ");
AfxMessageBox("An unexpected exception ocurred writing a packet to database. Please close the database to prevent corruption.");
}
// finished with update
trans.CompleteTransaction();
*/
// MAD_DB
if ( m_pfilePackets == NULL )
return 0;
// We're messing with file pointers so lock out other threads before this write
CSingleLock lock( &writeLock );
lock.Lock();
DWORD dwFileLength = m_pfilePackets->SeekToEnd();
try
{
m_pfilePackets->Write(&pkt.packetHdr, sizeof(pkt.packetHdr));
m_pfilePackets->Write(&pkt.packetLen, sizeof(int));
if ( pkt.packetLen != 0 )
m_pfilePackets->Write(pkt.packetData, pkt.packetLen);
// now write the total length of all this data so we can pull it out later
// This allows us to move backwards through the file one record at a time
int nTotal = sizeof(pkt.packetHdr) + sizeof(int) + pkt.packetLen;
m_pfilePackets->Write(&nTotal, sizeof(int));
}
catch (CFileException e)
{
// There was a problem writing one of these guys... rollback the file and return the error
m_pfilePackets->SetLength(dwFileLength);
m_pfilePackets->Flush();
// return an error
}
lock.Unlock();
return dwFileLength; // return file position where this record was written
}
/* MAD_DB
//
// VTSDBTransaction::VTSDBTransaction
//
// Bind to a database and start a transaction. The writeLock will be locked first,
// the the database will be told to start.
//
VTSDBTransaction::VTSDBTransaction( VTSDBPtr dbp )
: dbPtr(dbp), dbTransInProgress(false)
{
StartTransaction();
}
//
// VTSDBTransaction::~VTSDBTransaction
//
// When this object is destroyed, the transaction context is complete. If there
// was an exception thrown, the application might not have the chance to call
// CancelTransaction or CompleteTransaction. The safe thing to do is cancel it.
//
VTSDBTransaction::~VTSDBTransaction( void )
{
if (dbTransInProgress)
CancelTransaction();
}
//
// VTSDBTransaction::StartTransaction
//
void VTSDBTransaction::StartTransaction( void )
{
// lock the database
dbPtr->writeLock.Lock();
// start the transaction
dbPtr->StartTransaction();
dbTransInProgress = true;
}
//
// VTSDBTransaction::CompleteTransaction
//
// Let the datbase know that the transaction has completed successfully and then
// unlock it for other threads.
//
void VTSDBTransaction::CompleteTransaction( void )
{
// complete the transaction
dbPtr->CompleteTransaction();
dbTransInProgress = false;
// unlock for other updates
dbPtr->writeLock.Unlock();
}
//
// VTSDBTransaction::CancelTransaction
//
// Something bad happened and the transaction needs to be canceled. Make sure
// it is properly cleaned up before releasing the lock for other threads.
//
void VTSDBTransaction::CancelTransaction( void )
{
// cancel the transaction
dbPtr->CancelTransaction();
dbTransInProgress = false;
// unlock for other updates
dbPtr->writeLock.Unlock();
}
*/