Page 1 of 2
Tsocket Bug
Posted: Mon Apr 19, 2010 12:55 am
by Davide
Hello all.
Small sample taken from senddata.prg:
Code: Select all
// Sockets use sample developed by Enrico M.G.
#include "Fivewin.ch"
FUNCTION MAIN()
LOCAL oWnd
DEFINE WINDOW oWnd
@ 1, 2 BUTTON "Send";
SIZE 100, 50;
ACTION SENDDATA( 25, "209.191.88.254") // yahoo.com - Infinite loop
// ACTION SENDDATA( 25, "209.85.135.111") // smtp.gmail.com - This works good
ACTIVATE WINDOW oWnd
RETURN NIL
STATIC FUNCTION SENDDATA( nPort, cIP, cMsg )
LOCAL oSocket := TSocket():New( nPort )
oSocket:lDebug :=.t.
oSocket:cLogFile:="senddata.log"
oSocket:bConnect := { || oSocket:GetData() , SysWait(1) , oSocket:SendData( "HELO TEST"+CRLF ), SysWait(1),;
oSocket:GetData() , SysWait(1) , oSocket:SendData( "QUIT"+CRLF ), SysWait(1),;
oSocket:GetData() , SysWait(1) , oSocket:End() }
oSocket:Connect( cIP )
RETURN NIL
When it's run through smtp.gmail.com you obtain a senddata.log file like follows:
04/19/10 02:23:14: Connect Socket handle: 340
04/19/10 02:23:14:
04/19/10 02:23:14: Write Socket handle: 340
04/19/10 02:23:14: Read Socket handle: 340
04/19/10 02:23:16: 220 mx.google.com ESMTP j10sm25406824mue.48
250 mx.google.com at your service
04/19/10 02:23:17: Read Socket handle: 340
04/19/10 02:23:17: Close Socket handle: 340
04/19/10 02:23:18: 221 2.0.0 closing connection j10sm25406824mue.48
While with yahoo.com ...
04/19/10 02:26:31: Connect Socket handle: 340
04/19/10 02:26:31:
04/19/10 02:26:32: Sent: -1 Len: 11 Buffer Len: 0 Error: 10057
04/19/10 02:26:32: Sent: -1 Len: 11 Buffer Len: 0 Error: 10057
04/19/10 02:26:32: Sent: -1 Len: 11 Buffer Len: 0 Error: 10057
04/19/10 02:26:32: Sent: -1 Len: 11 Buffer Len: 0 Error: 10057
04/19/10 02:26:32: Sent: -1 Len: 11 Buffer Len: 0 Error: 10057
... infinite
I tried manually telnetting the yahoo IP and it kindly reply me a couple of text lines stating that I'm disallowed because I'm on a residential/dynamic IP, then it puts the connection down, but that's not the problem (this is just a sample I made for you to understand the problem).
The problem is that looks like a WSA error in SendData() like the above puts tSocket in an infinite loop instead of retrieving those 2 lines of text, that are informative and helpful to know why the 10057 error was triggered, and then closing the socket.
How could I fix it ?
Thanks,
Davide
Re: Tsocket Bug
Posted: Mon Apr 19, 2010 2:53 am
by Bayron
Davide,
Do you have a Yahoo Mail Plus account???
If you don't, that may be the problem......
Re: Tsocket Bug
Posted: Mon Apr 19, 2010 7:05 am
by xProgrammer
Hi Davide
At face value it looks like yahoo is dropping the connection (as per your telnet experience) and you pc keeps retrying the failed connection. Given your "success" with the gmail address it is less likely to be a "bug" in tsocket.
I have mainly done IP socket programming from[x]Harbour running on Linux, but I have successfully run sessions between Linux and Windows pcs. I know that I had to fiddle with timeouts and looping to get code that was working properly on Linux hosts to work on Windows hosts.
In case its of any use, here is the TSocket class that I am currently using:
Code: Select all
// Socket.prg
#include "hbclass.ch"
CLASS TSocket
CLASSDATA log_Initialised INIT .F.
DATA str_IPAddress
DATA int_PortNumber
DATA pSocket
DATA log_Connected
DATA str_Data
METHOD New() CONSTRUCTOR
METHOD SetIP( str_IPAddress )
METHOD SetPort( int_PortNumber )
METHOD CreateQueryObject()
METHOD Connect()
METHOD Send( cMessage )
METHOD Receive()
METHOD Close()
METHOD SendReceive( cMessage )
METHOD CleanUp()
ENDCLASS
METHOD New() CLASS TSocket
::str_IPAddress := "127.0.0.1"
::int_PortNumber := 1800
IF !::log_Initialised
INetInit()
::log_Initialised := .T.
ENDIF
RETURN self
METHOD SetIP( str_IPAddress ) CLASS TSocket
::str_IPAddress := AllTrim( str_IPAddress )
RETURN nil
METHOD SetPort( int_PortNumber ) CLASS TSocket
::int_PortNumber := int_PortNumber
RETURN nil
METHOD CreateQueryObject()
RETURN( TQuery():New( self ) )
METHOD Connect() CLASS TSocket
LOCAL log_OK
LOCAL log_Retry
log_Retry := .T.
DO WHILE log_Retry
log_OK := .T.
TRY
::pSocket := INetConnect( ::str_IPAddress, ::int_PortNumber )
CATCH
MsgInfo( "Unable to connect to data server" )
log_OK := .F.
END
IF log_OK
IF INetErrorCode( ::pSocket ) == 0
::log_Connected := .T.
RETURN .T.
ELSE
? "Socket error:", INetErrorDesc( ::pSocket )
ENDIF
ENDIF
log_OK := .F.
::log_Connected := .F.
// ? "Press [Esc] to exit, [Enter] to retry"
// IF InKey( 0 ) == 27
IF !MsgYesNo( "Can't communicate with the server. Do you want to retry?", "Communication Error" )
INetCleanUp()
log_OK := .F.
ProgExit()
ENDIF
ENDDO
METHOD Send( var_Message ) CLASS TSocket
INetSend( ::pSocket, var_Message )
RETURN nil
METHOD Receive() CLASS TSocket
LOCAL str_Buffer
LOCAL int_Bytes
INetSetTimeOut( ::pSocket, 1000 )
::str_Data := ""
int_Bytes := 1
DO WHILE int_Bytes > 0
? "in loop"
str_Buffer := Space( 1024 )
int_Bytes := INetRecv( ::pSocket, @str_Buffer )
? int_Bytes
::str_Data += Left( str_Buffer, int_Bytes )
ENDDO
RETURN nil
METHOD Close() CLASS TSocket
INetClose( ::pSocket )
RETURN nil
METHOD SendReceive( cMessage ) CLASS TSocket
::Send( cMessage )
::Receive()
::Close()
RETURN ::cData
METHOD CleanUp() CLASS TSocket
RETURN InetCleanUp()
Re: Tsocket Bug
Posted: Mon Apr 19, 2010 11:11 am
by Davide
Thank you guys for your replies.
Bayron wrote:
Do you have a Yahoo Mail Plus account???
No, but I don't need to necessarily connect to that yahoo server. That was just an example to show the problem.
xProgrammer wrote:At face value it looks like yahoo is dropping the connection (as per your telnet experience) and you pc keeps retrying the failed connection. Given your "success" with the gmail address it is less likely to be a "bug" in tsocket.
The Google sample works good because that server doesn't drop the connection down, but replies as expected.
The Yahoo sample doesn't work because tSocket.prg doesn't correctly handle the 10057 WSA error.
Thank you for posting your class, but tSocket is used by other classes, like tSmtp, tWebClient, etc. so I need to fix the original one shipped with FWH because in reality this is causing me trouble on other classes, when the remote server closes the connection unexpectedly (for many reasons; not necessarily the reason in this sample).
Thanks,
Davide
Re: Tsocket Bug
Posted: Wed Apr 21, 2010 3:42 pm
by Davide
ok, this solves the endless loop (and even a problem with WSAGetLastError() that's called twice if logging is enabled):
Code: Select all
METHOD SendData( cData ) CLASS TSocket
local nSize := Len( cData )
local nLen := nSize
local nSent := 0
local nError:= 0
if ! ::lSending
::lSending = .t.
else
AAdd( ::aBuffer, cData )
return nSize
endif
while ( nLen > 0 .and. ;
( nSent := SocketSend( ::nSocket, cData ) ) < nLen ) .or. ;
Len( ::aBuffer ) > 0
if ::lDebug .and. ! Empty( ::cLogFile )
nError:=WSAGetLastError()
LogFile( ::cLogFile, { "Sent:", nSent, "Len:", Len( cData ), "Buffer Len:", Len( ::aBuffer ), "Error:", nError } )
endif
// Check for buffered packets to send
if nLen == 0 .and. Len( ::aBuffer ) > 0
cData = ::aBuffer[ 1 ]
ADel( ::aBuffer, 1 )
ASize( ::aBuffer, Len( ::aBuffer ) - 1 )
endif
if nSent != -1
cData = SubStr( cData, nSent + 1 )
nLen = Len( cData )
else
if WSAGetLastError() != WSAEWOULDBLOCK
// exit
endif
if !(::lDebug .and. ! Empty( ::cLogFile )) ; nError:=WSAGetLastError() ; Endif // *GD* Cannot do it twice
if nError = 10057 // WSAENOTCONN *GD* 21.04.2010
cData:="" ; nSize:=0 ; exit // ::lSending:=.f. ; ::End()
endif
endif
SysRefresh()
end
// if ::lDebug .and. ! Empty( ::cLogFile )
// LogFile( ::cLogFile, { cData } )
// endif
::lSending = .f.
return nSize
however, I found out that the source of the problem is before this point.
Method ConnectTo() doesn't detect the dropdown and returns a 10060 WSA Error just when the Timeout expires.
Any chance to have ConnectTo() acting like the Terminal Emulator (retrieving the server's reply and returning immediately) ?
Thanks,
Davide
Re: Tsocket Bug
Posted: Sat May 07, 2011 11:52 am
by Horizon
Hi Davide,
Can you solve this problem?
I have 11.01. When I try to run SockCli.prg as an example without running SockSer.prg, Tsocket runs to bConnect. I think it should say can not connected.
Thanks,
Re: Tsocket Bug
Posted: Sat May 07, 2011 12:16 pm
by Davide
Dear Hakan,
Horizon wrote:I have 11.01. When I try to run SockCli.prg as an example without running SockSer.prg, Tsocket runs to bConnect. I think it should say can not connected.
unfortunately I never solved the problem above, and I'm still on 9.05
Hi,
Davide
Re: Tsocket Bug
Posted: Sat May 07, 2011 12:21 pm
by Horizon
Daniel,
Can you help us?
Re: Tsocket Bug
Posted: Sat May 07, 2011 2:04 pm
by Daniel Garcia-Gil
Hello
yes, sure...
can you post a little sample?
or the sample in first post is enough?
Re: Tsocket Bug
Posted: Sat May 07, 2011 8:42 pm
by Horizon
Hi Daniel,
I use standart SockCli.prg and SockSer.prg's as an example.
My main problem is connect method. My scenario is like below.
SockSer.prg is not running. There is not any Socket server as I know. I use standart port 2000 and use 127.0.0.1 as IP. (I have tried several unknown ip)
I run SockCli.prg and connect. The bConnect block is evaluated, but the return value of connect method is -1. It is not connected. so if you call senddata method after that, the unexpected errors occur. The socket thinks connection is establish. but there is no connection.
if the senddata method is used in this situation, it gives an error. if the logfile is used, logfile is grow and grow. (Davide explained this above messages)
I think the other problem is checking the connection is established or not.
Re: Tsocket Bug
Posted: Sat May 07, 2011 9:18 pm
by Daniel Garcia-Gil
Hello
i tested sockserv.prg and sockcli.prg and run fine
from samples folder
Download:
http://www.sitasoft.net/fivewin/samples/testsock.zip
sockserv.prg
Code: Select all
// Socket server connection sample
#include "FiveWin.ch"
#define ST_COMMAND 1
#define ST_SENDFILE 2
#define FILE_BLOCK 8000
static oWnd, oSocket, oClient
//------------------------------------------------------------------------//
function Main()
local oBar
DEFINE WINDOW oWnd TITLE "Server socket"
DEFINE BUTTONBAR oBar OF oWnd _3D
DEFINE BUTTON OF oBar ACTION Server() TOOLTIP "Listen"
DEFINE BUTTON OF oBar ACTION oClient:SendData( "Hello from server!" ) TOOLTIP "Talk to client"
ACTIVATE WINDOW oWnd
return nil
//------------------------------------------------------------------------//
function Server()
oSocket = TSocket():New( 2000 )
oSocket:bAccept = { | oSocket | oClient := TSocket():Accept( oSocket:nSocket ),;
oClient:Cargo := ST_COMMAND,;
oClient:bRead := { | oSocket | OnRead( oSocket ) },;
oClient:bClose := { | oSocket | OnClose( oSocket ) } }
oSocket:Listen()
return nil
//------------------------------------------------------------------------//
function OnRead( oSocket )
local cData := oSocket:GetData()
local cToken
LogFile( "sockserv.txt", { Len( cData ), cData } )
do case
case oSocket:Cargo == ST_COMMAND
cToken = StrToken( cData, 1 )
do case
case cToken == "SENDFILE"
oSocket:Cargo = ST_SENDFILE
oSocket:hFile = fcreate( StrToken( cData, 2 ) )
case cToken == "MSG"
MsgInfo( SubStr( cData, 5 ) )
endcase
case oSocket:Cargo == ST_SENDFILE
fwrite( oSocket:hFile, cData, Len( cData ) )
LogFile( "sockserv.txt", { "writting..." } )
if Len( cData ) < FILE_BLOCK
// fclose( oSocket:hFile )
// MsgInfo( Len( cData ) )
// oSocket:Cargo = ST_COMMAND
endif
endcase
return nil
//------------------------------------------------------------------------//
function OnClose( oSocket )
MsgInfo( "Client has closed!" )
do case
case oSocket:Cargo == ST_SENDFILE
fclose( oSocket:hFile )
endcase
oSocket:End()
return nil
//------------------------------------------------------------------------//
sockcli.prg
Code: Select all
// Socket server connection sample
#include "FiveWin.ch"
static oWnd, oSocket
function Main()
local oBar
DEFINE WINDOW oWnd TITLE "Client socket"
DEFINE BUTTONBAR oBar OF oWnd _3D
DEFINE BUTTON OF oBar ACTION Client() TOOLTIP "Connect"
DEFINE BUTTON OF oBar ;
ACTION oSocket:SendData( "MSG This is a test" ) ;
TOOLTIP "Send data"
DEFINE BUTTON OF oBar ;
ACTION SendFile() TOOLTIP "Send file"
ACTIVATE WINDOW oWnd
return nil
function Client()
oSocket = TSocket():New( 2000 )
oSocket:bRead = { | oSocket | MsgInfo( oSocket:GetData() ) }
// Never use a MsgInfo() here because it hangs Windows!!!
oSocket:bConnect = { || oWnd:SetText( "Connected!" ) }
oSocket:bClose = { || MsgInfo( "Server has closed!" ) }
oSocket:Connect( "127.0.0.1" ) // use the server IP address here
return nil
function SendFile()
local cFileName := cGetFile( "*.*", "Select a file to send by Internet" )
if ! Empty( cFileName ) .and. File( cFileName )
oSocket:SendData( "SENDFILE " + cFileName( cFileName ) )
oSocket:SendFile( cFileName )
MsgInfo( "File sent" )
endif
return nil
Re: Tsocket Bug
Posted: Mon May 09, 2011 10:31 am
by Horizon
Hi Daniel,
I have tested your sockcli.exe in my computers. All of my computers says Connected, when I press connect button. There is no working socket server.
Re: Tsocket Bug
Posted: Mon May 09, 2011 11:43 am
by Daniel Garcia-Gil
Hello...
can you contact with me by msn (
danielgarciagil@cantv.net) or gmail chat (
danielgarciagil@gmail.com) or other way? for test
Re: Tsocket Bug
Posted: Mon May 09, 2011 5:37 pm
by Daniel Garcia-Gil
Horizon
i'll explain...
it isn't a bug... is a behavior of windows socket...
when we connected to socket, we are open a port to send and receive data, it's no a direct link to a server, the ip address is only the "path" between client and server...
we dont know if the server accept the connection until them notify us, i didn't found a message send by server to notify "connection accepted"
With a nonblocking socket, the connection attempt cannot be completed immediately. In this case, connect will return SOCKET_ERROR, and WSAGetLastError will return WSAEWOULDBLOCK. ( you can call WSAGetLastError after connect, will see )
try with this new sockcli.prg / socksrv.prg
look oSocket:bAccept ... i sent "ok" to notify the client the connection is accepted, other way the client no show "connected" only show "port opened"
Code: Select all
// Socket server connection sample
#include "FiveWin.ch"
#define ST_COMMAND 1
#define ST_SENDFILE 2
#define FILE_BLOCK 8000
static oWnd, oSocket, oClient
//------------------------------------------------------------------------//
function Main()
local oBar
DEFINE WINDOW oWnd TITLE "Server socket"
DEFINE BUTTONBAR oBar OF oWnd _3D
DEFINE BUTTON OF oBar ACTION Server() TOOLTIP "Listen"
DEFINE BUTTON OF oBar ACTION oClient:SendData( "Hello from server!" ) TOOLTIP "Talk to client"
ACTIVATE WINDOW oWnd
return nil
//------------------------------------------------------------------------//
function Server()
oSocket = TSocket():New( 5000 )
oSocket:bAccept = { | oSocket | oClient := TSocket():Accept( oSocket:nSocket ),;
oClient:Cargo := ST_COMMAND,;
oClient:bRead := { | oSocket | OnRead( oSocket ) },;
oClient:bClose := { | oSocket | OnClose( oSocket ) },;
oClient:SendData( "ok" ),;
MsgInfo( "accepted" ) }
oSocket:Listen()
return nil
//------------------------------------------------------------------------//
function OnRead( oSocket )
local cData := oSocket:GetData()
local cToken
LogFile( "sockserv.txt", { Len( cData ), cData } )
do case
case oSocket:Cargo == ST_COMMAND
cToken = StrToken( cData, 1 )
do case
case cToken == "SENDFILE"
oSocket:Cargo = ST_SENDFILE
oSocket:hFile = fcreate( StrToken( cData, 2 ) )
case cToken == "MSG"
MsgInfo( SubStr( cData, 5 ) )
endcase
case oSocket:Cargo == ST_SENDFILE
fwrite( oSocket:hFile, cData, Len( cData ) )
LogFile( "sockserv.txt", { "writting..." } )
if Len( cData ) < FILE_BLOCK
// fclose( oSocket:hFile )
// MsgInfo( Len( cData ) )
// oSocket:Cargo = ST_COMMAND
endif
endcase
return nil
//------------------------------------------------------------------------//
function OnClose( oSocket )
MsgInfo( "Client has closed!" )
do case
case oSocket:Cargo == ST_SENDFILE
fclose( oSocket:hFile )
endcase
oSocket:End()
return nil
//------------------------------------------------------------------------//
Code: Select all
// Socket server connection sample
#include "FiveWin.ch"
static oWnd, oSocket
function Main()
local oBar
DEFINE WINDOW oWnd TITLE "Client socket"
DEFINE BUTTONBAR oBar OF oWnd _3D
DEFINE BUTTON OF oBar ACTION Client() TOOLTIP "Connect"
DEFINE BUTTON OF oBar ;
ACTION oSocket:SendData( "MSG This is a test" ) ;
TOOLTIP "Send data"
DEFINE BUTTON OF oBar ;
ACTION SendFile() TOOLTIP "Send file"
ACTIVATE WINDOW oWnd
return nil
function Client()
if oSocket != NIL
oSocket:End()
endif
oSocket = TSocket():New( 5000 )
oSocket:bRead = { | oSocket | HandleRecived( oSocket, oWnd ) }
// Never use a MsgInfo() here because it hangs Windows!!!
oSocket:bConnect = { || oWnd:SetText( "Socked Opened!" ) }
oSocket:bClose = { || MsgInfo( "Server has closed!" ) }
oSocket:Connect( "127.0.0.1" )
MsgInfo( WSAGetLastError() )
return nil
function SendFile()
local cFileName := cGetFile( "*.*", "Select a file to send by Internet" )
if ! Empty( cFileName ) .and. File( cFileName )
oSocket:SendData( "SENDFILE " + cFileName( cFileName ) )
oSocket:SendFile( cFileName )
MsgInfo( "File sent" )
endif
return nil
function HandleRecived( oSocket, oWnd )
local cData := oSocket:GetData()
if cData = "ok"
oWnd:SetText( "Connected!!" )
else
MsgInfo( cData )
endif
return nil
Re: Tsocket Bug
Posted: Mon May 09, 2011 6:46 pm
by Horizon
Thank you very much Daniel.
There is a help in Fivewin Function about ConnectTo like that.
ConnectTo( <nSocket>, <nPort>, <cIPAddr ) --> nRetCode
<nRetCode> Zero if successful, otherwise SOCKET_ERROR.
unfortunately, it does not work. It returns always -1.