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 kamaelia@googlegroups.com
To unsubscribe from this group, send email to 
kamaelia+unsubscr...@googlegroups.com
For more options, visit this group at 
http://groups.google.com/group/kamaelia?hl=en
-~----------~----~----~----~------~----~------~--~---

Reply via email to