📄 saf.cpp
字号:
//
// IT24 Sistemas S.A.
// SAF Library Manager
//
// Libreria de Manejo de SAF (StoreAndForward), que es una cola en disco de
// acumulacion de transacciones entrantes que no pueden rutearse momentaneamente,
// y son grabadas para su posterior reintento de envio.
// Posee por seguridad un limite logico de cantidad de registros maximos.
// Las funciones de I/O son estandard de bajo nivel ANSI C y ANSI UNIX.
//
// Tarea Fecha Autor Observaciones
// (Inicial) 1997.09.10 mdc Base
// (Inicial) 1997.09.11 mdc _WIN32: WORD cambiados a UINT
// (Inicial) 1997.09.23 mdc lcCurrPos (Cursor de I/O)
// (Inicial) 1997.10.17 mdc Primer Registro STORED
// (Alfa) 1997.10.21 mdc Precondiciones extendidas
// (Alfa) 1998.12.02 mdc iMode para _sopen
// (Alfa) 2002.07.25 mdc Adaptacion a mensajes ISO8583 por LNET+ATM
// (Alfa) 2002.08.20 mdc Remove() agregado. UseRandomNumber() tambien.
// (Beta) 2003.07.04 mdc Cambio de libreria estandar IO.H por STDIO.H
//
// Header propio/local
#include <qusrinc/saf.h>
#include <qusrinc/typedefs.h>
// Headers globales
#include <memory.h>
#include <string.h>
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <limits.h>
#ifdef _WIN32
#include <io.h>
#endif // _WIN32
#define RET_INVAL (-1)
#ifndef _POSIX_
#define _fsopen fopen
#endif /* POSIX */
// Constructor
EXPORT StoreAndForward::StoreAndForward(LPSTR szXFileName, BOOL bUseRandomNumber)
{
/////////////////////////////////////////////////////////////////
tSAFInit = time(NULL); // TimeStamp del inicio de SAF
tLastSAFCheck = 0L; // TimeStamp del ultimo chequeo SAF
/////////////////////////////////////////////////////////////////
// Nro. pseudo-aleatorio por instancia de clase.
// El nro 971 es primo de forma de obtener una distribucion buena,
// en un rango desde 0 a 999.
// Iniciar criba de numeros pseudo-aleatorios
srand( time( NULL ) );
iRandomNum = rand() % 971 ;
bUseRandom = bUseRandomNumber; // Usar nombre random ?
/////////////////////////////////////////////////////////////////
// Asegurar handle de flujo de I/O en NULL
hfFile = NULL;
// Bytes de I/O
cbReadWrite = 0;
// Limite logico de registros por default
dwLimit = SAF_RECORDS_LIMIT;
// Cuenta de Registros
dwStdRecords = dwFwdRecords = 0L;
// Cursores de Primero y Ultimo STORED
dwFirstStdRecord = dwLastStdRecord = 0L;
// Tamano de archivo inicialmente
lFileSize = 0L;
// Apertura con nombre fijo , y Estadisticas
InitStatistics( szXFileName );
}
// Constructor
EXPORT StoreAndForward::StoreAndForward(LPSTR szXFileName)
{
/////////////////////////////////////////////////////////////////
tSAFInit = time(NULL); // TimeStamp del inicio de SAF
tLastSAFCheck = 0L; // TimeStamp del ultimo chequeo SAF
/////////////////////////////////////////////////////////////////
// Nro. pseudo-aleatorio por instancia de clase.
// El nro 971 es primo de forma de obtener una distribucion buena,
// en un rango desde 0 a 999.
// Iniciar criba de numeros pseudo-aleatorios
srand( time( NULL ) );
iRandomNum = rand() % 971 ;
bUseRandom = TRUE; // Usar nombre random ?
/////////////////////////////////////////////////////////////////
// Asegurar handle de flujo de I/O en NULL
hfFile = NULL;
// Bytes de I/O
cbReadWrite = 0;
// Limite logico de registros por default
dwLimit = SAF_RECORDS_LIMIT;
// Cuenta de Registros
dwStdRecords = dwFwdRecords = 0L;
// Cursores de Primero y Ultimo STORED
dwFirstStdRecord = dwLastStdRecord = 0L;
// Tamano de archivo inicialmente
lFileSize = 0L;
// Apertura y Estadisticas
if(szXFileName != NULL)
Open(szXFileName);
}
// Destructor
EXPORT StoreAndForward::~StoreAndForward(void)
{
int iRetval = 0;
// Precondicion : recuperar tamano de archivo
if(NULL != hfFile)
{
fseek( hfFile, 0L, SEEK_END );
lFileSize = ftell( hfFile );
fseek( hfFile, 0L, SEEK_SET );
}
// Cierre de archivo
Close();
// Si no tenia ningun registro, borrar el archivo
if( 0L == dwStdRecords && 0 <= dwFwdRecords && 0L <= lFileSize )
iRetval = remove( szFileName );
// Estadisticas a cero
dwLimit = dwStdRecords = dwFwdRecords = 0L;
dwFirstStdRecord = dwLastStdRecord = 0L;
iRandomNum = 0 ;
bUseRandom = FALSE; // Usar nombre random ?
}
// Apertura y Estadisticas
BOOL EXPORT StoreAndForward::Open(LPSTR szXFileName)
{
BOOL bRetVal = FALSE;
// Precondicion: Cerrado
Close();
// Cambiar nombre segun fecha de hoy
SetTodayFileName ( szXFileName, szFileName );
// Error al abrir en modo BINARIO compartido?
if((hfFile = _fsopen((LPSTR)szFileName, "br+" )) == NULL)
{
// Intentar crearlo para saber si no existe ya
if (!Create(szFileName))
return FALSE;
// Una vez creado, cerrarlo y reabrirlo
Close();
bRetVal = ((hfFile = _fsopen((LPSTR)szFileName, "br+" )) == NULL)
? FALSE
: InitStatistics(szFileName) ;
// Postcondicion : recuperar tamano de archivo
if(NULL != hfFile)
{
fseek( hfFile, 0L, SEEK_END );
lFileSize = ftell( hfFile );
fseek( hfFile, 0L, SEEK_SET );
}
// Postcondicion : TRUE/FALSE segun se haya podido abrir
return bRetVal;
}
else
{
// Postcondicion : recuperar tamano de archivo
if(NULL != hfFile)
{
fseek( hfFile, 0L, SEEK_END );
lFileSize = ftell( hfFile );
fseek( hfFile, 0L, SEEK_SET );
}
// Iniciar estadisticas
return InitStatistics(szFileName);
}
}
// Establecer FORWARDED ultimo registro STORED leido
BOOL EXPORT StoreAndForward::SetForwarded(void)
{
// Posicion del Cursor de I/O sobre el archivo SAF
long lcCurrPos = 0L;
// Precondicion: handle valido
if(NULL == hfFile)
return FALSE;
/////////////////////////////////////////////
// Grabar fecha-hora de este chequeo
tLastSAFCheck = time( NULL );
/////////////////////////////////////////////
// Cursor磗 Current Position
lcCurrPos = ftell(hfFile);
// Se asume que el ultimo registro leido es el que se
// quiere marcar como FORWARDED.
// Asegurar posicion multiplo de registro
if( (lcCurrPos % sizeof(safRecord)) != 0)
return FALSE;
// Es STORED?
if(safRecord.wState == SAF_RECSTATE_STORED)
{
// Retroceder 1 registro (hasta el inicio del actual)
// antes de regrabar
if( fseek(hfFile, lcCurrPos - sizeof(safRecord), SEEK_SET)
== RET_INVAL )
return FALSE;
// Forwarded
safRecord.wState = SAF_RECSTATE_FORWARDED;
// Hora (TIME_T Standard ANSI Unix)
safRecord.tFwdTime = time(NULL);
// Escritura en si misma, en la posicion del registro actual
cbReadWrite = (SHORT)fwrite( (LPBYTE)&safRecord, 1,
sizeof(safRecord), hfFile);
// Asegurar que se baje el buffer del Sistema Operativo a disco
fflush(hfFile);
// Error?
if((cbReadWrite == RET_INVAL) || (cbReadWrite == 0))
return FALSE;
// Un Forwarded mas...
if(dwFwdRecords < ULONG_MAX) dwFwdRecords++;
else return FALSE;
// Un Stored menos...
if(dwStdRecords > 0L) dwStdRecords--;
// Era primer registro STORED? Avanzar a siguiente registro...
// ...que aunque no sea STORED, ya reasigna el cursor inicial a los mismos.
if(dwFirstStdRecord == (DWORD)safRecord.dwRecord)
dwFirstStdRecord++;
// Reposicionar el Cursor de I/O como el original
if( fseek(hfFile, lcCurrPos, SEEK_SET) == RET_INVAL )
return FALSE;
return TRUE;
}
else
return FALSE;
}
// Establecer CANCELLED ultimo registro STORED leido
BOOL EXPORT StoreAndForward::SetCancelled(void)
{
// Precondicion: handle valido
if(NULL == hfFile)
return FALSE;
// Posicion del Cursor de I/O sobre el archivo SAF:
// Se asume que el ultimo registro leido es el que se
// quiere marcar como CANCELLED.
// Cursor磗 Current Position
long lcCurrPos = ftell(hfFile);
// Asegurar posicion multiplo de registro
if( (lcCurrPos % sizeof(safRecord)) != 0)
return FALSE;
if(safRecord.wState == SAF_RECSTATE_STORED)
{
// Retroceder 1 registro (hasta el inicio del actual)
// antes de regrabar
if( fseek(hfFile, lcCurrPos - sizeof(safRecord), SEEK_SET)
== RET_INVAL )
return FALSE;
// Cancelled
safRecord.wState = SAF_RECSTATE_CANCELLED; // Estado CANCELLED
// Escritura en si misma, en la posicion actual
cbReadWrite = (SHORT)fwrite((LPBYTE)&safRecord, 1,
sizeof(safRecord), hfFile );
// Asegurar que se baje el buffer del Sistema Operativo a disco
fflush(hfFile);
// Error?
if((cbReadWrite == RET_INVAL) || (cbReadWrite == 0))
return FALSE;
// Un Stored menos...
if(dwStdRecords > 0L) dwStdRecords--;
// Reposicionar el Cursor de I/O como el original
if( fseek(hfFile, lcCurrPos, SEEK_SET) == RET_INVAL )
return FALSE;
return TRUE;
}
else
return FALSE;
}
// Lectura de siguiente registro STORED
BOOL EXPORT StoreAndForward::ReadStored(LPBYTE lpbBuffer,
size_t cbLen,
size_t *pcbCopy,
PDWORD pdwTraceNum,
PDWORD pdwRefNum)
{
// Precondicion
if(NULL == hfFile)
return FALSE;
// Lectura en si misma de 1 registro STORED
cbReadWrite = (SHORT)fread((LPBYTE)&safRecord, 1,
sizeof(safRecord), hfFile );
// Ciclo de lectura
while ((cbReadWrite != 0) && (cbReadWrite != RET_INVAL))
{
// Si es STORED...
if(safRecord.wState == SAF_RECSTATE_STORED)
{
// Copiar Buffer de Datos generico. Asegurar longitud de copia.
if((safRecord.cbBufferLen <= (short)cbLen) &&
(safRecord.cbBufferLen <= (short)sizeof(safRecord.bBuffer) ))
{
memcpy(lpbBuffer, (LPBYTE)safRecord.bBuffer,
safRecord.cbBufferLen);
if(pcbCopy)
(*pcbCopy) = safRecord.cbBufferLen ;
if(pdwTraceNum)
(*pdwTraceNum) = safRecord.dwTraceNum ;
if(pdwTraceNum)
(*pdwTraceNum) = safRecord.dwRefNum ;
return ((cbReadWrite != 0) && (cbReadWrite != RET_INVAL))
? TRUE
: FALSE;
}
else if((short)cbLen < safRecord.cbBufferLen)
{
memcpy(lpbBuffer, (LPBYTE)safRecord.bBuffer, cbLen);
if(pcbCopy)
(*pcbCopy) = safRecord.cbBufferLen ;
if(pdwTraceNum)
(*pdwTraceNum) = safRecord.dwTraceNum ;
if(pdwTraceNum)
(*pdwTraceNum) = safRecord.dwRefNum ;
return ((cbReadWrite != 0) && (cbReadWrite != RET_INVAL))
? TRUE
: FALSE;
}
else
return FALSE;
};
// Siguiente registro
cbReadWrite = (SHORT)fread((LPBYTE)&safRecord, 1,
sizeof(safRecord), hfFile);
}
return FALSE;
}
// Escritura de registro STORED
BOOL EXPORT StoreAndForward::WriteStored(LPBYTE lpbBuffer,
SHORT cbLen,
DWORD dwTraceNum,
DWORD dwRefNum)
{
// Precondiciones
if(NULL == hfFile)
return FALSE;
if(dwStdRecords > dwLimit)
return FALSE;
// Armado de Registro SAF
safRecord.chEyeCatcher = '>'; // Marca visual, nada mas
safRecord.dwRecord = dwStdRecords + 1L; // Registro Ordinal Autonumerado
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -