fpc/rtl/inc/sockets.inc
Jonas Maebe b5494c534c * handle EsockEINTR for fpaccept and fpconnect
git-svn-id: trunk@12939 -
2009-03-21 16:11:08 +00:00

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;