{ $Project$ $Workfile$ $Revision$ $DateUTC$ $Id$ This file is part of the Indy (Internet Direct) project, and is offered under the dual-licensing agreement described on the Indy website. (http://www.indyproject.org/) Copyright: (c) 1993-2005, Chad Z. Hower and the Indy Pit Crew. All rights reserved. } { $Log$ } { Rev 1.8 10/26/2004 8:12:30 PM JPMugaas Now uses TIdStrings and TIdStringList for portability. Rev 1.7 12/06/2004 15:16:44 CCostelloe Restructured to remove inconsistencies with derived classes Rev 1.6 07/06/2004 21:30:48 CCostelloe Kylix 3 changes Rev 1.5 5/15/2004 3:32:30 AM DSiders Corrected case in name of TIdIPAddressRec. Rev 1.4 4/18/04 10:29:24 PM RLebeau Added TIdInt64Parts structure Rev 1.3 2004.04.18 4:41:40 PM czhower RaiseSocketError Rev 1.2 2004.03.07 11:45:24 AM czhower Flushbuffer fix + other minor ones found Rev 1.1 3/6/2004 5:16:24 PM JPMugaas Bug 67 fixes. Do not write to const values. Rev 1.0 2004.02.03 3:14:44 PM czhower Move and updates Rev 1.22 2/1/2004 3:28:26 AM JPMugaas Changed WSGetLocalAddress to GetLocalAddress and moved into IdStack since that will work the same in the DotNET as elsewhere. This is required to reenable IPWatch. Rev 1.21 1/31/2004 1:13:00 PM JPMugaas Minor stack changes required as DotNET does support getting all IP addresses just like the other stacks. Rev 1.20 12/4/2003 3:14:56 PM BGooijen Added HostByAddress Rev 1.19 12/31/2003 9:52:00 PM BGooijen Added IPv6 support Rev 1.18 10/26/2003 5:04:24 PM BGooijen UDP Server and Client Rev 1.17 10/26/2003 09:10:24 AM JPMugaas Calls necessary for IPMulticasting. Rev 1.16 10/22/2003 04:41:04 PM JPMugaas Should compile with some restored functionality. Still not finished. Rev 1.15 10/21/2003 06:24:24 AM JPMugaas BSD Stack now have a global variable for refercing by platform specific things. Removed corresponding var from Windows stack. Rev 1.14 10/19/2003 5:21:28 PM BGooijen SetSocketOption Rev 1.13 2003.10.11 5:51:08 PM czhower -VCL fixes for servers -Chain suport for servers (Super core) -Scheduler upgrades -Full yarn support Rev 1.12 10/5/2003 9:55:28 PM BGooijen TIdTCPServer works on D7 and DotNet now Rev 1.11 04/10/2003 22:32:02 HHariri moving of WSNXXX method to IdStack and renaming of the DotNet ones Rev 1.10 10/2/2003 7:36:28 PM BGooijen .net Rev 1.9 2003.10.02 10:16:30 AM czhower .Net Rev 1.8 2003.10.01 9:11:22 PM czhower .Net Rev 1.7 2003.10.01 5:05:16 PM czhower .Net Rev 1.6 2003.10.01 2:30:42 PM czhower .Net Rev 1.3 10/1/2003 12:14:16 AM BGooijen DotNet: removing CheckForSocketError Rev 1.2 2003.10.01 1:12:38 AM czhower .Net Rev 1.1 2003.09.30 1:25:02 PM czhower Added .inc file. Rev 1.0 2003.09.30 1:24:20 PM czhower Initial Checkin Rev 1.10 2003.09.30 10:36:02 AM czhower Moved stack creation to IdStack Added DotNet stack. Rev 1.9 9/8/2003 02:13:14 PM JPMugaas SupportsIP6 function added for determining if IPv6 is installed on a system. Rev 1.8 2003.07.17 4:57:04 PM czhower Added new exception type so it can be added to debugger list of ignored exceptions. Rev 1.7 2003.07.14 11:46:46 PM czhower IOCP now passes all bubbles. Rev 1.6 2003.07.14 1:57:24 PM czhower -First set of IOCP fixes. -Fixed a threadsafe problem with the stack class. Rev 1.5 7/1/2003 05:20:38 PM JPMugaas Minor optimizations. Illiminated some unnecessary string operations. Rev 1.4 7/1/2003 03:39:54 PM JPMugaas Started numeric IP function API calls for more efficiency. Rev 1.3 7/1/2003 12:46:08 AM JPMugaas Preliminary stack functions taking an IP address numerical structure instead of a string. Rev 1.2 5/10/2003 4:02:22 PM BGooijen Rev 1.1 2003.05.09 10:59:26 PM czhower Rev 1.0 11/13/2002 08:59:02 AM JPMugaas } unit IdStackBSDBase; interface {$I IdCompilerDefines.inc} {$IFDEF DOTNET} Improper compile. This unit must NOT be linked into DotNet applications. {$ENDIF} uses Classes, IdException, IdStack, IdStackConsts, IdGlobal; type // RLebeau - for use with the HostToNetwork() and NetworkToHost() // methods under Windows and Linux since the Socket API doesn't // have native conversion functions for int64 values... TIdInt64Parts = packed record case Integer of 0: ( {$IFDEF ENDIAN_BIG} HighPart: UInt32; LowPart: UInt32); {$ELSE} LowPart: UInt32; HighPart: UInt32); {$ENDIF} 1: ( QuadPart: Int64); end; TIdUInt64Parts = packed record case Integer of 0: ( {$IFDEF ENDIAN_BIG} HighPart: UInt32; LowPart: UInt32); {$ELSE} LowPart: UInt32; HighPart: UInt32); {$ENDIF} 1: ( QuadPart: UInt64); end; TIdIPv6AddressRec = packed array[0..7] of UInt16; TIdIPAddressRec = packed record IPVer: TIdIPVersion; case Integer of 0: (IPv4, Junk1, Junk2, Junk3: UInt32); 2: (IPv6 : TIdIPv6AddressRec); end; //procedure EmptyIPRec(var VIP : TIdIPAddress); TIdSunB = packed record s_b1, s_b2, s_b3, s_b4: UInt8; end; TIdSunW = packed record s_w1, s_w2: UInt16; end; PIdIn4Addr = ^TIdIn4Addr; TIdIn4Addr = packed record case integer of 0: (S_un_b: TIdSunB); 1: (S_un_w: TIdSunW); 2: (S_addr: UInt32); end; PIdIn6Addr = ^TIdIn6Addr; TIdIn6Addr = packed record case Integer of 0: (s6_addr: packed array [0..16-1] of UInt8); 1: (s6_addr16: packed array [0..8-1] of UInt16); end; (*$HPPEMIT '#ifdef s6_addr'*) (*$HPPEMIT ' #undef s6_addr'*) (*$HPPEMIT '#endif'*) (*$HPPEMIT '#ifdef s6_addr16'*) (*$HPPEMIT ' #undef s6_addr16'*) (*$HPPEMIT '#endif'*) PIdInAddr = ^TIdInAddr; TIdInAddr = {$IFDEF IPv6} TIdIn6Addr; {$ELSE} TIdIn4Addr; {$ENDIF} //Do not change these structures or insist on objects //because these are parameters to IP_ADD_MEMBERSHIP and IP_DROP_MEMBERSHIP TIdIPMreq = packed record IMRMultiAddr : TIdIn4Addr; // IP multicast address of group */ IMRInterface : TIdIn4Addr; // local IP address of interface */ end; TIdIPv6Mreq = packed record ipv6mr_multiaddr : TIdIn6Addr; //IPv6 multicast addr ipv6mr_interface : UInt32; //interface index end; TIdStackBSDBase = class(TIdStack) protected function WSCloseSocket(ASocket: TIdStackSocketHandle): Integer; virtual; abstract; function WSRecv(ASocket: TIdStackSocketHandle; var ABuffer; const ABufferLength, AFlags: Integer): Integer; virtual; abstract; function WSSend(ASocket: TIdStackSocketHandle; const ABuffer; const ABufferLength, AFlags: Integer): Integer; virtual; abstract; function WSShutdown(ASocket: TIdStackSocketHandle; AHow: Integer): Integer; virtual; abstract; {$IFNDEF VCL_XE3_OR_ABOVE} procedure WSGetSocketOption(ASocket: TIdStackSocketHandle; ALevel: TIdSocketOptionLevel; AOptName: TIdSocketOption; var AOptVal; var AOptLen: Integer); virtual; abstract; procedure WSSetSocketOption(ASocket: TIdStackSocketHandle; ALevel: TIdSocketOptionLevel; AOptName: TIdSocketOption; const AOptVal; const AOptLen: Integer); virtual; abstract; {$ENDIF} //internal for multicast membership stuff procedure MembershipSockOpt(AHandle: TIdStackSocketHandle; const AGroupIP, ALocalIP : String; const ASockOpt : Integer; const AIPVersion: TIdIPVersion = ID_DEFAULT_IP_VERSION); public constructor Create; override; function CheckIPVersionSupport(const AIPVersion: TIdIPVersion): boolean; virtual; abstract; function Receive(ASocket: TIdStackSocketHandle; var VBuffer: TIdBytes): Integer; override; function Send(ASocket: TIdStackSocketHandle; const ABuffer: TIdBytes; const AOffset: Integer = 0; const ASize: Integer = -1): Integer; override; function ReceiveFrom(ASocket: TIdStackSocketHandle; var VBuffer: TIdBytes; var VIP: string; var VPort: TIdPort; var VIPVersion: TIdIPVersion): Integer; override; function SendTo(ASocket: TIdStackSocketHandle; const ABuffer: TIdBytes; const AOffset: Integer; const ASize: Integer; const AIP: string; const APort: TIdPort; const AIPVersion: TIdIPVersion = ID_DEFAULT_IP_VERSION): Integer; override; procedure GetSocketOption(ASocket: TIdStackSocketHandle; ALevel: TIdSocketOptionLevel; AOptName: TIdSocketOption; out AOptVal: Integer); overload; override; procedure GetSocketOption(ASocket: TIdStackSocketHandle; ALevel: TIdSocketOptionLevel; AOptName: TIdSocketOption; var AOptVal; var AOptLen: Integer); {$IFDEF VCL_XE3_OR_ABOVE}overload; virtual; abstract;{$ELSE}reintroduce; overload;{$ENDIF} procedure SetSocketOption(ASocket: TIdStackSocketHandle; ALevel: TIdSocketOptionLevel; AOptName: TIdSocketOption; AOptVal: Integer); overload; override; procedure SetSocketOption(ASocket: TIdStackSocketHandle; ALevel: TIdSocketOptionLevel; AOptName: TIdSocketOption; const AOptVal; const AOptLen: Integer); {$IFDEF VCL_XE3_OR_ABOVE}overload; virtual; abstract;{$ELSE}reintroduce; overload;{$ENDIF} function TranslateTInAddrToString(var AInAddr; const AIPVersion: TIdIPVersion): string; procedure TranslateStringToTInAddr(const AIP: string; var AInAddr; const AIPVersion: TIdIPVersion); function WSGetServByName(const AServiceName: string): TIdPort; virtual; abstract; function WSGetServByPort(const APortNumber: TIdPort): TStrings; virtual; {$IFDEF HAS_DEPRECATED}deprecated{$IFDEF HAS_DEPRECATED_MSG} 'Use AddServByPortToList()'{$ENDIF};{$ENDIF} procedure AddServByPortToList(const APortNumber: TIdPort; AAddresses: TStrings); virtual; abstract; function RecvFrom(const ASocket: TIdStackSocketHandle; var ABuffer; const ALength, AFlags: Integer; var VIP: string; var VPort: TIdPort; var VIPVersion: TIdIPVersion): Integer; virtual; abstract; procedure WSSendTo(ASocket: TIdStackSocketHandle; const ABuffer; const ABufferLength, AFlags: Integer; const AIP: string; const APort: TIdPort; AIPVersion: TIdIPVersion = ID_DEFAULT_IP_VERSION); virtual; abstract; function WSSocket(AFamily : Integer; AStruct : TIdSocketType; AProtocol: Integer; const AOverlapped: Boolean = False): TIdStackSocketHandle; virtual; abstract; procedure SetBlocking(ASocket: TIdStackSocketHandle; const ABlocking: Boolean); virtual; abstract; function WouldBlock(const AResult: Integer): Boolean; virtual; abstract; function NewSocketHandle(const ASocketType: TIdSocketType; const AProtocol: TIdSocketProtocol; const AIPVersion: TIdIPVersion = ID_DEFAULT_IP_VERSION; const AOverlapped: Boolean = False) : TIdStackSocketHandle; override; //multicast stuff Kudzu permitted me to add here. procedure SetMulticastTTL(AHandle: TIdStackSocketHandle; const AValue : Byte; const AIPVersion: TIdIPVersion = ID_DEFAULT_IP_VERSION); override; procedure SetLoopBack(AHandle: TIdStackSocketHandle; const AValue: Boolean; const AIPVersion: TIdIPVersion = ID_DEFAULT_IP_VERSION); override; procedure DropMulticastMembership(AHandle: TIdStackSocketHandle; const AGroupIP, ALocalIP : String; const AIPVersion: TIdIPVersion = ID_DEFAULT_IP_VERSION); override; procedure AddMulticastMembership(AHandle: TIdStackSocketHandle; const AGroupIP, ALocalIP : String; const AIPVersion: TIdIPVersion = ID_DEFAULT_IP_VERSION); override; end; EIdInvalidServiceName = class(EIdException); EIdStackInitializationFailed = class (EIdStackError); EIdStackSetSizeExceeded = class (EIdStackError); //for some reason, if GDBSDStack is in the same block as GServeFileProc then //FPC gives a type declaration error. var GBSDStack: TIdStackBSDBase = nil; const IdIPFamily : array[TIdIPVersion] of Integer = (Id_PF_INET4, Id_PF_INET6); implementation uses //done this way so we can have a separate stack for the Unix systems in FPC {$IFDEF UNIX} {$IFDEF KYLIXCOMPAT} IdStackLibc, {$ENDIF} {$IFDEF USE_BASEUNIX} IdStackUnix, {$ENDIF} {$IFDEF USE_VCL_POSIX} IdStackVCLPosix, {$ENDIF} {$ENDIF} {$IFDEF WINDOWS} IdStackWindows, {$ENDIF} {$IFDEF DOTNET} IdStackDotNet, {$ENDIF} IdResourceStrings, SysUtils; { TIdStackBSDBase } function TIdStackBSDBase.TranslateTInAddrToString(var AInAddr; const AIPVersion: TIdIPVersion): string; var i: Integer; begin case AIPVersion of Id_IPv4: begin // TODO: use RtlIpv4AddressToString() on Windows when available... Result := IntToStr(TIdIn4Addr(AInAddr).S_un_b.s_b1) + '.' {Do not Localize} + IntToStr(TIdIn4Addr(AInAddr).S_un_b.s_b2) + '.' {Do not Localize} + IntToStr(TIdIn4Addr(AInAddr).S_un_b.s_b3) + '.' {Do not Localize} + IntToStr(TIdIn4Addr(AInAddr).S_un_b.s_b4); end; Id_IPv6: begin // TODO: use RtlIpv6AddressToString() on Windows when available... Result := ''; for i := 0 to 7 do begin Result := Result + IntToHex(NetworkToHost(TIdIn6Addr(AInAddr).s6_addr16[i]), 1) + ':'; end; SetLength(Result, Length(Result)-1); end; else begin IPVersionUnsupported; end; end; end; procedure TIdStackBSDBase.TranslateStringToTInAddr(const AIP: string; var AInAddr; const AIPVersion: TIdIPVersion); var LIP: String; LAddress: TIdIPv6Address; begin case AIPVersion of Id_IPv4: begin // TODO: use RtlIpv4StringToAddress() on Windows when available... LIP := AIP; TIdIn4Addr(AInAddr).S_un_b.s_b1 := IndyStrToInt(Fetch(LIP, '.')); {Do not Localize} TIdIn4Addr(AInAddr).S_un_b.s_b2 := IndyStrToInt(Fetch(LIP, '.')); {Do not Localize} TIdIn4Addr(AInAddr).S_un_b.s_b3 := IndyStrToInt(Fetch(LIP, '.')); {Do not Localize} TIdIn4Addr(AInAddr).S_un_b.s_b4 := IndyStrToInt(Fetch(LIP, '.')); {Do not Localize} end; Id_IPv6: begin // TODO: use RtlIpv6StringToAddress() on Windows when available... IPv6ToIdIPv6Address(AIP, LAddress); TIdIPv6Address(TIdIn6Addr(AInAddr).s6_addr16) := HostToNetwork(LAddress); end; else begin IPVersionUnsupported; end; end; end; function TIdStackBSDBase.NewSocketHandle(const ASocketType:TIdSocketType; const AProtocol: TIdSocketProtocol; const AIPVersion: TIdIPVersion = ID_DEFAULT_IP_VERSION; const AOverlapped: Boolean = False): TIdStackSocketHandle; begin // RLebeau 04/17/2008: Don't use CheckForSocketError() here. It expects // an Integer error code, not a TSocket handle. When WSSocket() fails, // it returns Id_INVALID_SOCKET. Although that is technically the same // value as Id_SOCKET_ERROR, passing Id_INVALID_SOCKET to CheckForSocketError() // causes a range check error to be raised. Result := WSSocket(IdIPFamily[AIPVersion], ASocketType, AProtocol, AOverlapped); if Result = Id_INVALID_SOCKET then begin RaiseLastSocketError; end; end; constructor TIdStackBSDBase.Create; begin inherited Create; GBSDStack := Self; end; function TIdStackBSDBase.Receive(ASocket: TIdStackSocketHandle; var VBuffer: TIdBytes): Integer; begin Result := CheckForSocketError(WSRecv(ASocket, VBuffer[0], Length(VBuffer) , 0)); end; function TIdStackBSDBase.Send(ASocket: TIdStackSocketHandle; const ABuffer: TIdBytes; const AOffset: Integer = 0; const ASize: Integer = -1): Integer; var Tmp: Byte; begin Result := IndyLength(ABuffer, ASize, AOffset); if Result > 0 then begin Result := WSSend(ASocket, ABuffer[AOffset], Result, 0); end else begin // RLebeau: this is to allow UDP sockets to send 0-length packets. // Have to use a variable because the Buffer parameter is declared // as an untyped 'const'... // // TODO: check the socket type and only allow this for UDP sockets... // Result := WSSend(ASocket, Tmp, 0, 0); end; end; function TIdStackBSDBase.ReceiveFrom(ASocket: TIdStackSocketHandle; var VBuffer: TIdBytes; var VIP: string; var VPort: TIdPort; var VIPVersion: TIdIPVersion): Integer; begin Result := CheckForSocketError(RecvFrom(ASocket, VBuffer[0], Length(VBuffer), 0, VIP, VPort, VIPVersion)); end; function TIdStackBSDBase.SendTo(ASocket: TIdStackSocketHandle; const ABuffer: TIdBytes; const AOffset: Integer; const ASize: Integer; const AIP: string; const APort: TIdPort; const AIPVersion: TIdIPVersion = ID_DEFAULT_IP_VERSION): Integer; var Tmp: Byte; begin Result := IndyLength(ABuffer, ASize, AOffset); if Result > 0 then begin WSSendTo(ASocket, ABuffer[AOffset], Result, 0, AIP, APort, AIPVersion); end else begin // RLebeau: this is to allow UDP sockets to send 0-length packets. // Have to use a variable because the Buffer parameter is declared // as an untyped 'const'... // // TODO: check the socket type and only allow this for UDP sockets... // WSSendTo(ASocket, Tmp, 0, 0, AIP, APort, AIPVersion); end; end; procedure TIdStackBSDBase.GetSocketOption(ASocket: TIdStackSocketHandle; ALevel: TIdSocketOptionLevel; AOptName: TIdSocketOption; out AOptVal: Integer); var LBuf, LLen: Integer; begin LLen := SizeOf(LBuf); {$IFDEF VCL_XE3_OR_ABOVE}GetSocketOption{$ELSE}WSGetSocketOption{$ENDIF}(ASocket, ALevel, AOptName, LBuf, LLen); AOptVal := LBuf; end; {$IFNDEF VCL_XE3_OR_ABOVE} procedure TIdStackBSDBase.GetSocketOption(ASocket: TIdStackSocketHandle; ALevel: TIdSocketOptionLevel; AOptName: TIdSocketOption; var AOptVal; var AOptLen: Integer); begin WSGetSocketOption(ASocket, ALevel, AOptName, AOptVal, AOptLen); end; {$ENDIF} procedure TIdStackBSDBase.SetSocketOption(ASocket: TIdStackSocketHandle; ALevel: TIdSocketOptionLevel; AOptName: TIdSocketOption; AOptVal: Integer); begin {$IFDEF VCL_XE3_OR_ABOVE}SetSocketOption{$ELSE}WSSetSocketOption{$ENDIF}(ASocket, ALevel, AOptName, AOptVal, SizeOf(AOptVal)); end; {$IFNDEF VCL_XE3_OR_ABOVE} procedure TIdStackBSDBase.SetSocketOption(ASocket: TIdStackSocketHandle; ALevel: TIdSocketOptionLevel; AOptName: TIdSocketOption; const AOptVal; const AOptLen: Integer); begin WSSetSocketOption(ASocket, ALevel, AOptName, AOptVal, AOptLen); end; {$ENDIF} procedure TIdStackBSDBase.DropMulticastMembership(AHandle: TIdStackSocketHandle; const AGroupIP, ALocalIP : String; const AIPVersion: TIdIPVersion = ID_DEFAULT_IP_VERSION); begin MembershipSockOpt(AHandle, AGroupIP, ALocalIP, iif(AIPVersion = Id_IPv4, Id_IP_DROP_MEMBERSHIP, Id_IPV6_DROP_MEMBERSHIP), AIPVersion); end; procedure TIdStackBSDBase.AddMulticastMembership(AHandle: TIdStackSocketHandle; const AGroupIP, ALocalIP : String; const AIPVersion: TIdIPVersion = ID_DEFAULT_IP_VERSION); begin MembershipSockOpt(AHandle, AGroupIP, ALocalIP, iif(AIPVersion = Id_IPv4, Id_IP_ADD_MEMBERSHIP, Id_IPV6_ADD_MEMBERSHIP), AIPVersion); end; procedure TIdStackBSDBase.SetMulticastTTL(AHandle: TIdStackSocketHandle; const AValue: Byte; const AIPVersion: TIdIPVersion = ID_DEFAULT_IP_VERSION); var LLevel, LOpt: Integer; begin case AIPVersion of Id_IPv4: begin LLevel := Id_IPPROTO_IP; LOpt := Id_IP_MULTICAST_TTL; end; id_IPv6: begin LLevel := Id_IPPROTO_IPv6; LOpt := Id_IPV6_MULTICAST_HOPS; end; else begin // keep the compiler happy LLevel := 0; LOpt := 0; IPVersionUnsupported; end; end; SetSocketOption(AHandle, LLevel, LOpt, AValue); end; procedure TIdStackBSDBase.SetLoopBack(AHandle: TIdStackSocketHandle; const AValue: Boolean; const AIPVersion: TIdIPVersion = ID_DEFAULT_IP_VERSION); var LLevel, LOpt: Integer; begin case AIPVersion of Id_IPv4: begin LLevel := Id_IPPROTO_IP; LOpt := Id_IP_MULTICAST_LOOP; end; Id_IPv6: begin LLevel := Id_IPPROTO_IPv6; LOpt := Id_IPV6_MULTICAST_LOOP; end; else begin // keep the compiler happy LLevel := 0; LOpt := 0; IPVersionUnsupported; end; end; SetSocketOption(AHandle, LLevel, LOpt, Ord(AValue)); end; procedure TIdStackBSDBase.MembershipSockOpt(AHandle: TIdStackSocketHandle; const AGroupIP, ALocalIP: String; const ASockOpt: Integer; const AIPVersion: TIdIPVersion = ID_DEFAULT_IP_VERSION); var LIP4: TIdIPMreq; LIP6: TIdIPv6Mreq; begin case AIPVersion of Id_IPv4: begin if IsValidIPv4MulticastGroup(AGroupIP) then begin TranslateStringToTInAddr(AGroupIP, LIP4.IMRMultiAddr, Id_IPv4); TranslateStringToTInAddr(ALocalIP, LIP4.IMRInterface, Id_IPv4); SetSocketOption(AHandle, Id_IPPROTO_IP, ASockOpt, LIP4, SizeOf(LIP4)); end; end; Id_IPv6: begin if IsValidIPv6MulticastGroup(AGroupIP) then begin TranslateStringToTInAddr(AGroupIP, LIP6.ipv6mr_multiaddr, Id_IPv6); //this should be safe meaning any adaptor //we can't support a localhost address in IPv6 because we can't get that //and even if you could, you would have to convert it into a network adaptor //index - Yuk LIP6.ipv6mr_interface := 0; SetSocketOption(AHandle, Id_IPPROTO_IPv6, ASockOpt, LIP6, SizeOf(LIP6)); end; end; else begin IPVersionUnsupported; end; end; end; {$I IdDeprecatedImplBugOff.inc} function TIdStackBSDBase.WSGetServByPort(const APortNumber: TIdPort): TStrings; {$I IdDeprecatedImplBugOn.inc} begin Result := TStringList.Create; try AddServByPortToList(APortNumber, Result); except FreeAndNil(Result); raise; end; end; end.