From 316ed093f818d17ca35bbb6b15d4e4d1ba9afc1d Mon Sep 17 00:00:00 2001 From: geby Date: Thu, 24 Apr 2008 07:40:57 +0000 Subject: [PATCH] Release 37 git-svn-id: https://svn.code.sf.net/p/synalist/code/trunk@80 7c85be65-684b-0410-a082-b2ed4fbef004 --- blcksock.pas | 852 +++++++++---------------------------------- clamsend.pas | 218 +++++++++++ dnssend.pas | 93 +---- ftpsend.pas | 13 +- httpsend.pas | 173 +++++---- ldapsend.pas | 8 +- mimepart.pas | 21 +- pingsend.pas | 26 +- pop3send.pas | 58 ++- snmpsend.pas | 2 +- ssdotnet.pas | 142 ++++++-- ssfpc.pas | 868 ++++++++++++++++++++++++++++++++++++++++++++ ssl_cryptlib.pas | 42 ++- ssl_openssl.pas | 22 +- ssl_openssl_lib.pas | 12 +- ssl_sbb.pas | 594 ++++++++++++++++++++++++++++++ sslinux.pas | 459 ++++++++++++++++++++--- sswin32.pas | 449 ++++++++++++++++++++--- synachar.pas | 4 +- synafpc.pas | 99 +++-- synaicnv.pas | 8 +- synaip.pas | 390 ++++++++++++++++++++ synamisc.pas | 5 +- synautil.pas | 265 +++++--------- synsock.pas | 13 +- winver.pp | 76 ---- 26 files changed, 3601 insertions(+), 1311 deletions(-) create mode 100644 clamsend.pas create mode 100644 ssfpc.pas create mode 100644 ssl_sbb.pas create mode 100644 synaip.pas delete mode 100644 winver.pp diff --git a/blcksock.pas b/blcksock.pas index ab4f4cb..4354752 100644 --- a/blcksock.pas +++ b/blcksock.pas @@ -1,9 +1,9 @@ {==============================================================================| -| Project : Ararat Synapse | 009.000.007 | +| Project : Ararat Synapse | 009.001.003 | |==============================================================================| | Content: Library base | |==============================================================================| -| Copyright (c)1999-2005, Lukas Gebauer | +| Copyright (c)1999-2006, Lukas Gebauer | | All rights reserved. | | | | Redistribution and use in source and binary forms, with or without | @@ -33,7 +33,7 @@ | DAMAGE. | |==============================================================================| | The Initial Developer of the Original Code is Lukas Gebauer (Czech Republic).| -| Portions created by Lukas Gebauer are Copyright (c)1999-2005. | +| Portions created by Lukas Gebauer are Copyright (c)1999-2006. | | All Rights Reserved. | |==============================================================================| | Contributor(s): | @@ -88,16 +88,8 @@ interface uses SysUtils, Classes, -{$IFDEF LINUX} - {$IFDEF FPC} synafpc, - {$ENDIF} - Libc, -{$ENDIF} -{$IFDEF WIN32} - Windows, -{$ENDIF} - synsock, synautil, synacode + synsock, synautil, synacode, synaip {$IFDEF CIL} ,System.Net ,System.Net.Sockets @@ -107,7 +99,7 @@ uses const - SynapseRelease = '36'; + SynapseRelease = '37'; cLocalhost = '127.0.0.1'; cAnyHost = '0.0.0.0'; @@ -119,8 +111,7 @@ const CR = #$0d; LF = #$0a; CRLF = CR + LF; - c64k = 65535; - + c64k = 65536; type @@ -271,9 +262,9 @@ type FNonBlockMode: Boolean; FMaxLineLength: Integer; FMaxSendBandwidth: Integer; - FNextSend: ULong; + FNextSend: LongWord; FMaxRecvBandwidth: Integer; - FNextRecv: ULong; + FNextRecv: LongWord; FConvertLineEnd: Boolean; FLastCR: Boolean; FLastLF: Boolean; @@ -298,10 +289,10 @@ type procedure SetNonBlockMode(Value: Boolean); procedure SetTTL(TTL: integer); function GetTTL:integer; - function IsNewApi: Boolean; procedure SetFamily(Value: TSocketFamily); virtual; procedure SetSocket(Value: TSocket); virtual; function GetWsaData: TWSAData; + function FamilyToAF(f: TSocketFamily): TAddrFamily; protected FSocket: TSocket; FLastError: Integer; @@ -317,9 +308,10 @@ type procedure DoReadFilter(Buffer: TMemory; var Len: Integer); procedure DoMonitor(Writing: Boolean; const Buffer: TMemory; Len: Integer); procedure DoCreateSocket; - procedure LimitBandwidth(Length: Integer; MaxB: integer; var Next: ULong); + procedure LimitBandwidth(Length: Integer; MaxB: integer; var Next: LongWord); procedure SetBandwidth(Value: Integer); function TestStopFlag: Boolean; + procedure InternalSendStream(const Stream: TStream; WithSize, Indy: boolean); virtual; public constructor Create; @@ -656,14 +648,6 @@ type it. (It not supported by all socket providers!)} procedure SetRecvTimeout(Timeout: Integer); - {:Convert IPv6 address from their string form to binary. This function - working only on systems with IPv6 support!} - function StrToIP6(const value: string): TSockAddrIn6; - - {:Convert IPv6 address from binary to string form. This function working - only on systems with IPv6 support!} - function IP6ToStr(const value: TSockAddrIn6): string; - {:Return value of socket type.} function GetSocketType: integer; Virtual; @@ -774,8 +758,8 @@ type specify if is used IPv4 (dafault - @true) or IPv6.} property PreferIP4: Boolean read FPreferIP4 Write FPreferIP4; - {:By dafault (@false) is all timeouts used as timeout between two packets in - reading operations. If you set this to @true, then Timeouts is for overall + {:By default (@true) is all timeouts used as timeout between two packets in + reading operations. If you set this to @false, then Timeouts is for overall reading operation!} property InterPacketTimeout: Boolean read FInterPacketTimeout Write FInterPacketTimeout; @@ -1332,9 +1316,9 @@ type TTL: Byte; Protocol: Byte; CheckSum: Word; - SourceIp: DWORD; - DestIp: DWORD; - Options: DWORD; + SourceIp: LongWord; + DestIp: LongWord; + Options: LongWord; end; {:@abstract(Parent class of application protocol implementations.) @@ -1460,11 +1444,16 @@ begin inherited Destroy; end; -function TBlockSocket.IsNewApi: Boolean; +function TBlockSocket.FamilyToAF(f: TSocketFamily): TAddrFamily; begin - Result := SockEnhancedApi; - if not Result then - Result := (FFamily = SF_ip6) and SockWship6Api; + case f of + SF_ip4: + Result := AF_INET; + SF_ip6: + Result := AF_INET6; + else + Result := AF_UNSPEC; + end; end; procedure TBlockSocket.SetDelayedOption(const Value: TSynaOption); @@ -1510,7 +1499,7 @@ begin begin FNonBlockMode := Value.Enabled; x := Ord(FNonBlockMode); - synsock.IoctlSocket(FSocket, FIONBIO, u_long(x)); + synsock.IoctlSocket(FSocket, FIONBIO, x); end; SOT_RecvTimeout: begin @@ -1622,242 +1611,36 @@ begin end; procedure TBlockSocket.SetSin(var Sin: TVarSin; IP, Port: string); -{$IFNDEF CIL} -type - pu_long = ^u_long; var - ProtoEnt: PProtoEnt; - ServEnt: PServEnt; - HostEnt: PHostEnt; - r: integer; - Hints1, Hints2: TAddrInfo; - Sin1, Sin2: TVarSin; - TwoPass: boolean; - - function GetAddr(const IP, port: string; Hints: TAddrInfo; var Sin: TVarSin): integer; - var - Addr: PAddrInfo; - begin - Addr := nil; - try - FillChar(Sin, Sizeof(Sin), 0); - if Hints.ai_socktype = SOCK_RAW then - begin - Hints.ai_socktype := 0; - Hints.ai_protocol := 0; - Result := synsock.GetAddrInfo(PChar(IP), nil, @Hints, Addr); - end - else - begin - if (IP = cAnyHost) or (IP = c6AnyHost) then - begin - Hints.ai_flags := AI_PASSIVE; - Result := synsock.GetAddrInfo(nil, PChar(Port), @Hints, Addr); - end - else - if (IP = cLocalhost) or (IP = c6Localhost) then - begin - Result := synsock.GetAddrInfo(nil, PChar(Port), @Hints, Addr); - end - else - begin - Result := synsock.GetAddrInfo(PChar(IP), PChar(Port), @Hints, Addr); - end; - end; - if Result = 0 then - if (Addr <> nil) then - Move(Addr^.ai_addr^, Sin, Addr^.ai_addrlen); - finally - if Assigned(Addr) then - synsock.FreeAddrInfo(Addr); - end; - end; - + f: TSocketFamily; begin DoStatus(HR_ResolvingBegin, IP + ':' + Port); FLastError := 0; - FillChar(Sin, Sizeof(Sin), 0); - if not IsNewApi then + //if socket exists, then use their type, else use users selection + f := SF_Any; + if (FSocket = INVALID_SOCKET) and (FFamily = SF_any) then begin - SynSockCS.Enter; - try - Sin.sin_family := AF_INET; - ProtoEnt := synsock.GetProtoByNumber(GetSocketProtocol); - ServEnt := nil; - if ProtoEnt <> nil then - ServEnt := synsock.GetServByName(PChar(Port), ProtoEnt^.p_name); - if ServEnt = nil then - Sin.sin_port := synsock.htons(StrToIntDef(Port, 0)) - else - Sin.sin_port := ServEnt^.s_port; - if IP = cBroadcast then - Sin.sin_addr.s_addr := u_long(INADDR_BROADCAST) - else - begin - Sin.sin_addr.s_addr := synsock.inet_addr(PChar(IP)); - if Sin.sin_addr.s_addr = u_long(INADDR_NONE) then - begin - HostEnt := synsock.GetHostByName(PChar(IP)); - FLastError := synsock.WSAGetLastError; - if HostEnt <> nil then - Sin.sin_addr.S_addr := u_long(Pu_long(HostEnt^.h_addr_list^)^); - end; - end; - finally - SynSockCS.Leave; - end; + if IsIP(IP) then + f := SF_IP4 + else + if IsIP6(IP) then + f := SF_IP6; end else - begin - FillChar(Hints1, Sizeof(Hints1), 0); - FillChar(Hints2, Sizeof(Hints2), 0); - TwoPass := False; - //if socket exists, then use their type, else use users selection - if FSocket = INVALID_SOCKET then - case FFamily of - SF_Any: - begin - if IsIP(IP) then - Hints1.ai_family := AF_INET - else - if IsIP6(IP) then - Hints1.ai_family := AF_INET6 - else - if FPreferIP4 then - begin - Hints1.ai_family := AF_INET; - Hints2.ai_family := AF_INET6; - TwoPass := True; - end - else - begin - Hints2.ai_family := AF_INET; - Hints1.ai_family := AF_INET6; - TwoPass := True; - end - end; - SF_IP4: - Hints1.ai_family := AF_INET; - SF_IP6: - Hints1.ai_family := AF_INET6; - end - else - if FIP6Used then - Hints1.ai_family := AF_INET6 - else - Hints1.ai_family := AF_INET; - Hints1.ai_socktype := GetSocketType; - Hints1.ai_protocol := GetSocketprotocol; - Hints2.ai_socktype := Hints1.ai_socktype; - Hints2.ai_protocol := Hints1.ai_protocol; - - r := GetAddr(IP, Port, Hints1, Sin1); - FLastError := r; - sin := sin1; - if r <> 0 then - if TwoPass then - begin - r := GetAddr(IP, Port, Hints2, Sin2); - FLastError := r; - if r = 0 then - sin := sin2; - end; - end; -{$ELSE} -var - IPs: array of IPAddress; - n: integer; - ip4, ip6: string; - sip: string; -begin - ip4 := ''; - ip6 := ''; - IPs := Dns.Resolve(IP).AddressList; - for n :=low(IPs) to high(IPs) do begin - if (ip4 = '') and (IPs[n].AddressFamily = AF_INET) then - ip4 := IPs[n].toString; - if (ip6 = '') and (IPs[n].AddressFamily = AF_INET6) then - ip6 := IPs[n].toString; - if (ip4 <> '') and (ip6 <> '') then - break; - end; - if FSocket = INVALID_SOCKET then - case FFamily of - SF_Any: - begin - if (ip4 <> '') and (ip6 <> '') then - begin - if FPreferIP4 then - sip := ip4 - else - Sip := ip6; - end - else - begin - sip := ip4; - if (ip6 <> '') then - sip := ip6; - end; - end; - SF_IP4: - sip := ip4; - SF_IP6: - sip := ip6; - end - else - if FIP6Used then - sip := ip6 - else - sip := ip4; - - sin := TVarSin.Create(IPAddress.Parse(sip), GetPortService(Port)); -{$ENDIF} + f := FFamily; + FLastError := synsock.SetVarSin(sin, ip, port, FamilyToAF(f), + GetSocketprotocol, GetSocketType, FPreferIP4); DoStatus(HR_ResolvingEnd, IP + ':' + Port); end; function TBlockSocket.GetSinIP(Sin: TVarSin): string; -{$IFNDEF CIL} -var - p: PChar; - host, serv: string; - hostlen, servlen: integer; - r: integer; begin - Result := ''; - if not IsNewApi then - begin - p := synsock.inet_ntoa(Sin.sin_addr); - if p <> nil then - Result := p; - end - else - begin - hostlen := NI_MAXHOST; - servlen := NI_MAXSERV; - setlength(host, hostlen); - setlength(serv, servlen); - r := getnameinfo(@sin, SizeOfVarSin(sin), PChar(host), hostlen, - PChar(serv), servlen, NI_NUMERICHOST + NI_NUMERICSERV); - if r = 0 then - Result := PChar(host); - end; -{$ELSE} -begin - Result := Sin.Address.ToString; -{$ENDIF} + Result := synsock.GetSinIP(sin); end; function TBlockSocket.GetSinPort(Sin: TVarSin): Integer; -{$IFNDEF CIL} begin - if (Sin.sin_family = AF_INET6) then - Result := synsock.ntohs(Sin.sin6_port) - else - Result := synsock.ntohs(Sin.sin_port); -{$ELSE} -begin - Result := Sin.Port; -{$ENDIF} + Result := synsock.GetSinPort(sin); end; procedure TBlockSocket.CreateSocket; @@ -2014,10 +1797,10 @@ begin MaxRecvBandwidth := Value; end; -procedure TBlockSocket.LimitBandwidth(Length: Integer; MaxB: integer; var Next: ULong); +procedure TBlockSocket.LimitBandwidth(Length: Integer; MaxB: integer; var Next: LongWord); var - x: ULong; - y: ULong; + x: LongWord; + y: LongWord; begin if MaxB > 0 then begin @@ -2131,22 +1914,30 @@ begin end; procedure TBlockSocket.SendBlock(const Data: AnsiString); +var + i: integer; begin - SendInteger(Length(data)); - SendString(Data); + i := SwapBytes(Length(data)); + SendString(Codelongint(i) + Data); end; -procedure TBlockSocket.SendStreamRaw(const Stream: TStream); +procedure TBlockSocket.InternalSendStream(const Stream: TStream; WithSize, Indy: boolean); var - si: integer; + si, l: integer; x, y, yr: integer; s: AnsiString; + b: boolean; {$IFDEF CIL} buf: TMemory; {$ENDIF} begin si := Stream.Size - Stream.Position; + if not indy then + l := SwapBytes(si) + else + l := si; x := 0; + b := true; while x < si do begin y := si - x; @@ -2157,6 +1948,11 @@ begin yr := Stream.read(buf, y); if yr > 0 then begin + if WithSize and b then + begin + b := false; + SendString(CodeLongInt(l)); + end; SendBuffer(buf, yr); if FLastError <> 0 then break; @@ -2170,7 +1966,13 @@ begin if yr > 0 then begin SetLength(s, yr); - SendString(s); + if WithSize and b then + begin + b := false; + SendString(CodeLongInt(l) + s); + end + else + SendString(s); if FLastError <> 0 then break; Inc(x, yr); @@ -2181,23 +1983,19 @@ begin end; end; -procedure TBlockSocket.SendStreamIndy(const Stream: TStream); -var - si: integer; +procedure TBlockSocket.SendStreamRaw(const Stream: TStream); begin - si := Stream.Size - Stream.Position; - si := synsock.HToNL(si); - SendInteger(si); - SendStreamRaw(Stream); + InternalSendStream(Stream, false, false); +end; + +procedure TBlockSocket.SendStreamIndy(const Stream: TStream); +begin + InternalSendStream(Stream, true, true); end; procedure TBlockSocket.SendStream(const Stream: TStream); -var - si: integer; begin - si := Stream.Size - Stream.Position; - SendInteger(si); - SendStreamRaw(Stream); + InternalSendStream(Stream, true, false); end; function TBlockSocket.RecvBuffer(Buffer: TMemory; Length: Integer): Integer; @@ -2213,10 +2011,13 @@ begin else SockCheck(Result); ExceptCheck; - Inc(FRecvCounter, Result); - DoStatus(HR_ReadCount, IntToStr(Result)); - DoMonitor(False, Buffer, Result); - DoReadFilter(Buffer, Result); + if Result > 0 then + begin + Inc(FRecvCounter, Result); + DoStatus(HR_ReadCount, IntToStr(Result)); + DoMonitor(False, Buffer, Result); + DoReadFilter(Buffer, Result); + end; end; function TBlockSocket.RecvBufferEx(Buffer: TMemory; Len: Integer; @@ -2224,45 +2025,49 @@ function TBlockSocket.RecvBufferEx(Buffer: TMemory; Len: Integer; var s: AnsiString; rl, l: integer; - ti: ULong; + ti: LongWord; {$IFDEF CIL} n: integer; b: TMemory; {$ENDIF} begin FLastError := 0; - rl := 0; - repeat - ti := GetTick; - s := RecvPacket(Timeout); - l := Length(s); - if (rl + l) > Len then - l := Len - rl; - {$IFDEF CIL} - b := BytesOf(s); - for n := 0 to l do - Buffer[rl + n] := b[n]; - {$ELSE} - Move(Pointer(s)^, IncPoint(Buffer, rl)^, l); - {$ENDIF} - rl := rl + l; - if FLastError <> 0 then - Break; - if rl >= Len then - Break; - if not FInterPacketTimeout then - begin - Timeout := Timeout - integer(TickDelta(ti, GetTick)); - if Timeout <= 0 then - begin - FLastError := WSAETIMEDOUT; + Result := 0; + if Len > 0 then + begin + rl := 0; + repeat + ti := GetTick; + s := RecvPacket(Timeout); + l := Length(s); + if (rl + l) > Len then + l := Len - rl; + {$IFDEF CIL} + b := BytesOf(s); + for n := 0 to l do + Buffer[rl + n] := b[n]; + {$ELSE} + Move(Pointer(s)^, IncPoint(Buffer, rl)^, l); + {$ENDIF} + rl := rl + l; + if FLastError <> 0 then Break; + if rl >= Len then + Break; + if not FInterPacketTimeout then + begin + Timeout := Timeout - integer(TickDelta(ti, GetTick)); + if Timeout <= 0 then + begin + FLastError := WSAETIMEDOUT; + Break; + end; end; - end; - until False; - delete(s, 1, l); - FBuffer := s; - Result := rl; + until False; + delete(s, 1, l); + FBuffer := s; + Result := rl; + end; end; function TBlockSocket.RecvBufferStr(Length: Integer; Timeout: Integer): AnsiString; @@ -2312,8 +2117,10 @@ begin end else begin + {$IFDEF WIN32} //not drain CPU on large downloads... Sleep(0); + {$ENDIF} x := WaitingData; if x > 0 then begin @@ -2361,6 +2168,15 @@ begin FLastError := WSAETIMEDOUT; end; end; + if FConvertLineEnd and (Result <> '') then + begin + if FLastCR and (Result[1] = LF) then + Delete(Result, 1, 1); + if FLastLF and (Result[1] = CR) then + Delete(Result, 1, 1); + FLastCR := False; + FLastLF := False; + end; ExceptCheck; end; @@ -2397,7 +2213,7 @@ var CorCRLF: Boolean; t: AnsiString; tl: integer; - ti: ULong; + ti: LongWord; begin FLastError := 0; Result := ''; @@ -2418,12 +2234,6 @@ begin if Length(s) > 0 then if CorCRLF then begin - if FLastCR and (s[1] = LF) then - Delete(s, 1, 1); - if FLastLF and (s[1] = CR) then - Delete(s, 1, 1); - FLastCR := False; - FLastLF := False; t := ''; x := PosCRLF(s, t); tl := Length(t); @@ -2623,8 +2433,10 @@ var x: Integer; begin Result := 0; - if synsock.IoctlSocket(FSocket, FIONREAD, u_long(x)) = 0 then + if synsock.IoctlSocket(FSocket, FIONREAD, x) = 0 then Result := x; + if Result > c64k then + Result := c64k; end; function TBlockSocket.WaitingDataEx: Integer; @@ -2640,7 +2452,11 @@ begin Sleep(1); try while (Length(FBuffer) > 0) or (WaitingData > 0) do + begin RecvPacket(0); + if FLastError <> 0 then + break; + end; except on exception do; end; @@ -2665,116 +2481,13 @@ begin Result := '127.0.0.1'; end; -{$IFDEF CIL} procedure TBlockSocket.ResolveNameToIP(Name: string; const IPList: TStrings); -var - IPs :array of IPAddress; - n: integer; begin IPList.Clear; - IPs := Dns.Resolve(Name).AddressList; - for n := low(IPs) to high(IPs) do - begin - if not(((FFamily = SF_IP6) and (IPs[n].AddressFamily = AF_INET)) - or ((FFamily = SF_IP4) and (IPs[n].AddressFamily = AF_INET6))) then - begin - IPList.Add(IPs[n].toString); - end; - end; -end; - -{$ELSE} -procedure TBlockSocket.ResolveNameToIP(Name: string; const IPList: TStrings); -type - TaPInAddr = array[0..250] of PInAddr; - PaPInAddr = ^TaPInAddr; -var - Hints: TAddrInfo; - Addr: PAddrInfo; - AddrNext: PAddrInfo; - r: integer; - host, serv: string; - hostlen, servlen: integer; - RemoteHost: PHostEnt; - IP: u_long; - PAdrPtr: PaPInAddr; - i: Integer; - s: string; - InAddr: TInAddr; -begin - IPList.Clear; - if not IsNewApi then - begin - IP := synsock.inet_addr(PChar(Name)); - if IP = u_long(INADDR_NONE) then - begin - SynSockCS.Enter; - try - RemoteHost := synsock.GetHostByName(PChar(Name)); - if RemoteHost <> nil then - begin - PAdrPtr := PAPInAddr(RemoteHost^.h_addr_list); - i := 0; - while PAdrPtr^[i] <> nil do - begin - InAddr := PAdrPtr^[i]^; - with InAddr.S_un_b do - s := Format('%d.%d.%d.%d', - [Ord(s_b1), Ord(s_b2), Ord(s_b3), Ord(s_b4)]); - IPList.Add(s); - Inc(i); - end; - end; - finally - SynSockCS.Leave; - end; - end - else - IPList.Add(Name); - end - else - begin - Addr := nil; - try - FillChar(Hints, Sizeof(Hints), 0); - Hints.ai_family := AF_UNSPEC; - Hints.ai_socktype := GetSocketType; - Hints.ai_protocol := GetSocketprotocol; - Hints.ai_flags := 0; - r := synsock.GetAddrInfo(PChar(Name), nil, @Hints, Addr); - if r = 0 then - begin - AddrNext := Addr; - while not(AddrNext = nil) do - begin - if not(((FFamily = SF_IP6) and (AddrNext^.ai_family = AF_INET)) - or ((FFamily = SF_IP4) and (AddrNext^.ai_family = AF_INET6))) then - begin - hostlen := NI_MAXHOST; - servlen := NI_MAXSERV; - setlength(host, hostlen); - setlength(serv, servlen); - r := getnameinfo(AddrNext^.ai_addr, AddrNext^.ai_addrlen, - PChar(host), hostlen, PChar(serv), servlen, - NI_NUMERICHOST + NI_NUMERICSERV); - if r = 0 then - begin - host := PChar(host); - IPList.Add(host); - end; - end; - AddrNext := AddrNext^.ai_next; - end; - end; - finally - if Assigned(Addr) then - synsock.FreeAddrInfo(Addr); - end; - end; + synsock.ResolveNameToIP(Name, FamilyToAF(FFamily), GetSocketprotocol, GetSocketType, IPList); if IPList.Count = 0 then IPList.Add(cAnyHost); end; -{$ENDIF} function TBlockSocket.ResolveName(Name: string): string; var @@ -2790,123 +2503,16 @@ begin end; function TBlockSocket.ResolvePort(Port: string): Word; -{$IFDEF CIL} begin - Result := SynSock.GetPortService(Port); + Result := synsock.ResolvePort(Port, FamilyToAF(FFamily), GetSocketProtocol, GetSocketType); end; -{$ELSE} -var - ProtoEnt: PProtoEnt; - ServEnt: PServEnt; - Hints: TAddrInfo; - Addr: PAddrInfo; - r: integer; -begin - Result := 0; - if not IsNewApi then - begin - SynSockCS.Enter; - try - ProtoEnt := synsock.GetProtoByNumber(GetSocketProtocol); - ServEnt := nil; - if ProtoEnt <> nil then - ServEnt := synsock.GetServByName(PChar(Port), ProtoEnt^.p_name); - if ServEnt = nil then - Result := StrToIntDef(Port, 0) - else - Result := synsock.htons(ServEnt^.s_port); - finally - SynSockCS.Leave; - end; - end - else - begin - Addr := nil; - try - FillChar(Hints, Sizeof(Hints), 0); - Hints.ai_family := AF_UNSPEC; - Hints.ai_socktype := GetSocketType; - Hints.ai_protocol := GetSocketprotocol; - Hints.ai_flags := AI_PASSIVE; - r := synsock.GetAddrInfo(nil, PChar(Port), @Hints, Addr); - if (r = 0) and Assigned(Addr) then - begin - if Addr^.ai_family = AF_INET then - Result := synsock.htons(Addr^.ai_addr^.sin_port); - if Addr^.ai_family = AF_INET6 then - Result := synsock.htons(PSockAddrIn6(Addr^.ai_addr)^.sin6_port); - end; - finally - if Assigned(Addr) then - synsock.FreeAddrInfo(Addr); - end; - end; -end; -{$ENDIF} -{$IFDEF CIL} function TBlockSocket.ResolveIPToName(IP: string): string; begin - Result := Dns.GetHostByAddress(IP).HostName; + if not IsIP(IP) or not IsIp6(IP) then + IP := ResolveName(IP); + Result := synsock.ResolveIPToName(IP, FamilyToAF(FFamily), GetSocketProtocol, GetSocketType); end; -{$ELSE} -function TBlockSocket.ResolveIPToName(IP: string): string; -var - Hints: TAddrInfo; - Addr: PAddrInfo; - r: integer; - host, serv: string; - hostlen, servlen: integer; - RemoteHost: PHostEnt; - IPn: u_long; -begin - Result := IP; - if not IsNewApi then - begin - if not IsIP(IP) then - IP := ResolveName(IP); - IPn := synsock.inet_addr(PChar(IP)); - if IPn <> u_long(INADDR_NONE) then - begin - SynSockCS.Enter; - try - RemoteHost := GetHostByAddr(@IPn, SizeOf(IPn), AF_INET); - if RemoteHost <> nil then - Result := RemoteHost^.h_name; - finally - SynSockCS.Leave; - end; - end; - end - else - begin - Addr := nil; - try - FillChar(Hints, Sizeof(Hints), 0); - Hints.ai_family := AF_UNSPEC; - Hints.ai_socktype := GetSocketType; - Hints.ai_protocol := GetSocketprotocol; - Hints.ai_flags := 0; - r := synsock.GetAddrInfo(PChar(IP), nil, @Hints, Addr); - if (r = 0) and Assigned(Addr)then - begin - hostlen := NI_MAXHOST; - servlen := NI_MAXSERV; - setlength(host, hostlen); - setlength(serv, servlen); - r := getnameinfo(Addr^.ai_addr, Addr^.ai_addrlen, - PChar(host), hostlen, PChar(serv), servlen, - NI_NUMERICSERV); - if r = 0 then - Result := PChar(host); - end; - finally - if Assigned(Addr) then - synsock.FreeAddrInfo(Addr); - end; - end; -end; -{$ENDIF} procedure TBlockSocket.SetRemoteSin(IP, Port: string); begin @@ -3004,7 +2610,7 @@ begin Exit; DoMonitor(True, Buffer, Length); LimitBandwidth(Length, FMaxSendBandwidth, FNextsend); - Result := synsock.SendTo(FSocket, Buffer, Length, 0, FRemoteSin); + Result := synsock.SendTo(FSocket, Buffer, Length, MSG_NOSIGNAL, FRemoteSin); SockCheck(Result); ExceptCheck; Inc(FSendCounter, Result); @@ -3017,7 +2623,7 @@ begin if TestStopFlag then Exit; LimitBandwidth(Length, FMaxRecvBandwidth, FNextRecv); - Result := synsock.RecvFrom(FSocket, Buffer, Length, 0, FRemoteSin); + Result := synsock.RecvFrom(FSocket, Buffer, Length, MSG_NOSIGNAL, FRemoteSin); SockCheck(Result); ExceptCheck; Inc(FRecvCounter, Result); @@ -3212,107 +2818,6 @@ begin FIP6Used := FRemoteSin.AddressFamily = AF_INET6; end; -{$IFDEF CIL} -function TBlockSocket.StrToIP6(const value: string): TSockAddrIn6; -var - buf: TMemory; - IP: IPAddress; -begin - IP := IPAddress.Parse(Value); - buf := IP.GetAddressBytes; - result.sin6_addr.S_un_b.s_b1 := char(buf[0]); - result.sin6_addr.S_un_b.s_b2 := char(buf[1]); - result.sin6_addr.S_un_b.s_b3 := char(buf[2]); - result.sin6_addr.S_un_b.s_b4 := char(buf[3]); - result.sin6_addr.S_un_b.s_b5 := char(buf[4]); - result.sin6_addr.S_un_b.s_b6 := char(buf[5]); - result.sin6_addr.S_un_b.s_b7 := char(buf[6]); - result.sin6_addr.S_un_b.s_b8 := char(buf[7]); - result.sin6_addr.S_un_b.s_b9 := char(buf[8]); - result.sin6_addr.S_un_b.s_b10 := char(buf[9]); - result.sin6_addr.S_un_b.s_b11 := char(buf[10]); - result.sin6_addr.S_un_b.s_b12 := char(buf[11]); - result.sin6_addr.S_un_b.s_b13 := char(buf[12]); - result.sin6_addr.S_un_b.s_b14 := char(buf[13]); - result.sin6_addr.S_un_b.s_b15 := char(buf[14]); - result.sin6_addr.S_un_b.s_b16 := char(buf[15]); - result.sin6_family := Word(AF_INET6); -end; -{$ELSE} -function TBlockSocket.StrToIP6(const value: string): TSockAddrIn6; -var - addr: PAddrInfo; - hints: TAddrInfo; - r: integer; -begin - FillChar(Result, Sizeof(Result), 0); - if SockEnhancedApi or SockWship6Api then - begin - Addr := nil; - try - FillChar(Hints, Sizeof(Hints), 0); - Hints.ai_family := AF_INET6; - Hints.ai_flags := AI_NUMERICHOST; - r := synsock.GetAddrInfo(PChar(value), nil, @Hints, Addr); - if (r = 0) and Assigned(Addr) then - if (Addr^.ai_family = AF_INET6) then - Move(Addr^.ai_addr^, Result, SizeOf(Result)); - finally - if Assigned(Addr) then - synsock.FreeAddrInfo(Addr); - end; - end; -end; -{$ENDIF} - -{$IFDEF CIL} -function TBlockSocket.IP6ToStr(const value: TSockAddrIn6): string; -var - buf: TMemory; - IP: IPAddress; -begin - setlength(buf, 16); - buf[0] := byte(value.sin6_addr.S_un_b.s_b1); - buf[1] := byte(value.sin6_addr.S_un_b.s_b2); - buf[2] := byte(value.sin6_addr.S_un_b.s_b3); - buf[3] := byte(value.sin6_addr.S_un_b.s_b4); - buf[4] := byte(value.sin6_addr.S_un_b.s_b5); - buf[5] := byte(value.sin6_addr.S_un_b.s_b6); - buf[6] := byte(value.sin6_addr.S_un_b.s_b7); - buf[7] := byte(value.sin6_addr.S_un_b.s_b8); - buf[8] := byte(value.sin6_addr.S_un_b.s_b9); - buf[9] := byte(value.sin6_addr.S_un_b.s_b10); - buf[10] := byte(value.sin6_addr.S_un_b.s_b11); - buf[11] := byte(value.sin6_addr.S_un_b.s_b12); - buf[12] := byte(value.sin6_addr.S_un_b.s_b13); - buf[13] := byte(value.sin6_addr.S_un_b.s_b14); - buf[14] := byte(value.sin6_addr.S_un_b.s_b15); - buf[15] := byte(value.sin6_addr.S_un_b.s_b16); - IP := IPAddress.Create(buf); - Result := IP.ToString; -end; -{$ELSE} -function TBlockSocket.IP6ToStr(const value: TSockAddrIn6): string; -var - host, serv: string; - hostlen, servlen: integer; - r: integer; -begin - Result := ''; - if SockEnhancedApi or SockWship6Api then - begin - hostlen := NI_MAXHOST; - servlen := NI_MAXSERV; - setlength(host, hostlen); - setlength(serv, servlen); - r := getnameinfo(@Value, SizeOf(value), PChar(host), hostlen, - PChar(serv), servlen, NI_NUMERICHOST + NI_NUMERICSERV); - if r = 0 then - Result := PChar(host); - end; -end; -{$ENDIF} - function TBlockSocket.GetWsaData: TWSAData; begin Result := WsaDataOnce; @@ -3648,8 +3153,8 @@ end; function TSocksBlockSocket.SocksCode(IP, Port: string): string; var - s: string; - ip6: TSockAddrIn6; + ip6: TIp6Bytes; + n: integer; begin if FSocksType <> ST_Socks5 then begin @@ -3678,24 +3183,9 @@ begin if IsIP6(IP) then begin ip6 := StrToIP6(IP); - setlength(s, 16); - s[1] := ip6.sin6_addr.S_un_b.s_b1; - s[2] := ip6.sin6_addr.S_un_b.s_b2; - s[3] := ip6.sin6_addr.S_un_b.s_b3; - s[4] := ip6.sin6_addr.S_un_b.s_b4; - s[5] := ip6.sin6_addr.S_un_b.s_b5; - s[6] := ip6.sin6_addr.S_un_b.s_b6; - s[7] := ip6.sin6_addr.S_un_b.s_b7; - s[8] := ip6.sin6_addr.S_un_b.s_b8; - s[9] := ip6.sin6_addr.S_un_b.s_b9; - s[10] := ip6.sin6_addr.S_un_b.s_b10; - s[11] := ip6.sin6_addr.S_un_b.s_b11; - s[12] := ip6.sin6_addr.S_un_b.s_b12; - s[13] := ip6.sin6_addr.S_un_b.s_b13; - s[14] := ip6.sin6_addr.S_un_b.s_b14; - s[15] := ip6.sin6_addr.S_un_b.s_b15; - s[16] := ip6.sin6_addr.S_un_b.s_b16; - Result := #4 + s; + Result := #4; + for n := 0 to 15 do + Result := Result + char(ip6[n]); end else Result := #3 + char(Length(IP)) + IP; @@ -3708,7 +3198,7 @@ var Atyp: Byte; y, n: integer; w: Word; - ip6: TSockAddrIn6; + ip6: TIp6Bytes; begin FSocksResponsePort := '0'; Result := 0; @@ -3751,26 +3241,8 @@ begin begin if Length(Value) < 22 then Exit; - ip6.sin6_addr.S_un_b.s_b1 := Value[5]; - ip6.sin6_addr.S_un_b.s_b2 := Value[6]; - ip6.sin6_addr.S_un_b.s_b3 := Value[7]; - ip6.sin6_addr.S_un_b.s_b4 := Value[8]; - ip6.sin6_addr.S_un_b.s_b5 := Value[9]; - ip6.sin6_addr.S_un_b.s_b6 := Value[10]; - ip6.sin6_addr.S_un_b.s_b7 := Value[11]; - ip6.sin6_addr.S_un_b.s_b8 := Value[12]; - ip6.sin6_addr.S_un_b.s_b9 := Value[13]; - ip6.sin6_addr.S_un_b.s_b10 := Value[14]; - ip6.sin6_addr.S_un_b.s_b11 := Value[15]; - ip6.sin6_addr.S_un_b.s_b12 := Value[16]; - ip6.sin6_addr.S_un_b.s_b13 := Value[17]; - ip6.sin6_addr.S_un_b.s_b14 := Value[18]; - ip6.sin6_addr.S_un_b.s_b15 := Value[19]; - ip6.sin6_addr.S_un_b.s_b16 := Value[20]; - ip6.sin6_family := word(AF_INET6); - ip6.sin6_port := 0; - ip6.sin6_flowinfo := 0; - ip6.sin6_scope_id := 0; + for n := 0 to 15 do + ip6[n] := ord(Value[n + 5]); FSocksResponseIP := IP6ToStr(ip6); Result := 21; end; @@ -3913,18 +3385,22 @@ procedure TUDPBlockSocket.AddMulticast(MCastIP: string); var Multicast: TIP_mreq; Multicast6: TIPv6_mreq; + n: integer; + ip6: Tip6bytes; begin if FIP6Used then begin - Multicast6.ipv6mr_multiaddr := StrToIp6(MCastIP).sin6_addr; + ip6 := StrToIp6(MCastIP); + for n := 0 to 15 do + Multicast6.ipv6mr_multiaddr.u6_addr8[n] := Ip6[n]; Multicast6.ipv6mr_interface := 0; SockCheck(synsock.SetSockOpt(FSocket, IPPROTO_IPV6, IPV6_JOIN_GROUP, pchar(@Multicast6), SizeOf(Multicast6))); end else begin - Multicast.imr_multiaddr.S_addr := synsock.inet_addr(PChar(MCastIP)); - Multicast.imr_interface.S_addr := u_long(INADDR_ANY); + Multicast.imr_multiaddr.S_addr := strtoip(MCastIP); + Multicast.imr_interface.S_addr := INADDR_ANY; SockCheck(synsock.SetSockOpt(FSocket, IPPROTO_IP, IP_ADD_MEMBERSHIP, pchar(@Multicast), SizeOf(Multicast))); end; @@ -3935,18 +3411,22 @@ procedure TUDPBlockSocket.DropMulticast(MCastIP: string); var Multicast: TIP_mreq; Multicast6: TIPv6_mreq; + n: integer; + ip6: Tip6bytes; begin if FIP6Used then begin - Multicast6.ipv6mr_multiaddr := StrToIp6(MCastIP).sin6_addr; + ip6 := StrToIp6(MCastIP); + for n := 0 to 15 do + Multicast6.ipv6mr_multiaddr.u6_addr8[n] := Ip6[n]; Multicast6.ipv6mr_interface := 0; SockCheck(synsock.SetSockOpt(FSocket, IPPROTO_IPV6, IPV6_LEAVE_GROUP, pchar(@Multicast6), SizeOf(Multicast6))); end else begin - Multicast.imr_multiaddr.S_addr := synsock.inet_addr(PChar(MCastIP)); - Multicast.imr_interface.S_addr := u_long(INADDR_ANY); + Multicast.imr_multiaddr.S_addr := strtoip(MCastIP); + Multicast.imr_interface.S_addr := INADDR_ANY; SockCheck(synsock.SetSockOpt(FSocket, IPPROTO_IP, IP_DROP_MEMBERSHIP, pchar(@Multicast), SizeOf(Multicast))); end; @@ -4038,7 +3518,7 @@ end; function TTCPBlockSocket.WaitingData: Integer; begin Result := 0; - if FSSL.SSLEnabled then + if FSSL.SSLEnabled and (FSocket <> INVALID_SOCKET) then Result := FSSL.WaitingData; if Result = 0 then Result := inherited WaitingData; diff --git a/clamsend.pas b/clamsend.pas new file mode 100644 index 0000000..81dd5f6 --- /dev/null +++ b/clamsend.pas @@ -0,0 +1,218 @@ +{==============================================================================| +| Project : Ararat Synapse | 001.000.000 | +|==============================================================================| +| Content: ClamAV-daemon client | +|==============================================================================| +| Copyright (c)2005, Lukas Gebauer | +| All rights reserved. | +| | +| 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. | +| | +| Redistributions in binary form must reproduce the above copyright notice, | +| this list of conditions and the following disclaimer in the documentation | +| and/or other materials provided with the distribution. | +| | +| Neither the name of Lukas Gebauer nor the names of its contributors may | +| be used to endorse or promote products derived from this software without | +| specific prior written permission. | +| | +| 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. | +|==============================================================================| +| The Initial Developer of the Original Code is Lukas Gebauer (Czech Republic).| +| Portions created by Lukas Gebauer are Copyright (c)2003. | +| All Rights Reserved. | +|==============================================================================| +| Contributor(s): | +|==============================================================================| +| History: see HISTORY.HTM from distribution package | +| (Found at URL: http://www.ararat.cz/synapse/) | +|==============================================================================} + +{:@abstract( ClamAV-daemon client) + +This unit is capable to do antivirus scan of your data by TCP channel to ClamD +daemon from ClamAV. See more about ClamAV on @LINK(http://www.clamav.net) +} + +{$IFDEF FPC} + {$MODE DELPHI} +{$ENDIF} +{$Q-} +{$H+} + +unit clamsend; + +interface + +uses + SysUtils, Classes, + synsock, blcksock, synautil; + +const + cClamProtocol = '3310'; + +type + + {:@abstract(Implementation of ClamAV-daemon client protocol) + By this class you can scan any your data by ClamAV opensource antivirus. + + This class can connect to ClamD by TCP channel, send your data to ClamD + and read result.} + TClamSend = class(TSynaClient) + private + FSock: TTCPBlockSocket; + FDSock: TTCPBlockSocket; + FSession: boolean; + function Login: boolean; virtual; + function Logout: Boolean; virtual; + function OpenStream: Boolean; virtual; + public + constructor Create; + destructor Destroy; override; + + {:Call any command to ClamD. Used internally by other methods.} + function DoCommand(const Value: AnsiString): AnsiString; virtual; + + {:Return ClamAV version and version of loaded databases.} + function GetVersion: AnsiString; virtual; + + {:Scan content of TStrings.} + function ScanStrings(const Value: TStrings): AnsiString; virtual; + + {:Scan content of TStream.} + function ScanStream(const Value: TStream): AnsiString; virtual; + published + {:Socket object used for TCP/IP operation. Good for seting OnStatus hook, etc.} + property Sock: TTCPBlockSocket read FSock; + + {:Socket object used for TCP data transfer operation. Good for seting OnStatus hook, etc.} + property DSock: TTCPBlockSocket read FDSock; + + {:Can turn-on session mode of communication with ClamD. Default is @false, + because ClamAV developers design their TCP code very badly and session mode + is broken now (CVS-20051031). Maybe ClamAV developers fix their bugs + and this mode will be possible in future.} + property Session: boolean read FSession write FSession; + end; + +implementation + +constructor TClamSend.Create; +begin + inherited Create; + FSock := TTCPBlockSocket.Create; + FDSock := TTCPBlockSocket.Create; + FTimeout := 60000; + FTargetPort := cClamProtocol; + FSession := false; +end; + +destructor TClamSend.Destroy; +begin + Logout; + FDSock.Free; + FSock.Free; + inherited Destroy; +end; + +function TClamSend.DoCommand(const Value: AnsiString): AnsiString; +begin + Result := ''; + if not FSession then + FSock.CloseSocket + else + FSock.SendString(Value + LF); + if not FSession or (FSock.LastError <> 0) then + begin + if Login then + FSock.SendString(Value + LF) + else + Exit; + end; + Result := FSock.RecvTerminated(FTimeout, LF); +end; + +function TClamSend.Login: boolean; +begin + Result := False; + Sock.CloseSocket; + FSock.Bind(FIPInterface, cAnyPort); + if FSock.LastError <> 0 then + Exit; + FSock.Connect(FTargetHost, FTargetPort); + if FSock.LastError <> 0 then + Exit; + if FSession then + FSock.SendString('SESSION' + LF); + Result := FSock.LastError = 0; +end; + +function TClamSend.Logout: Boolean; +begin + FSock.SendString('END' + LF); + Result := FSock.LastError = 0; + FSock.CloseSocket; +end; + +function TClamSend.GetVersion: AnsiString; +begin + Result := DoCommand('VERSION'); +end; + +function TClamSend.OpenStream: Boolean; +var + S: AnsiString; +begin + Result := False; + s := DoCommand('STREAM'); + if (s <> '') and (Copy(s, 1, 4) = 'PORT') then + begin + s := SeparateRight(s, ' '); + FDSock.CloseSocket; + FDSock.Bind(FIPInterface, cAnyPort); + if FDSock.LastError <> 0 then + Exit; + FDSock.Connect(FTargetHost, s); + if FDSock.LastError <> 0 then + Exit; + Result := True; + end; +end; + +function TClamSend.ScanStrings(const Value: TStrings): AnsiString; +begin + Result := ''; + if OpenStream then + begin + DSock.SendString(Value.Text); + DSock.CloseSocket; + Result := FSock.RecvTerminated(FTimeout, LF); + end; +end; + +function TClamSend.ScanStream(const Value: TStream): AnsiString; +begin + Result := ''; + if OpenStream then + begin + DSock.SendStreamRaw(Value); + DSock.CloseSocket; + Result := FSock.RecvTerminated(FTimeout, LF); + end; +end; + +end. diff --git a/dnssend.pas b/dnssend.pas index 2e21865..16f0cb9 100644 --- a/dnssend.pas +++ b/dnssend.pas @@ -1,5 +1,5 @@ {==============================================================================| -| Project : Ararat Synapse | 002.007.000 | +| Project : Ararat Synapse | 002.007.003 | |==============================================================================| | Content: DNS client | |==============================================================================| @@ -60,7 +60,7 @@ interface uses SysUtils, Classes, - blcksock, synautil, synsock; + blcksock, synautil, synaip, synsock; const cDnsProtocol = 'domain'; @@ -120,13 +120,11 @@ type FSock: TUDPBlockSocket; FTCPSock: TTCPBlockSocket; FUseTCP: Boolean; - FAnsferInfo: TStringList; + FAnswerInfo: TStringList; FNameserverInfo: TStringList; FAdditionalInfo: TStringList; FAuthoritative: Boolean; FTruncated: Boolean; - function ReverseIP(Value: AnsiString): AnsiString; - function ReverseIP6(Value: AnsiString): AnsiString; function CompressName(const Value: AnsiString): AnsiString; function CodeHeader: AnsiString; function CodeQuery(const Name: AnsiString; QType: Integer): AnsiString; @@ -177,16 +175,16 @@ type 4-not implemented, 5-refused.} property RCode: Integer read FRCode; - {:@True, if ansfer is authoritative.} + {:@True, if answer is authoritative.} property Authoritative: Boolean read FAuthoritative; - {:@True, if ansfer is truncated to 512 bytes.} + {:@True, if answer is truncated to 512 bytes.} property Truncated: Boolean read FTRuncated; {:Detailed informations from name server reply. One record per line. Record have comma delimited entries with type number, TTL and data filelds. This information contains detailed information about query reply.} - property AnsferInfo: TStringList read FAnsferInfo; + property AnswerInfo: TStringList read FAnswerInfo; {:Detailed informations from name server reply. One record per line. Record have comma delimited entries with type number, TTL and data filelds. @@ -218,7 +216,7 @@ begin FUseTCP := False; FTimeout := 10000; FTargetPort := cDnsProtocol; - FAnsferInfo := TStringList.Create; + FAnswerInfo := TStringList.Create; FNameserverInfo := TStringList.Create; FAdditionalInfo := TStringList.Create; Randomize; @@ -226,7 +224,7 @@ end; destructor TDNSSend.Destroy; begin - FAnsferInfo.Free; + FAnswerInfo.Free; FNameserverInfo.Free; FAdditionalInfo.Free; FTCPSock.Free; @@ -234,44 +232,6 @@ begin inherited Destroy; end; -function TDNSSend.ReverseIP(Value: AnsiString): AnsiString; -var - x: Integer; -begin - Result := ''; - repeat - x := LastDelimiter('.', Value); - Result := Result + '.' + Copy(Value, x + 1, Length(Value) - x); - Delete(Value, x, Length(Value) - x + 1); - until x < 1; - if Length(Result) > 0 then - if Result[1] = '.' then - Delete(Result, 1, 1); -end; - -function TDNSSend.ReverseIP6(Value: AnsiString): AnsiString; -var - ip6: TSockAddrIn6; -begin - ip6 := FSock.StrToIP6(Value); - Result := ip6.sin6_addr.S_un_b.s_b16 - + '.' + ip6.sin6_addr.S_un_b.s_b15 - + '.' + ip6.sin6_addr.S_un_b.s_b14 - + '.' + ip6.sin6_addr.S_un_b.s_b13 - + '.' + ip6.sin6_addr.S_un_b.s_b12 - + '.' + ip6.sin6_addr.S_un_b.s_b11 - + '.' + ip6.sin6_addr.S_un_b.s_b10 - + '.' + ip6.sin6_addr.S_un_b.s_b9 - + '.' + ip6.sin6_addr.S_un_b.s_b8 - + '.' + ip6.sin6_addr.S_un_b.s_b7 - + '.' + ip6.sin6_addr.S_un_b.s_b6 - + '.' + ip6.sin6_addr.S_un_b.s_b5 - + '.' + ip6.sin6_addr.S_un_b.s_b4 - + '.' + ip6.sin6_addr.S_un_b.s_b3 - + '.' + ip6.sin6_addr.S_un_b.s_b2 - + '.' + ip6.sin6_addr.S_un_b.s_b1; -end; - function TDNSSend.CompressName(const Value: AnsiString): AnsiString; var n: Integer; @@ -363,7 +323,7 @@ var RType, Len, j, x, y, z, n: Integer; R: AnsiString; t1, t2, ttl: integer; - ip6: TSockAddrIn6; + ip6: TIp6bytes; begin Result := ''; R := ''; @@ -393,28 +353,9 @@ begin end; QTYPE_AAAA: begin -// FillChar(ip6, SizeOf(ip6), 0); - ip6.sin6_addr.S_un_b.s_b1 := Char(FBuffer[j]); - ip6.sin6_addr.S_un_b.s_b2 := Char(FBuffer[j + 1]); - ip6.sin6_addr.S_un_b.s_b3 := Char(FBuffer[j + 2]); - ip6.sin6_addr.S_un_b.s_b4 := Char(FBuffer[j + 3]); - ip6.sin6_addr.S_un_b.s_b5 := Char(FBuffer[j + 4]); - ip6.sin6_addr.S_un_b.s_b6 := Char(FBuffer[j + 5]); - ip6.sin6_addr.S_un_b.s_b7 := Char(FBuffer[j + 6]); - ip6.sin6_addr.S_un_b.s_b8 := Char(FBuffer[j + 7]); - ip6.sin6_addr.S_un_b.s_b9 := Char(FBuffer[j + 8]); - ip6.sin6_addr.S_un_b.s_b10 := Char(FBuffer[j + 9]); - ip6.sin6_addr.S_un_b.s_b11 := Char(FBuffer[j + 10]); - ip6.sin6_addr.S_un_b.s_b12 := Char(FBuffer[j + 11]); - ip6.sin6_addr.S_un_b.s_b13 := Char(FBuffer[j + 12]); - ip6.sin6_addr.S_un_b.s_b14 := Char(FBuffer[j + 13]); - ip6.sin6_addr.S_un_b.s_b15 := Char(FBuffer[j + 14]); - ip6.sin6_addr.S_un_b.s_b16 := Char(FBuffer[j + 15]); - ip6.sin6_family := word(AF_INET6); - ip6.sin6_port := 0; - ip6.sin6_flowinfo := 0; - ip6.sin6_scope_id := 0; - R := FSock.IP6ToStr(ip6); + for n := 0 to 15 do + ip6[n] := ord(FBuffer[j + n]); + R := IP6ToStr(ip6); end; QTYPE_NS, QTYPE_MD, QTYPE_MF, QTYPE_CNAME, QTYPE_MB, QTYPE_MG, QTYPE_MR, QTYPE_PTR, QTYPE_X25, QTYPE_NSAP, @@ -514,7 +455,7 @@ var begin Result := False; Reply.Clear; - FAnsferInfo.Clear; + FAnswerInfo.Clear; FNameserverInfo.Clear; FAdditionalInfo.Clear; FAuthoritative := False; @@ -542,7 +483,7 @@ begin if (ancount > 0) and (Length(Buf) > i) then // decode reply for n := 1 to ancount do begin - s := DecodeResource(i, FAnsferInfo, QType); + s := DecodeResource(i, FAnswerInfo, QType); if s <> '' then Reply.Add(s); end; @@ -588,11 +529,11 @@ begin try repeat b := DecodeResponse(FBuffer, Reply, QType); - if (t.Count > 1) and (AnsferInfo.Count > 0) then //find end of transfer - b := b and (t[0] <> AnsferInfo[AnsferInfo.count - 1]); + if (t.Count > 1) and (AnswerInfo.Count > 0) then //find end of transfer + b := b and (t[0] <> AnswerInfo[AnswerInfo.count - 1]); if b then begin - t.AddStrings(AnsferInfo); + t.AddStrings(AnswerInfo); FBuffer := RecvTCPResponse(WorkSock); if FBuffer = '' then Break; diff --git a/ftpsend.pas b/ftpsend.pas index 1c1ff1c..2ec6f7f 100644 --- a/ftpsend.pas +++ b/ftpsend.pas @@ -1,5 +1,5 @@ {==============================================================================| -| Project : Ararat Synapse | 003.004.005 | +| Project : Ararat Synapse | 003.004.008 | |==============================================================================| | Content: FTP client | |==============================================================================| @@ -59,7 +59,7 @@ interface uses SysUtils, Classes, - blcksock, synautil, synsock; + blcksock, synautil, synaip, synsock; const cFtpProtocol = 'ftp'; @@ -1220,6 +1220,7 @@ begin //VMS FMasks.add('v*$ DD TTT YYYY hh mm'); FMasks.add('v*$!DD TTT YYYY hh mm'); + FMasks.add('n*$ YYYY MM DD hh mm$S*'); //AS400 FMasks.add('!S*$MM DD YY hh mm ss !n*'); FMasks.add('!S*$DD MM YY hh mm ss !n*'); @@ -1246,7 +1247,7 @@ begin //tandem FMasks.add('nnnnnnnn SSSSSSS DD TTT YY hh mm ss'); //MVS - FMasks.add('- YYYY MM DD SSSSS d=O n*'); + FMasks.add('- YYYY MM DD SSSSS d=O n*'); //BullGCOS8 FMasks.add(' $S* MM DD YY hh mm ss !n*'); FMasks.add('d $S* MM DD YY !n*'); @@ -1738,14 +1739,14 @@ begin if Value[1] = '+' then begin os := Value; + Delete(Value, 1, 1); flr := TFTPListRec.create; + flr.FileName := SeparateRight(Value, #9); s := Fetch(Value, ','); while s <> '' do begin if s[1] = #9 then - begin - flr.FileName := Copy(s, 2, Length(s) - 1); - end; + Break; case s[1] of '/': flr.Directory := true; diff --git a/httpsend.pas b/httpsend.pas index 2e9e937..b23812d 100644 --- a/httpsend.pas +++ b/httpsend.pas @@ -1,9 +1,9 @@ {==============================================================================| -| Project : Ararat Synapse | 003.010.001 | +| Project : Ararat Synapse | 003.010.005 | |==============================================================================| | Content: HTTP client | |==============================================================================| -| Copyright (c)1999-2005, Lukas Gebauer | +| Copyright (c)1999-2006, Lukas Gebauer | | All rights reserved. | | | | Redistribution and use in source and binary forms, with or without | @@ -33,7 +33,7 @@ | DAMAGE. | |==============================================================================| | The Initial Developer of the Original Code is Lukas Gebauer (Czech Republic).| -| Portions created by Lukas Gebauer are Copyright (c) 1999-2005. | +| Portions created by Lukas Gebauer are Copyright (c) 1999-2006. | | All Rights Reserved. | |==============================================================================| | Contributor(s): | @@ -58,7 +58,7 @@ interface uses SysUtils, Classes, - blcksock, synautil, synacode; + blcksock, synautil, synaip, synacode, synsock; const cHttpProtocol = '80'; @@ -97,6 +97,9 @@ type function ReadIdentity(Size: Integer): Boolean; function ReadChunked: Boolean; procedure ParseCookies; + function PrepareHeaders: string; + function InternalDoConnect(needssl: Boolean): Boolean; + function InternalConnect(needssl: Boolean): Boolean; public constructor Create; destructor Destroy; override; @@ -302,6 +305,51 @@ begin FResultString := ''; end; +function THTTPSend.PrepareHeaders: string; +begin + if FProtocol = '0.9' then + Result := FHeaders[0] + CRLF + else +{$IFNDEF WIN32} + Result := AdjustLineBreaks(FHeaders.Text, tlbsCRLF); +{$ELSE} + Result := FHeaders.Text; +{$ENDIF} +end; + +function THTTPSend.InternalDoConnect(needssl: Boolean): Boolean; +begin + Result := False; + FSock.CloseSocket; + FSock.Bind(FIPInterface, cAnyPort); + if FSock.LastError <> 0 then + Exit; + FSock.Connect(FTargetHost, FTargetPort); + if FSock.LastError <> 0 then + Exit; + if needssl then + begin + FSock.SSLDoConnect; + if FSock.LastError <> 0 then + Exit; + end; + FAliveHost := FTargetHost; + FAlivePort := FTargetPort; + Result := True; +end; + +function THTTPSend.InternalConnect(needssl: Boolean): Boolean; +begin + if FSock.Socket = INVALID_SOCKET then + Result := InternalDoConnect(needssl) + else + if (FAliveHost <> FTargetHost) or (FAlivePort <> FTargetPort) + or FSock.CanRead(0) then + Result := InternalDoConnect(needssl) + else + Result := True; +end; + function THTTPSend.HTTPMethod(const Method, URL: string): Boolean; var Sending, Receiving: Boolean; @@ -344,14 +392,14 @@ begin FSock.HTTPTunnelPass := ''; end; - Sending := Document.Size > 0; + Sending := FDocument.Size > 0; {Headers for Sending data} status100 := FStatus100 and Sending and (FProtocol = '1.1'); if status100 then FHeaders.Insert(0, 'Expect: 100-continue'); - FHeaders.Insert(0, 'Content-Length: ' + IntToStr(FDocument.Size)); if Sending then begin + FHeaders.Insert(0, 'Content-Length: ' + IntToStr(FDocument.Size)); if FMimeType <> '' then FHeaders.Insert(0, 'Content-Type: ' + FMimeType); end; @@ -415,91 +463,68 @@ begin FHeaders.Add(''); { connect } - if (FAliveHost <> FTargetHost) or (FAlivePort <> FTargetPort) then + if not InternalConnect(UpperCase(Prot) = 'HTTPS') then begin FSock.CloseSocket; - FSock.Bind(FIPInterface, cAnyPort); - if FSock.LastError <> 0 then - Exit; - if FSock.LastError <> 0 then - Exit; - FSock.Connect(FTargetHost, FTargetPort); - if FSock.LastError <> 0 then - Exit; - if UpperCase(Prot) = 'HTTPS' then - FSock.SSLDoConnect; - if FSock.LastError <> 0 then - Exit; - FAliveHost := FTargetHost; - FAlivePort := FTargetPort; - end - else - begin - if FSock.CanRead(0) then - begin - FSock.CloseSocket; - FSock.Bind(FIPInterface, cAnyPort); - if FSock.LastError <> 0 then - Exit; - if FSock.LastError <> 0 then - Exit; - FSock.Connect(FTargetHost, FTargetPort); - if FSock.LastError = 0 then - if UpperCase(Prot) = 'HTTPS' then - FSock.SSLDoConnect; - if FSock.LastError <> 0 then - begin - FSock.CloseSocket; - FAliveHost := ''; - FAlivePort := ''; - Exit; - end; - end; + FAliveHost := ''; + FAlivePort := ''; + Exit; end; - { send Headers } - if FProtocol = '0.9' then - FSock.SendString(FHeaders[0] + CRLF) - else -{$IFDEF LINUX} - FSock.SendString(AdjustLineBreaks(FHeaders.Text, tlbsCRLF)); -{$ELSE} - FSock.SendString(FHeaders.Text); -{$ENDIF} - if FSock.LastError <> 0 then - Exit; - { reading Status } + FDocument.Position := 0; Status100Error := ''; if status100 then begin + { send Headers } + FSock.SendString(PrepareHeaders); + if FSock.LastError <> 0 then + Exit; repeat s := FSock.RecvString(FTimeout); if s <> '' then Break; until FSock.LastError <> 0; DecodeStatus(s); + Status100Error := s; + repeat + s := FSock.recvstring(FTimeout); + if s = '' then + Break; + until FSock.LastError <> 0; if (FResultCode >= 100) and (FResultCode < 200) then - repeat - s := FSock.recvstring(FTimeout); - if s = '' then - Break; - until FSock.LastError <> 0 + begin + { we can upload content } + Status100Error := ''; + FUploadSize := FDocument.Size; + FSock.SendBuffer(FDocument.Memory, FDocument.Size); + end; + end + else + { upload content } + if sending then + begin + if FDocument.Size >= c64k then + begin + FSock.SendString(PrepareHeaders); + FUploadSize := FDocument.Size; + FSock.SendBuffer(FDocument.Memory, FDocument.Size); + end + else + begin + s := PrepareHeaders + ReadStrFromStream(FDocument, FDocument.Size); + FUploadSize := Length(s); + FSock.SendString(s); + end; + end else begin - Sending := False; - Status100Error := s; + { we not need to upload document, send headers only } + FSock.SendString(PrepareHeaders); end; - end; - { send document } - if Sending then - begin - FUploadSize := FDocument.Size; - FSock.SendBuffer(FDocument.Memory, FDocument.Size); - if FSock.LastError <> 0 then - Exit; - end; + if FSock.LastError <> 0 then + Exit; Clear; Size := -1; @@ -556,6 +581,8 @@ begin ToClose := True; until FSock.LastError <> 0; Result := FSock.LastError = 0; + if not Result then + Exit; {if need receive response body, read it} Receiving := Method <> 'HEAD'; @@ -590,7 +617,7 @@ begin if FSock.LastError = 0 then WriteStrToStream(FDocument, s); until FSock.LastError <> 0; - Result := True; + Result := FSock.LastError = WSAECONNRESET; end; function THTTPSend.ReadIdentity(Size: Integer): Boolean; diff --git a/ldapsend.pas b/ldapsend.pas index efac6b6..2b6532d 100644 --- a/ldapsend.pas +++ b/ldapsend.pas @@ -1,5 +1,5 @@ {==============================================================================| -| Project : Ararat Synapse | 001.004.000 | +| Project : Ararat Synapse | 001.004.001 | |==============================================================================| | Content: LDAP client | |==============================================================================| @@ -344,7 +344,9 @@ var begin s := Value; if FIsbinary then - s := EncodeBase64(Value); + s := EncodeBase64(Value) + else + s :=UnquoteStr(s, '"'); inherited Put(Index, s); end; @@ -1091,7 +1093,7 @@ begin while n < i do begin u := ASNItem(n, t, x); - a.Add(UnquoteStr(u, '"')); + a.Add(u); end; end; end; diff --git a/mimepart.pas b/mimepart.pas index f3e91a3..9aad90e 100644 --- a/mimepart.pas +++ b/mimepart.pas @@ -1,5 +1,5 @@ {==============================================================================| -| Project : Ararat Synapse | 002.007.002 | +| Project : Ararat Synapse | 002.007.005 | |==============================================================================| | Content: MIME support procedures and functions | |==============================================================================| @@ -61,13 +61,7 @@ interface uses SysUtils, Classes, -{$IFDEF LINUX} - {$IFDEF FPC} synafpc, - {$ENDIF} -{$ELSE} - Windows, -{$ENDIF} synachar, synacode, synautil, mimeinln; type @@ -542,6 +536,7 @@ begin Result.DefaultCharset := FDefaultCharset; FSubParts.Add(Result); Result.SubLevel := FSubLevel + 1; + Result.MaxSubLevel := FMaxSubLevel; end; {==============================================================================} @@ -762,12 +757,16 @@ begin if FConvertCharset and (FPrimaryCode = MP_TEXT) then if (not FForcedHTMLConvert) and (uppercase(FSecondary) = 'HTML') then begin + b := false; t := uppercase(s); t := SeparateLeft(t, ''); - t := SeparateRight(t, ''); - t := ReplaceString(t, '"', ''); - t := ReplaceString(t, ' ', ''); - b := Pos('HTTP-EQUIV=CONTENT-TYPE', t) > 0; + if length(t) <> length(s) then + begin + t := SeparateRight(t, ''); + t := ReplaceString(t, '"', ''); + t := ReplaceString(t, ' ', ''); + b := Pos('HTTP-EQUIV=CONTENT-TYPE', t) > 0; + end; if not b then s := CharsetConversion(s, FCharsetCode, FTargetCharset); end diff --git a/pingsend.pas b/pingsend.pas index 2ab07c3..5e88fc8 100644 --- a/pingsend.pas +++ b/pingsend.pas @@ -1,5 +1,5 @@ {==============================================================================| -| Project : Ararat Synapse | 003.001.006 | +| Project : Ararat Synapse | 003.001.008 | |==============================================================================| | Content: PING sender | |==============================================================================| @@ -59,16 +59,15 @@ Note: IPv6 not working under .NET. It is lack of Microsoft's .NET framework. {$R-} {$H+} +{$IFDEF CIL} + Sorry, this unit is not for .NET! +{$ENDIF} + unit pingsend; interface uses -{$IFDEF LINUX} - Libc, -{$ELSE} - Windows, -{$ENDIF} SysUtils, synsock, blcksock, synautil; @@ -91,7 +90,7 @@ type i_checkSum: Word; i_Id: Word; i_seq: Word; - TimeStamp: ULong; + TimeStamp: integer; end; {:record used internally by TPingSend for compute checksum of ICMPv6 packet @@ -274,7 +273,7 @@ begin break; if fSock.IP6used then begin -{$IFDEF LINUX} +{$IFNDEF WIN32} IcmpEchoHeaderPtr := Pointer(FBuffer); {$ELSE} //WinXP SP1 with networking update doing this think by another way ;-O @@ -289,6 +288,12 @@ begin IpHdrLen := (IPHeadPtr^.VerLen and $0F) * 4; IcmpEchoHeaderPtr := @FBuffer[IpHdrLen + 1]; end; + //check for timeout + if TickDelta(x, GetTick) > FTimeout then + begin + t := false; + Break; + end; //it discard sometimes possible 'echoes' of previosly sended packet //or other unwanted ICMP packets... until (IcmpEchoHeaderPtr^.i_type <> FIcmpEcho) @@ -307,7 +312,7 @@ end; function TPINGSend.Checksum(Value: string): Word; var - CkSum: DWORD; + CkSum: integer; Num, Remain: Integer; n, i: Integer; begin @@ -341,9 +346,8 @@ var ip6: TSockAddrIn6; x: integer; begin -{$IFDEF LINUX} Result := 0; -{$ELSE} +{$IFDEF WIN32} s := StringOfChar(#0, SizeOf(TICMP6Packet)) + Value; ICMP6Ptr := Pointer(s); x := synsock.WSAIoctl(FSock.Socket, SIO_ROUTING_INTERFACE_QUERY, diff --git a/pop3send.pas b/pop3send.pas index 33d35b9..790b921 100644 --- a/pop3send.pas +++ b/pop3send.pas @@ -1,5 +1,5 @@ {==============================================================================| -| Project : Ararat Synapse | 002.004.000 | +| Project : Ararat Synapse | 002.005.000 | |==============================================================================| | Content: POP3 client | |==============================================================================| @@ -84,6 +84,7 @@ type FFullResult: TStringList; FStatCount: Integer; FStatSize: Integer; + FListSize: Integer; FTimeStamp: string; FAuthType: TPOP3AuthType; FPOP3cap: TStringList; @@ -125,6 +126,10 @@ type @link(FullResult). If all OK, result is @true.} function Retr(Value: Integer): Boolean; + {:Send RETR command. After successful operation dowloaded message in + @link(Stream). If all OK, result is @true.} + function RetrStream(Value: Integer; Stream: TStream): Boolean; + {:Send DELE command for delete specified message. If all OK, result is @true.} function Dele(Value: Integer): Boolean; @@ -161,6 +166,9 @@ type {:After STAT command is there size of all messages in inbox.} property StatSize: Integer read FStatSize; + {:After LIST 0 command size of all messages on server, After LIST x size of message x on server} + property ListSize: Integer read FListSize; + {:If server support this, after comnnect is in this property timestamp of remote server.} property TimeStamp: string read FTimeStamp; @@ -195,6 +203,7 @@ begin FTargetPort := cPop3Protocol; FStatCount := 0; FStatSize := 0; + FListSize := 0; FAuthType := POP3AuthAll; FAutoTLS := False; FFullSSL := False; @@ -351,12 +360,25 @@ begin end; function TPOP3Send.List(Value: Integer): Boolean; +var + s: string; + n: integer; begin if Value = 0 then FSock.SendString('LIST' + CRLF) else FSock.SendString('LIST ' + IntToStr(Value) + CRLF); Result := ReadResult(Value = 0) = 1; + FListSize := 0; + if Result then + if Value <> 0 then + begin + s := SeparateRight(ResultString, '+OK '); + FListSize := StrToIntDef(SeparateLeft(SeparateRight(s, ' '), ' '), 0); + end + else + for n := 0 to FFullResult.Count - 1 do + FListSize := FListSize + StrToIntDef(SeparateLeft(SeparateRight(s, ' '), ' '), 0); end; function TPOP3Send.Retr(Value: Integer): Boolean; @@ -365,6 +387,40 @@ begin Result := ReadResult(True) = 1; end; +//based on code by Miha Vrhovnik +function TPOP3Send.RetrStream(Value: Integer; Stream: TStream): Boolean; +var + s: string; +begin + Result := False; + FFullResult.Clear; + Stream.Size := 0; + FSock.SendString('RETR ' + IntToStr(Value) + CRLF); + + s := FSock.RecvString(FTimeout); + if Pos('+OK', s) = 1 then + Result := True; + FResultString := s; + if Result then begin + repeat + s := FSock.RecvString(FTimeout); + if s = '.' then + Break; + if s <> '' then begin + if s[1] = '.' then + Delete(s, 1, 1); + end; + WriteStrToStream(Stream, s); + WriteStrToStream(Stream, CRLF); + until FSock.LastError <> 0; + end; + + if Result then + FResultCode := 1 + else + FResultCode := 0; +end; + function TPOP3Send.Dele(Value: Integer): Boolean; begin FSock.SendString('DELE ' + IntToStr(Value) + CRLF); diff --git a/snmpsend.pas b/snmpsend.pas index fc39c9b..e5c2939 100644 --- a/snmpsend.pas +++ b/snmpsend.pas @@ -62,7 +62,7 @@ interface uses Classes, SysUtils, - blcksock, synautil, asn1util, synacode; + blcksock, synautil, asn1util, synaip, synacode; const cSnmpProtocol = '161'; diff --git a/ssdotnet.pas b/ssdotnet.pas index 799ea28..8a54cd8 100644 --- a/ssdotnet.pas +++ b/ssdotnet.pas @@ -49,7 +49,7 @@ interface uses - SyncObjs, SysUtils, + SyncObjs, SysUtils, Classes, System.Net, System.Net.Sockets; @@ -73,6 +73,7 @@ type TMemory = Array of byte; TLinger = LingerOption; TSocket = socket; + TAddrFamily = AddressFamily; const WSADESCRIPTION_LEN = 256; @@ -89,33 +90,10 @@ type // lpVendorInfo: PChar; end; - SunB6 = packed record - s_b1, s_b2, s_b3, s_b4, - s_b5, s_b6, s_b7, s_b8, - s_b9, s_b10, s_b11, s_b12, - s_b13, s_b14, s_b15, s_b16: u_char; - end; - - S6_Bytes = SunB6; - S6_Addr = SunB6; - - TInAddr6 = packed record - S_un_b: SunB6; - end; - - TSockAddrIn6 = packed record - sin6_family: u_short; // AF_INET6 - sin6_port: u_short; // Transport level port number - sin6_flowinfo: u_long; // IPv6 flow information - sin6_addr: TInAddr6; // IPv6 address - sin6_scope_id: u_long; // Scope Id: IF number for link-local - // SITE id for site-local - end; - - const MSG_NOSIGNAL = 0; INVALID_SOCKET = nil; + AF_UNSPEC = AddressFamily.Unspecified; AF_INET = AddressFamily.InterNetwork; AF_INET6 = AddressFamily.InterNetworkV6; SOCKET_ERROR = integer(-1); @@ -387,7 +365,7 @@ function RecvFrom(s: TSocket; Buf: TMemory; len, flags: Integer; var from: TVarS function ntohs(netshort: u_short): u_short; function ntohl(netlong: u_long): u_long; function Listen(s: TSocket; backlog: Integer): Integer; - function IoctlSocket(s: TSocket; cmd: DWORD; var arg: u_long): Integer; + function IoctlSocket(s: TSocket; cmd: DWORD; var arg: integer): Integer; function htons(hostshort: u_short): u_short; function htonl(hostlong: u_long): u_long; // function GetSockName(s: TSocket; name: PSockAddr; var namelen: Integer): Integer; @@ -414,6 +392,14 @@ function RecvFrom(s: TSocket; Buf: TMemory; len, flags: Integer; var from: TVarS function GetPortService(value: string): integer; +function IsNewApi(Family: TAddrFamily): Boolean; +function SetVarSin(var Sin: TVarSin; IP, Port: string; Family: TAddrFamily; SockProtocol, SockType: integer; PreferIP4: Boolean): integer; +function GetSinIP(Sin: TVarSin): string; +function GetSinPort(Sin: TVarSin): Integer; +procedure ResolveNameToIP(Name: string; Family: TAddrFamily; SockProtocol, SockType: integer; const IPList: TStrings); +function ResolveIPToName(IP: string; Family: TAddrFamily; SockProtocol, SockType: integer): string; +function ResolvePort(Port: string; Family: TAddrFamily; SockProtocol, SockType: integer): Word; + var SynSockCS: SyncObjs.TCriticalSection; SockEnhancedApi: Boolean; @@ -826,7 +812,7 @@ begin end; end; -function IoctlSocket(s: TSocket; cmd: DWORD; var arg: u_long): Integer; +function IoctlSocket(s: TSocket; cmd: DWORD; var arg: integer): Integer; var inv, outv: TMemory; begin @@ -840,7 +826,7 @@ begin inv := BitConverter.GetBytes(arg); outv := BitConverter.GetBytes(integer(0)); s.IOControl(cmd, inv, outv); - arg := BitConverter.ToUInt32(outv, 0); + arg := BitConverter.ToInt32(outv, 0); end; except on e: System.Net.Sockets.SocketException do @@ -985,6 +971,106 @@ begin Result := StrToIntDef(value, 0); end; +{=============================================================================} +function IsNewApi(Family: TAddrFamily): Boolean; +begin + Result := true; +end; + +function SetVarSin(var Sin: TVarSin; IP, Port: string; Family: TAddrFamily; SockProtocol, SockType: integer; PreferIP4: Boolean): integer; +var + IPs: array of IPAddress; + n: integer; + ip4, ip6: string; + sip: string; +begin + sip := ''; + ip4 := ''; + ip6 := ''; + IPs := Dns.Resolve(IP).AddressList; + for n :=low(IPs) to high(IPs) do begin + if (ip4 = '') and (IPs[n].AddressFamily = AF_INET) then + ip4 := IPs[n].toString; + if (ip6 = '') and (IPs[n].AddressFamily = AF_INET6) then + ip6 := IPs[n].toString; + if (ip4 <> '') and (ip6 <> '') then + break; + end; + case Family of + AF_UNSPEC: + begin + if (ip4 <> '') and (ip6 <> '') then + begin + if PreferIP4 then + sip := ip4 + else + Sip := ip6; + end + else + begin + sip := ip4; + if (ip6 <> '') then + sip := ip6; + end; + end; + AF_INET: + sip := ip4; + AF_INET6: + sip := ip6; + end; + sin := TVarSin.Create(IPAddress.Parse(sip), GetPortService(Port)); +end; + +function GetSinIP(Sin: TVarSin): string; +begin + Result := Sin.Address.ToString; +end; + +function GetSinPort(Sin: TVarSin): Integer; +begin + Result := Sin.Port; +end; + +procedure ResolveNameToIP(Name: string; Family: TAddrFamily; SockProtocol, SockType: integer; const IPList: TStrings); +var + IPs :array of IPAddress; + n: integer; +begin + IPList.Clear; + IPs := Dns.Resolve(Name).AddressList; + for n := low(IPs) to high(IPs) do + begin + if not(((Family = AF_INET6) and (IPs[n].AddressFamily = AF_INET)) + or ((Family = AF_INET) and (IPs[n].AddressFamily = AF_INET6))) then + begin + IPList.Add(IPs[n].toString); + end; + end; +end; + +function ResolvePort(Port: string; Family: TAddrFamily; SockProtocol, SockType: integer): Word; +var + n: integer; +begin + Result := StrToIntDef(port, 0); + if Result = 0 then + begin + port := Lowercase(port); + for n := 0 to High(Services) do + if services[n, 0] = port then + begin + Result := strtointdef(services[n, 1], 0); + break; + end; + end; +end; + +function ResolveIPToName(IP: string; Family: TAddrFamily; SockProtocol, SockType: integer): string; +begin + Result := Dns.GetHostByAddress(IP).HostName; +end; + + {=============================================================================} function InitSocketInterface(stack: string): Boolean; begin diff --git a/ssfpc.pas b/ssfpc.pas new file mode 100644 index 0000000..6957bbf --- /dev/null +++ b/ssfpc.pas @@ -0,0 +1,868 @@ +{==============================================================================| +| Project : Ararat Synapse | 001.000.003 | +|==============================================================================| +| Content: Socket Independent Platform Layer - FreePascal definition include | +|==============================================================================| +| Copyright (c)2006, Lukas Gebauer | +| All rights reserved. | +| | +| 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. | +| | +| Redistributions in binary form must reproduce the above copyright notice, | +| this list of conditions and the following disclaimer in the documentation | +| and/or other materials provided with the distribution. | +| | +| Neither the name of Lukas Gebauer nor the names of its contributors may | +| be used to endorse or promote products derived from this software without | +| specific prior written permission. | +| | +| 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. | +|==============================================================================| +| The Initial Developer of the Original Code is Lukas Gebauer (Czech Republic).| +| Portions created by Lukas Gebauer are Copyright (c)2006. | +| All Rights Reserved. | +|==============================================================================| +| Contributor(s): | +|==============================================================================| +| History: see HISTORY.HTM from distribution package | +| (Found at URL: http://www.ararat.cz/synapse/) | +|==============================================================================} + +{:@exclude} + +{$IFDEF FPC} + +//{$DEFINE FORCEOLDAPI} +{Note about define FORCEOLDAPI: +If you activate this compiler directive, then is allways used old socket API +for name resolution. If you leave this directive inactive, then the new API +is used, when running system allows it. + +For IPv6 support you must have new API! +} + +{$IFDEF FPC} + {$MODE DELPHI} +{$ENDIF} +{$H+} + +{$ifdef FreeBSD} +{$DEFINE SOCK_HAS_SINLEN} // BSD definition of scoketaddr +{$endif} +{$ifdef darwin} +{$DEFINE SOCK_HAS_SINLEN} // BSD definition of scoketaddr +{$endif} + +interface + +uses + SyncObjs, SysUtils, Classes, + synafpc, BaseUnix, Unix, termio, sockets, netdb; + +function InitSocketInterface(stack: string): Boolean; +function DestroySocketInterface: Boolean; + +const + DLLStackName = ''; + WinsockLevel = $0202; + + cLocalHost = '127.0.0.1'; + cAnyHost = '0.0.0.0'; + c6AnyHost = '::0'; + +type + TSocket = longint; + TAddrFamily = integer; + + TMemory = pointer; + + +type + TFDSet = Baseunix.TFDSet; + PFDSet = ^TFDSet; + Ptimeval = Baseunix.ptimeval; + Ttimeval = Baseunix.ttimeval; + +const + FIONREAD = termio.FIONREAD; + FIONBIO = termio.FIONBIO; + FIOASYNC = termio.FIOASYNC; + +const + IPPROTO_IP = 0; { Dummy } + IPPROTO_ICMP = 1; { Internet Control Message Protocol } + IPPROTO_IGMP = 2; { Internet Group Management Protocol} + IPPROTO_TCP = 6; { TCP } + IPPROTO_UDP = 17; { User Datagram Protocol } + IPPROTO_IPV6 = 41; + IPPROTO_ICMPV6 = 58; + + IPPROTO_RAW = 255; + IPPROTO_MAX = 256; + +type + PInAddr = ^TInAddr; + TInAddr = sockets.in_addr; + + PSockAddrIn = ^TSockAddrIn; + TSockAddrIn = sockets.TInetSockAddr; + + + TIP_mreq = record + imr_multiaddr: TInAddr; // IP multicast address of group + imr_interface: TInAddr; // local IP address of interface + end; + + + PInAddr6 = ^TInAddr6; + TInAddr6 = sockets.Tin6_addr; + + PSockAddrIn6 = ^TSockAddrIn6; + TSockAddrIn6 = sockets.TInetSockAddr6; + + + TIPv6_mreq = record + ipv6mr_multiaddr: TInAddr6; // IPv6 multicast address. + ipv6mr_interface: integer; // Interface index. + end; + +const + INADDR_ANY = $00000000; + INADDR_LOOPBACK = $7F000001; + INADDR_BROADCAST = $FFFFFFFF; + INADDR_NONE = $FFFFFFFF; + ADDR_ANY = INADDR_ANY; + INVALID_SOCKET = TSocket(NOT(0)); + SOCKET_ERROR = -1; + +Const + IP_TOS = sockets.IP_TOS; { int; IP type of service and precedence. } + IP_TTL = sockets.IP_TTL; { int; IP time to live. } + IP_HDRINCL = sockets.IP_HDRINCL; { int; Header is included with data. } + IP_OPTIONS = sockets.IP_OPTIONS; { ip_opts; IP per-packet options. } +// IP_ROUTER_ALERT = sockets.IP_ROUTER_ALERT; { bool } + IP_RECVOPTS = sockets.IP_RECVOPTS; { bool } + IP_RETOPTS = sockets.IP_RETOPTS; { bool } +// IP_PKTINFO = sockets.IP_PKTINFO; { bool } +// IP_PKTOPTIONS = sockets.IP_PKTOPTIONS; +// IP_PMTUDISC = sockets.IP_PMTUDISC; { obsolete name? } +// IP_MTU_DISCOVER = sockets.IP_MTU_DISCOVER; { int; see below } +// IP_RECVERR = sockets.IP_RECVERR; { bool } +// IP_RECVTTL = sockets.IP_RECVTTL; { bool } +// IP_RECVTOS = sockets.IP_RECVTOS; { bool } + IP_MULTICAST_IF = sockets.IP_MULTICAST_IF; { in_addr; set/get IP multicast i/f } + IP_MULTICAST_TTL = sockets.IP_MULTICAST_TTL; { u_char; set/get IP multicast ttl } + IP_MULTICAST_LOOP = sockets.IP_MULTICAST_LOOP; { i_char; set/get IP multicast loopback } + IP_ADD_MEMBERSHIP = sockets.IP_ADD_MEMBERSHIP; { ip_mreq; add an IP group membership } + IP_DROP_MEMBERSHIP = sockets.IP_DROP_MEMBERSHIP; { ip_mreq; drop an IP group membership } + + SOL_SOCKET = sockets.SOL_SOCKET; + + SO_DEBUG = sockets.SO_DEBUG; + SO_REUSEADDR = sockets.SO_REUSEADDR; + SO_TYPE = sockets.SO_TYPE; + SO_ERROR = sockets.SO_ERROR; + SO_DONTROUTE = sockets.SO_DONTROUTE; + SO_BROADCAST = sockets.SO_BROADCAST; + SO_SNDBUF = sockets.SO_SNDBUF; + SO_RCVBUF = sockets.SO_RCVBUF; + SO_KEEPALIVE = sockets.SO_KEEPALIVE; + SO_OOBINLINE = sockets.SO_OOBINLINE; +// SO_NO_CHECK = sockets.SO_NO_CHECK; +// SO_PRIORITY = sockets.SO_PRIORITY; + SO_LINGER = sockets.SO_LINGER; +// SO_BSDCOMPAT = sockets.SO_BSDCOMPAT; +// SO_REUSEPORT = sockets.SO_REUSEPORT; +// SO_PASSCRED = sockets.SO_PASSCRED; +// SO_PEERCRED = sockets.SO_PEERCRED; + SO_RCVLOWAT = sockets.SO_RCVLOWAT; + SO_SNDLOWAT = sockets.SO_SNDLOWAT; + SO_RCVTIMEO = sockets.SO_RCVTIMEO; + SO_SNDTIMEO = sockets.SO_SNDTIMEO; +{ Security levels - as per NRL IPv6 - don't actually do anything } +// SO_SECURITY_AUTHENTICATION = sockets.SO_SECURITY_AUTHENTICATION; +// SO_SECURITY_ENCRYPTION_TRANSPORT = sockets.SO_SECURITY_ENCRYPTION_TRANSPORT; +// SO_SECURITY_ENCRYPTION_NETWORK = sockets.SO_SECURITY_ENCRYPTION_NETWORK; +// SO_BINDTODEVICE = sockets.SO_BINDTODEVICE; +{ Socket filtering } +// SO_ATTACH_FILTER = sockets.SO_ATTACH_FILTER; +// SO_DETACH_FILTER = sockets.SO_DETACH_FILTER; + + SOMAXCONN = 1024; + + IPV6_UNICAST_HOPS = sockets.IPV6_UNICAST_HOPS; + IPV6_MULTICAST_IF = sockets.IPV6_MULTICAST_IF; + IPV6_MULTICAST_HOPS = sockets.IPV6_MULTICAST_HOPS; + IPV6_MULTICAST_LOOP = sockets.IPV6_MULTICAST_LOOP; + IPV6_JOIN_GROUP = sockets.IPV6_JOIN_GROUP; + IPV6_LEAVE_GROUP = sockets.IPV6_LEAVE_GROUP; + +const + SOCK_STREAM = 1; { stream socket } + SOCK_DGRAM = 2; { datagram socket } + SOCK_RAW = 3; { raw-protocol interface } + SOCK_RDM = 4; { reliably-delivered message } + SOCK_SEQPACKET = 5; { sequenced packet stream } + +{ TCP options. } + TCP_NODELAY = $0001; + +{ Address families. } + + AF_UNSPEC = 0; { unspecified } + AF_INET = 2; { internetwork: UDP, TCP, etc. } + AF_INET6 = 10; { Internetwork Version 6 } + AF_MAX = 24; + +{ Protocol families, same as address families for now. } + PF_UNSPEC = AF_UNSPEC; + PF_INET = AF_INET; + PF_INET6 = AF_INET6; + PF_MAX = AF_MAX; + +type +{ Structure used for manipulating linger option. } + PLinger = ^TLinger; + TLinger = packed record + l_onoff: integer; + l_linger: integer; + end; + +const + + MSG_OOB = sockets.MSG_OOB; // Process out-of-band data. + MSG_PEEK = sockets.MSG_PEEK; // Peek at incoming messages. + MSG_NOSIGNAL = sockets.MSG_NOSIGNAL; // Do not generate SIGPIPE. + +const + WSAEINTR = ESysEINTR; + WSAEBADF = ESysEBADF; + WSAEACCES = ESysEACCES; + WSAEFAULT = ESysEFAULT; + WSAEINVAL = ESysEINVAL; + WSAEMFILE = ESysEMFILE; + WSAEWOULDBLOCK = ESysEWOULDBLOCK; + WSAEINPROGRESS = ESysEINPROGRESS; + WSAEALREADY = ESysEALREADY; + WSAENOTSOCK = ESysENOTSOCK; + WSAEDESTADDRREQ = ESysEDESTADDRREQ; + WSAEMSGSIZE = ESysEMSGSIZE; + WSAEPROTOTYPE = ESysEPROTOTYPE; + WSAENOPROTOOPT = ESysENOPROTOOPT; + WSAEPROTONOSUPPORT = ESysEPROTONOSUPPORT; + WSAESOCKTNOSUPPORT = ESysESOCKTNOSUPPORT; + WSAEOPNOTSUPP = ESysEOPNOTSUPP; + WSAEPFNOSUPPORT = ESysEPFNOSUPPORT; + WSAEAFNOSUPPORT = ESysEAFNOSUPPORT; + WSAEADDRINUSE = ESysEADDRINUSE; + WSAEADDRNOTAVAIL = ESysEADDRNOTAVAIL; + WSAENETDOWN = ESysENETDOWN; + WSAENETUNREACH = ESysENETUNREACH; + WSAENETRESET = ESysENETRESET; + WSAECONNABORTED = ESysECONNABORTED; + WSAECONNRESET = ESysECONNRESET; + WSAENOBUFS = ESysENOBUFS; + WSAEISCONN = ESysEISCONN; + WSAENOTCONN = ESysENOTCONN; + WSAESHUTDOWN = ESysESHUTDOWN; + WSAETOOMANYREFS = ESysETOOMANYREFS; + WSAETIMEDOUT = ESysETIMEDOUT; + WSAECONNREFUSED = ESysECONNREFUSED; + WSAELOOP = ESysELOOP; + WSAENAMETOOLONG = ESysENAMETOOLONG; + WSAEHOSTDOWN = ESysEHOSTDOWN; + WSAEHOSTUNREACH = ESysEHOSTUNREACH; + WSAENOTEMPTY = ESysENOTEMPTY; + WSAEPROCLIM = -1; + WSAEUSERS = ESysEUSERS; + WSAEDQUOT = ESysEDQUOT; + WSAESTALE = ESysESTALE; + WSAEREMOTE = ESysEREMOTE; + WSASYSNOTREADY = -2; + WSAVERNOTSUPPORTED = -3; + WSANOTINITIALISED = -4; + WSAEDISCON = -5; + WSAHOST_NOT_FOUND = 1; + WSATRY_AGAIN = 2; + WSANO_RECOVERY = 3; + WSANO_DATA = -6; + +const + WSADESCRIPTION_LEN = 256; + WSASYS_STATUS_LEN = 128; +type + PWSAData = ^TWSAData; + TWSAData = packed record + wVersion: Word; + wHighVersion: Word; + szDescription: array[0..WSADESCRIPTION_LEN] of Char; + szSystemStatus: array[0..WSASYS_STATUS_LEN] of Char; + iMaxSockets: Word; + iMaxUdpDg: Word; + lpVendorInfo: PChar; + end; + + function IN6_IS_ADDR_UNSPECIFIED(const a: PInAddr6): boolean; + function IN6_IS_ADDR_LOOPBACK(const a: PInAddr6): boolean; + function IN6_IS_ADDR_LINKLOCAL(const a: PInAddr6): boolean; + function IN6_IS_ADDR_SITELOCAL(const a: PInAddr6): boolean; + function IN6_IS_ADDR_MULTICAST(const a: PInAddr6): boolean; + function IN6_ADDR_EQUAL(const a: PInAddr6; const b: PInAddr6):boolean; + procedure SET_IN6_IF_ADDR_ANY (const a: PInAddr6); + procedure SET_LOOPBACK_ADDR6 (const a: PInAddr6); + +var + in6addr_any, in6addr_loopback : TInAddr6; + +procedure FD_CLR(Socket: TSocket; var FDSet: TFDSet); +function FD_ISSET(Socket: TSocket; var FDSet: TFDSet): Boolean; +procedure FD_SET(Socket: TSocket; var FDSet: TFDSet); +procedure FD_ZERO(var FDSet: TFDSet); + +{=============================================================================} + +var + SynSockCS: SyncObjs.TCriticalSection; + SockEnhancedApi: Boolean; + SockWship6Api: Boolean; + +type + TVarSin = packed record + {$ifdef SOCK_HAS_SINLEN} + sin_len : cuchar; + {$endif} + case integer of + 0: (AddressFamily: sa_family_t); + 1: ( + case sin_family: sa_family_t of + AF_INET: (sin_port: word; + sin_addr: TInAddr; + sin_zero: array[0..7] of Char); + AF_INET6: (sin6_port: word; + sin6_flowinfo: longword; + sin6_addr: TInAddr6; + sin6_scope_id: longword); + ); + end; + +function SizeOfVarSin(sin: TVarSin): integer; + + function WSAStartup(wVersionRequired: Word; var WSData: TWSAData): Integer; + function WSACleanup: Integer; + function WSAGetLastError: Integer; + function GetHostName: string; + function Shutdown(s: TSocket; how: Integer): Integer; + function SetSockOpt(s: TSocket; level, optname: Integer; optval: TMemory; + optlen: Integer): Integer; + function GetSockOpt(s: TSocket; level, optname: Integer; optval: TMemory; + var optlen: Integer): Integer; + function Send(s: TSocket; Buf: TMemory; len, flags: Integer): Integer; + function Recv(s: TSocket; Buf: TMemory; len, flags: Integer): Integer; + function SendTo(s: TSocket; Buf: TMemory; len, flags: Integer; addrto: TVarSin): Integer; + function RecvFrom(s: TSocket; Buf: TMemory; len, flags: Integer; var from: TVarSin): Integer; + function ntohs(netshort: word): word; + function ntohl(netlong: longword): longword; + function Listen(s: TSocket; backlog: Integer): Integer; + function IoctlSocket(s: TSocket; cmd: DWORD; var arg: integer): Integer; + function htons(hostshort: word): word; + function htonl(hostlong: longword): longword; + function GetSockName(s: TSocket; var name: TVarSin): Integer; + function GetPeerName(s: TSocket; var name: TVarSin): Integer; + function Connect(s: TSocket; const name: TVarSin): Integer; + function CloseSocket(s: TSocket): Integer; + function Bind(s: TSocket; const addr: TVarSin): Integer; + function Accept(s: TSocket; var addr: TVarSin): TSocket; + function Socket(af, Struc, Protocol: Integer): TSocket; + function Select(nfds: Integer; readfds, writefds, exceptfds: PFDSet; + timeout: PTimeVal): Longint; + +function IsNewApi(Family: integer): Boolean; +function SetVarSin(var Sin: TVarSin; IP, Port: string; Family, SockProtocol, SockType: integer; PreferIP4: Boolean): integer; +function GetSinIP(Sin: TVarSin): string; +function GetSinPort(Sin: TVarSin): Integer; +procedure ResolveNameToIP(Name: string; Family, SockProtocol, SockType: integer; const IPList: TStrings); +function ResolveIPToName(IP: string; Family, SockProtocol, SockType: integer): string; +function ResolvePort(Port: string; Family, SockProtocol, SockType: integer): Word; + + +{==============================================================================} +implementation + + +function IN6_IS_ADDR_UNSPECIFIED(const a: PInAddr6): boolean; +begin + Result := ((a^.u6_addr32[0] = 0) and (a^.u6_addr32[1] = 0) and + (a^.u6_addr32[2] = 0) and (a^.u6_addr32[3] = 0)); +end; + +function IN6_IS_ADDR_LOOPBACK(const a: PInAddr6): boolean; +begin + Result := ((a^.u6_addr32[0] = 0) and (a^.u6_addr32[1] = 0) and + (a^.u6_addr32[2] = 0) and + (a^.u6_addr8[12] = 0) and (a^.u6_addr8[13] = 0) and + (a^.u6_addr8[14] = 0) and (a^.u6_addr8[15] = 1)); +end; + +function IN6_IS_ADDR_LINKLOCAL(const a: PInAddr6): boolean; +begin + Result := ((a^.u6_addr8[0] = $FE) and (a^.u6_addr8[1] = $80)); +end; + +function IN6_IS_ADDR_SITELOCAL(const a: PInAddr6): boolean; +begin + Result := ((a^.u6_addr8[0] = $FE) and (a^.u6_addr8[1] = $C0)); +end; + +function IN6_IS_ADDR_MULTICAST(const a: PInAddr6): boolean; +begin + Result := (a^.u6_addr8[0] = $FF); +end; + +function IN6_ADDR_EQUAL(const a: PInAddr6; const b: PInAddr6): boolean; +begin + Result := (CompareMem( a, b, sizeof(TInAddr6))); +end; + +procedure SET_IN6_IF_ADDR_ANY (const a: PInAddr6); +begin + FillChar(a^, sizeof(TInAddr6), 0); +end; + +procedure SET_LOOPBACK_ADDR6 (const a: PInAddr6); +begin + FillChar(a^, sizeof(TInAddr6), 0); + a^.u6_addr8[15] := 1; +end; + +{=============================================================================} + +function WSAStartup(wVersionRequired: Word; var WSData: TWSAData): Integer; +begin + with WSData do + begin + wVersion := wVersionRequired; + wHighVersion := $202; + szDescription := 'Synsock - Synapse Platform Independent Socket Layer'; + szSystemStatus := 'Running on Unix/Linux by FreePascal'; + iMaxSockets := 32768; + iMaxUdpDg := 8192; + end; + Result := 0; +end; + +function WSACleanup: Integer; +begin + Result := 0; +end; + +function WSAGetLastError: Integer; +begin + Result := fpGetErrno; +end; + +function FD_ISSET(Socket: TSocket; var fdset: TFDSet): Boolean; +begin + Result := fpFD_ISSET(socket, fdset) <> 0; +end; + +procedure FD_SET(Socket: TSocket; var fdset: TFDSet); +begin + fpFD_SET(Socket, fdset); +end; + +procedure FD_CLR(Socket: TSocket; var fdset: TFDSet); +begin + fpFD_CLR(Socket, fdset); +end; + +procedure FD_ZERO(var fdset: TFDSet); +begin + fpFD_ZERO(fdset); +end; + +{=============================================================================} + +function SizeOfVarSin(sin: TVarSin): integer; +begin + case sin.sin_family of + AF_INET: + Result := SizeOf(TSockAddrIn); + AF_INET6: + Result := SizeOf(TSockAddrIn6); + else + Result := 0; + end; +end; + +{=============================================================================} + +function Bind(s: TSocket; const addr: TVarSin): Integer; +begin + if sockets.Bind(s, addr, SizeOfVarSin(addr)) then + Result := 0 + else + Result := SOCKET_ERROR; +end; + +function Connect(s: TSocket; const name: TVarSin): Integer; +begin + if sockets.Connect(s, name, SizeOfVarSin(name)) then + Result := 0 + else + Result := SOCKET_ERROR; +end; + +function GetSockName(s: TSocket; var name: TVarSin): Integer; +var + len: integer; +begin + len := SizeOf(name); + FillChar(name, len, 0); + Result := sockets.GetSocketName(s, name, Len); +end; + +function GetPeerName(s: TSocket; var name: TVarSin): Integer; +var + len: integer; +begin + len := SizeOf(name); + FillChar(name, len, 0); + Result := sockets.GetPeerName(s, name, Len); +end; + +function GetHostName: string; +begin + Result := unix.GetHostName; +end; + +function Send(s: TSocket; Buf: TMemory; len, flags: Integer): Integer; +begin + Result := sockets.Send(s, Buf^, len, flags); +end; + +function Recv(s: TSocket; Buf: TMemory; len, flags: Integer): Integer; +begin + Result := sockets.Recv(s, Buf^, len, flags); +end; + +function SendTo(s: TSocket; Buf: TMemory; len, flags: Integer; addrto: TVarSin): Integer; +begin + Result := sockets.SendTo(s, Buf^, len, flags, addrto, SizeOfVarSin(addrto)); +end; + +function RecvFrom(s: TSocket; Buf: TMemory; len, flags: Integer; var from: TVarSin): Integer; +var + x: integer; +begin + x := SizeOf(from); + Result := sockets.RecvFrom(s, Buf^, len, flags, from, x); +end; + +function Accept(s: TSocket; var addr: TVarSin): TSocket; +var + x: integer; +begin + x := SizeOf(addr); + Result := sockets.Accept(s, addr, x); +end; + +function Shutdown(s: TSocket; how: Integer): Integer; +begin + Result := sockets.Shutdown(s, how); +end; + +function SetSockOpt(s: TSocket; level, optname: Integer; optval: Tmemory; + optlen: Integer): Integer; +begin + Result := sockets.SetSocketOptions(s, level, optname, optval^, optlen); +end; + +function GetSockOpt(s: TSocket; level, optname: Integer; optval: Tmemory; + var optlen: Integer): Integer; +begin + Result := sockets.GetSocketOptions(s, level, optname, optval^, optlen); +end; + +function ntohs(netshort: word): word; +begin + Result := sockets.ntohs(NetShort); +end; + +function ntohl(netlong: longword): longword; +begin + Result := sockets.ntohl(NetLong); +end; + +function Listen(s: TSocket; backlog: Integer): Integer; +begin + if sockets.Listen(s, backlog) then + Result := 0 + else + Result := SOCKET_ERROR; +end; + +function IoctlSocket(s: TSocket; cmd: DWORD; var arg: integer): Integer; +begin + Result := fpIoctl(s, cmd, @arg); +end; + +function htons(hostshort: word): word; +begin + Result := sockets.htons(Hostshort); +end; + +function htonl(hostlong: longword): longword; +begin + Result := sockets.htonl(HostLong); +end; + +function CloseSocket(s: TSocket): Integer; +begin + Result := sockets.CloseSocket(s); +end; + +function Socket(af, Struc, Protocol: Integer): TSocket; +begin + Result := sockets.Socket(af, struc, protocol); +end; + +function Select(nfds: Integer; readfds, writefds, exceptfds: PFDSet; + timeout: PTimeVal): Longint; +begin + Result := fpSelect(nfds, readfds, writefds, exceptfds, timeout); +end; + +{=============================================================================} +function IsNewApi(Family: integer): Boolean; +begin + Result := SockEnhancedApi; + if not Result then + Result := (Family = AF_INET6) and SockWship6Api; +end; + +function SetVarSin(var Sin: TVarSin; IP, Port: string; Family, SockProtocol, SockType: integer; PreferIP4: Boolean): integer; +var + TwoPass: boolean; + f1, f2: integer; + + function GetAddr(f:integer): integer; + var + a4: array [1..1] of in_addr; + a6: array [1..1] of Tin6_addr; + begin + Result := WSAEPROTONOSUPPORT; + case f of + AF_INET: + begin + if IP = cAnyHost then + begin + Sin.sin_family := AF_INET; + Result := 0; + end + else + begin + a4[1].s_addr := 0; + Result := WSAHOST_NOT_FOUND; + a4[1] := StrTonetAddr(IP); + if a4[1].s_addr = INADDR_ANY then + Resolvename(ip, a4); + if a4[1].s_addr <> INADDR_ANY then + begin + Sin.sin_family := AF_INET; + sin.sin_addr := a4[1]; + Result := 0; + end; + end; + end; + AF_INET6: + begin + if IP = c6AnyHost then + begin + Sin.sin_family := AF_INET6; + Result := 0; + end + else + begin + Result := WSAHOST_NOT_FOUND; + SET_IN6_IF_ADDR_ANY(@a6[1]); + a6[1] := StrTonetAddr6(IP); + if IN6_IS_ADDR_UNSPECIFIED(@a6[1]) then + Resolvename6(ip, a6); + if IN6_IS_ADDR_UNSPECIFIED(@a6[1]) then + begin + Sin.sin_family := AF_INET6; + sin.sin6_addr := a6[1]; + Result := 0; + end; + end; + end; + end; + end; +begin + Result := 0; + FillChar(Sin, Sizeof(Sin), 0); + Sin.sin_port := Resolveport(port, family, SockProtocol, SockType); + TwoPass := False; + if Family = AF_UNSPEC then + begin + if PreferIP4 then + begin + f1 := AF_INET; + f2 := AF_INET6; + TwoPass := True; + end + else + begin + f2 := AF_INET; + f1 := AF_INET6; + TwoPass := True; + end; + end + else + f1 := Family; + Result := GetAddr(f1); + if Result <> 0 then + if TwoPass then + Result := GetAddr(f2); +end; + +function GetSinIP(Sin: TVarSin): string; +begin + Result := ''; + case sin.AddressFamily of + AF_INET: + begin + result := NetAddrToStr(sin.sin_addr); + end; + AF_INET6: + begin + result := NetAddrToStr6(sin.sin6_addr); + end; + end; +end; + +function GetSinPort(Sin: TVarSin): Integer; +begin + if (Sin.sin_family = AF_INET6) then + Result := synsock.ntohs(Sin.sin6_port) + else + Result := synsock.ntohs(Sin.sin_port); +end; + +procedure ResolveNameToIP(Name: string; Family, SockProtocol, SockType: integer; const IPList: TStrings); +var + x, n: integer; + a4: array [1..255] of in_addr; + a6: array [1..255] of Tin6_addr; +begin + IPList.Clear; + if (family = AF_INET) or (family = AF_UNSPEC) then + begin + a4[1] := StrTonetAddr(name); + if a4[1].s_addr = INADDR_ANY then + x := Resolvename(name, a4) + else + x := 1; + for n := 1 to x do + IpList.Add(netaddrToStr(a4[n])); + end; + + if (family = AF_INET6) or (family = AF_UNSPEC) then + begin + a6[1] := StrTonetAddr6(name); + if IN6_IS_ADDR_UNSPECIFIED(@a6[1]) then + x := Resolvename6(name, a6) + else + x := 1; + for n := 1 to x do + IpList.Add(netaddrToStr6(a6[n])); + end; + + if IPList.Count = 0 then + IPList.Add(cLocalHost); +end; + +function ResolvePort(Port: string; Family, SockProtocol, SockType: integer): Word; +var + ProtoEnt: TProtocolEntry; + ServEnt: TServiceEntry; +begin + Result := synsock.htons(StrToIntDef(Port, 0)); + if Result = 0 then + begin + ProtoEnt.Name := ''; + GetProtocolByNumber(SockProtocol, ProtoEnt); + ServEnt.port := 0; + GetServiceByName(Port, ProtoEnt.Name, ServEnt); + Result := ServEnt.port; + end; +end; + +function ResolveIPToName(IP: string; Family, SockProtocol, SockType: integer): string; +var + n: integer; + a4: array [1..1] of in_addr; + a6: array [1..1] of Tin6_addr; + a: array [1..1] of string; +begin + Result := IP; + a4[1] := StrToNetAddr(IP); + if a4[1].s_addr <> INADDR_ANY then + begin +//why ResolveAddress need address in HOST order? :-O + n := ResolveAddress(nettohost(a4[1]), a); + if n > 0 then + Result := a[1]; + end + else + begin + a6[1] := StrToNetAddr6(IP); + n := ResolveAddress6(a6[1], a); + if n > 0 then + Result := a[1]; + end; +end; + +{=============================================================================} + +function InitSocketInterface(stack: string): Boolean; +begin + SockEnhancedApi := False; + SockWship6Api := False; +// Libc.Signal(Libc.SIGPIPE, TSignalHandler(Libc.SIG_IGN)); + Result := True; +end; + +function DestroySocketInterface: Boolean; +begin + Result := True; +end; + +initialization +begin + SynSockCS := SyncObjs.TCriticalSection.Create; + SET_IN6_IF_ADDR_ANY (@in6addr_any); + SET_LOOPBACK_ADDR6 (@in6addr_loopback); +end; + +finalization +begin + SynSockCS.Free; +end; + +{$ENDIF} + diff --git a/ssl_cryptlib.pas b/ssl_cryptlib.pas index ec76bae..84dd4d8 100644 --- a/ssl_cryptlib.pas +++ b/ssl_cryptlib.pas @@ -1,5 +1,5 @@ {==============================================================================| -| Project : Ararat Synapse | 001.000.002 | +| Project : Ararat Synapse | 001.001.000 | |==============================================================================| | Content: SSL/SSH support by Peter Gutmann's CryptLib | |==============================================================================| @@ -97,12 +97,14 @@ type FCryptSession: CRYPT_SESSION; FPrivateKeyLabel: string; FDelCert: Boolean; + FReadBuffer: string; function SSLCheck(Value: integer): Boolean; function Init(server:Boolean): Boolean; function DeInit: Boolean; function Prepare(server:Boolean): Boolean; function GetString(const cryptHandle: CRYPT_HANDLE; const attributeType: CRYPT_ATTRIBUTE_TYPE): string; function CreateSelfSignedCert(Host: string): Boolean; override; + function PopAll: string; public {:See @inherited} constructor Create(const Value: TTCPBlockSocket); override; @@ -203,6 +205,8 @@ function TSSLCryptLib.SSLCheck(Value: integer): Boolean; begin Result := true; FLastErrorDesc := ''; + if Value = CRYPT_ERROR_COMPLETE then + Value := 0; FLastError := Value; if FLastError <> 0 then begin @@ -243,6 +247,28 @@ begin Result := True; end; +function TSSLCryptLib.PopAll: string; +const + BufferMaxSize = 32768; +var + Outbuffer: string; + WriteLen: integer; +begin + Result := ''; + repeat + setlength(outbuffer, BufferMaxSize); + Writelen := 0; + SSLCheck(CryptPopData(FCryptSession, @OutBuffer[1], BufferMaxSize, Writelen)); + if FLastError <> 0 then + Break; + if WriteLen > 0 then + begin + setlength(outbuffer, WriteLen); + Result := Result + outbuffer; + end; + until WriteLen = 0; +end; + function TSSLCryptLib.Init(server:Boolean): Boolean; var st: CRYPT_SESSION_TYPE; @@ -385,6 +411,7 @@ begin Exit; FSSLEnabled := True; Result := True; + FReadBuffer := ''; end; end; @@ -401,6 +428,7 @@ begin Exit; FSSLEnabled := True; Result := True; + FReadBuffer := ''; end; end; @@ -414,6 +442,7 @@ begin if FcryptSession <> CRYPT_SESSION(CRYPT_SESSION_NONE) then cryptSetAttribute(FCryptSession, CRYPT_SESSINFO_ACTIVE, 0); DeInit; + FReadBuffer := ''; Result := True; end; @@ -434,13 +463,18 @@ var begin FLastError := 0; FLastErrorDesc := ''; - SSLCheck(cryptPopData(FCryptSession, Buffer, Len, L)); - Result := l; + if Length(FReadBuffer) = 0 then + FReadBuffer := PopAll; + if Len > Length(FReadBuffer) then + Len := Length(FReadBuffer); + Move(Pointer(FReadBuffer)^, buffer^, Len); + Delete(FReadBuffer, 1, Len); + Result := Len; end; function TSSLCryptLib.WaitingData: Integer; begin - Result := 0; + Result := Length(FReadBuffer); end; function TSSLCryptLib.GetSSLVersion: string; diff --git a/ssl_openssl.pas b/ssl_openssl.pas index 5452705..12c2f1e 100644 --- a/ssl_openssl.pas +++ b/ssl_openssl.pas @@ -1,5 +1,5 @@ {==============================================================================| -| Project : Ararat Synapse | 001.000.003 | +| Project : Ararat Synapse | 001.000.004 | |==============================================================================| | Content: SSL support by OpenSSL | |==============================================================================| @@ -643,6 +643,11 @@ begin Exit; end; cert := SSLGetPeerCertificate(Fssl); + if not assigned(cert) then + begin + Result := ''; + Exit; + end; {$IFDEF CIL} sb := StringBuilder.Create(4096); Result := X509NameOneline(X509GetSubjectName(cert), sb, 4096); @@ -676,6 +681,11 @@ begin Exit; end; cert := SSLGetPeerCertificate(Fssl); + if not assigned(cert) then + begin + Result := ''; + Exit; + end; {$IFDEF CIL} sb := StringBuilder.Create(4096); Result := X509NameOneline(X509GetIssuerName(cert), sb, 4096); @@ -700,6 +710,11 @@ begin Exit; end; cert := SSLGetPeerCertificate(Fssl); + if not assigned(cert) then + begin + Result := ''; + Exit; + end; {$IFDEF CIL} sb := StringBuilder.Create(EVP_MAX_MD_SIZE); X509Digest(cert, EvpGetDigestByName('MD5'), sb, x); @@ -729,6 +744,11 @@ begin Exit; end; cert := SSLGetPeerCertificate(Fssl); + if not assigned(cert) then + begin + Result := ''; + Exit; + end; b := BioNew(BioSMem); try X509Print(b, cert); diff --git a/ssl_openssl_lib.pas b/ssl_openssl_lib.pas index 0a2db22..bb26a8a 100644 --- a/ssl_openssl_lib.pas +++ b/ssl_openssl_lib.pas @@ -1,5 +1,5 @@ {==============================================================================| -| Project : Ararat Synapse | 003.004.000 | +| Project : Ararat Synapse | 003.004.001 | |==============================================================================| | Content: SSL support by OpenSSL | |==============================================================================| @@ -76,10 +76,8 @@ uses System.Text, {$ENDIF} Classes, -{$IFDEF LINUX} - {$IFDEF FPC} synafpc, - {$ENDIF} +{$IFNDEF WIN32} Libc, SysUtils; {$ELSE} Windows; @@ -97,7 +95,7 @@ const {$ENDIF} {$ELSE} var - {$IFDEF LINUX} + {$IFNDEF WIN32} DLLSSLName: string = 'libssl.so'; DLLUtilName: string = 'libcrypto.so'; {$ELSE} @@ -205,8 +203,8 @@ const EVP_PKEY_RSA = 6; var - SSLLibHandle: Integer = 0; - SSLUtilHandle: Integer = 0; + SSLLibHandle: TLibHandle = 0; + SSLUtilHandle: TLibHandle = 0; SSLLibFile: string = ''; SSLUtilFile: string = ''; diff --git a/ssl_sbb.pas b/ssl_sbb.pas new file mode 100644 index 0000000..5692fd6 --- /dev/null +++ b/ssl_sbb.pas @@ -0,0 +1,594 @@ +{==============================================================================| +| Project : Ararat Synapse | 001.000.001 | +|==============================================================================| +| Content: SSL support for SecureBlackBox | +|==============================================================================| +| Copyright (c)1999-2005, Lukas Gebauer | +| All rights reserved. | +| | +| 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. | +| | +| Redistributions in binary form must reproduce the above copyright notice, | +| this list of conditions and the following disclaimer in the documentation | +| and/or other materials provided with the distribution. | +| | +| Neither the name of Lukas Gebauer nor the names of its contributors may | +| be used to endorse or promote products derived from this software without | +| specific prior written permission. | +| | +| 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. | +|==============================================================================| +| The Initial Developer of the Original Code is Lukas Gebauer (Czech Republic).| +| Portions created by Lukas Gebauer are Copyright (c)2005. | +| All Rights Reserved. | +|==============================================================================| +| Contributor(s): | +| Allen Drennan (adrennan@wiredred.com) | +|==============================================================================| +| History: see HISTORY.HTM from distribution package | +| (Found at URL: http://www.ararat.cz/synapse/) | +|==============================================================================} + +{:@abstract(SSL plugin for Eldos SecureBlackBox) + +For handling keys and certificates you can use this properties: +@link(TCustomSSL.CertCAFile), @link(TCustomSSL.CertCA), +@link(TCustomSSL.TrustCertificateFile), @link(TCustomSSL.TrustCertificate), +@link(TCustomSSL.PrivateKeyFile), @link(TCustomSSL.PrivateKey), +@link(TCustomSSL.CertificateFile), @link(TCustomSSL.Certificate), +@link(TCustomSSL.PFXFile). For usage of this properties and for possible formats +of keys and certificates refer to SecureBlackBox documentation. +} + +{$IFDEF FPC} + {$MODE DELPHI} +{$ENDIF} +{$H+} + +unit ssl_sbb; + +interface + +uses + SysUtils, Classes, Windows, blcksock, synsock, synautil, synacode, + SBClient, SBServer, SBX509, SBWinCertStorage, SBCustomCertStorage, + SBUtils, SBConstants, SBSessionPool; + +const + DEFAULT_RECV_BUFFER=32768; + +type + {:@abstract(class implementing SecureBlackbox SSL plugin.) + Instance of this class will be created for each @link(TTCPBlockSocket). + You not need to create instance of this class, all is done by Synapse itself!} + TSSLSBB=class(TCustomSSL) + protected + FServer: Boolean; + FElSecureClient:TElSecureClient; + FElSecureServer:TElSecureServer; + FElCertStorage:TElMemoryCertStorage; + FElX509Certificate:TElX509Certificate; + private + FRecvBuffer:String; + FRecvBuffers:String; + FRecvDecodedBuffers:String; + function Init(Server:Boolean):Boolean; + function DeInit:Boolean; + function Prepare(Server:Boolean):Boolean; + procedure OnError(Sender:TObject; ErrorCode:Integer; Fatal:Boolean; Remote:Boolean); + procedure OnSend(Sender:TObject;Buffer:Pointer;Size:LongInt); + procedure OnReceive(Sender:TObject;Buffer:Pointer;MaxSize:LongInt;out Written:LongInt); + procedure OnData(Sender:TObject;Buffer:Pointer;Size:LongInt); + public + constructor Create(const Value: TTCPBlockSocket); override; + destructor Destroy; override; + {:See @inherited} + function LibVersion: String; override; + {:See @inherited} + function LibName: String; override; + {:See @inherited and @link(ssl_sbb) for more details.} + function Connect: boolean; override; + {:See @inherited and @link(ssl_sbb) for more details.} + function Accept: boolean; override; + {:See @inherited} + function Shutdown: boolean; override; + {:See @inherited} + function BiShutdown: boolean; override; + {:See @inherited} + function SendBuffer(Buffer: TMemory; Len: Integer): Integer; override; + {:See @inherited} + function RecvBuffer(Buffer: TMemory; Len: Integer): Integer; override; + {:See @inherited} + function WaitingData: Integer; override; + {:See @inherited} + function GetSSLVersion: string; override; + {:See @inherited} + function GetPeerSubject: string; override; + {:See @inherited} + function GetPeerIssuer: string; override; + {:See @inherited} + function GetPeerName: string; override; + {:See @inherited} + function GetPeerFingerprint: string; override; + {:See @inherited} + function GetCertInfo: string; override; + published + property ELSecureClient:TElSecureClient read FElSecureClient write FElSecureClient; + property ELSecureServer:TElSecureServer read FElSecureServer write FElSecureServer; + end; + +implementation + +// on error +procedure TSSLSBB.OnError(Sender:TObject; ErrorCode:Integer; Fatal:Boolean; Remote:Boolean); + +begin + FLastErrorDesc:=''; + FLastError:=ErrorCode; +end; + +// on send +procedure TSSLSBB.OnSend(Sender:TObject;Buffer:Pointer;Size:LongInt); + +var + lResult:Integer; + +begin + lResult:=Send(FSocket.Socket,Buffer,Size,0); + if lResult=SOCKET_ERROR then + begin + FLastErrorDesc:=''; + FLastError:=WSAGetLastError; + end; +end; + +// on receive +procedure TSSLSBB.OnReceive(Sender:TObject;Buffer:Pointer;MaxSize:LongInt;out Written:LongInt); + +begin + if Length(FRecvBuffers)<=MaxSize then + begin + Written:=Length(FRecvBuffers); + Move(FRecvBuffers[1],Buffer^,Written); + FRecvBuffers:=''; + end + else + begin + Written:=MaxSize; + Move(FRecvBuffers[1],Buffer^,Written); + Delete(FRecvBuffers,1,Written); + end; +end; + +// on data +procedure TSSLSBB.OnData(Sender:TObject;Buffer:Pointer;Size:LongInt); + +var + lString:String; + +begin + SetLength(lString,Size); + Move(Buffer^,lString[1],Size); + FRecvDecodedBuffers:=FRecvDecodedBuffers+lString; +end; + +{ inherited } + +constructor TSSLSBB.Create(const Value: TTCPBlockSocket); + +begin + inherited Create(Value); + FServer:=FALSE; + FElSecureClient:=NIL; + FElSecureServer:=NIL; + FElCertStorage:=NIL; + FElX509Certificate:=NIL; + SetLength(FRecvBuffer,DEFAULT_RECV_BUFFER); + FRecvBuffers:=''; + FRecvDecodedBuffers:=''; +end; + +destructor TSSLSBB.Destroy; + +begin + DeInit; + inherited Destroy; +end; + +function TSSLSBB.LibVersion: String; + +begin + Result:='SecureBlackBox'; +end; + +function TSSLSBB.LibName: String; + +begin + Result:='ssl_sbb'; +end; + +function FileToString(lFile:String):String; + +var + lStream:TMemoryStream; + +begin + Result:=''; + lStream:=TMemoryStream.Create; + if lStream<>NIL then + begin + lStream.LoadFromFile(lFile); + if lStream.Size>0 then + begin + lStream.Position:=0; + SetLength(Result,lStream.Size); + Move(lStream.Memory^,Result[1],lStream.Size); + end; + lStream.Free; + end; +end; + +function TSSLSBB.Init(Server:Boolean):Boolean; + +var + loop1:Integer; + lStream:TMemoryStream; + lCertificate,lPrivateKey:String; + +begin + Result:=FALSE; + FServer:=Server; + + // init, certificate + if FCertificateFile<>'' then + lCertificate:=FileToString(FCertificateFile) + else + lCertificate:=FCertificate; + if FPrivateKeyFile<>'' then + lPrivateKey:=FileToString(FPrivateKeyFile) + else + lPrivateKey:=FPrivateKey; + if (lCertificate<>'') and (lPrivateKey<>'') then + begin + FElX509Certificate:=TElX509Certificate.Create(NIL); + if FElX509Certificate<>NIL then + begin + with FElX509Certificate do + begin + lStream:=TMemoryStream.Create; + try + WriteStrToStream(lStream,lCertificate); + lStream.Seek(0,soFromBeginning); + LoadFromStream(lStream); + finally + lStream.Free; + end; + lStream:=TMemoryStream.Create; + try + WriteStrToStream(lStream,lPrivateKey); + lStream.Seek(0,soFromBeginning); + LoadKeyFromStream(lStream); + finally + lStream.Free; + end; + FElCertStorage:=TElMemoryCertStorage.Create(NIL); + if FElCertStorage<>NIL then + begin + FElCertStorage.Clear; + FElCertStorage.Add(FElX509Certificate); + end; + end; + end; + end; + + // init, as server + if FServer then + begin + FElSecureServer:=TElSecureServer.Create(NIL); + if FElSecureServer<>NIL then + begin + // init, ciphers + for loop1:=SB_SUITE_FIRST to SB_SUITE_LAST do + FElSecureServer.CipherSuites[loop1]:=TRUE; + FElSecureServer.Versions:=[sbSSL2,sbSSL3,sbTLS1]; + FElSecureServer.ClientAuthentication:=FALSE; + FElSecureServer.OnError:=OnError; + FElSecureServer.OnSend:=OnSend; + FElSecureServer.OnReceive:=OnReceive; + FElSecureServer.OnData:=OnData; + FElSecureServer.CertStorage:=FElCertStorage; + Result:=TRUE; + end; + end + else + // init, as client + begin + FElSecureClient:=TElSecureClient.Create(NIL); + if FElSecureClient<>NIL then + begin + // init, ciphers + for loop1:=SB_SUITE_FIRST to SB_SUITE_LAST do + FElSecureClient.CipherSuites[loop1]:=TRUE; + FElSecureClient.Versions:=[sbSSL3,sbTLS1]; + FElSecureClient.OnError:=OnError; + FElSecureClient.OnSend:=OnSend; + FElSecureClient.OnReceive:=OnReceive; + FElSecureClient.OnData:=OnData; + FElSecureClient.CertStorage:=FElCertStorage; + Result:=TRUE; + end; + end; +end; + +function TSSLSBB.DeInit:Boolean; + +begin + Result:=TRUE; + if FElSecureServer<>NIL then + FreeAndNIL(FElSecureServer); + if FElSecureClient<>NIL then + FreeAndNIL(FElSecureClient); + if FElX509Certificate<>NIL then + FreeAndNIL(FElX509Certificate); + if FElCertStorage<>NIL then + FreeAndNIL(FElCertStorage); + FSSLEnabled:=FALSE; +end; + +function TSSLSBB.Prepare(Server:Boolean): Boolean; + +begin + Result:=FALSE; + DeInit; + if Init(Server) then + Result:=TRUE + else + DeInit; +end; + +function TSSLSBB.Connect: boolean; + +var + lResult:Integer; + +begin + Result:=FALSE; + if FSocket.Socket=INVALID_SOCKET then + Exit; + if Prepare(FALSE) then + begin + FElSecureClient.Open; + + // wait for open or error + while (not FElSecureClient.Active) and + (FLastError=0) do + begin + // data available? + if FRecvBuffers<>'' then + FElSecureClient.DataAvailable + else + begin + // socket recv + lResult:=Recv(FSocket.Socket,@FRecvBuffer[1],Length(FRecvBuffer),0); + if lResult=SOCKET_ERROR then + begin + FLastErrorDesc:=''; + FLastError:=WSAGetLastError; + end + else + begin + if lResult>0 then + FRecvBuffers:=FRecvBuffers+Copy(FRecvBuffer,1,lResult) + else + Break; + end; + end; + end; + if FLastError<>0 then + Exit; + FSSLEnabled:=FElSecureClient.Active; + Result:=FSSLEnabled; + end; +end; + +function TSSLSBB.Accept: boolean; + +var + lResult:Integer; + +begin + Result:=FALSE; + if FSocket.Socket=INVALID_SOCKET then + Exit; + if Prepare(TRUE) then + begin + FElSecureServer.Open; + + // wait for open or error + while (not FElSecureServer.Active) and + (FLastError=0) do + begin + // data available? + if FRecvBuffers<>'' then + FElSecureServer.DataAvailable + else + begin + // socket recv + lResult:=Recv(FSocket.Socket,@FRecvBuffer[1],Length(FRecvBuffer),0); + if lResult=SOCKET_ERROR then + begin + FLastErrorDesc:=''; + FLastError:=WSAGetLastError; + end + else + begin + if lResult>0 then + FRecvBuffers:=FRecvBuffers+Copy(FRecvBuffer,1,lResult) + else + Break; + end; + end; + end; + if FLastError<>0 then + Exit; + FSSLEnabled:=FElSecureServer.Active; + Result:=FSSLEnabled; + end; +end; + +function TSSLSBB.Shutdown: boolean; + +begin + Result:=BiShutdown; +end; + +function TSSLSBB.BiShutdown: boolean; + +begin + DeInit; + Result:=TRUE; +end; + +function TSSLSBB.SendBuffer(Buffer: TMemory; Len: Integer): Integer; + +begin + if FServer then + FElSecureServer.SendData(Buffer,Len) + else + FElSecureClient.SendData(Buffer,Len); + Result:=Len; +end; + +function TSSLSBB.RecvBuffer(Buffer: TMemory; Len: Integer): Integer; + +begin + if Length(FRecvDecodedBuffers)'' then + begin + if FServer then + FElSecureServer.DataAvailable + else + FElSecureClient.DataAvailable; + end + else + begin + // socket recv + lResult:=Recv(FSocket.Socket,@FRecvBuffer[1],Length(FRecvBuffer),0); + if lResult=SOCKET_ERROR then + begin + FLastErrorDesc:=''; + FLastError:=WSAGetLastError; + end + else + FRecvBuffers:=FRecvBuffers+Copy(FRecvBuffer,1,lResult); + + // data available? + if FRecvBuffers<>'' then + begin + if FServer then + FElSecureServer.DataAvailable + else + FElSecureClient.DataAvailable; + end; + end; + Result:=Length(FRecvDecodedBuffers); +end; + +function TSSLSBB.GetSSLVersion: string; + +begin + Result:='SSLv3 or TLSv1'; +end; + +function TSSLSBB.GetPeerSubject: string; + +begin + Result := ''; +// if FServer then + // must return subject of the client certificate +// else + // must return subject of the server certificate +end; + +function TSSLSBB.GetPeerName: string; + +begin + Result := ''; +// if FServer then + // must return commonname of the client certificate +// else + // must return commonname of the server certificate +end; + +function TSSLSBB.GetPeerIssuer: string; + +begin + Result := ''; +// if FServer then + // must return issuer of the client certificate +// else + // must return issuer of the server certificate +end; + +function TSSLSBB.GetPeerFingerprint: string; + +begin + Result := ''; +// if FServer then + // must return a unique hash string of the client certificate +// else + // must return a unique hash string of the server certificate +end; + +function TSSLSBB.GetCertInfo: string; + +begin + Result := ''; +// if FServer then + // must return a text representation of the ASN of the client certificate +// else + // must return a text representation of the ASN of the server certificate +end; + +{==============================================================================} + +initialization + SSLImplementation := TSSLSBB; + +finalization + +end. diff --git a/sslinux.pas b/sslinux.pas index 536c54f..887b666 100644 --- a/sslinux.pas +++ b/sslinux.pas @@ -1,5 +1,5 @@ {==============================================================================| -| Project : Ararat Synapse | 002.000.005 | +| Project : Ararat Synapse | 002.000.007 | |==============================================================================| | Content: Socket Independent Platform Layer - Linux definition include | |==============================================================================| @@ -62,10 +62,8 @@ For IPv6 support you must have new API! interface uses - SyncObjs, SysUtils, - {$IFDEF FPC} + SyncObjs, SysUtils, Classes, synafpc, - {$ENDIF} Libc; function InitSocketInterface(stack: string): Boolean; @@ -82,6 +80,7 @@ type pu_long = ^u_long; pu_short = ^u_short; TSocket = u_int; + TAddrFamily = integer; TMemory = pointer; @@ -89,6 +88,14 @@ type const DLLStackName = 'libc.so.6'; + cLocalhost = '127.0.0.1'; + cAnyHost = '0.0.0.0'; + cBroadcast = '255.255.255.255'; + c6Localhost = '::1'; + c6AnyHost = '::0'; + c6Broadcast = 'ffff::1'; + cAnyPort = '0'; + type DWORD = Integer; __fd_mask = LongWord; @@ -127,20 +134,11 @@ const IPPROTO_MAX = 256; type - SunB = packed record - s_b1, s_b2, s_b3, s_b4: u_char; - end; - - SunW = packed record - s_w1, s_w2: u_short; - end; - PInAddr = ^TInAddr; TInAddr = packed record case integer of - 0: (S_un_b: SunB); - 1: (S_un_w: SunW); - 2: (S_addr: u_long); + 0: (S_bytes: packed array [0..3] of byte); + 1: (S_addr: u_long); end; PSockAddrIn = ^TSockAddrIn; @@ -159,33 +157,13 @@ type imr_interface: TInAddr; { local IP address of interface } end; - SunB6 = packed record - s_b1, s_b2, s_b3, s_b4, - s_b5, s_b6, s_b7, s_b8, - s_b9, s_b10, s_b11, s_b12, - s_b13, s_b14, s_b15, s_b16: u_char; - end; - - SunW6 = packed record - s_w1, s_w2, s_w3, s_w4, - s_w5, s_w6, s_w7, s_w8: u_short; - end; - - SunDW6 = packed record - s_dw1, s_dw2, s_dw3, s_dw4: longint; - end; - - S6_Bytes = SunB6; - S6_Words = SunW6; - S6_DWords = SunDW6; - S6_Addr = SunB6; - PInAddr6 = ^TInAddr6; TInAddr6 = packed record case integer of - 0: (S_un_b: SunB6); - 1: (S_un_w: SunW6); - 2: (S_un_dw: SunDW6); + 0: (S6_addr: packed array [0..15] of byte); + 1: (u6_addr8: packed array [0..15] of byte); + 2: (u6_addr16: packed array [0..7] of word); + 3: (u6_addr32: packed array [0..7] of integer); end; PSockAddrIn6 = ^TSockAddrIn6; @@ -200,7 +178,7 @@ type TIPv6_mreq = record ipv6mr_multiaddr: TInAddr6; // IPv6 multicast address. - ipv6mr_interface: u_long; // Interface index. + ipv6mr_interface: integer; // Interface index. padding: u_long; end; @@ -378,8 +356,8 @@ type { Structure used for manipulating linger option. } PLinger = ^TLinger; TLinger = packed record - l_onoff: u_short; - l_linger: u_short; + l_onoff: integer; + l_linger: integer; end; const @@ -530,7 +508,7 @@ type cdecl; TListen = function(s: TSocket; backlog: Integer): Integer; cdecl; - TIoctlSocket = function(s: TSocket; cmd: DWORD; var arg: u_long): Integer; + TIoctlSocket = function(s: TSocket; cmd: DWORD; var arg: integer): Integer; cdecl; TInet_ntoa = function(inaddr: TInAddr): PChar; cdecl; @@ -644,41 +622,49 @@ function SendTo(s: TSocket; Buf: TMemory; len, flags: Integer; addrto: TVarSin): function RecvFrom(s: TSocket; Buf: TMemory; len, flags: Integer; var from: TVarSin): Integer; function Accept(s: TSocket; var addr: TVarSin): TSocket; +function IsNewApi(Family: integer): Boolean; +function SetVarSin(var Sin: TVarSin; IP, Port: string; Family, SockProtocol, SockType: integer; PreferIP4: Boolean): integer; +function GetSinIP(Sin: TVarSin): string; +function GetSinPort(Sin: TVarSin): Integer; +procedure ResolveNameToIP(Name: string; Family, SockProtocol, SockType: integer; const IPList: TStrings); +function ResolveIPToName(IP: string; Family, SockProtocol, SockType: integer): string; +function ResolvePort(Port: string; Family, SockProtocol, SockType: integer): Word; + {==============================================================================} implementation var SynSockCount: Integer = 0; - LibHandle: THandle = 0; - Libwship6Handle: THandle = 0; + LibHandle: TLibHandle = 0; + Libwship6Handle: TLibHandle = 0; function IN6_IS_ADDR_UNSPECIFIED(const a: PInAddr6): boolean; begin - Result := ((a^.s_un_dw.s_dw1 = 0) and (a^.s_un_dw.s_dw2 = 0) and - (a^.s_un_dw.s_dw3 = 0) and (a^.s_un_dw.s_dw4 = 0)); + Result := ((a^.u6_addr32[0] = 0) and (a^.u6_addr32[1] = 0) and + (a^.u6_addr32[2] = 0) and (a^.u6_addr32[3] = 0)); end; function IN6_IS_ADDR_LOOPBACK(const a: PInAddr6): boolean; begin - Result := ((a^.s_un_dw.s_dw1 = 0) and (a^.s_un_dw.s_dw2 = 0) and - (a^.s_un_dw.s_dw3 = 0) and - (a^.s_un_b.s_b13 = char(0)) and (a^.s_un_b.s_b14 = char(0)) and - (a^.s_un_b.s_b15 = char(0)) and (a^.s_un_b.s_b16 = char(1))); + Result := ((a^.u6_addr32[0] = 0) and (a^.u6_addr32[1] = 0) and + (a^.u6_addr32[2] = 0) and + (a^.u6_addr8[12] = 0) and (a^.u6_addr8[13] = 0) and + (a^.u6_addr8[14] = 0) and (a^.u6_addr8[15] = 1)); end; function IN6_IS_ADDR_LINKLOCAL(const a: PInAddr6): boolean; begin - Result := ((a^.s_un_b.s_b1 = u_char($FE)) and (a^.s_un_b.s_b2 = u_char($80))); + Result := ((a^.u6_addr8[0] = $FE) and (a^.u6_addr8[1] = $80)); end; function IN6_IS_ADDR_SITELOCAL(const a: PInAddr6): boolean; begin - Result := ((a^.s_un_b.s_b1 = u_char($FE)) and (a^.s_un_b.s_b2 = u_char($C0))); + Result := ((a^.u6_addr8[0] = $FE) and (a^.u6_addr8[1] = $C0)); end; function IN6_IS_ADDR_MULTICAST(const a: PInAddr6): boolean; begin - Result := (a^.s_un_b.s_b1 = char($FF)); + Result := (a^.u6_addr8[0] = $FF); end; function IN6_ADDR_EQUAL(const a: PInAddr6; const b: PInAddr6): boolean; @@ -694,7 +680,7 @@ end; procedure SET_LOOPBACK_ADDR6 (const a: PInAddr6); begin FillChar(a^, sizeof(TInAddr6), 0); - a^.s_un_b.s_b16 := char(1); + a^.u6_addr8[15] := 1; end; {=============================================================================} @@ -851,6 +837,369 @@ begin Result := ssAccept(s, @addr, x); end; +{=============================================================================} +function IsNewApi(Family: integer): Boolean; +begin + Result := SockEnhancedApi; + if not Result then + Result := (Family = AF_INET6) and SockWship6Api; +end; + +function SetVarSin(var Sin: TVarSin; IP, Port: string; Family, SockProtocol, SockType: integer; PreferIP4: Boolean): integer; +type + pu_long = ^u_long; +var + ProtoEnt: PProtoEnt; + ServEnt: PServEnt; + HostEnt: PHostEnt; + r: integer; + Hints1, Hints2: TAddrInfo; + Sin1, Sin2: TVarSin; + TwoPass: boolean; + + function GetAddr(const IP, port: string; Hints: TAddrInfo; var Sin: TVarSin): integer; + var + Addr: PAddrInfo; + begin + Addr := nil; + try + FillChar(Sin, Sizeof(Sin), 0); + if Hints.ai_socktype = SOCK_RAW then + begin + Hints.ai_socktype := 0; + Hints.ai_protocol := 0; + Result := synsock.GetAddrInfo(PChar(IP), nil, @Hints, Addr); + end + else + begin + if (IP = cAnyHost) or (IP = c6AnyHost) then + begin + Hints.ai_flags := AI_PASSIVE; + Result := synsock.GetAddrInfo(nil, PChar(Port), @Hints, Addr); + end + else + if (IP = cLocalhost) or (IP = c6Localhost) then + begin + Result := synsock.GetAddrInfo(nil, PChar(Port), @Hints, Addr); + end + else + begin + Result := synsock.GetAddrInfo(PChar(IP), PChar(Port), @Hints, Addr); + end; + end; + if Result = 0 then + if (Addr <> nil) then + Move(Addr^.ai_addr^, Sin, Addr^.ai_addrlen); + finally + if Assigned(Addr) then + synsock.FreeAddrInfo(Addr); + end; + end; + +begin + Result := 0; + FillChar(Sin, Sizeof(Sin), 0); + if not IsNewApi(family) then + begin + SynSockCS.Enter; + try + Sin.sin_family := AF_INET; + ProtoEnt := synsock.GetProtoByNumber(SockProtocol); + ServEnt := nil; + if ProtoEnt <> nil then + ServEnt := synsock.GetServByName(PChar(Port), ProtoEnt^.p_name); + if ServEnt = nil then + Sin.sin_port := synsock.htons(StrToIntDef(Port, 0)) + else + Sin.sin_port := ServEnt^.s_port; + if IP = cBroadcast then + Sin.sin_addr.s_addr := u_long(INADDR_BROADCAST) + else + begin + Sin.sin_addr.s_addr := synsock.inet_addr(PChar(IP)); + if Sin.sin_addr.s_addr = u_long(INADDR_NONE) then + begin + HostEnt := synsock.GetHostByName(PChar(IP)); + Result := synsock.WSAGetLastError; + if HostEnt <> nil then + Sin.sin_addr.S_addr := u_long(Pu_long(HostEnt^.h_addr_list^)^); + end; + end; + finally + SynSockCS.Leave; + end; + end + else + begin + FillChar(Hints1, Sizeof(Hints1), 0); + FillChar(Hints2, Sizeof(Hints2), 0); + TwoPass := False; + if Family = AF_UNSPEC then + begin + if PreferIP4 then + begin + Hints1.ai_family := AF_INET; + Hints2.ai_family := AF_INET6; + TwoPass := True; + end + else + begin + Hints2.ai_family := AF_INET; + Hints1.ai_family := AF_INET6; + TwoPass := True; + end; + end + else + Hints1.ai_family := Family; + + Hints1.ai_socktype := SockType; + Hints1.ai_protocol := SockProtocol; + Hints2.ai_socktype := Hints1.ai_socktype; + Hints2.ai_protocol := Hints1.ai_protocol; + + r := GetAddr(IP, Port, Hints1, Sin1); + Result := r; + sin := sin1; + if r <> 0 then + if TwoPass then + begin + r := GetAddr(IP, Port, Hints2, Sin2); + Result := r; + if r = 0 then + sin := sin2; + end; + end; +end; + +function GetSinIP(Sin: TVarSin): string; +var + p: PChar; + host, serv: string; + hostlen, servlen: integer; + r: integer; +begin + Result := ''; + if not IsNewApi(Sin.AddressFamily) then + begin + p := synsock.inet_ntoa(Sin.sin_addr); + if p <> nil then + Result := p; + end + else + begin + hostlen := NI_MAXHOST; + servlen := NI_MAXSERV; + setlength(host, hostlen); + setlength(serv, servlen); + r := getnameinfo(@sin, SizeOfVarSin(sin), PChar(host), hostlen, + PChar(serv), servlen, NI_NUMERICHOST + NI_NUMERICSERV); + if r = 0 then + Result := PChar(host); + end; +end; + +function GetSinPort(Sin: TVarSin): Integer; +begin + if (Sin.sin_family = AF_INET6) then + Result := synsock.ntohs(Sin.sin6_port) + else + Result := synsock.ntohs(Sin.sin_port); +end; + +procedure ResolveNameToIP(Name: string; Family, SockProtocol, SockType: integer; const IPList: TStrings); +type + TaPInAddr = array[0..250] of PInAddr; + PaPInAddr = ^TaPInAddr; +var + Hints: TAddrInfo; + Addr: PAddrInfo; + AddrNext: PAddrInfo; + r: integer; + host, serv: string; + hostlen, servlen: integer; + RemoteHost: PHostEnt; + IP: u_long; + PAdrPtr: PaPInAddr; + i: Integer; + s: string; + InAddr: TInAddr; +begin + IPList.Clear; + if not IsNewApi(Family) then + begin + IP := synsock.inet_addr(PChar(Name)); + if IP = u_long(INADDR_NONE) then + begin + SynSockCS.Enter; + try + RemoteHost := synsock.GetHostByName(PChar(Name)); + if RemoteHost <> nil then + begin + PAdrPtr := PAPInAddr(RemoteHost^.h_addr_list); + i := 0; + while PAdrPtr^[i] <> nil do + begin + InAddr := PAdrPtr^[i]^; + s := Format('%d.%d.%d.%d', [InAddr.S_bytes[0], InAddr.S_bytes[1], + InAddr.S_bytes[2], InAddr.S_bytes[3]]); + IPList.Add(s); + Inc(i); + end; + end; + finally + SynSockCS.Leave; + end; + end + else + IPList.Add(Name); + end + else + begin + Addr := nil; + try + FillChar(Hints, Sizeof(Hints), 0); + Hints.ai_family := AF_UNSPEC; + Hints.ai_socktype := SockType; + Hints.ai_protocol := SockProtocol; + Hints.ai_flags := 0; + r := synsock.GetAddrInfo(PChar(Name), nil, @Hints, Addr); + if r = 0 then + begin + AddrNext := Addr; + while not(AddrNext = nil) do + begin + if not(((Family = AF_INET6) and (AddrNext^.ai_family = AF_INET)) + or ((Family = AF_INET) and (AddrNext^.ai_family = AF_INET6))) then + begin + hostlen := NI_MAXHOST; + servlen := NI_MAXSERV; + setlength(host, hostlen); + setlength(serv, servlen); + r := getnameinfo(AddrNext^.ai_addr, AddrNext^.ai_addrlen, + PChar(host), hostlen, PChar(serv), servlen, + NI_NUMERICHOST + NI_NUMERICSERV); + if r = 0 then + begin + host := PChar(host); + IPList.Add(host); + end; + end; + AddrNext := AddrNext^.ai_next; + end; + end; + finally + if Assigned(Addr) then + synsock.FreeAddrInfo(Addr); + end; + end; + if IPList.Count = 0 then + IPList.Add(cAnyHost); +end; + +function ResolvePort(Port: string; Family, SockProtocol, SockType: integer): Word; +var + ProtoEnt: PProtoEnt; + ServEnt: PServEnt; + Hints: TAddrInfo; + Addr: PAddrInfo; + r: integer; +begin + Result := 0; + if not IsNewApi(Family) then + begin + SynSockCS.Enter; + try + ProtoEnt := synsock.GetProtoByNumber(SockProtocol); + ServEnt := nil; + if ProtoEnt <> nil then + ServEnt := synsock.GetServByName(PChar(Port), ProtoEnt^.p_name); + if ServEnt = nil then + Result := StrToIntDef(Port, 0) + else + Result := synsock.htons(ServEnt^.s_port); + finally + SynSockCS.Leave; + end; + end + else + begin + Addr := nil; + try + FillChar(Hints, Sizeof(Hints), 0); + Hints.ai_family := AF_UNSPEC; + Hints.ai_socktype := SockType; + Hints.ai_protocol := Sockprotocol; + Hints.ai_flags := AI_PASSIVE; + r := synsock.GetAddrInfo(nil, PChar(Port), @Hints, Addr); + if (r = 0) and Assigned(Addr) then + begin + if Addr^.ai_family = AF_INET then + Result := synsock.htons(Addr^.ai_addr^.sin_port); + if Addr^.ai_family = AF_INET6 then + Result := synsock.htons(PSockAddrIn6(Addr^.ai_addr)^.sin6_port); + end; + finally + if Assigned(Addr) then + synsock.FreeAddrInfo(Addr); + end; + end; +end; + +function ResolveIPToName(IP: string; Family, SockProtocol, SockType: integer): string; +var + Hints: TAddrInfo; + Addr: PAddrInfo; + r: integer; + host, serv: string; + hostlen, servlen: integer; + RemoteHost: PHostEnt; + IPn: u_long; +begin + Result := IP; + if not IsNewApi(Family) then + begin + IPn := synsock.inet_addr(PChar(IP)); + if IPn <> u_long(INADDR_NONE) then + begin + SynSockCS.Enter; + try + RemoteHost := GetHostByAddr(@IPn, SizeOf(IPn), AF_INET); + if RemoteHost <> nil then + Result := RemoteHost^.h_name; + finally + SynSockCS.Leave; + end; + end; + end + else + begin + Addr := nil; + try + FillChar(Hints, Sizeof(Hints), 0); + Hints.ai_family := AF_UNSPEC; + Hints.ai_socktype := SockType; + Hints.ai_protocol := SockProtocol; + Hints.ai_flags := 0; + r := synsock.GetAddrInfo(PChar(IP), nil, @Hints, Addr); + if (r = 0) and Assigned(Addr)then + begin + hostlen := NI_MAXHOST; + servlen := NI_MAXSERV; + setlength(host, hostlen); + setlength(serv, servlen); + r := getnameinfo(Addr^.ai_addr, Addr^.ai_addrlen, + PChar(host), hostlen, PChar(serv), servlen, + NI_NUMERICSERV); + if r = 0 then + Result := PChar(host); + end; + finally + if Assigned(Addr) then + synsock.FreeAddrInfo(Addr); + end; + end; +end; + {=============================================================================} function InitSocketInterface(stack: string): Boolean; diff --git a/sswin32.pas b/sswin32.pas index 6964718..2e0824c 100644 --- a/sswin32.pas +++ b/sswin32.pas @@ -241,7 +241,7 @@ For IPv6 support you must have new API! interface uses - SyncObjs, SysUtils, + SyncObjs, SysUtils, Classes, Windows; function InitSocketInterface(stack: string): Boolean; @@ -262,6 +262,7 @@ type pu_long = ^u_long; pu_short = ^u_short; TSocket = u_int; + TAddrFamily = integer; TMemory = pointer; @@ -273,6 +274,15 @@ const {$ENDIF} DLLwship6 = 'wship6.dll'; + cLocalhost = '127.0.0.1'; + cAnyHost = '0.0.0.0'; + cBroadcast = '255.255.255.255'; + c6Localhost = '::1'; + c6AnyHost = '::0'; + c6Broadcast = 'ffff::1'; + cAnyPort = '0'; + + const FD_SETSIZE = 64; type @@ -307,20 +317,12 @@ const IPPROTO_MAX = 256; type - SunB = packed record - s_b1, s_b2, s_b3, s_b4: u_char; - end; - - SunW = packed record - s_w1, s_w2: u_short; - end; PInAddr = ^TInAddr; TInAddr = packed record case integer of - 0: (S_un_b: SunB); - 1: (S_un_w: SunW); - 2: (S_addr: u_long); + 0: (S_bytes: packed array [0..3] of byte); + 1: (S_addr: u_long); end; PSockAddrIn = ^TSockAddrIn; @@ -339,33 +341,13 @@ type imr_interface: TInAddr; { local IP address of interface } end; - SunB6 = packed record - s_b1, s_b2, s_b3, s_b4, - s_b5, s_b6, s_b7, s_b8, - s_b9, s_b10, s_b11, s_b12, - s_b13, s_b14, s_b15, s_b16: u_char; - end; - - SunW6 = packed record - s_w1, s_w2, s_w3, s_w4, - s_w5, s_w6, s_w7, s_w8: u_short; - end; - - SunDW6 = packed record - s_dw1, s_dw2, s_dw3, s_dw4: longint; - end; - - S6_Bytes = SunB6; - S6_Words = SunW6; - S6_DWords = SunDW6; - S6_Addr = SunB6; - PInAddr6 = ^TInAddr6; TInAddr6 = packed record case integer of - 0: (S_un_b: SunB6); - 1: (S_un_w: SunW6); - 2: (S_un_dw: SunDW6); + 0: (S6_addr: packed array [0..15] of byte); + 1: (u6_addr8: packed array [0..15] of byte); + 2: (u6_addr16: packed array [0..7] of word); + 3: (u6_addr32: packed array [0..7] of integer); end; PSockAddrIn6 = ^TSockAddrIn6; @@ -380,8 +362,8 @@ type TIPv6_mreq = record ipv6mr_multiaddr: TInAddr6; // IPv6 multicast address. - ipv6mr_interface: u_long; // Interface index. - padding: u_long; + ipv6mr_interface: integer; // Interface index. + padding: integer; end; PHostEnt = ^THostEnt; @@ -807,7 +789,7 @@ type stdcall; TListen = function(s: TSocket; backlog: Integer): Integer; stdcall; - TIoctlSocket = function(s: TSocket; cmd: DWORD; var arg: u_long): Integer; + TIoctlSocket = function(s: TSocket; cmd: DWORD; var arg: Integer): Integer; stdcall; TInet_ntoa = function(inaddr: TInAddr): PChar; stdcall; @@ -930,6 +912,14 @@ function SendTo(s: TSocket; Buf: TMemory; len, flags: Integer; addrto: TVarSin): function RecvFrom(s: TSocket; Buf: TMemory; len, flags: Integer; var from: TVarSin): Integer; function Accept(s: TSocket; var addr: TVarSin): TSocket; +function IsNewApi(Family: integer): Boolean; +function SetVarSin(var Sin: TVarSin; IP, Port: string; Family, SockProtocol, SockType: integer; PreferIP4: Boolean): integer; +function GetSinIP(Sin: TVarSin): string; +function GetSinPort(Sin: TVarSin): Integer; +procedure ResolveNameToIP(Name: string; Family, SockProtocol, SockType: integer; const IPList: TStrings); +function ResolveIPToName(IP: string; Family, SockProtocol, SockType: integer): string; +function ResolvePort(Port: string; Family, SockProtocol, SockType: integer): Word; + {==============================================================================} implementation @@ -940,31 +930,31 @@ var function IN6_IS_ADDR_UNSPECIFIED(const a: PInAddr6): boolean; begin - Result := ((a^.s_un_dw.s_dw1 = 0) and (a^.s_un_dw.s_dw2 = 0) and - (a^.s_un_dw.s_dw3 = 0) and (a^.s_un_dw.s_dw4 = 0)); + Result := ((a^.u6_addr32[0] = 0) and (a^.u6_addr32[1] = 0) and + (a^.u6_addr32[2] = 0) and (a^.u6_addr32[3] = 0)); end; function IN6_IS_ADDR_LOOPBACK(const a: PInAddr6): boolean; begin - Result := ((a^.s_un_dw.s_dw1 = 0) and (a^.s_un_dw.s_dw2 = 0) and - (a^.s_un_dw.s_dw3 = 0) and - (a^.s_un_b.s_b13 = char(0)) and (a^.s_un_b.s_b14 = char(0)) and - (a^.s_un_b.s_b15 = char(0)) and (a^.s_un_b.s_b16 = char(1))); + Result := ((a^.u6_addr32[0] = 0) and (a^.u6_addr32[1] = 0) and + (a^.u6_addr32[2] = 0) and + (a^.u6_addr8[12] = 0) and (a^.u6_addr8[13] = 0) and + (a^.u6_addr8[14] = 0) and (a^.u6_addr8[15] = 1)); end; function IN6_IS_ADDR_LINKLOCAL(const a: PInAddr6): boolean; begin - Result := ((a^.s_un_b.s_b1 = u_char($FE)) and (a^.s_un_b.s_b2 = u_char($80))); + Result := ((a^.u6_addr8[0] = $FE) and (a^.u6_addr8[1] = $80)); end; function IN6_IS_ADDR_SITELOCAL(const a: PInAddr6): boolean; begin - Result := ((a^.s_un_b.s_b1 = u_char($FE)) and (a^.s_un_b.s_b2 = u_char($C0))); + Result := ((a^.u6_addr8[0] = $FE) and (a^.u6_addr8[1] = $C0)); end; function IN6_IS_ADDR_MULTICAST(const a: PInAddr6): boolean; begin - Result := (a^.s_un_b.s_b1 = char($FF)); + Result := (a^.u6_addr8[0] = $FF); end; function IN6_ADDR_EQUAL(const a: PInAddr6; const b: PInAddr6): boolean; @@ -980,7 +970,7 @@ end; procedure SET_LOOPBACK_ADDR6 (const a: PInAddr6); begin FillChar(a^, sizeof(TInAddr6), 0); - a^.s_un_b.s_b16 := char(1); + a^.u6_addr8[15] := 1; end; {=============================================================================} @@ -1109,6 +1099,369 @@ begin Result := ssAccept(s, @addr, x); end; +{=============================================================================} +function IsNewApi(Family: integer): Boolean; +begin + Result := SockEnhancedApi; + if not Result then + Result := (Family = AF_INET6) and SockWship6Api; +end; + +function SetVarSin(var Sin: TVarSin; IP, Port: string; Family, SockProtocol, SockType: integer; PreferIP4: Boolean): integer; +type + pu_long = ^u_long; +var + ProtoEnt: PProtoEnt; + ServEnt: PServEnt; + HostEnt: PHostEnt; + r: integer; + Hints1, Hints2: TAddrInfo; + Sin1, Sin2: TVarSin; + TwoPass: boolean; + + function GetAddr(const IP, port: string; Hints: TAddrInfo; var Sin: TVarSin): integer; + var + Addr: PAddrInfo; + begin + Addr := nil; + try + FillChar(Sin, Sizeof(Sin), 0); + if Hints.ai_socktype = SOCK_RAW then + begin + Hints.ai_socktype := 0; + Hints.ai_protocol := 0; + Result := synsock.GetAddrInfo(PChar(IP), nil, @Hints, Addr); + end + else + begin + if (IP = cAnyHost) or (IP = c6AnyHost) then + begin + Hints.ai_flags := AI_PASSIVE; + Result := synsock.GetAddrInfo(nil, PChar(Port), @Hints, Addr); + end + else + if (IP = cLocalhost) or (IP = c6Localhost) then + begin + Result := synsock.GetAddrInfo(nil, PChar(Port), @Hints, Addr); + end + else + begin + Result := synsock.GetAddrInfo(PChar(IP), PChar(Port), @Hints, Addr); + end; + end; + if Result = 0 then + if (Addr <> nil) then + Move(Addr^.ai_addr^, Sin, Addr^.ai_addrlen); + finally + if Assigned(Addr) then + synsock.FreeAddrInfo(Addr); + end; + end; + +begin + Result := 0; + FillChar(Sin, Sizeof(Sin), 0); + if not IsNewApi(family) then + begin + SynSockCS.Enter; + try + Sin.sin_family := AF_INET; + ProtoEnt := synsock.GetProtoByNumber(SockProtocol); + ServEnt := nil; + if ProtoEnt <> nil then + ServEnt := synsock.GetServByName(PChar(Port), ProtoEnt^.p_name); + if ServEnt = nil then + Sin.sin_port := synsock.htons(StrToIntDef(Port, 0)) + else + Sin.sin_port := ServEnt^.s_port; + if IP = cBroadcast then + Sin.sin_addr.s_addr := u_long(INADDR_BROADCAST) + else + begin + Sin.sin_addr.s_addr := synsock.inet_addr(PChar(IP)); + if Sin.sin_addr.s_addr = u_long(INADDR_NONE) then + begin + HostEnt := synsock.GetHostByName(PChar(IP)); + Result := synsock.WSAGetLastError; + if HostEnt <> nil then + Sin.sin_addr.S_addr := u_long(Pu_long(HostEnt^.h_addr_list^)^); + end; + end; + finally + SynSockCS.Leave; + end; + end + else + begin + FillChar(Hints1, Sizeof(Hints1), 0); + FillChar(Hints2, Sizeof(Hints2), 0); + TwoPass := False; + if Family = AF_UNSPEC then + begin + if PreferIP4 then + begin + Hints1.ai_family := AF_INET; + Hints2.ai_family := AF_INET6; + TwoPass := True; + end + else + begin + Hints2.ai_family := AF_INET; + Hints1.ai_family := AF_INET6; + TwoPass := True; + end; + end + else + Hints1.ai_family := Family; + + Hints1.ai_socktype := SockType; + Hints1.ai_protocol := SockProtocol; + Hints2.ai_socktype := Hints1.ai_socktype; + Hints2.ai_protocol := Hints1.ai_protocol; + + r := GetAddr(IP, Port, Hints1, Sin1); + Result := r; + sin := sin1; + if r <> 0 then + if TwoPass then + begin + r := GetAddr(IP, Port, Hints2, Sin2); + Result := r; + if r = 0 then + sin := sin2; + end; + end; +end; + +function GetSinIP(Sin: TVarSin): string; +var + p: PChar; + host, serv: string; + hostlen, servlen: integer; + r: integer; +begin + Result := ''; + if not IsNewApi(Sin.AddressFamily) then + begin + p := synsock.inet_ntoa(Sin.sin_addr); + if p <> nil then + Result := p; + end + else + begin + hostlen := NI_MAXHOST; + servlen := NI_MAXSERV; + setlength(host, hostlen); + setlength(serv, servlen); + r := getnameinfo(@sin, SizeOfVarSin(sin), PChar(host), hostlen, + PChar(serv), servlen, NI_NUMERICHOST + NI_NUMERICSERV); + if r = 0 then + Result := PChar(host); + end; +end; + +function GetSinPort(Sin: TVarSin): Integer; +begin + if (Sin.sin_family = AF_INET6) then + Result := synsock.ntohs(Sin.sin6_port) + else + Result := synsock.ntohs(Sin.sin_port); +end; + +procedure ResolveNameToIP(Name: string; Family, SockProtocol, SockType: integer; const IPList: TStrings); +type + TaPInAddr = array[0..250] of PInAddr; + PaPInAddr = ^TaPInAddr; +var + Hints: TAddrInfo; + Addr: PAddrInfo; + AddrNext: PAddrInfo; + r: integer; + host, serv: string; + hostlen, servlen: integer; + RemoteHost: PHostEnt; + IP: u_long; + PAdrPtr: PaPInAddr; + i: Integer; + s: string; + InAddr: TInAddr; +begin + IPList.Clear; + if not IsNewApi(Family) then + begin + IP := synsock.inet_addr(PChar(Name)); + if IP = u_long(INADDR_NONE) then + begin + SynSockCS.Enter; + try + RemoteHost := synsock.GetHostByName(PChar(Name)); + if RemoteHost <> nil then + begin + PAdrPtr := PAPInAddr(RemoteHost^.h_addr_list); + i := 0; + while PAdrPtr^[i] <> nil do + begin + InAddr := PAdrPtr^[i]^; + s := Format('%d.%d.%d.%d', [InAddr.S_bytes[0], InAddr.S_bytes[1], + InAddr.S_bytes[2], InAddr.S_bytes[3]]); + IPList.Add(s); + Inc(i); + end; + end; + finally + SynSockCS.Leave; + end; + end + else + IPList.Add(Name); + end + else + begin + Addr := nil; + try + FillChar(Hints, Sizeof(Hints), 0); + Hints.ai_family := AF_UNSPEC; + Hints.ai_socktype := SockType; + Hints.ai_protocol := SockProtocol; + Hints.ai_flags := 0; + r := synsock.GetAddrInfo(PChar(Name), nil, @Hints, Addr); + if r = 0 then + begin + AddrNext := Addr; + while not(AddrNext = nil) do + begin + if not(((Family = AF_INET6) and (AddrNext^.ai_family = AF_INET)) + or ((Family = AF_INET) and (AddrNext^.ai_family = AF_INET6))) then + begin + hostlen := NI_MAXHOST; + servlen := NI_MAXSERV; + setlength(host, hostlen); + setlength(serv, servlen); + r := getnameinfo(AddrNext^.ai_addr, AddrNext^.ai_addrlen, + PChar(host), hostlen, PChar(serv), servlen, + NI_NUMERICHOST + NI_NUMERICSERV); + if r = 0 then + begin + host := PChar(host); + IPList.Add(host); + end; + end; + AddrNext := AddrNext^.ai_next; + end; + end; + finally + if Assigned(Addr) then + synsock.FreeAddrInfo(Addr); + end; + end; + if IPList.Count = 0 then + IPList.Add(cAnyHost); +end; + +function ResolvePort(Port: string; Family, SockProtocol, SockType: integer): Word; +var + ProtoEnt: PProtoEnt; + ServEnt: PServEnt; + Hints: TAddrInfo; + Addr: PAddrInfo; + r: integer; +begin + Result := 0; + if not IsNewApi(Family) then + begin + SynSockCS.Enter; + try + ProtoEnt := synsock.GetProtoByNumber(SockProtocol); + ServEnt := nil; + if ProtoEnt <> nil then + ServEnt := synsock.GetServByName(PChar(Port), ProtoEnt^.p_name); + if ServEnt = nil then + Result := StrToIntDef(Port, 0) + else + Result := synsock.htons(ServEnt^.s_port); + finally + SynSockCS.Leave; + end; + end + else + begin + Addr := nil; + try + FillChar(Hints, Sizeof(Hints), 0); + Hints.ai_family := AF_UNSPEC; + Hints.ai_socktype := SockType; + Hints.ai_protocol := Sockprotocol; + Hints.ai_flags := AI_PASSIVE; + r := synsock.GetAddrInfo(nil, PChar(Port), @Hints, Addr); + if (r = 0) and Assigned(Addr) then + begin + if Addr^.ai_family = AF_INET then + Result := synsock.htons(Addr^.ai_addr^.sin_port); + if Addr^.ai_family = AF_INET6 then + Result := synsock.htons(PSockAddrIn6(Addr^.ai_addr)^.sin6_port); + end; + finally + if Assigned(Addr) then + synsock.FreeAddrInfo(Addr); + end; + end; +end; + +function ResolveIPToName(IP: string; Family, SockProtocol, SockType: integer): string; +var + Hints: TAddrInfo; + Addr: PAddrInfo; + r: integer; + host, serv: string; + hostlen, servlen: integer; + RemoteHost: PHostEnt; + IPn: u_long; +begin + Result := IP; + if not IsNewApi(Family) then + begin + IPn := synsock.inet_addr(PChar(IP)); + if IPn <> u_long(INADDR_NONE) then + begin + SynSockCS.Enter; + try + RemoteHost := GetHostByAddr(@IPn, SizeOf(IPn), AF_INET); + if RemoteHost <> nil then + Result := RemoteHost^.h_name; + finally + SynSockCS.Leave; + end; + end; + end + else + begin + Addr := nil; + try + FillChar(Hints, Sizeof(Hints), 0); + Hints.ai_family := AF_UNSPEC; + Hints.ai_socktype := SockType; + Hints.ai_protocol := SockProtocol; + Hints.ai_flags := 0; + r := synsock.GetAddrInfo(PChar(IP), nil, @Hints, Addr); + if (r = 0) and Assigned(Addr)then + begin + hostlen := NI_MAXHOST; + servlen := NI_MAXSERV; + setlength(host, hostlen); + setlength(serv, servlen); + r := getnameinfo(Addr^.ai_addr, Addr^.ai_addrlen, + PChar(host), hostlen, PChar(serv), servlen, + NI_NUMERICSERV); + if r = 0 then + Result := PChar(host); + end; + finally + if Assigned(Addr) then + synsock.FreeAddrInfo(Addr); + end; + end; +end; + {=============================================================================} function InitSocketInterface(stack: string): Boolean; diff --git a/synachar.pas b/synachar.pas index 102fd20..586341e 100644 --- a/synachar.pas +++ b/synachar.pas @@ -65,7 +65,7 @@ unit synachar; interface uses -{$IFDEF LINUX} +{$IFNDEF WIN32} Libc, {$ELSE} Windows, @@ -1469,7 +1469,7 @@ begin end; {==============================================================================} -{$IFDEF LINUX} +{$IFNDEF WIN32} function GetCurCP: TMimeChar; begin diff --git a/synafpc.pas b/synafpc.pas index c31f01e..0370d5e 100644 --- a/synafpc.pas +++ b/synafpc.pas @@ -1,9 +1,9 @@ {==============================================================================| -| Project : Ararat Synapse | 001.000.000 | +| Project : Ararat Synapse | 001.001.000 | |==============================================================================| | Content: Utils for FreePascal compatibility | |==============================================================================| -| Copyright (c)1999-2003, Lukas Gebauer | +| Copyright (c)1999-2006, Lukas Gebauer | | All rights reserved. | | | | Redistribution and use in source and binary forms, with or without | @@ -33,7 +33,7 @@ | DAMAGE. | |==============================================================================| | The Initial Developer of the Original Code is Lukas Gebauer (Czech Republic).| -| Portions created by Lukas Gebauer are Copyright (c)2003. | +| Portions created by Lukas Gebauer are Copyright (c)2003-2006. | | All Rights Reserved. | |==============================================================================| | Contributor(s): | @@ -53,56 +53,79 @@ unit synafpc; interface -{$IFDEF LINUX} - {$IFDEF FPC} uses - Libc, - dynlibs; - -type - HMODULE = Longint; - -function LoadLibrary(ModuleName: PChar): HMODULE; -function FreeLibrary(Module: HMODULE): LongBool; -function GetProcAddress(Module: HMODULE; Proc: PChar): Pointer; -function GetModuleFileName(Module: HMODULE; Buffer: PChar; BufLen: Integer): Integer; -procedure Sleep(milliseconds: Cardinal); - +{$IFDEF FPC} + dynlibs, sysutils; +{$ELSE} + {$IFDEF WIN32} + Windows; + {$ELSE} + Sysutils; {$ENDIF} {$ENDIF} +{$IFDEF FPC} +type + TLibHandle = dynlibs.TLibHandle; + +function LoadLibrary(ModuleName: PChar): TLibHandle; +function FreeLibrary(Module: TLibHandle): LongBool; +function GetProcAddress(Module: TLibHandle; Proc: PChar): Pointer; +function GetModuleFileName(Module: TLibHandle; Buffer: PChar; BufLen: Integer): Integer; +{$ELSE} +type + {$IFDEF CIL} + TLibHandle = Integer; + {$ELSE} + TLibHandle = HModule; + {$ENDIF} + {$IFDEF VER100} + LongWord = DWord; + {$ENDIF} +{$ENDIF} + +procedure Sleep(milliseconds: Cardinal); + implementation {==============================================================================} -{$IFDEF LINUX} - {$IFDEF FPC} -function LoadLibrary(ModuleName: PChar): HMODULE; -begin - Result := HMODULE(dynlibs.LoadLibrary(Modulename)); -end; - -function FreeLibrary(Module: HMODULE): LongBool; +{$IFDEF FPC} +function LoadLibrary(ModuleName: PChar): TLibHandle; begin - Result := dynlibs.UnloadLibrary(pointer(Module)); + Result := dynlibs.LoadLibrary(Modulename); end; -function GetProcAddress(Module: HMODULE; Proc: PChar): Pointer; +function FreeLibrary(Module: TLibHandle): LongBool; begin - Result := dynlibs.GetProcedureAddress(pointer(Module), Proc); + Result := dynlibs.UnloadLibrary(Module); end; -function GetModuleFileName(Module: HMODULE; Buffer: PChar; BufLen: Integer): Integer; -begin - Result := 0; -end; - -procedure Sleep(milliseconds: Cardinal); -begin - usleep(milliseconds * 1000); // usleep is in microseconds +function GetProcAddress(Module: TLibHandle; Proc: PChar): Pointer; +begin + Result := dynlibs.GetProcedureAddress(Module, Proc); end; - - {$ENDIF} + +function GetModuleFileName(Module: TLibHandle; Buffer: PChar; BufLen: Integer): Integer; +begin + Result := 0; +end; + +{$ELSE} {$ENDIF} +procedure Sleep(milliseconds: Cardinal); +begin +{$IFDEF WIN32} + {$IFDEF FPC} + sysutils.sleep(milliseconds); + {$ELSE} + windows.sleep(milliseconds); + {$ENDIF} +{$ELSE} + sysutils.sleep(milliseconds); +{$ENDIF} + +end; + end. diff --git a/synaicnv.pas b/synaicnv.pas index de1cc4a..72a0623 100644 --- a/synaicnv.pas +++ b/synaicnv.pas @@ -62,10 +62,8 @@ uses System.Runtime.InteropServices, System.Text, {$ENDIF} -{$IFDEF LINUX} - {$IFDEF FPC} synafpc, - {$ENDIF} +{$IFNDEF WIN32} Libc, SysUtils; {$ELSE} Windows; @@ -73,7 +71,7 @@ uses const - {$IFDEF LINUX} + {$IFNDEF WIN32} DLLIconvName = 'libiconv.so'; {$ELSE} DLLIconvName = 'iconv.dll'; @@ -89,7 +87,7 @@ type argptr = iconv_t; var - iconvLibHandle: Integer = 0; + iconvLibHandle: TLibHandle = 0; function SynaIconvOpen(const tocode, fromcode: string): iconv_t; function SynaIconvOpenTranslit(const tocode, fromcode: string): iconv_t; diff --git a/synaip.pas b/synaip.pas new file mode 100644 index 0000000..9d93c9c --- /dev/null +++ b/synaip.pas @@ -0,0 +1,390 @@ +{==============================================================================| +| Project : Ararat Synapse | 001.000.000 | +|==============================================================================| +| Content: IP address support procedures and functions | +|==============================================================================| +| Copyright (c)2006, Lukas Gebauer | +| All rights reserved. | +| | +| 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. | +| | +| Redistributions in binary form must reproduce the above copyright notice, | +| this list of conditions and the following disclaimer in the documentation | +| and/or other materials provided with the distribution. | +| | +| Neither the name of Lukas Gebauer nor the names of its contributors may | +| be used to endorse or promote products derived from this software without | +| specific prior written permission. | +| | +| 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. | +|==============================================================================| +| The Initial Developer of the Original Code is Lukas Gebauer (Czech Republic).| +| Portions created by Lukas Gebauer are Copyright (c) 2006. | +| All Rights Reserved. | +|==============================================================================| +| Contributor(s): | +|==============================================================================| +| History: see HISTORY.HTM from distribution package | +| (Found at URL: http://www.ararat.cz/synapse/) | +|==============================================================================} + +{:@abstract(IP adress support procedures and functions)} + +{$IFDEF FPC} + {$MODE DELPHI} +{$ENDIF} +{$Q-} +{$R-} +{$H+} + +unit synaip; + +interface + +uses + SysUtils, SynaUtil; + +type +{:binary form of IPv6 adress (for string conversion routines)} + TIp6Bytes = array [0..15] of Byte; +{:binary form of IPv6 adress (for string conversion routines)} + TIp6Words = array [0..7] of Word; + +{:Returns @TRUE, if "Value" is a valid IPv4 address. Cannot be a symbolic Name!} +function IsIP(const Value: string): Boolean; + +{:Returns @TRUE, if "Value" is a valid IPv6 address. Cannot be a symbolic Name!} +function IsIP6(const Value: string): Boolean; + +{:Returns a string with the "Host" ip address converted to binary form.} +function IPToID(Host: string): string; + +{:Convert IPv6 address from their string form to binary byte array.} +function StrToIp6(value: string): TIp6Bytes; + +{:Convert IPv6 address from binary byte array to string form.} +function Ip6ToStr(value: TIp6Bytes): string; + +{:Convert IPv4 address from their string form to binary.} +function StrToIp(value: string): integer; + +{:Convert IPv4 address from binary to string form.} +function IpToStr(value: integer): string; + +{:Convert IPv4 address to reverse form.} +function ReverseIP(Value: AnsiString): AnsiString; + +{:Convert IPv6 address to reverse form.} +function ReverseIP6(Value: AnsiString): AnsiString; + + +implementation + +{==============================================================================} + +function IsIP(const Value: string): Boolean; +var + TempIP: string; + function ByteIsOk(const Value: string): Boolean; + var + x, n: integer; + begin + x := StrToIntDef(Value, -1); + Result := (x >= 0) and (x < 256); + // X may be in correct range, but value still may not be correct value! + // i.e. "$80" + if Result then + for n := 1 to length(Value) do + if not (Value[n] in ['0'..'9']) then + begin + Result := False; + Break; + end; + end; +begin + TempIP := Value; + Result := False; + if not ByteIsOk(Fetch(TempIP, '.')) then + Exit; + if not ByteIsOk(Fetch(TempIP, '.')) then + Exit; + if not ByteIsOk(Fetch(TempIP, '.')) then + Exit; + if ByteIsOk(TempIP) then + Result := True; +end; + +{==============================================================================} + +function IsIP6(const Value: string): Boolean; +var + TempIP: string; + s,t: string; + x: integer; + partcount: integer; + zerocount: integer; + First: Boolean; +begin + TempIP := Value; + Result := False; + if Value = '::' then + begin + Result := True; + Exit; + end; + partcount := 0; + zerocount := 0; + First := True; + while tempIP <> '' do + begin + s := fetch(TempIP, ':'); + if not(First) and (s = '') then + Inc(zerocount); + First := False; + if zerocount > 1 then + break; + Inc(partCount); + if s = '' then + Continue; + if partCount > 8 then + break; + if tempIP = '' then + begin + t := SeparateRight(s, '%'); + s := SeparateLeft(s, '%'); + x := StrToIntDef('$' + t, -1); + if (x < 0) or (x > $ffff) then + break; + end; + x := StrToIntDef('$' + s, -1); + if (x < 0) or (x > $ffff) then + break; + if tempIP = '' then + if not((PartCount = 1) and (ZeroCount = 0)) then + Result := True; + end; +end; + +{==============================================================================} +function IPToID(Host: string): string; +var + s: string; + i, x: Integer; +begin + Result := ''; + for x := 0 to 3 do + begin + s := Fetch(Host, '.'); + i := StrToIntDef(s, 0); + Result := Result + Chr(i); + end; +end; + +{==============================================================================} + +function StrToIp(value: string): integer; +var + s: string; + i, x: Integer; +begin + Result := 0; + for x := 0 to 3 do + begin + s := Fetch(value, '.'); + i := StrToIntDef(s, 0); + Result := (256 * Result) + i; + end; +end; + +{==============================================================================} + +function IpToStr(value: integer): string; +var + x1, x2: word; + y1, y2: byte; +begin + Result := ''; + x1 := value div $10000; + x2 := value mod $10000; + y1 := x1 div $100; + y2 := x1 mod $100; + Result := inttostr(y1) + '.' + inttostr(y2) + '.'; + y1 := x2 div $100; + y2 := x2 mod $100; + Result := Result + inttostr(y1) + '.' + inttostr(y2); +end; + +{==============================================================================} + +function StrToIp6(Value: string): TIp6Bytes; +var + IPv6: TIp6Words; + Index: Integer; + ZeroAt: Integer; + n: integer; + b1, b2: byte; + s: string; + x: integer; +begin + for n := 0 to 15 do + Result[n] := 0; + for n := 0 to 7 do + Ipv6[n] := 0; + Index := 0; + ZeroAt := -1; + + while Value <> '' do + begin + if Index > 7 then + Exit; + s := fetch(value, ':'); + if s = '@' then + break; + if s = '' then + begin + ZeroAt := Index; + IPv6[Index] := 0; + end + else + begin + x := StrToIntDef('$' + s, -1); + if (x > 65535) or (x < 0) then + Exit; + IPv6[Index] := x; + end; + Inc(Index); + end; + if ZeroAt >= 0 then + Begin + x := Index - ZeroAt - 1; + for n := 1 to x do + IPv6[7 - n + 1] := Ipv6[ZeroAt + x - 1 + n]; + for n := ZeroAt + 1 to Index - 1 do + IPv6[n] := 0; + End; + for n := 0 to 7 do + begin + b1 := ipv6[n] div 256; + b2 := ipv6[n] mod 256; + Result[n * 2] := b1; + Result[(n * 2) + 1] := b2; + end; +end; + +{==============================================================================} +//based on routine by the Free Pascal development team +function Ip6ToStr(value: TIp6Bytes): string; +var + i, x: byte; + zr1,zr2: set of byte; + zc1,zc2: byte; + have_skipped: boolean; + ip6w: TIp6words; +begin + zr1 := []; + zr2 := []; + zc1 := 0; + zc2 := 0; + for i := 0 to 7 do + begin + x := i * 2; + ip6w[i] := value[x] * 256 + value[x + 1]; + if ip6w[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 + zr1 := zr2; + end; + SetLength(Result, 8*5-1); + SetLength(Result, 0); + have_skipped := false; + for i := 0 to 7 do + begin + if not(i in zr1) then + begin + if have_skipped then + begin + if Result = '' then + Result := '::' + else + Result := Result + ':'; + have_skipped := false; + end; + Result := Result + IntToHex(Ip6w[i], 1) + ':'; + end + else + begin + have_skipped := true; + end; + end; + if have_skipped then + if Result = '' then + Result := '::0' + else + Result := Result + ':'; + + if Result = '' then + Result := '::0'; + if not (7 in zr1) then + SetLength(Result, Length(Result)-1); + Result := LowerCase(result); +end; + +{==============================================================================} +function ReverseIP(Value: AnsiString): AnsiString; +var + x: Integer; +begin + Result := ''; + repeat + x := LastDelimiter('.', Value); + Result := Result + '.' + Copy(Value, x + 1, Length(Value) - x); + Delete(Value, x, Length(Value) - x + 1); + until x < 1; + if Length(Result) > 0 then + if Result[1] = '.' then + Delete(Result, 1, 1); +end; + +{==============================================================================} +function ReverseIP6(Value: AnsiString): AnsiString; +var + ip6: TIp6bytes; + n: integer; +begin + ip6 := StrToIP6(Value); + Result := char(ip6[15]); + for n := 14 downto 0 do + Result := Result + '.' + char(ip6[n]); +end; + +{==============================================================================} +end. diff --git a/synamisc.pas b/synamisc.pas index 312d834..8b861a9 100644 --- a/synamisc.pas +++ b/synamisc.pas @@ -1,5 +1,5 @@ {==============================================================================| -| Project : Ararat Synapse | 001.001.003 | +| Project : Ararat Synapse | 001.001.004 | |==============================================================================| | Content: misc. procedures and functions | |==============================================================================| @@ -67,9 +67,6 @@ uses {$IFDEF LINUX} Libc; {$ELSE} -{$IFDEF FPC} - winver, -{$ENDIF} Windows; {$ENDIF} diff --git a/synautil.pas b/synautil.pas index fab0f16..863fc2f 100644 --- a/synautil.pas +++ b/synautil.pas @@ -1,9 +1,9 @@ {==============================================================================| -| Project : Ararat Synapse | 004.008.001 | +| Project : Ararat Synapse | 004.010.001 | |==============================================================================| | Content: support procedures and functions | |==============================================================================| -| Copyright (c)1999-2004, Lukas Gebauer | +| Copyright (c)1999-2005, Lukas Gebauer | | All rights reserved. | | | | Redistribution and use in source and binary forms, with or without | @@ -33,7 +33,7 @@ | DAMAGE. | |==============================================================================| | The Initial Developer of the Original Code is Lukas Gebauer (Czech Republic).| -| Portions created by Lukas Gebauer are Copyright (c) 1999-2004. | +| Portions created by Lukas Gebauer are Copyright (c) 1999-2005. | | Portions created by Hernan Sanchez are Copyright (c) 2000. | | All Rights Reserved. | |==============================================================================| @@ -58,15 +58,19 @@ unit synautil; interface uses -{$IFDEF LINUX} - Libc, -{$ELSE} +{$IFDEF WIN32} Windows, +{$ELSE} + {$IFDEF FPC} + UnixUtil, Unix, BaseUnix, + {$ELSE} + Libc, + {$ENDIF} {$ENDIF} {$IFDEF CIL} System.IO, {$ENDIF} - SysUtils, Classes; + SysUtils, Classes, SynaFpc; {:Return your timezone bias from UTC time in minutes.} function TimeZoneBias: integer; @@ -131,11 +135,11 @@ function SetUTTime(Newdt: TDateTime): Boolean; {:Return current value of system timer with precizion 1 millisecond. Good for measure time difference.} -function GetTick: ULong; +function GetTick: LongWord; {:Return difference between two timestamps. It working fine only for differences smaller then maxint. (difference must be smaller then 24 days.)} -function TickDelta(TickOld, TickNew: ULong): ULong; +function TickDelta(TickOld, TickNew: LongWord): LongWord; {:Return two characters, which ordinal values represents the value in byte format. (High-endian)} @@ -153,15 +157,6 @@ function CodeLongInt(Value: LongInt): Ansistring; string to LongInt values.} function DecodeLongInt(const Value: Ansistring; Index: Integer): LongInt; -{:Returns @TRUE, if "Value" is a valid IPv4 address. Cannot be a symbolic Name!} -function IsIP(const Value: string): Boolean; - -{:Returns @TRUE, if "Value" is a valid IPv6 address. Cannot be a symbolic Name!} -function IsIP6(const Value: string): Boolean; - -{:Returns a string with the "Host" ip address converted to binary form.} -function IPToID(Host: string): string; - {:Dump binary buffer stored in a string to a result string.} function DumpStr(const Buffer: Ansistring): string; @@ -341,19 +336,18 @@ var {==============================================================================} function TimeZoneBias: integer; -{$IFDEF LINUX} +{$IFNDEF WIN32} +{$IFNDEF FPC} var t: TTime_T; UT: TUnixTime; begin -{$IFNDEF FPC} __time(@T); localtime_r(@T, UT); Result := ut.__tm_gmtoff div 60; {$ELSE} - __time(T); - localtime_r(T, UT); - Result := ut.tm_gmtoff div 60; +begin + Result := TZSeconds div 60; {$ENDIF} {$ELSE} var @@ -688,7 +682,7 @@ end; {==============================================================================} function GetUTTime: TDateTime; -{$IFNDEF LINUX} +{$IFDEF WIN32} {$IFNDEF FPC} var st: TSystemTime; @@ -711,23 +705,26 @@ begin result := SystemTimeToDateTime(st); {$ENDIF} {$ELSE} +{$IFNDEF FPC} var TV: TTimeVal; - TZ: Ttimezone; - PZ: PTimeZone; begin - TZ.tz_minuteswest := 0; - TZ.tz_dsttime := 0; - PZ := @TZ; - gettimeofday(TV, PZ); + gettimeofday(TV, nil); Result := UnixDateDelta + (TV.tv_sec + TV.tv_usec / 1000000) / 86400; +{$ELSE} +var + TV: TimeVal; +begin + fpgettimeofday(@TV, nil); + Result := UnixDateDelta + (TV.tv_sec + TV.tv_usec / 1000000) / 86400; +{$ENDIF} {$ENDIF} end; {==============================================================================} function SetUTTime(Newdt: TDateTime): Boolean; -{$IFNDEF LINUX} +{$IFDEF WIN32} {$IFNDEF FPC} var st: TSystemTime; @@ -750,6 +747,7 @@ begin Result := SetSystemTime(stw); {$ENDIF} {$ELSE} +{$IFNDEF FPC} var TV: TTimeVal; d: double; @@ -764,13 +762,23 @@ begin TV.tv_sec := trunc(d); TV.tv_usec := trunc(frac(d) * 1000000); Result := settimeofday(TV, TZ) <> -1; +{$ELSE} +var + TV: TimeVal; + d: double; +begin + d := (newdt - UnixDateDelta) * 86400; + TV.tv_sec := trunc(d); + TV.tv_usec := trunc(frac(d) * 1000000); + Result := fpsettimeofday(@TV, nil) <> -1; +{$ENDIF} {$ENDIF} end; {==============================================================================} -{$IFDEF LINUX} -function GetTick: ULong; +{$IFNDEF WIN32} +function GetTick: LongWord; var Stamp: TTimeStamp; begin @@ -778,15 +786,31 @@ begin Result := Stamp.Time; end; {$ELSE} -function GetTick: ULong; +function GetTick: LongWord; +var + tick, freq: TLargeInteger; +{$IFDEF VER100} + x: TLargeInteger; +{$ENDIF} begin - Result := Windows.GetTickCount; + if Windows.QueryPerformanceFrequency(freq) then + begin + Windows.QueryPerformanceCounter(tick); +{$IFDEF VER100} + x.QuadPart := (tick.QuadPart / freq.QuadPart) * 1000; + Result := x.LowPart; +{$ELSE} + Result := Trunc((tick / freq) * 1000) and High(LongWord) +{$ENDIF} + end + else + Result := Windows.GetTickCount; end; {$ENDIF} {==============================================================================} -function TickDelta(TickOld, TickNew: ULong): ULong; +function TickDelta(TickOld, TickNew: LongWord): LongWord; begin //if DWord is signed type (older Deplhi), // then it not work properly on differencies larger then maxint! @@ -795,8 +819,8 @@ begin begin if TickNew < TickOld then begin - TickNew := TickNew + ULong(MaxInt) + 1; - TickOld := TickOld + ULong(MaxInt) + 1; + TickNew := TickNew + LongWord(MaxInt) + 1; + TickOld := TickOld + LongWord(MaxInt) + 1; end; Result := TickNew - TickOld; if TickNew < TickOld then @@ -876,103 +900,6 @@ end; {==============================================================================} -function IsIP(const Value: string): Boolean; -var - TempIP: string; - function ByteIsOk(const Value: string): Boolean; - var - x, n: integer; - begin - x := StrToIntDef(Value, -1); - Result := (x >= 0) and (x < 256); - // X may be in correct range, but value still may not be correct value! - // i.e. "$80" - if Result then - for n := 1 to length(Value) do - if not (Value[n] in ['0'..'9']) then - begin - Result := False; - Break; - end; - end; -begin - TempIP := Value; - Result := False; - if not ByteIsOk(Fetch(TempIP, '.')) then - Exit; - if not ByteIsOk(Fetch(TempIP, '.')) then - Exit; - if not ByteIsOk(Fetch(TempIP, '.')) then - Exit; - if ByteIsOk(TempIP) then - Result := True; -end; - -{==============================================================================} - -function IsIP6(const Value: string): Boolean; -var - TempIP: string; - s,t: string; - x: integer; - partcount: integer; - zerocount: integer; - First: Boolean; -begin - TempIP := Value; - Result := False; - partcount := 0; - zerocount := 0; - First := True; - while tempIP <> '' do - begin - s := fetch(TempIP, ':'); - if not(First) and (s = '') then - Inc(zerocount); - First := False; - if zerocount > 1 then - break; - Inc(partCount); - if s = '' then - Continue; - if partCount > 8 then - break; - if tempIP = '' then - begin - t := SeparateRight(s, '%'); - s := SeparateLeft(s, '%'); - x := StrToIntDef('$' + t, -1); - if (x < 0) or (x > $ffff) then - break; - end; - x := StrToIntDef('$' + s, -1); - if (x < 0) or (x > $ffff) then - break; - if tempIP = '' then - Result := True; - end; -end; - -{==============================================================================} -//Hernan Sanchez -function IPToID(Host: string): string; -var - s: string; - i, x: Integer; -begin - Result := ''; - for x := 1 to 3 do - begin - s := Fetch(Host, '.'); - i := StrToIntDef(s, 0); - Result := Result + Chr(i); - end; - i := StrToIntDef(Host, 0); - Result := Result + Chr(i); -end; - -{==============================================================================} - function DumpStr(const Buffer: Ansistring): string; var n: Integer; @@ -1040,6 +967,9 @@ function TrimSPLeft(const S: string): string; var I, L: Integer; begin + Result := ''; + if S = '' then + Exit; L := Length(S); I := 1; while (I <= L) and (S[I] = ' ') do @@ -1053,6 +983,9 @@ function TrimSPRight(const S: string): string; var I: Integer; begin + Result := ''; + if S = '' then + Exit; I := Length(S); while (I > 0) and (S[I] = ' ') do Dec(I); @@ -1471,38 +1404,26 @@ end; function PosCRLF(const Value: AnsiString; var Terminator: AnsiString): integer; var - p1, p2, p3, p4: integer; -const - t1 = #$0d + #$0a; - t2 = #$0a + #$0d; - t3 = #$0d; - t4 = #$0a; + n, l: integer; begin + Result := -1; Terminator := ''; - p1 := Pos(t1, Value); - p2 := Pos(t2, Value); - p3 := Pos(t3, Value); - p4 := Pos(t4, Value); - if p1 > 0 then - Terminator := t1; - Result := p1; - if (p2 > 0) then - if (Result = 0) or (p2 < Result) then + l := length(value); + for n := 1 to l do + if value[n] in [#$0d, #$0a] then begin - Result := p2; - Terminator := t2; - end; - if (p3 > 0) then - if (Result = 0) or (p3 < Result) then - begin - Result := p3; - Terminator := t3; - end; - if (p4 > 0) then - if (Result = 0) or (p4 < Result) then - begin - Result := p4; - Terminator := t4; + Result := n; + Terminator := Value[n]; + if n <> l then + case value[n] of + #$0d: + if value[n + 1] = #$0a then + Terminator := #$0d + #$0a; + #$0a: + if value[n + 1] = #$0d then + Terminator := #$0a + #$0d; + end; + Break; end; end; @@ -1553,7 +1474,7 @@ end; {$IFNDEF CIL} function IncPoint(const p: pointer; Value: integer): pointer; begin - Result := pointer(integer(p) + Value); + Result := PChar(p) + Value; end; {$ENDIF} @@ -1686,7 +1607,7 @@ end; procedure HeadersToList(const Value: TStrings); var - n, x: integer; + n, x, y: integer; s: string; begin for n := 0 to Value.Count -1 do @@ -1695,8 +1616,12 @@ begin x := Pos(':', s); if x > 0 then begin - s[x] := '='; - Value[n] := s; + y:= Pos('=',s); + if not ((y > 0) and (y < x)) then + begin + s[x] := '='; + Value[n] := s; + end; end; end; end; @@ -1775,7 +1700,7 @@ end; {==============================================================================} function GetTempFile(const Dir, prefix: AnsiString): AnsiString; {$IFNDEF FPC} -{$IFNDEF LINUX} +{$IFDEF WIN32} var Path: AnsiString; x: integer; @@ -1785,7 +1710,7 @@ begin {$IFDEF FPC} Result := GetTempFileName(Dir, Prefix); {$ELSE} - {$IFDEF LINUX} + {$IFNDEF WIN32} Result := tempnam(Pointer(Dir), Pointer(prefix)); {$ELSE} {$IFDEF CIL} diff --git a/synsock.pas b/synsock.pas index 4b4fc46..c4bc977 100644 --- a/synsock.pas +++ b/synsock.pas @@ -1,5 +1,5 @@ {==============================================================================| -| Project : Ararat Synapse | 005.000.000 | +| Project : Ararat Synapse | 005.001.000 | |==============================================================================| | Content: Socket Independent Platform Layer | |==============================================================================| @@ -52,13 +52,16 @@ unit synsock; {$I ssdotnet.pas} {$ENDIF} -{$IFDEF LINUX} - {$I sslinux.pas} -{$ENDIF} - {$IFDEF WIN32} {$I sswin32.pas} +{$ELSE} + {$IFDEF FPC} + {$I ssfpc.pas} + {$ELSE} + {$I sslinux.pas} + {$ENDIF} {$ENDIF} + end. diff --git a/winver.pp b/winver.pp deleted file mode 100644 index ae1e140..0000000 --- a/winver.pp +++ /dev/null @@ -1,76 +0,0 @@ -{ - $Id: header,v 1.1.2.1 2003/01/05 20:47:31 michael Exp $ - This file is part of the Free Pascal run time library. - Copyright (c) 2003 by the Free Pascal development team - - Windows Version detection functionality. - - 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. - - **********************************************************************} - -{$mode objfpc} -unit winver; - -Interface - -Uses Windows; - -const - Win32Platform : Integer = 0; - Win32MajorVersion : Integer = 0; - Win32MinorVersion : Integer = 0; - Win32BuildNumber : Integer = 0; - - Win32CSDVersion : string = ''; - -function CheckWin32Version(Major,Minor : Integer ): Boolean; -function CheckWin32Version(Major : Integer): Boolean; - -Implementation - - -uses sysutils; - -procedure InitVersion; - -var - Info: TOSVersionInfo; - -begin - Info.dwOSVersionInfoSize := SizeOf(Info); - if GetVersionEx(Info) then - with Info do - begin - Win32Platform:=dwPlatformId; - Win32MajorVersion:=dwMajorVersion; - Win32MinorVersion:=dwMinorVersion; - if (Win32Platform=VER_PLATFORM_WIN32_WINDOWS) then - Win32BuildNumber:=dwBuildNumber and $FFFF - else - Win32BuildNumber := dwBuildNumber; - Win32CSDVersion := StrPas(szCSDVersion); - end; -end; - -function CheckWin32Version(Major : Integer): Boolean; - -begin - Result:=CheckWin32Version(Major,0) -end; - -function CheckWin32Version(Major,Minor: Integer): Boolean; - -begin - Result := (Win32MajorVersion>Major) or - ((Win32MajorVersion=Major) and (Win32MinorVersion>=Minor)); -end; - -initialization - InitVersion; -end. \ No newline at end of file