From: tom.rmadilo on
On Feb 2, 8:23 am, Alexandre Ferrieux <alexandre.ferri...(a)gmail.com>
wrote:
> On Feb 2, 2:29 am, WC <wcu...(a)cox.net> wrote:
>
>
>
>
>
> > [...]
> > will put the channel into blocking mode and attempt to flush the channel
> > of any remaining data, the interpreter does this for each open channel
> > when exit is called. However if the TCP stack is not accepting data the
> > application will never be able to exit or close channels without exiting
> > for that matter. This appears to be a pretty serious bug. I need to
> > 'kill -9' in order to force an exit... very ugly. Seems like what is
> > needed is an option to the close command to discard any data buffered in
> > the TCL channel's output buffer and close the channel.
>
> > I coded a small extension in C that closes the OS specific handle for
> > the channel and the unregisters the channel from the interpreter. This
> > causes send() to return -1 but the interpreter doesn't care at that
> > point and shutdown continues successfully.
>
> > Anyone else run into this? I'm I totally missing something here?
>
> > BTW I'm using TCL 8.4 on Linux and HP-UX but a review of the current 8.5
> > API it seems like this deadlock could still exist.
>
> > Any input/ideas are greatly appreciated,
> > Wayne
>
> You are absolutely right: that's a design flaw. If our hands were
> free, we'd fix that instantly. The problem is the existing base of Tcl
> apps... So we can only extend, not reform. Something like [chan
> unflush], or [chan discard].
>
> You can file a TIP for that; however,  in the meantime, you can use
> the following workaround:
>
>  set ff [open "|cat >@ $sok" w]
>  # do writes on $ff, reads on $sok
>  # you can still fconfigure $ff -blocking 0
>
>  # now assume it's time to close
>  exec kill -INT [pid $ff]
>  catch {close $ff}
>
> Ugly, eh ? Yup. Just one percent simpler than an extension ;-)


Why not try using [chan pending ]?

In my recent experiment with htclient, I found that the only way to
avoid failure on read (potential DOS attack) was to read only bytes
available in the tcl buffer.

The biggest deficit in the Tcl channel code is the lack of timeouts,
but the manpage for [chan puts] indicates that applications should
take care to not push too much data into the output channel with each
writable event.

Until the actual code is posted, hard to say this is a tcl failing, or
exactly what the failure is.
From: PaulWalton on
On Feb 2, 8:56 am, WC <wcu...(a)cox.net> wrote:
> PaulWalton wrote:
>
> > Why does this work?
>
> > Interp 1:
> > % socket -server accept 1515
> > sock5
> > % proc accept {socket clientAddr clientPort} {
> > ...
>
>  > ...
>  > ...
>
>
>
> > I ran 'exit' in Interp 2 before the 'after' was triggered in Interp 1.
> > As you can see tclsh exits fine for me. Or is there a flaw in this
> > test? I'm on Mac OS 10.4.
>
> Hi Paul,
>
> Well you're close but, it is not a valid test. The TCL IO system's
> buffers were able to flush before it exited. You sent a very small
> amount of data. Though you didn't do a read in your client app TCL was
> able to clear it's IO buffers down the TCP stack, in which the OS close
> succeeds.
>
> My application is streaming data to a number of clients and it is not
> unusual for it to build up a half meg of data rather quickly. For the
> test to be valid the receivers TCP input queue needs to be full as well
> as the senders TCP output queue. With moderm TCP stacks this can be
> several hundred K of data. Only then will TCL begin to buffer data in
> it's interp's IO buffers. That will definitely cause TCL to block when
> attempting to clear those buffers.
>
> Thanks,
> Wayne

Thank you for the explanation.
From: Wayne on
On Feb 2, 11:23 am, Alexandre Ferrieux <alexandre.ferri...(a)gmail.com>
wrote:
>
> You are absolutely right: that's a design flaw. If our hands were
> free, we'd fix that instantly. The problem is the existing base of Tcl
> apps... So we can only extend, not reform. Something like [chan
> unflush], or [chan discard].
>
> You can file a TIP for that; however,  in the meantime, you can use
> the following workaround:
>
>  set ff [open "|cat >@ $sok" w]
>  # do writes on $ff, reads on $sok
>  # you can still fconfigure $ff -blocking 0
>
>  # now assume it's time to close
>  exec kill -INT [pid $ff]
>  catch {close $ff}
>
> Ugly, eh ? Yup. Just one percent simpler than an extension ;-)
>
> -Alex

Alex,

Ugly... but clever my man!! Very Nice:) Do you think piping to
something like netcat would work bi-directionally so I can stick with
a single channel?

Ok, I will file a TIP for that as I feel it is very important to have
some mechanism in place for this condition. Either a separate function
as you mentioned or a flag to close. This would allow backward
compatibility.

close -noflush $chan

Thanks Alex,

Wayne
From: Wayne on
On Feb 2, 12:33 pm, "tom.rmadilo" <tom.rmad...(a)gmail.com> wrote:
>
> Why not try using [chan pending ]?
>
> In my recent experiment with htclient, I found that the only way to
> avoid failure on read (potential DOS attack) was to read only bytes
> available in the tcl buffer.
>
> The biggest deficit in the Tcl channel code is the lack of timeouts,
> but the manpage for [chan puts] indicates that applications should
> take care to not push too much data into the output channel with each
> writable event.
>
> Until the actual code is posted, hard to say this is a tcl failing, or
> exactly what the failure is.

Currently I'm only concerned with the [puts] case as I'm not reading
from clients, unless they close the connection.

Yeah, I saw that in the manpage, the problem with verbiage like that
is how much is "too much"? In fact just 1 byte in the interp's IO
buffers will cause the interp to block.

[chan pending] won't help because by the time there is data in the
interp's buffer it's to late:(

I'm stuck with 8.4 on my production system right now:(... so no [chan]
function for me.

It would be nice if one could turn off TCL buffering completely, I
have [fconfigure $chan -buffering none] but in non-blocking mode the
interp still accepts data via [puts] and this is stated so in the
[puts] manpage.

I understand they can't change the semantics since this API has
existed for many releases but I would have expected that if you
disable buffering and attempt to write to a non-blocking channel which
cannot accept data that [puts] would return just the number of bytes
it was able to write to the channel, in which case the application
could handle the buffering instead of the interp. Which is exactly
what my C implementation is doing.
From: Alexandre Ferrieux on
On Feb 2, 7:49 pm, Wayne <wcu...(a)gmail.com> wrote:
> On Feb 2, 11:23 am, Alexandre Ferrieux <alexandre.ferri...(a)gmail.com>
> wrote:
>
>
>
>
>
>
>
> > You are absolutely right: that's a design flaw. If our hands were
> > free, we'd fix that instantly. The problem is the existing base of Tcl
> > apps... So we can only extend, not reform. Something like [chan
> > unflush], or [chan discard].
>
> > You can file a TIP for that; however,  in the meantime, you can use
> > the following workaround:
>
> >  set ff [open "|cat >@ $sok" w]
> >  # do writes on $ff, reads on $sok
> >  # you can still fconfigure $ff -blocking 0
>
> >  # now assume it's time to close
> >  exec kill -INT [pid $ff]
> >  catch {close $ff}
>
> > Ugly, eh ? Yup. Just one percent simpler than an extension ;-)
>
> > -Alex
>
> Alex,
>
> Ugly... but clever my man!! Very Nice:) Do you think piping to
> something like netcat would work bi-directionally so I can stick with
> a single channel?

Oh yes of course, if you don't absolutely want Tcl sockets or close
monitoring of the connection attempt, [open "|nc ..." r+] will work
similarly.

> Ok, I will file a TIP for that as I feel it is very important to have
> some mechanism in place for this condition. Either a separate function
> as you mentioned or a flag to close. This would allow backward
> compatibility.
>
> close -noflush $chan

Not sure what you mean by backward compat here, since the current
[close] syntax doesn't have prefix options, but yes, I like this
syntax too :)

-Alex