Новичок
Регистрация: 31.03.2010
Сообщений: 22
Сказал(а) спасибо: 2
Поблагодарили 23 раз(а) в 8 сообщениях
|
сама сборка пакетов (для пикапа тоже пригодится)
Код:
constructor TTcpBuffer.Create;
begin
FCS:=TCriticalSection.Create;
setlength(FSeqArr, SIZE64);
FSeqCount:=0;
FCurrSeq:=0;
//FNextSeq:=0;
FDupCount:=0;
FOorCount:=0;
end;
destructor TTcpBuffer.Destroy;
var
i: integer;
begin
FCS.Enter;
// |--[ack|array] count,first
// | |--[seq|wsabuf]
// | |--[seq|wsabuf]
// | |--[seq|wsabuf]
for i:=0 to FSeqCount - 1 do
FreeMem(FSeqArr[i].wsa_buf.buf);
FSeqArr:=nil;
FCS.Leave;
FCS.Free;
inherited;
end;
procedure TTcpBuffer.ASwap(Lo, Hi: integer);
var
temp: TSeqRec;
begin
move(FSeqArr[Lo],temp,sizeof(TSeqRec));
move(FSeqArr[Hi],FSeqArr[Lo],sizeof(TSeqRec));
move(temp,FSeqArr[Hi],sizeof(TSeqRec));
end;
procedure TTcpBuffer.QuickSort(iLo, iHi: integer);
var
Lo, Hi: integer;
pivot: dword;
begin
Lo := iLo;
Hi := iHi;
pivot:=FSeqArr[(Lo + Hi) div 2].swappedSeq;
repeat
while FSeqArr[Lo].swappedSeq < pivot do Inc(Lo);
while FSeqArr[Hi].swappedSeq > pivot do Dec(Hi);
if Lo <= Hi then begin
if Lo <> Hi then ASwap(Lo,Hi);
Inc(Lo);
Dec(Hi);
end;
until Lo > Hi;
if Hi > iLo then QuickSort(iLo, Hi);
if Lo < iHi then QuickSort(Lo, iHi);
end;
{function TTcpBuffer.QuickFind(const looking_for: dword; iLo, iHi: integer):dword;
var
Mid: dword;
pivot: dword;
begin
if (iHi-iLo-1) > 0 then begin
Mid:=(iLo+iHi) div 2;
pivot:=FSeqArr[Mid].swappedSeq;
if pivot < looking_for then result:=QuickFind(looking_for,Mid,iHi)
else result:=QuickFind(looking_for,iLo,Mid);
end
else if looking_for > FSeqArr[iLo].swappedSeq then result:=iHi
else result:=iLo;
end;}
function TTcpBuffer.Match(Value: dword; ItemIndex: integer): integer;
begin
result:=0;
if Value < FSeqArr[ItemIndex].swappedSeq then result:=-1
else if Value > FSeqArr[ItemIndex].swappedSeq then result:=1;
end;
function TTcpBuffer.QuickSearch(Value: dword; Count: integer; MatchFunction: TMatchFunction): integer;
var
L, M, C: integer;
begin
if Count > 0 then
begin
L := 0;
Dec(Count);
while L <= Count do
begin
M := (L + Count) shr 1;
C := MatchFunction(Value, M);
if C > 0 then
L := M + 1
else if C <> 0 then
Count := M - 1
else
begin
Result := M;
Exit;
end;
end;
end;
Result := -1;
end;
{ Add any match cap sequence to array }
procedure TTcpBuffer.Add2Buffer(data: pointer; swappedSeq,len,dataOffs: dword; isFromServer: boolean);
var
prev: dword;
dataLen: dword;
i: integer;
begin
prev:=FSeqCount;
inc(FSeqCount);
if FSeqCount > length(FSeqArr) then
setlength(FSeqArr, ((length(FSeqArr) shr 6) + 1) shl 6); //by 64
GetMem(FSeqArr[prev].wsa_buf.buf, len);
move(data^, FSeqArr[prev].wsa_buf.buf^, len);
FSeqArr[prev].wsa_buf.len:=len;
FSeqArr[prev].swappedSeq:=swappedSeq;
FSeqArr[prev].dataOffs:=dataOffs;
dataLen:=len - dataOffs;
FSeqArr[prev].dataLen:=dataLen;
//if swappedSeq = FNextSeq then
// FNextSeq:=FCurrSeq + dataLen;
if FSeqCount > 1 then
QuickSort(0, FSeqCount - 1);
if FSeqCount = 10 then begin
if isFromServer then AddToLog('SMSG')
else AddToLog('CMSG');
AddToLog('current '+IntToHex(FCurrSeq,8)+' datalen '+IntToHex(dataLen,4));
AddToLog('expecting '+IntToHex(FCurrSeq + dataLen,8));
for i := 0 to 9 do AddToLog('seq['+IntToStr(i)+']='+IntToHex(FSeqArr[i].swappedSeq,8));
end;
end;
{ Add any packet from current to current+MAX_DELTA_BROWSE_SEQUENCE }
procedure TTcpBuffer.AddData(data: pointer; len: dword; isFromServer: boolean);
var
packetFlags: word;
ipHdrLen,tcpHdrDataOffs,dataOffs: dword;
pIpHdr: PIPHeader;
pTcpHdr: PTCPHeader;
pseudoHdr: TTCPPseudoHeader;
pseudohdrCS,cs: word;
swappedSeq,maxPossibleSeq: dword;
label fin;
begin
FCS.Enter;
pIpHdr:=PIPHeader(data);
ipHdrLen:=GetIPHeaderLen(pIpHdr);
pTcpHdr:=PTCPHeader(@TBytes(data)[ipHdrLen]);
//check already in array
swappedSeq:=ntohl(pTcpHdr.sequenceNumber);
if FSeqCount > 1 then begin
if QuickSearch(swappedSeq, FSeqCount, Match) >= 0 then begin
//AddToLog(Format('skip duplicated seq: %.8x swseq: %.8x',[pTcpHdr.sequenceNumber,swappedSeq]));
inc(FDupCount); goto fin;
end;
end
else if FSeqCount > 0 then begin
if FSeqArr[0].swappedSeq = swappedSeq then begin
//AddToLog(Format('skip duplicated seq: %.8x swseq: %.8x',[pTcpHdr.sequenceNumber,swappedSeq]));
inc(FDupCount); goto fin;
end;
end;
//check CS
cs:=GetChecksum(pIpHdr, ipHdrLen);
if cs <> 0 then begin
if isFromServer then AddToLog('wrong iphdr cs='+IntToHex(cs,4)+' src=server')
else AddToLog('wrong iphdr cs='+IntToHex(cs,4)+' src=client');
if (checkCS)and(isFromServer) then goto fin;
end;
if isFromServer then begin
pseudoHdr.iph_src:=pIpHdr.iph_src;
pseudoHdr.iph_dest:=pIpHdr.iph_dest;
pseudoHdr.reserved:=0;
pseudoHdr.iph_protocol:=pIpHdr.iph_protocol;
pseudoHdr.tcp_length:=ntohs(len - ipHdrLen); //ntohl shr 16;
pseudohdrCS:=not(GetChecksum(@pseudoHdr, sizeof(pseudoHdr)));
cs:=GetChecksum(pTcpHdr, len - ipHdrLen, pseudohdrCS);
if cs <> 0 then begin
if isFromServer then AddToLog('wrong iphdr cs='+IntToHex(cs,4)+' src=server')
else AddToLog('wrong iphdr cs='+IntToHex(cs,4)+' src=client');
if (checkCS) then goto fin;
end;
end;
packetFlags:=ntohs(pTcpHdr.flags);
//initial sequences
if (packetFlags and TCP_FLAG_SYN) <> 0 then begin
//FNextSeq:=
FCurrSeq:=swappedSeq + 1; //FNextSeq;
goto fin;
end;
//if (packetFlags and TCP_FLAG_ACK) <> 0 then goto fin;
maxPossibleSeq:=FCurrSeq + MAX_DELTA_BROWSE_SEQUENCE;
if ((FCurrSeq < maxPossibleSeq)and((swappedSeq < FCurrSeq)or(swappedSeq > maxPossibleSeq))) //linear
or ((FCurrSeq > maxPossibleSeq)and((swappedSeq < FCurrSeq)and(swappedSeq > maxPossibleSeq))) then begin
//AddToLog(Format('skip out of range seq: %.8x swseq: %.8x FCurrSeq: %.8x',[pTcpHdr.sequenceNumber,swappedSeq,FCurrSeq]));
inc(FOorCount); goto fin;
end;
tcpHdrDataOffs:=GetTCPDataOffset(@TBytes(data)[ipHdrLen]);
dataOffs:=ipHdrLen+tcpHdrDataOffs;
if len > dataOffs then
Add2Buffer(data, swappedSeq, len, dataOffs, isFromServer);
fin:
FCS.Leave;
end;
procedure TTcpBuffer.RemoveAt(seqArrPos: integer);
begin
Assert(seqArrPos < FSeqCount);
FreeMem(FSeqArr[seqArrPos].wsa_buf.buf);
if seqArrPos < (FSeqCount - 1) then
move(FSeqArr[seqArrPos+1], FSeqArr[seqArrPos], sizeof(TSeqRec)*(FSeqCount - seqArrPos - 1));
dec(FSeqCount);
end;
procedure TTcpBuffer.Release(swappedSeq: dword);
var
maxPossibleSeq: dword;
i,spos: integer;
begin
FCS.Enter;
if FSeqCount > 1 then begin
//AddToLog(Format('TTcpBuffer.Release seq: %.8x swseq: %.8x FSeqCount: %d',[bswap(swappedSeq),swappedSeq,FSeqCount]));
//for i := 0 to FSeqCount - 1 do
// AddToLog(Format('FSeqArr[%d] swseq: %.8x wsa_buf.buf: %.8x wsa_buf.len: %d',[i,FSeqArr[i].swappedSeq,dword(FSeqArr[i].wsa_buf.buf),FSeqArr[i].wsa_buf.len]));
spos:=QuickSearch(swappedSeq, FSeqCount, Match);
if spos >= 0 then begin
//AddToLog(Format('swseq found at %d',[spos]));
FCurrSeq:=FCurrSeq + FSeqArr[spos].dataLen;
RemoveAt(spos);
end;
//remove trash
i:=0;
while i < FSeqCount do begin
maxPossibleSeq:=FCurrSeq + MAX_DELTA_BROWSE_SEQUENCE;
if maxPossibleSeq > FCurrSeq then begin
if (FSeqArr[i].swappedSeq < FCurrSeq)or(FSeqArr[i].swappedSeq > maxPossibleSeq) then begin
//AddToLog(Format('FSeqCount: %d removing at: %d FCurrSeq: %.8x maxPossibleSeq: %.8x swseq: %.8x',[FSeqCount,i,FCurrSeq,maxPossibleSeq,FSeqArr[i].swappedSeq]));
RemoveAt(i);
end
else inc(i);
end
else if (FSeqArr[i].swappedSeq < FCurrSeq)and(FSeqArr[i].swappedSeq > maxPossibleSeq) then begin
//AddToLog(Format('FSeqCount: %d removing at: %d FCurrSeq: %.8x maxPossibleSeq: %.8x swseq: %.8x',[FSeqCount,i,FCurrSeq,maxPossibleSeq,FSeqArr[i].swappedSeq]));
RemoveAt(i);
end
else inc(i);
end;
end
else if FSeqCount > 0 then begin
if FSeqArr[0].swappedSeq = swappedSeq then begin
FCurrSeq:=FCurrSeq + FSeqArr[0].dataLen;
RemoveAt(0);
end;
end;
FCS.Leave;
end;
{ Get next matched sequence }
function TTcpBuffer.GetSequence: PSeqRec;
var
spos: integer;
begin
result:=nil;
FCS.Enter;
if FSeqCount > 1 then begin
spos:=QuickSearch(FCurrSeq, FSeqCount, Match);
if spos >= 0 then result:=@FSeqArr[spos];
end
else if FSeqCount > 0 then begin
if FSeqArr[0].swappedSeq = FCurrSeq then
result:=@FSeqArr[0];
end;
FCS.Leave;
end;
и вот тут были вопросы по самой организации обработки (если какой-то пакет не пришел то сколько надо хранить? не гигабайты же. Если потом пришел, но с него другие sequence пошли, то что? А приходили такие порой при глючной сети и жутких лагах). Потом описанная в никсах проверка контрольных сумм шла под ХР и нивкакую под вин7. Пришлось отказаться от проверки КС.
|