changeset 62:d108f780b76c

Fixes to the BEEP implementation: * Handle 'ERR' and 'NUL' messages as acknowledgements to sent messages (i.e. dealloc the message number). * When the peer disconnects without having closing any channels, close the channels automatically.
author cmlenz
date Tue, 28 Jun 2005 13:51:49 +0000
parents 47ab019508dd
children 2332aedba328
files bitten/util/beep.py bitten/util/tests/beep.py
diffstat 2 files changed, 61 insertions(+), 8 deletions(-) [+]
line wrap: on
line diff
--- a/bitten/util/beep.py
+++ b/bitten/util/beep.py
@@ -180,6 +180,14 @@
             logging.info('Session terminated')
         asynchat.async_chat.close(self)
 
+    def handle_close(self):
+        logging.warning('Peer %s:%s closed connection' % self.addr)
+        channels = self.channels.keys()
+        channels.reverse()
+        for channelno in channels:
+            self.channels[channelno].close()
+        asynchat.async_chat.handle_close(self)
+
     def handle_error(self):
         """Called by asyncore when an exception is raised."""
         cls, value = sys.exc_info()[:2]
@@ -435,7 +443,7 @@
             # Recombine queued messages
             payload = ''.join(self.inqueue[msgno]) + payload
             del self.inqueue[msgno]
-        if cmd == 'RPY' and msgno in self.msgnos:
+        if cmd in ('ERR', 'RPY', 'NUL') and msgno in self.msgnos:
             # Final reply using this message number, so dealloc
             self.msgnos.remove(msgno)
         message = None
--- a/bitten/util/tests/beep.py
+++ b/bitten/util/tests/beep.py
@@ -41,11 +41,22 @@
 
     def handle_msg(self, msgno, message):
         text = message.as_string().strip()
-        self.handled_messages.append(('MSG', msgno, text))
+        self.handled_messages.append(('MSG', msgno, text, None))
 
     def handle_rpy(self, msgno, message):
         text = message.as_string().strip()
-        self.handled_messages.append(('RPY', msgno, text))
+        self.handled_messages.append(('RPY', msgno, text, None))
+
+    def handle_err(self, msgno, message):
+        text = message.as_string().strip()
+        self.handled_messages.append(('ERR', msgno, text, None))
+
+    def handle_ans(self, msgno, ansno, message):
+        text = message.as_string().strip()
+        self.handled_messages.append(('ANS', msgno, text, ansno))
+
+    def handle_nul(self, msgno):
+        self.handled_messages.append(('NUL', msgno, '', None))
 
 
 class ChannelTestCase(unittest.TestCase):
@@ -60,7 +71,7 @@
         """
         channel = beep.Channel(self.session, 0, MockProfileHandler)
         channel.handle_data_frame('MSG', 0, False, 0, None, 'foo bar')
-        self.assertEqual(('MSG', 0, 'foo bar'),
+        self.assertEqual(('MSG', 0, 'foo bar', None),
                          channel.profile.handled_messages[0])
 
     def test_handle_segmented_msg_frames(self):
@@ -71,7 +82,7 @@
         channel = beep.Channel(self.session, 0, MockProfileHandler)
         channel.handle_data_frame('MSG', 0, True, 0, None, 'foo ')
         channel.handle_data_frame('MSG', 0, False, 4, None, 'bar')
-        self.assertEqual(('MSG', 0, 'foo bar'),
+        self.assertEqual(('MSG', 0, 'foo bar', None),
                          channel.profile.handled_messages[0])
 
     def test_handle_out_of_sync_frame(self):
@@ -137,8 +148,8 @@
 
     def test_message_and_reply(self):
         """
-        Verify that a message number is deallocated after a final reply has been
-        received.
+        Verify that a message number is deallocated after a final "RPY" reply
+        has been received.
         """
         channel = beep.Channel(self.session, 0, MockProfileHandler)
         msgno = channel.send_msg(beep.MIMEMessage('foo bar', None))
@@ -146,10 +157,44 @@
                          self.session.sent_messages[0])
         assert msgno in channel.msgnos
         channel.handle_data_frame('RPY', msgno, False, 0, None, '42')
-        self.assertEqual(('RPY', msgno, '42'),
+        self.assertEqual(('RPY', msgno, '42', None),
                          channel.profile.handled_messages[0])
         assert msgno not in channel.msgnos
 
+    def test_message_and_error(self):
+        """
+        Verify that a message number is deallocated after a final "ERR" reply
+        has been received.
+        """
+        channel = beep.Channel(self.session, 0, MockProfileHandler)
+        msgno = channel.send_msg(beep.MIMEMessage('foo bar', None))
+        self.assertEqual(('MSG', 0, msgno, False, 0L, None, 'foo bar'),
+                         self.session.sent_messages[0])
+        assert msgno in channel.msgnos
+        channel.handle_data_frame('ERR', msgno, False, 0, None, '42')
+        self.assertEqual(('ERR', msgno, '42', None),
+                         channel.profile.handled_messages[0])
+        assert msgno not in channel.msgnos
+
+    def test_message_and_ans_nul(self):
+        """
+        Verify that a message number is deallocated after a final "NUL" reply
+        has been received.
+        """
+        channel = beep.Channel(self.session, 0, MockProfileHandler)
+        msgno = channel.send_msg(beep.MIMEMessage('foo bar', None))
+        self.assertEqual(('MSG', 0, msgno, False, 0L, None, 'foo bar'),
+                         self.session.sent_messages[0])
+        assert msgno in channel.msgnos
+        channel.handle_data_frame('ANS', msgno, False, 0, 0, '42')
+        self.assertEqual(('ANS', msgno, '42', 0),
+                         channel.profile.handled_messages[0])
+        assert msgno in channel.msgnos
+        channel.handle_data_frame('NUL', msgno, False, 2, None, '42')
+        self.assertEqual(('NUL', msgno, '', None),
+                         channel.profile.handled_messages[1])
+        assert msgno not in channel.msgnos
+
     def test_send_error(self):
         """
         Verify that sending an ERR message is processed correctly.
Copyright (C) 2012-2017 Edgewall Software