unit uRODXSockClient; /////////////////////////////////////////////////////////////////////////////// // Component: TDXSockClient // Author: G.E. Ozz Nixon Jr. (onixon@dxsock.com) // ======================================================================== // Source Owner: DX, Inc. 1995-2002 // Copyright: All code is the property of DX, Inc. Licensed for // resell by Brain Patchwork DX (tm) and part of the // DX (r) product lines, which are (c) 1999-2002 // DX, Inc. Source may not be distributed without // written permission from both Brain Patchwork DX, // and DX, Inc. // License: (Reminder), None of this code can be added to other // developer products without permission. This includes // but not limited to DCU's, DCP's, DLL's, OCX's, or // any other form of merging our technologies. All of // your products released to a public consumer be it // shareware, freeware, commercial, etc. must contain a // license notification somewhere visible in the // application. // Example is Internet Explorer - Help->About screen // shows the licensed code contained in the application. // Code Version: (3rd Generation Code) // ======================================================================== // Description: // This is a low-level wrapper for the Winsock dll. It is designed to be a // CLIENT core. If you need to develop a client that supports server type // connections, you should visit our DXSockClientFTP component. It demonstrates // using this layer with an add-on for supporting listener routines. // ======================================================================== /////////////////////////////////////////////////////////////////////////////// interface {$I uRODXSock.def} {2.0} uses Classes, uRODXString, uRODXSock, uRODXSocket; type TDX_Connecting=procedure(ConnectingTo:String;Port:Integer) of object; TDX_Connected=procedure(ConnectedTo:String;Port:Integer) of object; TDX_ConnectFailed=procedure(ConnectTo:String;ErrorCode:Integer) of object; TDX_Disconnected=procedure(ConnectedTo:String) of object; TDX_SendingData=procedure(ConnectTo:String;Bytes:Integer) of object; TDX_DataSent=procedure(ConnectTo:String;Bytes:Integer) of object; TDX_DataPendingRead=procedure(CharactersWaiting:Integer) of object; // TDX_NewClientPendingAccept=procedure(Socket:u_Int) of object; TDX_ResolvingHost=procedure(ConnectTo:String) of object; TDX_ResolvedHost=procedure(ConnectTo:String;ResolvedTo:String) of object; TDX_ResolveFailed=procedure(ConnectTo:String) of object; TDXSockClient=class(TDXComponent) private // Component Oriented Variables: fsHost:String; fiPort:Integer; fbUseNagle:Boolean; fbUseUDP:Boolean; fbUseBlocking:Boolean; // Events: feResolvingHost:TDX_ResolvingHost; feResolvedHost:TDX_ResolvedHost; fMimicAsynch:Boolean; feConnecting:TDX_Connecting; feConnected:TDX_Connected; feConnectFailed:TDX_ConnectFailed; feSendingData:TDX_SendingData; feSendingDone:TDX_DataSent; feDisconnected:TDX_Disconnected; // Asynch Notification Variables: fNotifiedOfData:Boolean; fLastAddress:String; fLastIP:String; (* feDataPendingRead:TDX_DataPendingRead; // feNewClientPendingAccept:TDX_NewClientPendingAccept; feResolveFailed:TDX_ResolveFailed; fiSleepBetweenReads:Integer; *) protected // Procedure CheckInBuffer; Function GetPeerPort:Integer; Function GetPeerIPAddr:String; Function GetLocalPort:Integer; Function GetLocalIPAddr:String; Function IsConnected:Boolean; Function IsValidSocket:Boolean; Function IsReadable:Boolean; Function IsWritable:Boolean; Function DidReadTimeout:Boolean; // Procedure SetfBlockSizeFlags(Value:TBlockSizeFlags); Function CountWaiting:Integer; Function GetFErrStatus:Integer; public Socket:TDXSock; constructor Create(AOwner:TComponent); override; Destructor Destroy; override; Function DoConnect:Boolean; Function QuickConnect(DestAddr:String;DestPort:Integer):Boolean; Function Connect(Parameters:PNewConnect):Boolean; Function Listen(Parameters:PNewListen):Boolean; Function Accept(Var NewSock:TDXSockClient):Boolean; Procedure Disconnect; {2.0} {$IFDEF VER100} // D3 Function WriteCh(c:Char):Integer; Function Write(Const s:String):Integer; Function BlockWrite(buf:Pointer;len:Integer):Integer; Function BlockRead(buf:Pointer;len,tOut:Integer):Integer; Function Read(tOut:Integer):Char; Function SendFromStream(Stream:TStream):Boolean; Function SendFromWindowsFile(var Handle:Integer):boolean; Function SendFromBorlandFile(var Handle:File):boolean; Function SaveToStream(Stream:TStream;Timeout:Integer):Boolean; Function SaveToWindowsFile(var Handle:Integer;Timeout:Integer):boolean; Function SaveToBorlandFile(var Handle:File;Timeout:Integer):boolean; {$ELSE} // D4 or D5 Function Read(buf:Pointer;len,tOut:Integer):Integer; overload; Function Read(tOut:Integer):Char; overload; Function Write(c:Char):Integer; overload; Function Write(Const s:String):Integer; overload; Function Write(buf:Pointer;len:Integer):Integer; overload; Function SendFrom(Stream:TStream):Boolean; overload; Function SendFrom(var Handle:Integer):boolean; overload; Function SendFrom(var Handle:File):boolean; overload; Function SaveTo(Stream:TStream;Timeout:Integer):Boolean; overload; Function SaveTo(var Handle:Integer;Timeout:Integer):boolean; overload; Function SaveTo(var Handle:File;Timeout:Integer):boolean; overload; {$ENDIF} Function WriteLn(Const s:String):Integer; Function ReadStr(MaxLength,Timeout:Integer):String; {2.0.70} Function ReadLn(Timeout: Longword): string; Function PeekString:String; Function PeekChar:Char; Function GetErrorStr:String; Function GetErrorDesc(errorCode:Integer):String; Procedure SetNagle(TurnOn:Boolean); Procedure SetBlocking(TurnOn:Boolean); {2.0} Procedure WinsockVersion(Var WinsockInfo:PWinsockInfo); published Property Host:string read fsHost write fsHost; Property Port:Integer read fiPort write fiPort; Property EnabledNagle:Boolean read fbUseNagle write fbUseNagle; Property EnabledUDP:Boolean read fbUseUDP write fbUseUdp; Property EnabledBlocking:Boolean read fbUseBlocking write fbUseBlocking; Property PeerIPAddress:String read GetPeerIPAddr; {2.0} Property PeerPort:Integer read GetPeerPort; {2.0} Property LocalIPAddress:String read GetLocalIPAddr; {2.0} Property LocalPort:Integer read GetLocalPort; {2.0} Property Connected:Boolean read IsConnected; {2.0} Property ValidSocket:Boolean read IsValidSocket; {2.0} Property Readable:Boolean read IsReadable; {2.0} Property Writable:Boolean read IsWritable; {2.0} Property LastReadTimeout:Boolean read DidReadTimeout; {2.0} Property CharactersToRead:Integer read CountWaiting; {2.0} Property LastCommandStatus:Integer read GetFErrStatus; Property ConnectingToServer:TDX_Connecting read feConnecting write feConnecting; {2.0.70} Property ConnectedToServer:TDX_Connected read feConnected write feConnected; {2.0.70} Property ConnectionFailed:TDX_ConnectFailed read feConnectFailed write feConnectFailed; {2.0.70} Property ConnectionTerminated:TDX_Disconnected read feDisconnected write feDisconnected; {2.0.70} Property SendInProgress:TDX_SendingData read feSendingData write feSendingData; {2.0.70} Property SendDone:TDX_DataSent read feSendingDone write feSendingDone; {2.0.70} Property ResolvingHost:TDX_ResolvingHost read feResolvingHost write feResolvingHost; {2.0.70} Property ResolvedHost:TDX_ResolvedHost read feResolvedHost write feResolvedHost; {2.0.70} (* Property CheckData:Integer read fiSleepBetweenReads write fiSleepBetweenReads; Property PacketType:TPacketTypeFlags read fPacketType write fPacketType; Property OutputBufferSize:TBlockSizeFlags read fBlockSizeFlags write SetfBlockSizeFlags; Property DataReadyToRead:TDX_DataPendingRead read feDataPendingRead write feDataPendingRead; {2.0.70} Property ResolveFailed:TDX_ResolveFailed read feResolveFailed write feResolveFailed; {2.0.70} *) end; (* TDXClientThread=class(TThread) private TT:TDXSockClient; protected public constructor CreateTimerThread(TT:TDXSockClient); procedure Execute; override; end; *) implementation constructor TDXSockClient.Create(AOwner:TComponent); begin inherited Create(AOwner); Socket:=TDXSock.Create; fsHost:='127.0.0.1'; fiPort:=0; fbUseNagle:=True; fbUseUDP:=False; fMimicAsynch:=False; fNotifiedOfData:=False; fbUseBlocking:=True; fLastAddress:=''; fLastIP:=''; (* fiSleepBetweenReads:=500; *) end; destructor TDXSockClient.Destroy; begin try Socket.Free; finally inherited Destroy; end; end; Function TDXSockClient.DoConnect:Boolean; Var NewConnect:PNewConnect; Begin New(NewConnect); NewConnect^.Port:=fiPort; NewConnect^.UseNAGLE:=fbUseNagle; NewConnect^.UseUDP:=fbUseUDP; NewConnect^.UseBlocking:=fbUseBlocking; NewConnect^.ipAddress:=fsHost; Result:=Connect(NewConnect); Dispose(NewConnect); End; Function TDXSockClient.QuickConnect(DestAddr:String;DestPort:Integer):Boolean; Begin fiPort:=DestPort; // fbUseNagle:=True; // fbUseUDP:=False; fsHost:=DestAddr; Result:=DoConnect; End; Function TDXSockClient.Connect(Parameters:PNewConnect):Boolean; Var Ws:String; fErrStatus:Integer; Addr:String; begin Result := False; with Parameters^ do begin fsHost:=ipAddress; If Assigned(feResolvingHost) then Begin feResolvingHost(ipAddress); ProcessWindowsMessageQueue; End; If ipAddress<>fLastAddress then Begin If isNumericString(ipAddress) then Begin Ws:=GetHostByIPAddress(ipAddress); Addr:=ipAddress; End Else Begin Ws:=GetIPAddressByHost(ipAddress,1); Addr:=Ws; End; fLastIP:=Addr; fLastAddress:=ipAddress; End Else Begin Addr:=fLastIP; Ws:=fLastIP; End; If Ws='' then Ws:=ipAddress; If Assigned(feResolvedHost) then Begin feResolvedHost(ipAddress,Ws); ProcessWindowsMessageQueue; End; FbUseBlocking := UseBlocking; fbUseUDP := UseUDP; Socket.IsUDPMode:=fbUseUDP; If Assigned(feConnecting) then Begin feConnecting(ipAddress,Port); ProcessWindowsMessageQueue; End; Socket.Sock:=ClientConnectToServer(Addr, Port, UseUDP, UseNAGLE, @Socket.SockAddr,fErrStatus); Socket.LastCommandStatus:=fErrStatus; if (FErrStatus <> 0) then Begin If Assigned(feConnectFailed) then Begin feConnectFailed(IpAddress,FErrStatus); ProcessWindowsMessageQueue; End; Exit; End; Socket.SockClientSetGlobal( inet_ntoa(Socket.SockAddr.sin_addr), ntohs(Socket.SockAddr.sin_port)); If Not UseBlocking then Socket.SetBlocking(UseBlocking); Socket.IsKeepAliveMode:=False; { if not FbUseUDP then begin SetSockStatusBool(Socket.Sock, SO_KeepAlive, True, FErrStatus); Socket.IsKeepAliveMode:=FErrStatus = 0; end; } Socket.SetTimeoutAndBuffer(Socket.Sock); // 3.0c if FbUseUDP then begin // try to scale up the primary buffer. SetReceiveBuffer(Socket.Sock, TDXMaxSocketBuffer*4, FErrStatus); If FErrStatus<>0 then SetReceiveBuffer(Socket.Sock, TDXMaxSocketBuffer*3, FErrStatus); If FErrStatus<>0 then SetReceiveBuffer(Socket.Sock, TDXMaxSocketBuffer*2, FErrStatus); If FErrStatus<>0 then SetReceiveBuffer(Socket.Sock, TDXMaxSocketBuffer, FErrStatus); End; end; If Assigned(feConnected) then Begin feConnected(Parameters^.IpAddress,Parameters^.Port); ProcessWindowsMessageQueue; End; Result := True; If fMimicAsynch then Begin fNotifiedOfData:=False; (* with TDXClientThread.CreateTimerThread(self) do begin Priority:=tpIdle; // make a property! Resume; end; *) End; end; Function TDXSockClient.Listen(Parameters:PNewListen):Boolean; begin Result:=Socket.Listen(Parameters); end; {$WARNINGS OFF} function TDXSockClient.Accept(Var NewSock:TDXSockClient):Boolean; begin // Result:=Client.Accept(NewSock); //mh: result := false; end; {$WARNINGS ON} {$IFDEF VER100} // D3 function TDXSockClient.BlockWrite(buf:Pointer;len:Integer):Integer; {$ELSE} function TDXSockClient.Write(buf:Pointer;len:Integer):Integer; {$ENDIF} begin If Assigned(feSendingData) then Begin feSendingData(fsHost,Len); ProcessWindowsMessageQueue; End; Result:=Socket. {$IFDEF VER100} BlockWrite( {$ELSE} Write( {$ENDIF} Buf,Len); If Assigned(feSendingDone) then Begin feSendingDone(fsHost,Result); ProcessWindowsMessageQueue; End; end; {$IFDEF VER100} function TDXSockClient.WriteCh(c:Char):Integer; {$ELSE} function TDXSockClient.Write(c:Char):Integer; {$ENDIF} begin {$IFDEF VER100} // D3 Result:=BlockWrite(@C,1); {$ELSE} Result:=Write(@C,1); {$ENDIF} end; function TDXSockClient.Write(Const S:String):Integer; begin {$IFDEF VER100} // D3 Result:=BlockWrite(@S[1],Length(S)); {$ELSE} Result:=Write(@S[1],Length(S)); {$ENDIF} end; // this talks directly to DXSock to support OnFilter encoding // thus, you can not do write(string+#13#10) you have to do it // this way - to let TDXSock encode string and send raw #13#10! function TDXSockClient.WriteLn(Const s:String):Integer; begin If Assigned(feSendingData) then Begin feSendingData(fsHost,Length(S)); ProcessWindowsMessageQueue; End; Result:=Socket.WriteLn(S); If Assigned(feSendingDone) then Begin feSendingDone(fsHost,Result); ProcessWindowsMessageQueue; End; end; {$IFDEF VER100} function TDXSockClient.BlockRead(buf:Pointer;len,tOut:Integer):Integer; {$ELSE} function TDXSockClient.Read(buf:Pointer;len,tOut:Integer):Integer; {$ENDIF} begin Result:=Socket. {$IFDEF VER100} BlockRead( {$ELSE} Read( {$ENDIF} Buf,Len); fNotifiedOfData:=False; End; function TDXSockClient.Read(tOut:Integer):Char; begin {$IFDEF VER100} BlockRead(@Result,1,tOut); {$ELSE} Read(@Result,1,tOut); {$ENDIF} end; function TDXSockClient.ReadStr(MaxLength,Timeout:Integer):String; begin Result:=Socket.ReadStr(MaxLength); fNotifiedOfData:=False; end; function TDXSockClient.ReadLn(Timeout: Longword): string; begin Result:=Socket.ReadLn(Timeout); fNotifiedOfData:=False; end; {$IFDEF VER100} function TDXSockClient.SendFromStream(Stream:TStream):Boolean; {$ELSE} function TDXSockClient.SendFrom(Stream:TStream):Boolean; {$ENDIF} Begin If Assigned(feSendingData) then Begin feSendingData(fsHost,Stream.Size); ProcessWindowsMessageQueue; End; Result:=Socket. {$IFDEF VER100} SendFromStream( {$ELSE} SendFrom( {$ENDIF} Stream); If Assigned(feSendingDone) then Begin feSendingDone(fsHost,Stream.Position); ProcessWindowsMessageQueue; End; fNotifiedOfData:=False; End; {$IFDEF VER100} function TDXSockClient.SendFromWindowsFile(var Handle:Integer):boolean; {$ELSE} function TDXSockClient.SendFrom(var Handle:Integer):boolean; {$ENDIF} Begin If Assigned(feSendingData) then Begin // feSendingData(fsHost,Stream.Size); ProcessWindowsMessageQueue; End; Result:=Socket. {$IFDEF VER100} SendFromWindowsFile( {$ELSE} SendFrom( {$ENDIF} Handle); If Assigned(feSendingDone) then Begin // feSendingDone(fsHost,Stream.Position); ProcessWindowsMessageQueue; End; fNotifiedOfData:=False; End; //***************************************************************************** // SENDFROMBORLANDFILE: Send the Borland File handle to the socket until end of // file //***************************************************************************** {$IFDEF VER100} function TDXSockClient.SendFromBorlandFile(var Handle:File):boolean; {$ELSE} function TDXSockClient.SendFrom(var Handle:File):boolean; {$ENDIF} Begin If Assigned(feSendingData) then Begin // feSendingData(fsHost,Stream.Size); ProcessWindowsMessageQueue; End; Result:=Socket. {$IFDEF VER100} SendFromBorlandFile( {$ELSE} SendFrom( {$ENDIF} Handle); If Assigned(feSendingDone) then Begin // feSendingDone(fsHost,Stream.Position); ProcessWindowsMessageQueue; End; fNotifiedOfData:=False; End; {$IFDEF VER100} function TDXSockClient.SaveToStream(Stream:TStream;Timeout:Integer):Boolean; {$ELSE} function TDXSockClient.SaveTo(Stream:TStream;Timeout:Integer):Boolean; {$ENDIF} Begin Result:=Socket. {$IFDEF VER100} SaveToStream( {$ELSE} SaveTo( {$ENDIF} Stream,Timeout); fNotifiedOfData:=False; End; {$IFDEF VER100} function TDXSockClient.SaveToWindowsFile(var Handle:Integer;Timeout:Integer):boolean; {$ELSE} function TDXSockClient.SaveTo(var Handle:Integer;Timeout:Integer):boolean; {$ENDIF} Begin Result:=Socket. {$IFDEF VER100} SaveToWindowsFile( {$ELSE} SaveTo( {$ENDIF} Handle,Timeout); fNotifiedOfData:=False; End; {$IFDEF VER100} function TDXSockClient.SaveToBorlandFile(var Handle:File;Timeout:Integer):boolean; {$ELSE} function TDXSockClient.SaveTo(var Handle:File;Timeout:Integer):boolean; {$ENDIF} Begin Result:=Socket. {$IFDEF VER100} SaveToBorlandFile( {$ELSE} SaveTo( {$ENDIF} Handle,Timeout); fNotifiedOfData:=False; End; function TDXSockClient.PeekString:String; begin Result:=Socket.PeekString; end; function TDXSockClient.PeekChar:Char; begin Result:=Socket.PeekChar; end; procedure TDXSockClient.Disconnect; begin if Not IsValidSocket then Exit; If Assigned(feDisconnected) then Begin feDisconnected(fsHost); ProcessWindowsMessageQueue; End; Socket.CloseGracefully; end; function TDXSockClient.IsValidSocket:Boolean; Begin If Assigned(Socket) then Result:=Socket.ValidSocket Else Result:=False; End; function TDXSockClient.IsConnected:Boolean; begin If Assigned(Socket) then Result:=Socket.Connected Else Result:=False; end; function TDXSockClient.IsReadable:Boolean; begin If Assigned(Socket) then Result:=Socket.Readable Else Result:=False; end; function TDXSockClient.IsWritable:Boolean; begin If Assigned(Socket) then Result:=Socket.Writable Else Result:=False; end; Function TDXSockClient.DidReadTimeout:Boolean; Begin If Assigned(Socket) then Result:=Socket.LastReadTimeout Else Result:=True; End; function TDXSockClient.GetPeerPort:Integer; begin If Assigned(Socket) then Result:=Socket.PeerPort Else Result:=-1; end; function TDXSockClient.GetPeerIPAddr:String; begin If Assigned(Socket) then Result:=Socket.PeerIPAddress Else Result:=''; end; function TDXSockClient.GetLocalPort:Integer; begin If Assigned(Socket) then Result:=Socket.LocalPort Else Result:=-1; end; function TDXSockClient.GetLocalIPAddr:String; begin If Assigned(Socket) then Result:=Socket.LocalIPAddress Else Result:=''; end; Function TDXSockClient.GetErrorStr:String; begin If Assigned(Socket) then Result:=Socket.GetErrorStr Else Result:='Socket instance does not exist'; end; Procedure TDXSockClient.WinsockVersion(Var WinsockInfo:PWinsockInfo); begin Socket.WinsockVersion(WinsockInfo); end; Procedure TDXSockClient.SetNagle(TurnOn:Boolean); Begin fbUseNagle:=TurnOn; Socket.SetNagle(fbUseNagle); End; Procedure TDXSockClient.SetBlocking(TurnOn:Boolean); Begin fbUseBlocking:=TurnOn; Socket.SetBlocking(fbUseBlocking); End; function TDXSockClient.GetErrorDesc(errorCode:Integer):String; begin Result:=Socket.GetErrorDesc(ErrorCode); end; Function TDXSockClient.CountWaiting:Integer; Begin Result:=Socket.CharactersToRead; End; Function TDXSockClient.GetFErrStatus:Integer; Begin Result:=Socket.LastCommandStatus; End; (* Procedure TDXSockClient.CheckInBuffer; Var MsgRec:TMsg; Begin While isValidSocket do Begin If (CountWaiting>0) then Begin If (Not fNotifiedOfData) then Begin fNotifiedOfData:=True; if Assigned(feDataPendingRead) then feDataPendingRead(CountWaiting); End End; SleepEx(fiSleepBetweenReads,True); {2.0.91} while PeekMessage(MsgRec,0{WindowHandle},0,0,PM_REMOVE) do begin TranslateMessage(MsgRec); DispatchMessage(MsgRec) end; End; End; constructor TDXClientThread.CreateTimerThread(TT:TDXSockClient); begin inherited Create(true); self.tt:=tt; FreeOnTerminate:=true; end; procedure TDXClientThread.Execute; begin Synchronize(TT.CheckInBuffer); end; *) end.