📄 cngpstructs.pas
字号:
unit CNGPStructs;
interface
uses
Windows, WinSock, General;
type
(******** CNGP message structures ********)
CNGPTLV = packed record
ParameterTag: Word;
Length: Word;
Value: Byte;
end;
(*
Message header: 16Bytes
Message body(required): variable length
Message body(optional): TLV -- Tag-Length-Value
*)
PHeader = ^CNGPHeader;
CNGPHeader = packed record
Total_Length: DWord; //Total length of message, including message header.
Command_Id: DWord; //Command identifier
Command_Status: DWord; //Command status
Sequence_Id: DWord; //Sequence NO., increased by 1
end;
(*
CNGP message format:
CNGPMessage = (packed) record
Header: CNGPHeader;
Body: CNGPBodyRequired;
TLV: CNGPBodyOptional;
end;
*)
PLogin = ^CNGPLogin;
CNGPLogin = packed record
Header: CNGPHeader;
ClientId: array[0..9] of Char; //SP identifier
AuthenticatorClient: array[0..15] of Byte; //MD5(ClinetID + #0 * 7 + ShareKey + Timestamp)
LoginMode: Byte; //0: Send, 1: Receive, 2: Send and receive, other: Reserved
TimeStamp: DWord; //mmddhhnnss, 10 decimal digits, right alignment
Version: Byte; //Client version, higher 4 bits: Major, lower 4 bits: Minor
end;
PLoginResp = ^CNGPLoginResp;
CNGPLoginResp = packed record
Header: CNGPHeader;
AuthenticatorServer: array[0..15] of Byte; //MD5(Status + AuthenticatorClient + ShareKey)
Version: Byte; //Server version
end;
//ShareKey, also named SharedSecret, 15 bytes max
PSubmit = ^CNGPSubmit;
CNGPSubmit = packed record
Header: CNGPHeader;
spid: array[0..9] of Char; //Same as the ClientId field of CNGPLogin structure
SubType: Byte; //0: Cancel, 1: Subs/order, 2: Order resp, 3: Subs MT
NeedReport: Byte; //0: No report, 1: Need report
Priority: Byte; //0..3
ServiceId: array[0..9] of Char;
FeeType: array[0..1] of Char;
//00: Free, 01: By msg, 02: Monthly, 03: Monthly max, 04: Charge req, 05: CR Charge
FeeUserType: Char; //Charge from: 0: DestTerm, 1: SrcTerm, 2: SP, 3: ChargeNo
FeeCode: array[0..5] of Char; //Fee (cent) per message
MsgFormat: Byte;
ValidTime: array[0..16] of Char;
AtTime: array[0..16] of Char;
SrcTermId: array[0..20] of Char;
ChargeTermId: array[0..20] of Char;
DestTermIdCount: Byte;
DestTermId: array[0..99] of array[0..20] of Char;
MsgLength: Byte;
msgContent: array[0..255] of Char;
ProtocolId: CNGPTLV;
end;
PSubmitResp = ^CNGPSubmitResp;
CNGPSubmitResp = packed record
Header: CNGPHeader;
MsgId: array[0..9] of Char;
CongestionState: CNGPTLV;
end;
PDeliver = ^CNGPDeliver;
CNGPDeliver = packed record
Header: CNGPHeader;
MsgId: array[0..9] of Char;
IsReport: Byte; //0: No, 1: Yes
MsgFormat: Byte;
RecvTime: array[0..13] of Char; //yyyymmddhhnnss
SrcTermId: array[0..20] of Char;
DestTermId: array[0..20] of Char;
MsgLength: Byte;
msgContent: array[0..255] of Char;
ProtocolId: CNGPTLV;
end;
PDeliverResp = ^CNGPDeliverResp;
CNGPDeliverResp = packed record
Header: CNGPHeader;
MsgId: array[0..9] of Char;
CongestionState: CNGPTLV;
end;
PActiveTest = ^CNGPActiveTest;
CNGPActiveTest = CNGPHeader;
PActiveTestResp = ^CNGPActiveTestResp;
CNGPActiveTestResp = CNGPHeader;
PExit = ^CNGPExit;
CNGPExit = CNGPHeader;
PExitResp = ^CNGPExitResp;
CNGPExitResp = CNGPHeader;
(*
CNGP report is the content of deliver package when the IsReport field value is 1
CNGPReport = (packed) record
id: char[10];
sub: char[3] = '001';
dlvrd: char[3] = '001';
submit_date: char[10];
done_date: char[10];
stat: char[7];
err: char[3];
txt: CNGPReportText;
end;
CNGPReportText = (packed) record
len: char[3];
content: char[17];
end;
*)
PReport = ^CNGPReport;
CNGPReport = packed record
id: array[0..9] of Char;
sub: array[0..2] of Char;
dlvrd: array[0..2] of Char;
submit_date: array[0..9] of Char;
done_date: array[0..9] of Char;
stat: array[0..6] of Char;
err: array[0..2] of Char;
txt: array[0..19] of Char;
end;
// 给定信息,构造CNGP消息头
procedure BuildHeader(var Header: CNGPHeader; totalLength, commandId, commandStatus: DWord);
// 把给定的Deliver消息中的msgContent解析成Report结构
procedure ParseReport(deliver: CNGPDeliver; var rpt: CNGPReport);
implementation
uses SysUtils;
var
publicSeqId: DWord = 0;
lock: TRTLCriticalSection;
procedure LockSeqId;
begin
EnterCriticalSection(lock);
end;
procedure UnlockSeqId;
begin
LeaveCriticalSection(lock);
end;
procedure BuildHeader(var Header: CNGPHeader; totalLength, commandId, commandStatus: DWord);
begin
// 现在,消息头中的序号,由数据库生成
//LockSeqId;
//Header.Sequence_Id := htonl(publicSeqId);
Header.Total_Length := htonl(totalLength);
Header.Command_Id := htonl(commandId);
Header.Command_Status := htonl(commandStatus);
{ if publicSeqId >= 4294967295 then
publicSeqId := 0
else
Inc(publicSeqId);
}
//UnlockSeqId;
end;
procedure ParseReport(deliver: CNGPDeliver; var rpt: CNGPReport);
var
i: integer;
begin
// 逐个解析出Report中的元素
i := ArrPos('id:', deliver.msgContent);
if i >= 0 then
CopyMemory(@rpt.id[0], @deliver.msgContent[i + 3], 10);
i := ArrPos('sub:', deliver.msgContent);
if i >= 0 then
CopyMemory(@rpt.sub[0], @deliver.msgContent[i + 4], 3);
i := ArrPos('dlvrd:', deliver.msgContent);
if i >= 0 then
CopyMemory(@rpt.dlvrd[0], @deliver.msgContent[i + 6], 3);
i := ArrPos('submit_date:', deliver.msgContent);
if i >= 0 then
CopyMemory(@rpt.submit_date[0], @deliver.msgContent[i + 12], 10);
i := ArrPos('done_date:', deliver.msgContent);
if i >= 0 then
CopyMemory(@rpt.done_date[0], @deliver.msgContent[i + 10], 10);
i := ArrPos('stat:', deliver.msgContent);
if i >= 0 then
CopyMemory(@rpt.stat[0], @deliver.msgContent[i + 5], 7);
i := ArrPos('err:', deliver.msgContent);
if i >= 0 then
CopyMemory(@rpt.err[0], @deliver.msgContent[i + 4], 3);
i := ArrPos('txt:', deliver.msgContent);
if i >= 0 then
CopyMemory(@rpt.txt[0], @deliver.msgContent[i + 4], 20);
end;
//
initialization
InitializeCriticalSection(lock);
finalization
DeleteCriticalSection(lock);
end.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -