🚀 go-pugleaf

RetroBBS NetNews Server

Inspired by RockSolid Light RIP Retro Guy

Thread View: borland.public.cppbuilder.internet.socket
9 messages
9 total messages Started by Mike Ruskai Tue, 04 Mar 2008 16:16
Indy10 usage
#481
Author: Mike Ruskai
Date: Tue, 04 Mar 2008 16:16
33 lines
2239 bytes
I have an application which uses Unix-style socket calls, to which I'm
attempting to add SOCKS support.

Indy supposedly supports SOCKS, so I'm trying to figure out how to
convert the normal socket code to the bizarre usage of Indy.

I'm using BCB6 for the app in question, so I removed Indy 8,
downloaded the latest Indy10 snapshot, and installed that (apparently
successfully).

Since the high-level protocol in use is proprietary, I'm using
TIdTCPClient.  I'm assigning a TIdIOHandlerStack to the IOHandler
property, and a TIdSocksInfo to the TransparentProxy property of the
IOHandler (though I've also tested with no proxy set - results are the
same).

One problem is that there's no simple functional equivalent of recv()
for the IOHandler.

I've tried ReadBytes() and ReadLn(), preceded by Readable() to make
sure the socket can be read (that functionality is a must), just to
get started on simply reading any data from the socket.

I connect to a server I control, which sends data over the socket as
soon as it's connected.  I've confirmed with packet capture that the
correct data is sent.

However, while Readable() returns true, both ReadBytes() and ReadLn()
read nothing at all.  The Length property of the TDynByteArray sent to
the former is 0, and the return string for the latter is empty.  Yet
calling them made the result of Readable() subsequently false.

What is the correct way to simply read and write a socket?
Re: Indy10 usage
#483
Author: Remy Lebeau (TeamB)
Date: Tue, 04 Mar 2008 17:41
29 lines
1935 bytes
"Mike Ruskai" <BUTthannydI@DONTearthlinkLIKE.netSPAM> wrote in message 
news:ghsqs35tipni65rjlntjpl7hgi6f1bv1g8@4ax.com...

> Indy supposedly supports SOCKS, so I'm trying to figure out
> how to convert the normal socket code to the bizarre usage of Indy.

Simply attach a TIdSocksInfo to your TIdTCPClient.  It will handle the SOCKS 
for you.  You don't have to change anything else in your reading/writing 
code.

> I'm assigning a TIdIOHandlerStack to the IOHandler property, and
> a TIdSocksInfo to the TransparentProxy property of the IOHandler

That is the way to go, yes.

> One problem is that there's no simple functional equivalent of recv()
> for the IOHandler.

Yes, there is, which you have already discovered - Readable() and 
ReadBytes().

> However, while Readable() returns true, both ReadBytes() and
> ReadLn() read nothing at all.

Please show your actual code.


Gambit 
Re: Indy10 usage
#484
Author: Mike Ruskai
Date: Tue, 04 Mar 2008 21:30
51 lines
3135 bytes
On or about Tue, 4 Mar 2008 09:41:29 -0800 did "Remy Lebeau \(TeamB\)"
<no.spam@no.spam.com> dribble thusly:

>
>"Mike Ruskai" <BUTthannydI@DONTearthlinkLIKE.netSPAM> wrote in message 
>news:ghsqs35tipni65rjlntjpl7hgi6f1bv1g8@4ax.com...
>
>> Indy supposedly supports SOCKS, so I'm trying to figure out
>> how to convert the normal socket code to the bizarre usage of Indy.
>
>Simply attach a TIdSocksInfo to your TIdTCPClient.  It will handle the SOCKS 
>for you.  You don't have to change anything else in your reading/writing 
>code.

You misunderstood.  I'm using normal socket code (e.g. connect(),
select(), send(), recv(), etc.), not Indy.  I'm adding conditional
code that uses Indy instead when a SOCKS server is configured.

>> One problem is that there's no simple functional equivalent of recv()
>> for the IOHandler.
>
>Yes, there is, which you have already discovered - Readable() and 
>ReadBytes().

It's not equivalent at all.  recv() reads data up to the buffer length
specified.  ReadBytes() blocks forever until the specified data length
is read, or the socket is closed.  In other words, ReadBytes() is
useless for a normal program (i.e. one without a dedicated socket
reading thread) that doesn't know exactly how many bytes are going to
be sent over the socket.

>> However, while Readable() returns true, both ReadBytes() and
>> ReadLn() read nothing at all.
>
>Please show your actual code.

I got that bit sort of working, by adding a delay to Readable().  

It's still iffy to use.  There is simply no way I can see to loop
while receiving available data until the received data is deemed
complete (due to the high-level protocol definition).  A hack with
ReadTimeout and ReadBytes() sort of works, but is so sensitive to
network timing that it's worthless.

As it happens, the current design uses text-only data on the control
connection, so ReadLn() might work for command responses.  The data
connection exists only for the duration of the transfer, so
ReadBytes() may actually work out.

Overall, however, I have to say that Indy is a huge pain to work with
for someone used to normal socket programming.
Re: Indy10 usage
#486
Author: Remy Lebeau (TeamB)
Date: Tue, 04 Mar 2008 22:12
45 lines
2703 bytes
"Mike Ruskai" <BUTthannydI@DONTearthlinkLIKE.netSPAM> wrote in message 
news:tefrs3lpnfkk0arr2qa3vospikaj3j491h@4ax.com...

> You misunderstood.  I'm using normal socket code (e.g. connect(),
> select(), send(), recv(), etc.), not Indy.

You can't use TIdSocksInfo with a non-Indy connection, and there is no way 
to assign your own SOCKET handle to Indy's classes without re-writing them.

> recv() reads data up to the buffer length specified.

So does ReadBytes().

> ReadBytes() blocks forever until the specified data length is read,
> or the socket is closed.

Or until a ReadTimeout elapses, if specified.

> In other words, ReadBytes() is useless for a normal program

Not really.  If you want to just read what is currently available, up to but 
maybe less than the desired length, then simply call the ReadFromSource() 
method first and then adjust the length based on the InputBuffer's current 
size.  For example:

    IOHandler->ReadFromSource(true, 10, false);
    IOHandler->ReadBytes(buffer, min(1024, IOHandler->InputBuffer->Size));

> that doesn't know exactly how many bytes are going to be sent over the 
> socket.

Most protocols are designed to offer a way of knowing that.  But for those 
rare cases where it simply is not, then that is why the ReadFromSource() 
method and the InputBuffer property are publically accessible.

> As it happens, the current design uses text-only data on the control
> connection, so ReadLn() might work for command responses.  The
> data connection exists only for the duration of the transfer, so
> ReadBytes() may actually work out.

Sounds like you are reproducing exactly what the FTP protocol already does.


Gambit 
Re: Indy10 usage
#488
Author: Mike Ruskai
Date: Wed, 05 Mar 2008 03:04
78 lines
4253 bytes
On or about Tue, 4 Mar 2008 14:12:01 -0800 did "Remy Lebeau \(TeamB\)"
<no.spam@no.spam.com> dribble thusly:

>
>"Mike Ruskai" <BUTthannydI@DONTearthlinkLIKE.netSPAM> wrote in message 
>news:tefrs3lpnfkk0arr2qa3vospikaj3j491h@4ax.com...
>
>> You misunderstood.  I'm using normal socket code (e.g. connect(),
>> select(), send(), recv(), etc.), not Indy.
>
>You can't use TIdSocksInfo with a non-Indy connection, and there is no way 
>to assign your own SOCKET handle to Indy's classes without re-writing them.

You misunderstood again.  The above is to explain that I have normal
socket code, not Indy code, which means your previous comment about
assigning a TIdSockInfo and leaving the rest of the code alone didn't
apply.

I'm not trying to use TIdSocksInfo with normal socket calls.

>
>> recv() reads data up to the buffer length specified.
>
>So does ReadBytes().
>
>> ReadBytes() blocks forever until the specified data length is read,
>> or the socket is closed.
>
>Or until a ReadTimeout elapses, if specified.

Which means you have to pick an arbitrary length of time you're
willing to have the program sit doing nothing, because there's no
function to read UP TO a number of bytes, from whatever's available,
without blocking until that number of bytes is completely filled.

>> In other words, ReadBytes() is useless for a normal program
>
>Not really.  If you want to just read what is currently available, up to but 
>maybe less than the desired length, then simply call the ReadFromSource() 
>method first and then adjust the length based on the InputBuffer's current 
>size.  For example:
>
>    IOHandler->ReadFromSource(true, 10, false);
>    IOHandler->ReadBytes(buffer, min(1024, IOHandler->InputBuffer->Size));
>
>> that doesn't know exactly how many bytes are going to be sent over the 
>> socket.
>
>Most protocols are designed to offer a way of knowing that.  But for those 
>rare cases where it simply is not, then that is why the ReadFromSource() 
>method and the InputBuffer property are publically accessible.

As it happens, ReadFromSource() is *not* publically accessible.  It's
protected.  

One of the big problems here is documentation.  All I have to go by is
the Indy 10.1.1 docs in BCB2007, since there's no hint of
documentation on the Indy home page.

From those docs, I can see that CheckForDataOnSource() calls
ReadFromSource() internally, so is a suitable replacement for your
suggestion.  It seems to work as intended, provide I use a Readable()
call before hand as an equivalent to select().

So thanks for that.

>> As it happens, the current design uses text-only data on the control
>> connection, so ReadLn() might work for command responses.  The
>> data connection exists only for the duration of the transfer, so
>> ReadBytes() may actually work out.
>
>Sounds like you are reproducing exactly what the FTP protocol already does.

Well, yes.  Aside from the fact that none of the commands match those
of FTP, the command response format is different, the data transferred
is not the contents of a file.  It's a proxy that sits between a
desktop client and a database server.  I modelled the basic design on
FTP, which I've written clients for.
Re: Indy10 usage
#490
Author: Mike Ruskai
Date: Wed, 05 Mar 2008 04:18
24 lines
1835 bytes
On or about Tue, 04 Mar 2008 22:04:47 -0500 did Mike Ruskai
<BUTthannydI@DONTearthlinkLIKE.netSPAM> dribble thusly:

>>    IOHandler->[CheckForDataOnSource(10)];
>>    IOHandler->ReadBytes(buffer, min(1024, IOHandler->InputBuffer->Size));

Just discovered something rather bizarre about this.  ReadBytes()
throws an EIdConnClosedGracefully when the socket has been closed by
the remote after all data had been sent.

And it fails to read the data remaining in the input buffer.

So, I have to do something like this to read all data:

try
	{
	sock->IOHandler->ReadBytes(buf, bufsize, false);
	}
catch (EIdConnClosedGracefully)
	{
	sock->IOHandler->InputBuffer->ExtractToBytes(buf);
	}

This is not a developer-friendly library.
Re: Indy10 usage
#492
Author: Remy Lebeau (TeamB)
Date: Wed, 05 Mar 2008 05:38
48 lines
2727 bytes
"Mike Ruskai" <BUTthannydI@DONTearthlinkLIKE.netSPAM> wrote in message 
news:tu0ss39uaq8j35if50r88eflpsf5nvs431@4ax.com...

> Which means you have to pick an arbitrary length of time you're
> willing to have the program sit doing nothing, because there's no
> function to read UP TO a number of bytes, from whatever's available,
> without blocking until that number of bytes is completely filled.

Yes, there is a way, which I mentioned in my previous reply, and below.

> As it happens, ReadFromSource() is *not* publically accessible.
> It's protected.

Sorry, I meant CheckForDataOnSource() instead:

    IOHandler->CheckForDataOnSource(10);
    IOHandler->ReadBytes(buffer, min(1024, IOHandler->InputBuffer->Size));

> One of the big problems here is documentation.  All I have to go by
> is the Indy 10.1.1 docs in BCB2007, since there's no hint of
> documentation on the Indy home page.

Then you didn't look very closely:

    http://www.indyproject.org
    Indy.Sockets (VCL) > Documentation

> From those docs, I can see that CheckForDataOnSource() calls
> ReadFromSource() internally, so is a suitable replacement for your
> suggestion.

Yes.

> It seems to work as intended, provide I use a Readable() call before hand
> as an equivalent to select().

You don't need to call Readable() or select() beforehand.  ReadFromSource() 
calls select() internally, using the timeout that you pass in.

> Well, yes.  Aside from the fact that none of the commands match those
> of FTP, the command response format is different, the data transferred
> is not the contents of a file.

TIdFTP is not limited to files only.  Any TStream can be used.


Gambit 
Re: Indy10 usage
#491
Author: Remy Lebeau (TeamB)
Date: Wed, 05 Mar 2008 05:46
22 lines
1973 bytes
"Mike Ruskai" <BUTthannydI@DONTearthlinkLIKE.netSPAM> wrote in message 
news:ch7ss31acm13alsqj2s3utjhnbusnks1a9@4ax.com...

> ReadBytes() throws an EIdConnClosedGracefully when the socket
> has been closed by the remote after all data had been sent.

It should not be.  The only time it should be raising that exception is if 
you are trying to read more than was actually sent.  Otherwise, ReadBytes() 
should be returning the full requested data without raising an exception, 
and then the next read/write operation will detect the disconnect 
afterwards.  Looking at the source, I do not see how that exception could be 
occuring.

> So, I have to do something like this to read all data:

No, you should not have to do that.  If what you describe is actually 
happening (which, looking at the soure code, I don't see how it can), then 
it is a bug that needs fixing.


Gambit 
Re: Indy10 usage
#500
Author: Mike Ruskai
Date: Wed, 05 Mar 2008 22:54
14 lines
1667 bytes
On or about Tue, 4 Mar 2008 21:38:47 -0800 did "Remy Lebeau \(TeamB\)"
<no.spam@no.spam.com> dribble thusly:

>> One of the big problems here is documentation.  All I have to go by
>> is the Indy 10.1.1 docs in BCB2007, since there's no hint of
>> documentation on the Indy home page.
>
>Then you didn't look very closely:
>
>    http://www.indyproject.org
>    Indy.Sockets (VCL) > Documentation

Apparently not.  Not sure how I missed that one.  Maybe I was paying too much
attention to the side area, since most of the other links are there.
Thread Navigation

This is a paginated view of messages in the thread with full content displayed inline.

Messages are displayed in chronological order, with the original post highlighted in green.

Use pagination controls to navigate through all messages in large threads.

Back to All Threads