Hi Steve,
This email may read a little odd. I've been writing this whilst reading and
trying things out, saw your update, and having had a thought. As a result
the train of thought changes as I go through this, but I've left that in
since it may be of use.
On Monday 02 March 2009 21:11:53 Steve wrote:
..
> TCPClient('127.0.0.1', 80).run()
>
> I have no server running on port 80 so it should timeout and return.
> Instead it tries (in a seemingly infinite loop) to make the connection. My
> software firewall (set to allow all) reports around 1 connection attempt
> every second.
That's rather odd. I've just tried the same thing here, and I don't see any
looping attempt to connect - it fails to connect and exits straight away:
~> python
Python 2.5.1 (r251:54863, Jan 10 2008, 18:01:57)
[GCC 4.2.1 (SUSE Linux)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> from Kamaelia.Internet.TCPClient import TCPClient
>>> TCPClient("127.0.0.1", 81).run()
>>>
That said, I'm not running a firewall though...
I've also checked that it's passing on shutdown correctly. First the case
that doesn't exit, until control-c :
>>> from Kamaelia.Chassis.Pipeline import Pipeline
>>> from Kamaelia.Util.Console import ConsoleEchoer
>>> Pipeline( ConsoleEchoer() ).run()
And then a version that does exit because the TCPClient passes on it's
shutdown on error:
~> python
Python 2.5.1 (r251:54863, Jan 10 2008, 18:01:57)
[GCC 4.2.1 (SUSE Linux)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> from Kamaelia.Chassis.Pipeline import Pipeline
>>> from Kamaelia.Util.Console import ConsoleEchoer
>>> from Kamaelia.Internet.TCPClient import TCPClient
>>> Pipeline( TCPClient("127.0.0.1", 81), ConsoleEchoer() ).run()
>>>
All this tells me is that the situation I've tested it in and mainly used
it in still works as expected. This isn't the same as your situation.
As a result, I'm no real information up - I'm not reproducing your
behaviour/environment correctly yet.
I'm beginning to think I ought to start up a windows VM and see if I can
reproduce this there.
> The end result is that I believe Kamaelia (or the socket layer) is not
> properly handling a silently refused connection
I can see this is possible, simply because a filtered connection that
doesn't send a TCP RESET won't cause an error at the socket layer
(it just won't connect). That leads to this hanging:
>>> Pipeline( TCPClient("www.google.com", 8000), ConsoleEchoer() ).run()
...
Which is (part of) why you're after timeouts etc, and go after that root
cause.
> Michael, I'm starting to think that this whole TTL component that I've
> made might be completely unneeded. I think I was just reacting to the
> bugs that I've been describing in other threads. If we could identify
> why refused connections are infinite looping on vista and why
> unconnected udp peers are refusing to shutdown, there might be no need
> for this kind of time terminating component
I agree that going after the root cause is a good idea. (That said, the TTL
component is sufficiently generic to be useful beyond this issue, even if
we deal with it differently)
I think you're hitting a combination of things, in the main code, we have:
while not self.safeConnect(sock,(self.host, self.port)):
if self.shutdown():
return
yield 1
This in combination with the other parts is probably why you're seeing a
looping connect attempt.
This goes into safeConnect, and if you're connecting to a filtered
connection, it would hit this logic path in safeConnect:
try:
sock.connect(*sockArgsList); # Expect socket.error: (115, 'Operation
now in progress')
....
except socket.error, socket.msg:
(errorno, errmsg) = socket.msg.args
if errorno==errno.EALREADY:
# The socket is non-blocking and a previous connection attempt has
not yet been completed
# We handle this by allowing the code to come back and repeatedly
retry
# connecting. This is a valid, if brute force approach.
assert(self.connecting==1)
return False
elif errorno==errno.EINPROGRESS or errorno==errno.EWOULDBLOCK:
#The socket is non-blocking and the connection cannot be completed
immediately.
# We handle this by allowing the code to come back and repeatedly
retry
# connecting. Rather brute force.
self.connecting=1
return False # Not connected should retry until no error
ie it hits one of these three conditions.
For what it's worth a non-filtered not connected socket hits this path:
try:
sock.connect(*sockArgsList); # Expect socket.error: (115, 'Operation
now in progress')
....
except socket.error, socket.msg:
(errorno, errmsg) = socket.msg.args
if errorno==errno.EALREADY:
....
# Anything else is an error we don't handle
else:
raise socket.msg
That causes the socket cleanup, producerFinished to be sent out of signal
and exit.
Now there's several ways that I could go down this, but I can see that
probably the simplest would be to add a connection timeout this way:
class TCPClient(Axon.Component.component):
def __init__(self,host,port,delay=0,connect_timeout=60):
self.connect_timeout = connect_timeout
...
connect_start = time.time()
while not self.safeConnect(sock,(self.host, self.port)):
if self.shutdown():
return
if ( time.time() - connect_start ) > self.connect_timeout:
self.howDied = "timeout"
raise Finality
yield 1
This by itself doesn't immediately resolve the "using CPU 100%" issue,
but one thing at a time.
Any thoughts welcome. In the meantime I'll experiment with this.
Michael.
--
http://yeoldeclue.com/blog
http://twitter.com/kamaelian
http://www.kamaelia.org/Home
--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups
"kamaelia" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to
[email protected]
For more options, visit this group at
http://groups.google.com/group/kamaelia?hl=en
-~----------~----~----~----~------~----~------~--~---