695 lines
19 KiB
ObjectPascal
695 lines
19 KiB
ObjectPascal
{******************************************************************************}
|
|
{ }
|
|
{ Library: Fundamentals 5.00 }
|
|
{ File name: flcTCPBuffer.pas }
|
|
{ File version: 5.08 }
|
|
{ Description: TCP buffer. }
|
|
{ }
|
|
{ Copyright: Copyright (c) 2007-2020, David J Butler }
|
|
{ All rights reserved. }
|
|
{ This file is licensed under the BSD License. }
|
|
{ See http://www.opensource.org/licenses/bsd-license.php }
|
|
{ Redistribution and use in source and binary forms, with }
|
|
{ or without modification, are permitted provided that }
|
|
{ the following conditions are met: }
|
|
{ Redistributions of source code must retain the above }
|
|
{ copyright notice, this list of conditions and the }
|
|
{ following disclaimer. }
|
|
{ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND }
|
|
{ CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED }
|
|
{ WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED }
|
|
{ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A }
|
|
{ PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL }
|
|
{ THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, }
|
|
{ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR }
|
|
{ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, }
|
|
{ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF }
|
|
{ USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) }
|
|
{ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER }
|
|
{ IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING }
|
|
{ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE }
|
|
{ USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE }
|
|
{ POSSIBILITY OF SUCH DAMAGE. }
|
|
{ }
|
|
{ Github: https://github.com/fundamentalslib }
|
|
{ E-mail: fundamentals.library at gmail.com }
|
|
{ }
|
|
{ Revision history: }
|
|
{ }
|
|
{ 2008/12/23 0.01 Initial development. }
|
|
{ 2010/12/02 0.02 Revision. }
|
|
{ 2011/04/22 0.03 Simple test cases. }
|
|
{ 2011/06/16 0.04 Minor change in PeekPtr routine. }
|
|
{ 2011/09/03 4.05 Revised for Fundamentals 4. }
|
|
{ 2016/01/09 5.06 Revised for Fundamentals 5. }
|
|
{ 2019/04/10 5.07 Change default buffer size. }
|
|
{ 2019/12/29 5.08 Minimum buffer size. }
|
|
{ }
|
|
{******************************************************************************}
|
|
|
|
{$INCLUDE ../flcInclude.inc}
|
|
{$INCLUDE flcTCP.inc}
|
|
|
|
unit flcTCPBuffer;
|
|
|
|
interface
|
|
|
|
uses
|
|
{ System }
|
|
|
|
SysUtils,
|
|
|
|
{ Utils }
|
|
|
|
flcStdTypes;
|
|
|
|
|
|
|
|
{ }
|
|
{ TCP Buffer }
|
|
{ }
|
|
type
|
|
ETCPBuffer = class(Exception);
|
|
|
|
TTCPBuffer = record
|
|
Ptr : Pointer;
|
|
Size : Integer;
|
|
Min : Int32;
|
|
Max : Int32;
|
|
Head : Int32;
|
|
Used : Int32;
|
|
end;
|
|
|
|
const
|
|
ETHERNET_MTU = 1500;
|
|
ETHERNET_MTU_JUMBO = 9000;
|
|
|
|
TCP_BUFFER_DEFAULTMAXSIZE = ETHERNET_MTU_JUMBO * 8; // 72,000 bytes
|
|
TCP_BUFFER_DEFAULTMINSIZE = ETHERNET_MTU * 6; // 9,000 bytes
|
|
|
|
procedure TCPBufferInitialise(
|
|
var TCPBuf: TTCPBuffer;
|
|
const TCPBufMaxSize: Int32 = TCP_BUFFER_DEFAULTMAXSIZE;
|
|
const TCPBufMinSize: Int32 = TCP_BUFFER_DEFAULTMINSIZE);
|
|
procedure TCPBufferFinalise(var TCPBuf: TTCPBuffer);
|
|
|
|
function TCPBufferGetMaxSize(const TCPBuf: TTCPBuffer): Int32; {$IFDEF UseInline}inline;{$ENDIF}
|
|
procedure TCPBufferSetMaxSize(
|
|
var TCPBuf: TTCPBuffer;
|
|
const MaxSize: Int32);
|
|
|
|
function TCPBufferGetMinSize(const TCPBuf: TTCPBuffer): Int32; {$IFDEF UseInline}inline;{$ENDIF}
|
|
procedure TCPBufferSetMinSize(
|
|
var TCPBuf: TTCPBuffer;
|
|
const MinSize: Int32);
|
|
|
|
procedure TCPBufferPack(var TCPBuf: TTCPBuffer);
|
|
procedure TCPBufferResize(
|
|
var TCPBuf: TTCPBuffer;
|
|
const TCPBufSize: Int32);
|
|
procedure TCPBufferExpand(
|
|
var TCPBuf: TTCPBuffer;
|
|
const Size: Int32);
|
|
procedure TCPBufferShrink(var TCPBuf: TTCPBuffer);
|
|
procedure TCPBufferMinimize(var TCPBuf: TTCPBuffer);
|
|
procedure TCPBufferClear(var TCPBuf: TTCPBuffer);
|
|
|
|
function TCPBufferAddPtr(
|
|
var TCPBuf: TTCPBuffer;
|
|
const Size: Int32): Pointer;
|
|
procedure TCPBufferAdded(
|
|
var TCPBuf: TTCPBuffer;
|
|
const Size: Int32);
|
|
procedure TCPBufferAddBuf(
|
|
var TCPBuf: TTCPBuffer;
|
|
const Buf; const Size: Int32);
|
|
|
|
function TCPBufferPeekPtr(
|
|
const TCPBuf: TTCPBuffer;
|
|
var BufPtr: Pointer): Int32; {$IFDEF UseInline}inline;{$ENDIF}
|
|
function TCPBufferPeek(
|
|
var TCPBuf: TTCPBuffer;
|
|
var Buf; const Size: Int32): Int32;
|
|
function TCPBufferPeekByte(
|
|
var TCPBuf: TTCPBuffer;
|
|
out B: Byte): Boolean;
|
|
|
|
function TCPBufferRemove(
|
|
var TCPBuf: TTCPBuffer;
|
|
var Buf; const Size: Int32): Int32;
|
|
function TCPBufferRemoveBuf(
|
|
var TCPBuf: TTCPBuffer;
|
|
var Buf; const Size: Int32): Boolean;
|
|
|
|
function TCPBufferDiscard(
|
|
var TCPBuf: TTCPBuffer;
|
|
const Size: Int32): Int32;
|
|
|
|
function TCPBufferUsed(const TCPBuf: TTCPBuffer): Int32; {$IFDEF UseInline}inline;{$ENDIF}
|
|
function TCPBufferEmpty(const TCPBuf: TTCPBuffer): Boolean; {$IFDEF UseInline}inline;{$ENDIF}
|
|
function TCPBufferAvailable(const TCPBuf: TTCPBuffer): Int32; {$IFDEF UseInline}inline;{$ENDIF}
|
|
|
|
function TCPBufferPtr(const TCPBuf: TTCPBuffer): Pointer; {$IFDEF UseInline}inline;{$ENDIF}
|
|
|
|
function TCPBufferLocateByteChar(const TCPBuf: TTCPBuffer;
|
|
const Delimiter: ByteCharSet; const MaxSize: Integer): Int32;
|
|
|
|
|
|
|
|
implementation
|
|
|
|
|
|
|
|
{ }
|
|
{ Resource strings }
|
|
{ }
|
|
const
|
|
SBufferOverflow = 'Buffer overflow';
|
|
|
|
|
|
|
|
{ }
|
|
{ TCP Buffer }
|
|
{ }
|
|
|
|
// Initialise a TCP buffer
|
|
procedure TCPBufferInitialise(
|
|
var TCPBuf: TTCPBuffer;
|
|
const TCPBufMaxSize: Int32;
|
|
const TCPBufMinSize: Int32);
|
|
var
|
|
L, M : Int32;
|
|
begin
|
|
TCPBuf.Ptr := nil;
|
|
TCPBuf.Size := 0;
|
|
TCPBuf.Head := 0;
|
|
TCPBuf.Used := 0;
|
|
L := TCPBufMinSize;
|
|
if L < 0 then
|
|
L := TCP_BUFFER_DEFAULTMINSIZE;
|
|
M := TCPBufMaxSize;
|
|
if M < 0 then
|
|
M := TCP_BUFFER_DEFAULTMAXSIZE;
|
|
if L > M then
|
|
L := M;
|
|
TCPBuf.Min := L;
|
|
TCPBuf.Max := M;
|
|
if L > 0 then
|
|
GetMem(TCPBuf.Ptr, L);
|
|
TCPBuf.Size := L;
|
|
end;
|
|
|
|
// Finalise a TCP buffer
|
|
procedure TCPBufferFinalise(var TCPBuf: TTCPBuffer);
|
|
var
|
|
P : Pointer;
|
|
begin
|
|
P := TCPBuf.Ptr;
|
|
if Assigned(P) then
|
|
begin
|
|
TCPBuf.Ptr := nil;
|
|
FreeMem(P);
|
|
end;
|
|
TCPBuf.Size := 0;
|
|
end;
|
|
|
|
// Gets maximum buffer size
|
|
function TCPBufferGetMaxSize(const TCPBuf: TTCPBuffer): Int32;
|
|
begin
|
|
Result := TCPBuf.Max;
|
|
end;
|
|
|
|
// Sets maximum buffer size
|
|
// Note: This limit is not enforced. It is used by TCPBufferAvailable.
|
|
procedure TCPBufferSetMaxSize(
|
|
var TCPBuf: TTCPBuffer;
|
|
const MaxSize: Int32);
|
|
var
|
|
L : Int32;
|
|
begin
|
|
L := MaxSize;
|
|
if L < 0 then
|
|
L := TCP_BUFFER_DEFAULTMAXSIZE;
|
|
TCPBuf.Max := L;
|
|
end;
|
|
|
|
// Gets minimum buffer size
|
|
function TCPBufferGetMinSize(const TCPBuf: TTCPBuffer): Int32;
|
|
begin
|
|
Result := TCPBuf.Min;
|
|
end;
|
|
|
|
procedure TCPBufferSetMinSize(
|
|
var TCPBuf: TTCPBuffer;
|
|
const MinSize: Int32);
|
|
var
|
|
L : Int32;
|
|
begin
|
|
L := MinSize;
|
|
if L < 0 then
|
|
L := TCP_BUFFER_DEFAULTMINSIZE;
|
|
TCPBuf.Min := L;
|
|
end;
|
|
|
|
// Pack a TCP buffer
|
|
// Moves data to front of buffer
|
|
// Post: TCPBuf.Head = 0
|
|
procedure TCPBufferPack(var TCPBuf: TTCPBuffer);
|
|
var
|
|
P, Q : PByte;
|
|
U, H : Int32;
|
|
begin
|
|
H := TCPBuf.Head;
|
|
if H <= 0 then
|
|
exit;
|
|
U := TCPBuf.Used;
|
|
if U <= 0 then
|
|
begin
|
|
TCPBuf.Head := 0;
|
|
exit;
|
|
end;
|
|
Assert(Assigned(TCPBuf.Ptr));
|
|
P := TCPBuf.Ptr;
|
|
Q := P;
|
|
Inc(P, H);
|
|
Move(P^, Q^, U);
|
|
TCPBuf.Head := 0;
|
|
end;
|
|
|
|
// Resize a TCP buffer
|
|
// New buffer size must be large enough to hold existing data
|
|
// Post: TCPBuf.Size = TCPBufSize
|
|
procedure TCPBufferResize(
|
|
var TCPBuf: TTCPBuffer;
|
|
const TCPBufSize: Int32);
|
|
var
|
|
U, L : Int32;
|
|
begin
|
|
L := TCPBufSize;
|
|
U := TCPBuf.Used;
|
|
// treat negative TCPBufSize parameter as zero
|
|
if L < 0 then
|
|
L := 0;
|
|
// check if shrinking buffer to less than used size
|
|
if U > L then
|
|
raise ETCPBuffer.Create(SBufferOverflow);
|
|
// check if packing required to fit buffer
|
|
if U + TCPBuf.Head > L then
|
|
TCPBufferPack(TCPBuf);
|
|
Assert(U + TCPBuf.Head <= L);
|
|
// resize
|
|
ReallocMem(TCPBuf.Ptr, L);
|
|
TCPBuf.Size := L;
|
|
end;
|
|
|
|
// Expand a TCP buffer
|
|
// Expands the size of the TCP buffer to at least Size
|
|
procedure TCPBufferExpand(
|
|
var TCPBuf: TTCPBuffer;
|
|
const Size: Int32);
|
|
var
|
|
S : Int32;
|
|
N : Int64;
|
|
I : Int64;
|
|
begin
|
|
S := TCPBuf.Size;
|
|
N := Size;
|
|
// check if expansion not required
|
|
if N <= S then
|
|
exit;
|
|
// scale up new size proportional to current size
|
|
// increase by at least quarter of current size
|
|
// this reduces the number of resizes in growing buffers
|
|
I := S + (S div 4);
|
|
if N < I then
|
|
N := I;
|
|
// ensure new size is multiple of MTU size
|
|
I := N mod ETHERNET_MTU;
|
|
if I > 0 then
|
|
Inc(N, ETHERNET_MTU - I);
|
|
// resize buffer
|
|
Assert(N >= Size);
|
|
TCPBufferResize(TCPBuf, N);
|
|
end;
|
|
|
|
// Shrink the size of a TCP buffer to release all unused memory
|
|
// Post: TCPBuf.Used = TCPBuf.Size and TCPBuf.Head = 0
|
|
procedure TCPBufferShrink(var TCPBuf: TTCPBuffer);
|
|
var
|
|
S, U : Int32;
|
|
begin
|
|
S := TCPBuf.Size;
|
|
if S <= 0 then
|
|
exit;
|
|
U := TCPBuf.Used;
|
|
if U = 0 then
|
|
begin
|
|
TCPBufferResize(TCPBuf, 0);
|
|
TCPBuf.Head := 0;
|
|
exit;
|
|
end;
|
|
if U = S then
|
|
exit;
|
|
TCPBufferPack(TCPBuf); // move data to front of buffer
|
|
TCPBufferResize(TCPBuf, U); // set size equal to used bytes
|
|
Assert(TCPBuf.Used = TCPBuf.Size);
|
|
end;
|
|
|
|
// Applies Min parameter to allocated memory
|
|
procedure TCPBufferMinimize(var TCPBuf: TTCPBuffer); {$IFDEF UseInline}inline;{$ENDIF}
|
|
var
|
|
Mi : Int32;
|
|
begin
|
|
Mi := TCPBuf.Min;
|
|
if Mi >= 0 then
|
|
if TCPBuf.Used <= Mi then
|
|
if TCPBuf.Size > Mi then
|
|
TCPBufferResize(TCPBuf, Mi);
|
|
end;
|
|
|
|
// Clear the data from a TCP buffer
|
|
procedure TCPBufferClear(var TCPBuf: TTCPBuffer); {$IFDEF UseInline}inline;{$ENDIF}
|
|
begin
|
|
TCPBuf.Used := 0;
|
|
TCPBuf.Head := 0;
|
|
TCPBufferMinimize(TCPBuf);
|
|
end;
|
|
|
|
// Returns a pointer to position in buffer to add new data of Size
|
|
// Handles resizing and packing of buffer to fit new data
|
|
function TCPBufferAddPtr(
|
|
var TCPBuf: TTCPBuffer;
|
|
const Size: Int32): Pointer; {$IFDEF UseInline}inline;{$ENDIF}
|
|
var
|
|
P : PByte;
|
|
U : Int32;
|
|
L : Int64;
|
|
H : Int32;
|
|
begin
|
|
// return nil if nothing to add
|
|
if Size <= 0 then
|
|
begin
|
|
Result := nil;
|
|
exit;
|
|
end;
|
|
U := TCPBuf.Used;
|
|
L := U + Size;
|
|
// resize if necessary
|
|
if L > TCPBuf.Size then
|
|
TCPBufferExpand(TCPBuf, L);
|
|
// pack if necessary
|
|
if TCPBuf.Head + L > TCPBuf.Size then
|
|
TCPBufferPack(TCPBuf);
|
|
// buffer should now be large enough for new data
|
|
H := TCPBuf.Head;
|
|
Assert(TCPBuf.Size > 0);
|
|
Assert(H + L <= TCPBuf.Size);
|
|
// get buffer pointer
|
|
Assert(Assigned(TCPBuf.Ptr));
|
|
P := TCPBuf.Ptr;
|
|
Inc(P, H);
|
|
Inc(P, U);
|
|
Result := P;
|
|
end;
|
|
|
|
// Increases data used in buffer by Size.
|
|
// TCPBufferAdded should only be called in conjuction with TCPBufferAddPtr.
|
|
procedure TCPBufferAdded(
|
|
var TCPBuf: TTCPBuffer;
|
|
const Size: Int32);
|
|
begin
|
|
if Size <= 0 then
|
|
exit;
|
|
Assert(TCPBuf.Head + TCPBuf.Used + Size <= TCPBuf.Size);
|
|
Inc(TCPBuf.Used, Size);
|
|
end;
|
|
|
|
// Adds new data from a buffer to a TCP buffer
|
|
procedure TCPBufferAddBuf(
|
|
var TCPBuf: TTCPBuffer;
|
|
const Buf; const Size: Int32); {$IFDEF UseInline}inline;{$ENDIF}
|
|
var
|
|
P : PByte;
|
|
begin
|
|
if Size <= 0 then
|
|
exit;
|
|
// get TCP buffer pointer
|
|
P := TCPBufferAddPtr(TCPBuf, Size);
|
|
// move user buffer to TCP buffer
|
|
Assert(Assigned(P));
|
|
Move(Buf, P^, Size);
|
|
Inc(TCPBuf.Used, Size);
|
|
Assert(TCPBuf.Head + TCPBuf.Used <= TCPBuf.Size);
|
|
end;
|
|
|
|
// Peek TCP buffer
|
|
// Returns the number of bytes available to peek
|
|
function TCPBufferPeekPtr(
|
|
const TCPBuf: TTCPBuffer;
|
|
var BufPtr: Pointer): Int32; {$IFDEF UseInline}inline;{$ENDIF}
|
|
var
|
|
P : PByte;
|
|
L : Int32;
|
|
begin
|
|
// handle empty TCP buffer
|
|
L := TCPBuf.Used;
|
|
if L <= 0 then
|
|
begin
|
|
BufPtr := nil;
|
|
Result := 0;
|
|
exit;
|
|
end;
|
|
// get buffer pointer
|
|
Assert(TCPBuf.Head + L <= TCPBuf.Size);
|
|
Assert(Assigned(TCPBuf.Ptr));
|
|
P := TCPBuf.Ptr;
|
|
Inc(P, TCPBuf.Head);
|
|
BufPtr := P;
|
|
// return size
|
|
Result := L;
|
|
end;
|
|
|
|
// Peek data from a TCP buffer
|
|
// Returns the number of bytes actually available and copied into the buffer
|
|
function TCPBufferPeek(
|
|
var TCPBuf: TTCPBuffer;
|
|
var Buf; const Size: Int32): Int32; {$IFDEF UseInline}inline;{$ENDIF}
|
|
var
|
|
P : Pointer;
|
|
L : Int32;
|
|
begin
|
|
// handle peeking zero bytes
|
|
if Size <= 0 then
|
|
begin
|
|
Result := 0;
|
|
exit;
|
|
end;
|
|
L := TCPBufferPeekPtr(TCPBuf, P);
|
|
// peek from TCP buffer
|
|
if L > Size then
|
|
L := Size;
|
|
Move(P^, Buf, L);
|
|
Result := L;
|
|
end;
|
|
|
|
// Peek byte from a TCP buffer
|
|
// Returns True if a byte is available
|
|
function TCPBufferPeekByte(
|
|
var TCPBuf: TTCPBuffer;
|
|
out B: Byte): Boolean;
|
|
var
|
|
P : Pointer;
|
|
L : Int32;
|
|
begin
|
|
L := TCPBufferPeekPtr(TCPBuf, P);
|
|
// peek from TCP buffer
|
|
if L = 0 then
|
|
Result := False
|
|
else
|
|
begin
|
|
B := PByte(P)^;
|
|
Result := True;
|
|
end;
|
|
end;
|
|
|
|
// Remove data from a TCP buffer
|
|
// Returns the number of bytes actually available and copied into the user buffer
|
|
function TCPBufferRemove(
|
|
var TCPBuf: TTCPBuffer;
|
|
var Buf; const Size: Int32): Int32; {$IFDEF UseInline}inline;{$ENDIF}
|
|
var
|
|
L, H, U : Int32;
|
|
begin
|
|
// peek data from buffer
|
|
L := TCPBufferPeek(TCPBuf, Buf, Size);
|
|
if L = 0 then
|
|
begin
|
|
Result := 0;
|
|
exit;
|
|
end;
|
|
// remove from TCP buffer
|
|
H := TCPBuf.Head;
|
|
U := TCPBuf.Used;
|
|
Dec(U, L);
|
|
if U = 0 then
|
|
H := 0
|
|
else
|
|
Inc(H, L);
|
|
TCPBuf.Head := H;
|
|
TCPBuf.Used := U;
|
|
TCPBufferMinimize(TCPBuf);
|
|
Result := L;
|
|
end;
|
|
|
|
// Remove data from a TCP buffer
|
|
// Returns True if Size bytes were available and copied into the user buffer
|
|
// Returns False if Size bytes were not available
|
|
function TCPBufferRemoveBuf(
|
|
var TCPBuf: TTCPBuffer;
|
|
var Buf; const Size: Int32): Boolean; {$IFDEF UseInline}inline;{$ENDIF}
|
|
var
|
|
H, U : Int32;
|
|
P : PByte;
|
|
begin
|
|
// handle invalid size
|
|
if Size <= 0 then
|
|
begin
|
|
Result := False;
|
|
exit;
|
|
end;
|
|
// check if enough data available
|
|
U := TCPBuf.Used;
|
|
if U < Size then
|
|
begin
|
|
Result := False;
|
|
exit;
|
|
end;
|
|
// get buffer
|
|
H := TCPBuf.Head;
|
|
Assert(H + Size <= TCPBuf.Size);
|
|
P := TCPBuf.Ptr;
|
|
Assert(Assigned(P));
|
|
Inc(P, H);
|
|
Move(P^, Buf, Size);
|
|
// remove from TCP buffer
|
|
Dec(U, Size);
|
|
if U = 0 then
|
|
H := 0
|
|
else
|
|
Inc(H, Size);
|
|
TCPBuf.Head := H;
|
|
TCPBuf.Used := U;
|
|
TCPBufferMinimize(TCPBuf);
|
|
Result := True;
|
|
end;
|
|
|
|
// Discard a number of bytes from the TCP buffer
|
|
// Returns the number of bytes actually discarded from buffer
|
|
function TCPBufferDiscard(
|
|
var TCPBuf: TTCPBuffer;
|
|
const Size: Int32): Int32; {$IFDEF UseInline}inline;{$ENDIF}
|
|
var
|
|
L, U : Int32;
|
|
begin
|
|
// handle discarding zero bytes from buffer
|
|
L := Size;
|
|
if L <= 0 then
|
|
begin
|
|
Result := 0;
|
|
exit;
|
|
end;
|
|
// handle discarding the complete buffer
|
|
U := TCPBuf.Used;
|
|
if L >= U then
|
|
begin
|
|
TCPBuf.Used := 0;
|
|
TCPBuf.Head := 0;
|
|
TCPBufferMinimize(TCPBuf);
|
|
Result := U;
|
|
exit;
|
|
end;
|
|
// discard partial buffer
|
|
Inc(TCPBuf.Head, L);
|
|
Dec(U, L);
|
|
TCPBuf.Used := U;
|
|
TCPBufferMinimize(TCPBuf);
|
|
Result := L;
|
|
end;
|
|
|
|
// Returns number of bytes used in TCP buffer
|
|
function TCPBufferUsed(const TCPBuf: TTCPBuffer): Int32; {$IFDEF UseInline}inline;{$ENDIF}
|
|
begin
|
|
Result := TCPBuf.Used;
|
|
end;
|
|
|
|
function TCPBufferEmpty(const TCPBuf: TTCPBuffer): Boolean; {$IFDEF UseInline}inline;{$ENDIF}
|
|
begin
|
|
Result := TCPBuf.Used = 0;
|
|
end;
|
|
|
|
// Returns number of bytes available in TCP buffer
|
|
// Note: this function can return a negative number if the TCP buffer uses more bytes than set in Max
|
|
function TCPBufferAvailable(const TCPBuf: TTCPBuffer): Int32; {$IFDEF UseInline}inline;{$ENDIF}
|
|
begin
|
|
Result := TCPBuf.Max - TCPBuf.Used;
|
|
end;
|
|
|
|
// Returns pointer to TCP buffer head
|
|
function TCPBufferPtr(const TCPBuf: TTCPBuffer): Pointer; {$IFDEF UseInline}inline;{$ENDIF}
|
|
var
|
|
P : PByte;
|
|
begin
|
|
Assert(Assigned(TCPBuf.Ptr));
|
|
P := TCPBuf.Ptr;
|
|
Inc(P, TCPBuf.Head);
|
|
Result := P;
|
|
end;
|
|
|
|
// LocateByteChar
|
|
// Returns position of Delimiter in buffer
|
|
// Returns >= 0 if found in buffer
|
|
// Returns -1 if not found in buffer
|
|
// MaxSize specifies maximum bytes before delimiter, of -1 for no limit
|
|
function TCPBufferLocateByteChar(const TCPBuf: TTCPBuffer;
|
|
const Delimiter: ByteCharSet; const MaxSize: Integer): Int32;
|
|
var
|
|
BufSize : Int32;
|
|
LocLen : Int32;
|
|
BufPtr : PByteChar;
|
|
I : Int32;
|
|
begin
|
|
if MaxSize = 0 then
|
|
begin
|
|
Result := -1;
|
|
exit;
|
|
end;
|
|
BufSize := TCPBuf.Used;
|
|
if BufSize <= 0 then
|
|
begin
|
|
Result := -1;
|
|
exit;
|
|
end;
|
|
if MaxSize < 0 then
|
|
LocLen := BufSize
|
|
else
|
|
if BufSize < MaxSize then
|
|
LocLen := BufSize
|
|
else
|
|
LocLen := MaxSize;
|
|
BufPtr := TCPBufferPtr(TCPBuf);
|
|
for I := 0 to LocLen - 1 do
|
|
if BufPtr^ in Delimiter then
|
|
begin
|
|
Result := I;
|
|
exit;
|
|
end
|
|
else
|
|
Inc(BufPtr);
|
|
Result := -1;
|
|
end;
|
|
|
|
|
|
|
|
end.
|
|
|