mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-04-15 07:39:31 +02:00
509 lines
12 KiB
PHP
509 lines
12 KiB
PHP
{
|
|
This file is part of the Free Pascal run time library.
|
|
Copyright (c) 1999-2000 by the Free Pascal development team
|
|
|
|
See the file COPYING.FPC, included in this distribution,
|
|
for details about the copyright.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
|
|
**********************************************************************}
|
|
|
|
{******************************************************************************
|
|
Text File Writeln/ReadLn Support
|
|
******************************************************************************}
|
|
|
|
|
|
Procedure OpenSock(var F:Text);
|
|
begin
|
|
if textrec(f).handle=UnusedHandle then
|
|
textrec(f).mode:=fmclosed
|
|
else
|
|
case textrec(f).userdata[1] of
|
|
S_OUT : textrec(f).mode:=fmoutput;
|
|
S_IN : textrec(f).mode:=fminput;
|
|
else
|
|
textrec(f).mode:=fmclosed;
|
|
end;
|
|
end;
|
|
|
|
|
|
|
|
procedure iosock(var f:text);
|
|
|
|
var r:sizeint;
|
|
def_error:word;
|
|
|
|
begin
|
|
with textrec(f) do
|
|
begin
|
|
case mode of
|
|
fmoutput:
|
|
begin
|
|
repeat
|
|
{$ifdef use_readwrite}
|
|
r:=fpwrite(handle,bufptr^,bufpos);
|
|
{$else}
|
|
r:=fpsend(handle,bufptr,bufpos,0);
|
|
{$endif}
|
|
until (r<>-1) or (SocketError <> EsockEINTR);
|
|
bufend:=r;
|
|
def_error:=101; {File write error.}
|
|
end;
|
|
fminput:
|
|
begin
|
|
repeat
|
|
{$ifdef use_readwrite}
|
|
r:=fpread(handle,bufptr^,bufsize);
|
|
{$else}
|
|
r:=fprecv(handle,bufptr,bufsize,0);
|
|
{$endif}
|
|
until (r<>-1) or (SocketError <> EsockEINTR);
|
|
bufend:=r;
|
|
def_error:=100; {File read error.}
|
|
end;
|
|
end;
|
|
if r=-1 then
|
|
case SocketError of
|
|
EsockEBADF:
|
|
{ EsysENOTSOCK:} {Why is this constant not defined? (DM)}
|
|
inoutres:=6; {Invalid file handle.}
|
|
EsockEFAULT:
|
|
inoutres:=217;
|
|
EsockEINVAL:
|
|
inoutres:=218;
|
|
else
|
|
inoutres:=def_error;
|
|
end;
|
|
bufpos:=0;
|
|
end;
|
|
end;
|
|
|
|
|
|
|
|
Procedure FlushSock(var F:Text);
|
|
begin
|
|
if (textrec(f).mode=fmoutput) and (textrec(f).bufpos<>0) then
|
|
begin
|
|
IOSock(f);
|
|
textrec(f).bufpos:=0;
|
|
end;
|
|
end;
|
|
|
|
|
|
|
|
Procedure CloseSock(var F:text);
|
|
begin
|
|
{ Nothing special has to be done here }
|
|
end;
|
|
|
|
|
|
|
|
Procedure Sock2Text(Sock:Longint;Var SockIn,SockOut:Text);
|
|
{
|
|
Set up two Pascal Text file descriptors for reading and writing)
|
|
}
|
|
begin
|
|
{ First the reading part.}
|
|
Assign(SockIn,'.');
|
|
Textrec(SockIn).Handle:=Sock;
|
|
Textrec(Sockin).userdata[1]:=S_IN;
|
|
TextRec(SockIn).OpenFunc:=@OpenSock;
|
|
TextRec(SockIn).InOutFunc:=@IOSock;
|
|
TextRec(SockIn).FlushFunc:=@FlushSock;
|
|
TextRec(SockIn).CloseFunc:=@CloseSock;
|
|
TextRec(SockIn).Mode := fmInput;
|
|
Case DefaultTextLineBreakStyle Of
|
|
tlbsLF: TextRec(sockin).LineEnd := #10;
|
|
tlbsCRLF: TextRec(sockin).LineEnd := #13#10;
|
|
tlbsCR: TextRec(sockin).LineEnd := #13;
|
|
End;
|
|
{ Now the writing part. }
|
|
Assign(SockOut,'.');
|
|
Textrec(SockOut).Handle:=Sock;
|
|
Textrec(SockOut).userdata[1]:=S_OUT;
|
|
TextRec(SockOut).OpenFunc:=@OpenSock;
|
|
TextRec(SockOut).InOutFunc:=@IOSock;
|
|
TextRec(SockOut).FlushFunc:=@FlushSock;
|
|
TextRec(SockOut).CloseFunc:=@CloseSock;
|
|
TextRec(SockOut).Mode := fmOutput;
|
|
|
|
Case DefaultTextLineBreakStyle Of
|
|
tlbsLF: TextRec(sockout).LineEnd := #10;
|
|
tlbsCRLF: TextRec(sockout).LineEnd := #13#10;
|
|
tlbsCR: TextRec(sockout).LineEnd := #13;
|
|
End;
|
|
end;
|
|
|
|
|
|
{******************************************************************************
|
|
Untyped File
|
|
******************************************************************************}
|
|
|
|
Procedure Sock2File(Sock:Longint;Var SockIn,SockOut:File);
|
|
begin
|
|
{Input}
|
|
Assign(SockIn,'.');
|
|
FileRec(SockIn).Handle:=Sock;
|
|
FileRec(SockIn).RecSize:=1;
|
|
FileRec(Sockin).userdata[1]:=S_IN;
|
|
FileRec(SockIn).Mode := fmInput;
|
|
|
|
{Output}
|
|
Assign(SockOut,'.');
|
|
FileRec(SockOut).Handle:=Sock;
|
|
FileRec(SockOut).RecSize:=1;
|
|
FileRec(SockOut).userdata[1]:=S_OUT;
|
|
FileRec(SockOut).Mode := fmOutput;
|
|
end;
|
|
|
|
{******************************************************************************
|
|
InetSock
|
|
******************************************************************************}
|
|
|
|
Function DoAccept(Sock:longint;Var addr:TInetSockAddr):longint;
|
|
|
|
Var AddrLen : Longint;
|
|
|
|
begin
|
|
AddrLEn:=SizeOf(Addr);
|
|
repeat
|
|
DoAccept:=fpaccept(Sock,@Addr,@AddrLen);
|
|
until (DoAccept<>-1) or (SocketError <> EsockEINTR);
|
|
end;
|
|
|
|
Function DoConnect(Sock:longint;const addr: TInetSockAddr): Boolean;
|
|
|
|
var
|
|
res: longint;
|
|
begin
|
|
repeat
|
|
res:=fpconnect(Sock,@Addr,SizeOF(TInetSockAddr));
|
|
until (res<>-1) or (SocketError <> EsockEINTR);
|
|
DoConnect:= res = 0;
|
|
end;
|
|
|
|
{$warnings off}
|
|
|
|
Function Connect(Sock:longint;const addr: TInetSockAddr;var SockIn,SockOut:text):Boolean;
|
|
|
|
begin
|
|
Connect:=DoConnect(Sock,addr);
|
|
If Connect then
|
|
Sock2Text(Sock,SockIn,SockOut);
|
|
end;
|
|
|
|
Function Connect(Sock:longint;const addr:TInetSockAddr;var SockIn,SockOut:file):Boolean;
|
|
|
|
begin
|
|
Connect:=DoConnect(Sock,addr);
|
|
If Connect then
|
|
Sock2File(Sock,SockIn,SockOut);
|
|
end;
|
|
|
|
Function Accept(Sock:longint;var addr:TInetSockAddr;var SockIn,SockOut:text):Boolean;
|
|
var
|
|
s : longint;
|
|
begin
|
|
S:=DoAccept(Sock,addr);
|
|
if S>0 then
|
|
begin
|
|
Sock2Text(S,SockIn,SockOut);
|
|
Accept:=true;
|
|
end
|
|
else
|
|
Accept:=false;
|
|
end;
|
|
|
|
Function Accept(Sock:longint;var addr:TInetSockAddr;var SockIn,SockOut:File):Boolean;
|
|
var
|
|
s : longint;
|
|
begin
|
|
S:=DoAccept(Sock,addr);
|
|
if S>0 then
|
|
begin
|
|
Sock2File(S,SockIn,SockOut);
|
|
Accept:=true;
|
|
end
|
|
else
|
|
Accept:=false;
|
|
end;
|
|
|
|
{$warnings on}
|
|
|
|
type thostaddr= packed array[1..4] of byte;
|
|
|
|
function htonl( host : longint):longint; inline;
|
|
|
|
begin
|
|
{$ifdef FPC_BIG_ENDIAN}
|
|
htonl:=host;
|
|
{$else}
|
|
htonl:=THostAddr(host)[4];
|
|
htonl:=htonl or longint( (THostAddr(host)[3]) shl 8);
|
|
htonl:=htonl or longint( (THostAddr(host)[2]) shl 16);
|
|
htonl:=htonl or longint( (THostAddr(host)[1]) shl 24);
|
|
{$endif}
|
|
end;
|
|
|
|
Function NToHl (Net : Longint) : Longint; inline;
|
|
|
|
begin
|
|
{$ifdef FPC_BIG_ENDIAN}
|
|
ntohl:=net;
|
|
{$else}
|
|
ntohl:=THostAddr(Net)[4];
|
|
ntohl:=ntohl or longint( (THostAddr(Net)[3]) shl 8);
|
|
ntohl:=ntohl or longint( (THostAddr(Net)[2]) shl 16);
|
|
ntohl:=ntohl or longint( (THostAddr(Net)[1]) shl 24);
|
|
{$endif}
|
|
end;
|
|
|
|
function htons( host : word):word; inline;
|
|
|
|
begin
|
|
{$ifdef FPC_BIG_ENDIAN}
|
|
htons:=host;
|
|
{$else}
|
|
htons:=swap(host);
|
|
{$endif}
|
|
end;
|
|
|
|
Function NToHs (Net : word):word; inline;
|
|
|
|
begin
|
|
{$ifdef FPC_BIG_ENDIAN}
|
|
ntohs:=net;
|
|
{$else}
|
|
ntohs:=swap(net);
|
|
{$endif}
|
|
end;
|
|
|
|
Type array4int = array[1..4] of byte;
|
|
|
|
function NetAddrToStr (Entry : in_addr) : AnsiString;
|
|
|
|
Var Dummy : Ansistring;
|
|
i,j : Longint;
|
|
|
|
begin
|
|
NetAddrToStr:='';
|
|
j:=entry.s_addr;
|
|
For I:=1 to 4 do
|
|
begin
|
|
Str(array4int(j)[i],Dummy);
|
|
NetAddrToStr:=NetAddrToStr+Dummy;
|
|
If I<4 Then
|
|
NetAddrToStr:=NetAddrToStr+'.';
|
|
end;
|
|
end;
|
|
|
|
function HostAddrToStr (Entry : in_addr) : AnsiString;
|
|
|
|
Var x: in_addr;
|
|
|
|
begin
|
|
x.s_addr:=htonl(entry.s_addr);
|
|
HostAddrToStr:=NetAddrToStr(x);
|
|
end;
|
|
|
|
function StrToHostAddr(IP : AnsiString) : in_addr ;
|
|
|
|
Var
|
|
Dummy : AnsiString;
|
|
I,j,k : Longint;
|
|
Temp : in_addr;
|
|
|
|
begin
|
|
strtohostaddr.s_addr:=0; //:=NoAddress;
|
|
For I:=1 to 4 do
|
|
begin
|
|
If I<4 Then
|
|
begin
|
|
J:=Pos('.',IP);
|
|
If J=0 then
|
|
exit;
|
|
Dummy:=Copy(IP,1,J-1);
|
|
Delete (IP,1,J);
|
|
end
|
|
else
|
|
Dummy:=IP;
|
|
Val (Dummy,k,J);
|
|
array4int(temp.s_addr)[i]:=k;
|
|
If J<>0 then Exit;
|
|
end;
|
|
strtohostaddr.s_addr:=ntohl(Temp.s_addr);
|
|
end;
|
|
|
|
function StrToNetAddr(IP : AnsiString) : in_addr;
|
|
|
|
begin
|
|
StrToNetAddr.s_addr:=htonl(StrToHostAddr(IP).s_addr);
|
|
end;
|
|
|
|
Function HostToNet (Host : in_addr):in_addr;
|
|
|
|
begin
|
|
HostToNet.s_addr:=htonl(host.s_addr);
|
|
end;
|
|
|
|
Function NetToHost (Net : in_addr) : in_addr;
|
|
|
|
begin
|
|
NetToHost.s_addr:=ntohl(net.s_addr);
|
|
end;
|
|
|
|
Function HostToNet (Host : Longint) : Longint;
|
|
|
|
begin
|
|
HostToNet:=htonl(host);
|
|
end;
|
|
|
|
Function NetToHost (Net : Longint) : Longint;
|
|
|
|
begin
|
|
NetToHost:=ntohl(net);
|
|
end;
|
|
|
|
Function ShortHostToNet (Host : Word) : Word;
|
|
|
|
begin
|
|
ShortHostToNet:=htons(host);
|
|
end;
|
|
|
|
Function ShortNetToHost (Net : Word) : Word;
|
|
|
|
begin
|
|
ShortNEtToHost:=ntohs(net);
|
|
end;
|
|
|
|
const digittab : shortstring = ('0123456789ABCDEF');
|
|
|
|
function lclinttohex (i:integer;digits:longint): ansistring;
|
|
|
|
begin
|
|
SetLength(lclinttohex,4);
|
|
lclinttohex[4]:=digittab[1+(i and 15)];
|
|
lclinttohex[3]:=digittab[1+((i shr 4) and 15)];
|
|
lclinttohex[2]:=digittab[1+((i shr 8) and 15)];
|
|
lclinttohex[1]:=digittab[1+((i shr 12) and 15)];;
|
|
end;
|
|
|
|
function HostAddrToStr6 (Entry : TIn6_Addr) :ansiString;
|
|
var
|
|
i: byte;
|
|
zr1,zr2: set of byte;
|
|
zc1,zc2: byte;
|
|
have_skipped: boolean;
|
|
begin
|
|
zr1 := [];
|
|
zr2 := [];
|
|
zc1 := 0;
|
|
zc2 := 0;
|
|
for i := 0 to 7 do begin
|
|
if Entry.u6_addr16[i] = 0 then begin
|
|
include(zr2, i);
|
|
inc(zc2);
|
|
end else begin
|
|
if zc1 < zc2 then begin
|
|
zc1 := zc2;
|
|
zr1 := zr2;
|
|
zc2 := 0; zr2 := [];
|
|
end;
|
|
end;
|
|
end;
|
|
if zc1 < zc2 then begin
|
|
zc1 := zc2;
|
|
zr1 := zr2;
|
|
end;
|
|
SetLength(HostAddrToStr6, 8*5-1);
|
|
SetLength(HostAddrToStr6, 0);
|
|
have_skipped := false;
|
|
for i := 0 to 7 do begin
|
|
if not (i in zr1) then begin
|
|
if have_skipped then begin
|
|
if HostAddrToStr6 = ''
|
|
then HostAddrToStr6 := '::'
|
|
else HostAddrToStr6 := HostAddrToStr6 + ':';
|
|
have_skipped := false;
|
|
end;
|
|
// FIXME: is that shortnettohost really proper there? I wouldn't be too sure...
|
|
HostAddrToStr6 := HostAddrToStr6 +lclIntToHex(ShortNetToHost(Entry.u6_addr16[i]), 1) + ':';
|
|
end else begin
|
|
have_skipped := true;
|
|
end;
|
|
end;
|
|
if have_skipped then
|
|
if HostAddrToStr6 = ''
|
|
then HostAddrToStr6 := '::'
|
|
else HostAddrToStr6 := HostAddrToStr6 + ':';
|
|
|
|
if HostAddrToStr6 = '' then HostAddrToStr6 := '::';
|
|
if not (7 in zr1) then
|
|
SetLength(HostAddrToStr6, Length(HostAddrToStr6)-1);
|
|
end;
|
|
|
|
|
|
function StrToHostAddr6(IP : String) : TIn6_addr;
|
|
Var Part : String;
|
|
IPv6 : TIn6_addr;
|
|
P,J : Integer;
|
|
W : Word;
|
|
Index : Integer;
|
|
ZeroAt : Integer;
|
|
Begin
|
|
FillChar(IPv6,SizeOf(IPv6),0);
|
|
{ Every 16-bit block is converted at its own and stored into Result. When }
|
|
{ the '::' zero-spacer is found, its location is stored. Afterwards the }
|
|
{ address is shifted and zero-filled. }
|
|
Index := 0; ZeroAt := -1;
|
|
J := 0;
|
|
P := Pos(':',IP);
|
|
While (P > 0) and (Length(IP) > 0) and (Index < 8) do
|
|
Begin
|
|
Part := '$'+Copy(IP,1,P-1);
|
|
Delete(IP,1,P);
|
|
if Length(Part) > 1 then { is there a digit after the '$'? }
|
|
Val(Part,W,J)
|
|
else W := 0;
|
|
IPv6.u6_addr16[Index] := HtoNS(W);
|
|
if J <> 0 then
|
|
Begin
|
|
FillChar(IPv6,SizeOf(IPv6),0);
|
|
Exit;
|
|
End;
|
|
if IP[1] = ':' then
|
|
Begin
|
|
ZeroAt := Index;
|
|
Delete(IP,1,1);
|
|
End;
|
|
Inc(Index);
|
|
P := Pos(':',IP); if P = 0 then P := Length(IP)+1;
|
|
End;
|
|
{ address a:b:c::f:g:h }
|
|
{ Result now a : b : c : f : g : h : 0 : 0, ZeroAt = 2, Index = 6 }
|
|
{ Result after a : b : c : 0 : 0 : f : g : h }
|
|
if ZeroAt >= 0 then
|
|
Begin
|
|
Move(IPv6.u6_addr16[ZeroAt+1],IPv6.u6_addr16[(8-Index)+ZeroAt+1],2*(Index-ZeroAt-1));
|
|
FillChar(IPv6.u6_addr16[ZeroAt+1],2*(8-Index),0);
|
|
End;
|
|
|
|
StrToHostAddr6:=IPv6;
|
|
End;
|
|
|
|
|
|
function NetAddrToStr6 (Entry : TIn6_Addr) : ansiString;
|
|
begin
|
|
netaddrtostr6 := HostAddrToStr6((Entry));
|
|
end;
|
|
|
|
function StrToNetAddr6(IP : ansiString) : TIn6_Addr;
|
|
begin
|
|
StrToNetAddr6 := StrToHostAddr6(IP);
|
|
end;
|
|
|
|
|