示例#1
0
    def __init__(self, fix, state_listeners=None):
        print "Protocol %s %s init" % (self.__class__, fix.version)
        self.fix = fix
        self.heartbeat_checks = {}
        self.pending_test_requests = {}
        self.heart_beat_interval = None
        self.factory = None
        self.session = None
        self.handler = None

        # State Objects
        self.awaiting_logon = self.AwaitingLogonKlazz(self)
        self.awaiting_logout = AwaitingLogout(self)
        self.normal_message_processing = NormalMessageProcessing(self)
        self.logged_out_state = LoggedOut(self)

        # Keep track of the callables I have scheduled at any given time
        # if the protocol dies want to cancel these so we don't have 'ghost'
        # calls after we''re done
        self.send_heartbeat_call = None
        self.test_request_checks = {}
        self.heartbeat_checks = {}

        self.state = None
        self.set_state(self.awaiting_logon)
        self.parser = FIXParser(self.fix, self.on_msg)
示例#2
0
    def __init__(self, fix, state_listeners=None):
        print "Protocol %s %s init" % (self.__class__, fix.version)
        self.fix = fix
        self.heartbeat_checks = {}
        self.pending_test_requests = {}
        self.heart_beat_interval = None
        self.factory = None
        self.session = None
        self.handler = None

        # State Objects
        self.awaiting_logon = self.AwaitingLogonKlazz(self)
        self.awaiting_logout = AwaitingLogout(self)
        self.normal_message_processing = NormalMessageProcessing(self)
        self.logged_out_state = LoggedOut(self)

        # Keep track of the callables I have scheduled at any given time
        # if the protocol dies want to cancel these so we don't have 'ghost'
        # calls after we''re done
        self.send_heartbeat_call = None
        self.test_request_checks = {}
        self.heartbeat_checks = {}

        self.state = None
        self.set_state(self.awaiting_logon)
        self.parser = FIXParser(self.fix, self.on_msg)
示例#3
0
 def connectionMade(self):
     print "Connection Made"
     self.parser = FIXParser(self.fix,
                             self.on_msg)
示例#4
0
class FIXProtocol(Protocol):
    def __init__(self, fix, state_listeners=None):
        print "Protocol %s %s init" % (self.__class__, fix.version)
        self.fix = fix
        self.heartbeat_checks = {}
        self.pending_test_requests = {}
        self.heart_beat_interval = None
        self.factory = None
        self.session = None
        self.handler = None

        # State Objects
        self.awaiting_logon = self.AwaitingLogonKlazz(self)
        self.awaiting_logout = AwaitingLogout(self)
        self.normal_message_processing = NormalMessageProcessing(self)
        self.logged_out_state = LoggedOut(self)

        # Keep track of the callables I have scheduled at any given time
        # if the protocol dies want to cancel these so we don't have 'ghost'
        # calls after we''re done
        self.send_heartbeat_call = None
        self.test_request_checks = {}
        self.heartbeat_checks = {}

        self.state = None
        self.set_state(self.awaiting_logon)
        self.parser = FIXParser(self.fix, self.on_msg)

    def set_state(self, s):
        print "State change %s->%s" % (self.state.__class__.__name__, s.__class__.__name__)
        old_state = self.state
        self.state = s
        if self.session:
            self.session.set_state(old_state, self.state)

    @staticmethod
    def get_seq(msg):
        return msg.getHeader

    def send_heartbeat(self):
        if self.state == self.normal_message_processing:
            msg = self.fix.Heartbeat()
            message_string = self.session.compile_message(msg)
            #print "Sending heartbeat ... %s" % strMsg
            msg_seq_num = msg.get_header_field_value(self.fix.MsgSeqNum)
            log(">>> %s %s %s" % (msg_seq_num, msg, message_string))
            self.transport.write(message_string)
            #print "Scheduling heartbeat in %s " % self.heartbeatInterval
        else:
            print "NOT SENDING HEARTBEAT - dodgy state %s" % self.state
            # Depending on what you want to do this may or may not be useful
        # from observation when a large number of sessions connect at roughly
        # the same time the heartbeats can cause a 'wave' of messages every heartbeat
        # interval ( or multiple thereof ). We'll help the reactor out a bit by
        # adding a small randomization ( 1 second standard deviation ) to the interval
        # this should be small enough to prevent any test request cycles but large enough
        # to smooth out heartbeats between multiple sessions
        delay = random.normalvariate(self.heartbeat_interval, 1)
        # Or if you're OCD or into Wagner/Kraftwerk/Techno you're probably
        # not a fan of randomness and like regularly spaced metronomic 'doof's
        # - uncomment the line below delay = self.heartbeatInterval
        # delay = self.heartbeatInterval

        self.send_heartbeat_call = reactor.callLater(delay, self.send_heartbeat)
        # We'll rely on our heartbeat but
        myObj = datetime.now()
        self.heartbeat_checks[myObj] = reactor.callLater(self.heartbeat_interval * 1.5, self.check_heartbeat, myObj)

    def on_logout(self, msg, in_msg_seq_num, poss_dup_flag):
        print "onLogout %s" % msg
        self.session.want_to_be_logged_on = False
        msg = self.fix.Logout(fields=[self.fix.Text("Accepted logoff request")])
        message_string = self.session.compile_message(msg, persist=False)
        print ">>> %s" % message_string
        self.transport.write(message_string)
        self.transport.loseConnection()
        reactor.callLater(0, self.clean_up_and_die)

    def check_heartbeat(self, token):
        assert self.heartbeat_checks.has_key(token)
        del self.heartbeat_checks[token]
        print "Check Heartbeat %s" % token
        if self.state == self.normal_message_processing:
            print "No heartbeat recieved for %s (%s seconds)" % (token, datetime.now() - token)
            challenge = "TEST_%s" % str(str(random.random())[2:15])
            test_request_id = self.fix.TestReqID(challenge)
            msg = self.fix.TestRequest(fields=[test_request_id])
            message_string = self.session.compile_message(msg)
            #print "Sending heartbeat ... %s" % strMsg
            msg_seq_num = msg.get_header_field_value(self.fix.MsgSeqNum)
            print ">>> %s %s %s" % (msg_seq_num, msg, message_string)
            self.transport.write(message_string)
            self.test_request_checks[challenge] = reactor.callLater(10, self.check_test_request_acknowledged, challenge)
        else:
            print "Skipping heartbeat checks - not in normal message processing phase"

    def check_test_request_acknowledged(self, challenge):
        assert self.test_request_checks.has_key(challenge)
        print "He's out of there"
        msg = self.fix.Logout(fields=[self.fix.Text("No response to test request %s" % challenge)])
        message_string = self.session.compile_message(msg)
        msg_seq_num = msg.get_header_field_value(self.fix.MsgSeqNum)
        print ">>> %s %s %s" % (msg_seq_num, msg, message_string)
        self.transport.write(message_string)
        # Bye bye
        self.transport.loseConnection()
        reactor.callLater(0, self.clean_up_and_die)

    def _logoff(self, reason=None, extreme_prejudice=False):
        """Don't call me - call the session objects logoff instead"""
        if not self.state == self.normal_message_processing:
            self.transport.loseConnection()
            self.clean_up_and_die()

        if reason:
            fields = [self.fix.Text(reason)]
        else:
            fields = []

        msg = self.fix.Logout(fields)
        message_string = self.session.compile_message(msg)
        self.transport.write(message_string)
        if extreme_prejudice:
            reactor.callLater(0, self.clean_up_and_die)
        else:
            self.set_state(self.awaiting_logout)

    def clean_up_and_die(self):
        # Get rid of the balls we've got already up in the air!
        # Note to self
        # I assume as long as code is logically correct I don't have to worry about
        if self.state == self.logged_out_state:
            print "Already cleaned up - nothing to do"
        else:
            self.set_state(self.logged_out_state)
            calls = [self.send_heartbeat_call] + self.test_request_checks.values() + self.heartbeat_checks.values()
            for call in calls:
                if call:
                    try:
                        call.cancel()
                    except AlreadyCancelled:
                        pass

            # TODO - pycharm complaining these havent been used.
            # Doesnt look like they're required. Delete when happy
            # self.loggedIn = False
            # self.loggedOut = True
            # self.parser = None

            # quick sanity checks on disconnect
            if self.session:
                assert self.session.protocol is self
                self.session.release_protocol()
            print "Cleaned up"

    def on_heartbeat(self, msg, seq, dup):
        test_request_id = msg.get_field(self.fix.TestReqID)
        if test_request_id:
            challenge = test_request_id.value
            if self.test_request_checks.has_key(challenge):
                self.test_request_checks[challenge].cancel()
                del self.test_request_checks[challenge]
            else:
                pass
                #print "Got testRequestID I didn't send!!! %s" % testRequestID
        else:
            for posted, cb in self.heartbeat_checks.items()[:]:
                #print "Clearing check %s %s after %s seconds" % ( callable, posted, (now-posted).seconds)
                cb.cancel()
                del self.heartbeat_checks[posted]

    def on_test_request(self, msg, seq, dup):
        #print "onTestRequest %s" % msg
        test_request_id = msg.get_field(self.fix.TestReqID)
        #assert self.loggedIn
        msg = self.fix.Heartbeat(fields=[test_request_id])
        message_string = self.session.compile_message(msg)
        #print "Test Request %s .. replying with %s" % (testRequestId, strMsg)
        self.transport.write(message_string)

    def connectionMade(self):
        print "Connection Made"
        self.parser = FIXParser(self.fix,
                                self.on_msg)

    def dataReceived(self, data):
        #print "============================================"
        #print "Got some data!!! %s" % data
        self.parser.feed(data)

    def on_resend_request(self, msg, seq, dup):
        begin = msg.get_field_value(self.fix.BeginSeqNo)
        tmp_end = msg.get_field_value(self.fix.EndSeqNo)
        resend_details = []
        gap = None
        db = self.session.out_db
        if tmp_end == 0:
            end_seq_no = self.session.out_msg_seq_num - 1
        else:
            end_seq_no = tmp_end

        print "onResendRequest %s-%s Playing back %s-%s" % ( begin, tmp_end, begin, end_seq_no)
        parser = SynchronousParser(self.fix)
        for i in range(begin, end_seq_no + 1):
            #print i , "... " ,
            haveMsg = False
            if db.has_key(i):
                message_string = db[i]
                msg, _, _ = parser.feed(message_string)
                #print "Recovered %s" % msg
                if msg.Section != 'Session':
                    # We have a message to resend
                    if gap:
                        resend_details.append(gap)
                    gap = None
                    resend_details.append(msg)
                    haveMsg = True
            if not haveMsg:
                if gap:
                    gap[1] = i
                else:
                    gap = [i, i]
        if gap:
            resend_details.append(gap)

        print "Resend Details %s" % len(resend_details)
        if 1:
            for obj in resend_details:
                if type(obj) == ListType:
                    # Gap Fill
                    [send_sequence_number, last_sequence_number] = obj
                    #print "GapFill %s-%s" % (sendSequenceNumber, lastSequenceNumber)
                else:
                    orig_seq = obj.get_header_field_value(self.fix.MsgSeqNum)
                    #obj.dump( "GapFill>>>")
                    #print "gf2 =%s %s %s" % (obj, msg.getHeaderField( self.pyfix.MsgSeqNum ).value, origSeq )

        for obj in resend_details:
            i = 0
            if type(obj) == ListType:
                # Gap Fill
                [send_sequence_number, last_sequence_number] = obj
                gapFill = self.fix.SequenceReset(fields=[self.fix.NewSeqNo(last_sequence_number + 1),
                                                         self.fix.GapFillFlag('Y')])
                message_string = self.session.compile_message(gapFill,
                                                              poss_dup=True,
                                                              force_sequence_number=send_sequence_number)
                print "Sending sequence reset %s->%s %s" % (
                    send_sequence_number, last_sequence_number + 1, message_string)
                self.transport.write(message_string)
            else:
                # Hmm wonder if this will work. Header of old msg is going to be blatted
                orig_seq = obj.get_header_field_value(self.fix.MsgSeqNum)
                print "%10s %s" % (obj, orig_seq)
                orig_sending_time = obj.get_header_field_value(self.fix.SendingTime)
                message_string = self.session.compile_message(obj,
                                                              poss_dup=True,
                                                              force_sequence_number=orig_seq,
                                                              orig_sending_time=orig_sending_time)
                #obj.dump("Recovered: " )
                #print "REC>>> %s %s %s" % (origSeq, obj, fixMsg)
                self.transport.write(message_string)
            i += 1
            if i % 100 == 0:
                print "Recovering %s ..."

    def on_sequence_reset(self, msg, seq, dup):
        #print "onSequenceReset %s %s" % ( msg, msg.toFix() )
        is_gap_fill = msg.get_optional_field_values(self.fix.GapFillFlag)
        if is_gap_fill:
            self.onGapFill(msg)
        else:
            assert False, "Pure sequence reset not handled yet"

    def connectionLost(self, reason):
        if self.state != self.logged_out_state:
            print "PROTOCOL: Connection lost reason = %s" % reason
            self.clean_up_and_die()
        else:
            print "Connection Closed"

    def on_msg(self, msg, data):
        message_class = msg.__class__
        message_seq_num = msg.get_header_field_value(self.fix.MsgSeqNum)
        poss_dup_flag = msg.get_header_field_value(self.fix.PossDupFlag)

        if self.session is not None:
            sender = self.session.sender
        else:
            sender = "UNKN"

        log("<<< %s %s %s->%s %s" % (sender, message_seq_num, msg, self.state, data))
        try:
            msg.validate()
        except MessageIntegrityException, e:
            print "Integrity Exception " + e.message
            e.msg.dump()
            self.session.last_integrity_exception = msg, e
            # No further processing required on a message that fails integrity checks
            if self.session.onIntegrityException:
                self.session.onIntegrityException(e)
            return
        except BusinessReject, br:
            self.last_business_reject = msg, br
            fields = [self.fix.RefSeqNum(message_seq_num),
                      self.fix.Text(br.message)]
            if br.field is not None:
                fields.append(br.field)
            reject = self.fix.Reject(fields=fields)  # br.field = SessionRejectReason
            print "Creating reject - fields are %s" % str(fields)
            reject_string = self.session.compile_message(reject)
            self.transport.write(reject_string)
            # Spec says messages which fail business validation sholud be logged + sequence numbers
            # incremented
            self.session.persist_and_advance(msg.to_fix(), checkInSequence=True)
            return
示例#5
0
 def connectionMade(self):
     print "Connection Made"
     self.parser = FIXParser(self.fix, self.on_msg)
示例#6
0
class FIXProtocol(Protocol):
    def __init__(self, fix, state_listeners=None):
        print "Protocol %s %s init" % (self.__class__, fix.version)
        self.fix = fix
        self.heartbeat_checks = {}
        self.pending_test_requests = {}
        self.heart_beat_interval = None
        self.factory = None
        self.session = None
        self.handler = None

        # State Objects
        self.awaiting_logon = self.AwaitingLogonKlazz(self)
        self.awaiting_logout = AwaitingLogout(self)
        self.normal_message_processing = NormalMessageProcessing(self)
        self.logged_out_state = LoggedOut(self)

        # Keep track of the callables I have scheduled at any given time
        # if the protocol dies want to cancel these so we don't have 'ghost'
        # calls after we''re done
        self.send_heartbeat_call = None
        self.test_request_checks = {}
        self.heartbeat_checks = {}

        self.state = None
        self.set_state(self.awaiting_logon)
        self.parser = FIXParser(self.fix, self.on_msg)

    def set_state(self, s):
        print "State change %s->%s" % (self.state.__class__.__name__,
                                       s.__class__.__name__)
        old_state = self.state
        self.state = s
        if self.session:
            self.session.set_state(old_state, self.state)

    @staticmethod
    def get_seq(msg):
        return msg.getHeader

    def send_heartbeat(self):
        if self.state == self.normal_message_processing:
            msg = self.fix.Heartbeat()
            message_string = self.session.compile_message(msg)
            #print "Sending heartbeat ... %s" % strMsg
            msg_seq_num = msg.get_header_field_value(self.fix.MsgSeqNum)
            log(">>> %s %s %s" % (msg_seq_num, msg, message_string))
            self.transport.write(message_string)
            #print "Scheduling heartbeat in %s " % self.heartbeatInterval
        else:
            print "NOT SENDING HEARTBEAT - dodgy state %s" % self.state
            # Depending on what you want to do this may or may not be useful
        # from observation when a large number of sessions connect at roughly
        # the same time the heartbeats can cause a 'wave' of messages every heartbeat
        # interval ( or multiple thereof ). We'll help the reactor out a bit by
        # adding a small randomization ( 1 second standard deviation ) to the interval
        # this should be small enough to prevent any test request cycles but large enough
        # to smooth out heartbeats between multiple sessions
        delay = random.normalvariate(self.heartbeat_interval, 1)
        # Or if you're OCD or into Wagner/Kraftwerk/Techno you're probably
        # not a fan of randomness and like regularly spaced metronomic 'doof's
        # - uncomment the line below delay = self.heartbeatInterval
        # delay = self.heartbeatInterval

        self.send_heartbeat_call = reactor.callLater(delay,
                                                     self.send_heartbeat)
        # We'll rely on our heartbeat but
        myObj = datetime.now()
        self.heartbeat_checks[myObj] = reactor.callLater(
            self.heartbeat_interval * 1.5, self.check_heartbeat, myObj)

    def on_logout(self, msg, in_msg_seq_num, poss_dup_flag):
        print "onLogout %s" % msg
        self.session.want_to_be_logged_on = False
        msg = self.fix.Logout(
            fields=[self.fix.Text("Accepted logoff request")])
        message_string = self.session.compile_message(msg, persist=False)
        print ">>> %s" % message_string
        self.transport.write(message_string)
        self.transport.loseConnection()
        reactor.callLater(0, self.clean_up_and_die)

    def check_heartbeat(self, token):
        assert self.heartbeat_checks.has_key(token)
        del self.heartbeat_checks[token]
        print "Check Heartbeat %s" % token
        if self.state == self.normal_message_processing:
            print "No heartbeat recieved for %s (%s seconds)" % (
                token, datetime.now() - token)
            challenge = "TEST_%s" % str(str(random.random())[2:15])
            test_request_id = self.fix.TestReqID(challenge)
            msg = self.fix.TestRequest(fields=[test_request_id])
            message_string = self.session.compile_message(msg)
            #print "Sending heartbeat ... %s" % strMsg
            msg_seq_num = msg.get_header_field_value(self.fix.MsgSeqNum)
            print ">>> %s %s %s" % (msg_seq_num, msg, message_string)
            self.transport.write(message_string)
            self.test_request_checks[challenge] = reactor.callLater(
                10, self.check_test_request_acknowledged, challenge)
        else:
            print "Skipping heartbeat checks - not in normal message processing phase"

    def check_test_request_acknowledged(self, challenge):
        assert self.test_request_checks.has_key(challenge)
        print "He's out of there"
        msg = self.fix.Logout(fields=[
            self.fix.Text("No response to test request %s" % challenge)
        ])
        message_string = self.session.compile_message(msg)
        msg_seq_num = msg.get_header_field_value(self.fix.MsgSeqNum)
        print ">>> %s %s %s" % (msg_seq_num, msg, message_string)
        self.transport.write(message_string)
        # Bye bye
        self.transport.loseConnection()
        reactor.callLater(0, self.clean_up_and_die)

    def _logoff(self, reason=None, extreme_prejudice=False):
        """Don't call me - call the session objects logoff instead"""
        if not self.state == self.normal_message_processing:
            self.transport.loseConnection()
            self.clean_up_and_die()

        if reason:
            fields = [self.fix.Text(reason)]
        else:
            fields = []

        msg = self.fix.Logout(fields)
        message_string = self.session.compile_message(msg)
        self.transport.write(message_string)
        if extreme_prejudice:
            reactor.callLater(0, self.clean_up_and_die)
        else:
            self.set_state(self.awaiting_logout)

    def clean_up_and_die(self):
        # Get rid of the balls we've got already up in the air!
        # Note to self
        # I assume as long as code is logically correct I don't have to worry about
        if self.state == self.logged_out_state:
            print "Already cleaned up - nothing to do"
        else:
            self.set_state(self.logged_out_state)
            calls = [self.send_heartbeat_call
                     ] + self.test_request_checks.values(
                     ) + self.heartbeat_checks.values()
            for call in calls:
                if call:
                    try:
                        call.cancel()
                    except AlreadyCancelled:
                        pass

            # TODO - pycharm complaining these havent been used.
            # Doesnt look like they're required. Delete when happy
            # self.loggedIn = False
            # self.loggedOut = True
            # self.parser = None

            # quick sanity checks on disconnect
            if self.session:
                assert self.session.protocol is self
                self.session.release_protocol()
            print "Cleaned up"

    def on_heartbeat(self, msg, seq, dup):
        test_request_id = msg.get_field(self.fix.TestReqID)
        if test_request_id:
            challenge = test_request_id.value
            if self.test_request_checks.has_key(challenge):
                self.test_request_checks[challenge].cancel()
                del self.test_request_checks[challenge]
            else:
                pass
                #print "Got testRequestID I didn't send!!! %s" % testRequestID
        else:
            for posted, cb in self.heartbeat_checks.items()[:]:
                #print "Clearing check %s %s after %s seconds" % ( callable, posted, (now-posted).seconds)
                cb.cancel()
                del self.heartbeat_checks[posted]

    def on_test_request(self, msg, seq, dup):
        #print "onTestRequest %s" % msg
        test_request_id = msg.get_field(self.fix.TestReqID)
        #assert self.loggedIn
        msg = self.fix.Heartbeat(fields=[test_request_id])
        message_string = self.session.compile_message(msg)
        #print "Test Request %s .. replying with %s" % (testRequestId, strMsg)
        self.transport.write(message_string)

    def connectionMade(self):
        print "Connection Made"
        self.parser = FIXParser(self.fix, self.on_msg)

    def dataReceived(self, data):
        #print "============================================"
        #print "Got some data!!! %s" % data
        self.parser.feed(data)

    def on_resend_request(self, msg, seq, dup):
        begin = msg.get_field_value(self.fix.BeginSeqNo)
        tmp_end = msg.get_field_value(self.fix.EndSeqNo)
        resend_details = []
        gap = None
        db = self.session.out_db
        if tmp_end == 0:
            end_seq_no = self.session.out_msg_seq_num - 1
        else:
            end_seq_no = tmp_end

        print "onResendRequest %s-%s Playing back %s-%s" % (begin, tmp_end,
                                                            begin, end_seq_no)
        parser = SynchronousParser(self.fix)
        for i in range(begin, end_seq_no + 1):
            #print i , "... " ,
            haveMsg = False
            if db.has_key(i):
                message_string = db[i]
                msg, _, _ = parser.feed(message_string)
                #print "Recovered %s" % msg
                if msg.Section != 'Session':
                    # We have a message to resend
                    if gap:
                        resend_details.append(gap)
                    gap = None
                    resend_details.append(msg)
                    haveMsg = True
            if not haveMsg:
                if gap:
                    gap[1] = i
                else:
                    gap = [i, i]
        if gap:
            resend_details.append(gap)

        print "Resend Details %s" % len(resend_details)
        if 1:
            for obj in resend_details:
                if type(obj) == ListType:
                    # Gap Fill
                    [send_sequence_number, last_sequence_number] = obj
                    #print "GapFill %s-%s" % (sendSequenceNumber, lastSequenceNumber)
                else:
                    orig_seq = obj.get_header_field_value(self.fix.MsgSeqNum)
                    #obj.dump( "GapFill>>>")
                    #print "gf2 =%s %s %s" % (obj, msg.getHeaderField( self.pyfix.MsgSeqNum ).value, origSeq )

        for obj in resend_details:
            i = 0
            if type(obj) == ListType:
                # Gap Fill
                [send_sequence_number, last_sequence_number] = obj
                gapFill = self.fix.SequenceReset(fields=[
                    self.fix.NewSeqNo(last_sequence_number + 1),
                    self.fix.GapFillFlag('Y')
                ])
                message_string = self.session.compile_message(
                    gapFill,
                    poss_dup=True,
                    force_sequence_number=send_sequence_number)
                print "Sending sequence reset %s->%s %s" % (
                    send_sequence_number, last_sequence_number + 1,
                    message_string)
                self.transport.write(message_string)
            else:
                # Hmm wonder if this will work. Header of old msg is going to be blatted
                orig_seq = obj.get_header_field_value(self.fix.MsgSeqNum)
                print "%10s %s" % (obj, orig_seq)
                orig_sending_time = obj.get_header_field_value(
                    self.fix.SendingTime)
                message_string = self.session.compile_message(
                    obj,
                    poss_dup=True,
                    force_sequence_number=orig_seq,
                    orig_sending_time=orig_sending_time)
                #obj.dump("Recovered: " )
                #print "REC>>> %s %s %s" % (origSeq, obj, fixMsg)
                self.transport.write(message_string)
            i += 1
            if i % 100 == 0:
                print "Recovering %s ..."

    def on_sequence_reset(self, msg, seq, dup):
        #print "onSequenceReset %s %s" % ( msg, msg.toFix() )
        is_gap_fill = msg.get_optional_field_values(self.fix.GapFillFlag)
        if is_gap_fill:
            self.onGapFill(msg)
        else:
            assert False, "Pure sequence reset not handled yet"

    def connectionLost(self, reason):
        if self.state != self.logged_out_state:
            print "PROTOCOL: Connection lost reason = %s" % reason
            self.clean_up_and_die()
        else:
            print "Connection Closed"

    def on_msg(self, msg, data):
        message_class = msg.__class__
        message_seq_num = msg.get_header_field_value(self.fix.MsgSeqNum)
        poss_dup_flag = msg.get_header_field_value(self.fix.PossDupFlag)

        if self.session is not None:
            sender = self.session.sender
        else:
            sender = "UNKN"

        log("<<< %s %s %s->%s %s" %
            (sender, message_seq_num, msg, self.state, data))
        try:
            msg.validate()
        except MessageIntegrityException, e:
            print "Integrity Exception " + e.message
            e.msg.dump()
            self.session.last_integrity_exception = msg, e
            # No further processing required on a message that fails integrity checks
            if self.session.onIntegrityException:
                self.session.onIntegrityException(e)
            return
        except BusinessReject, br:
            self.last_business_reject = msg, br
            fields = [
                self.fix.RefSeqNum(message_seq_num),
                self.fix.Text(br.message)
            ]
            if br.field is not None:
                fields.append(br.field)
            reject = self.fix.Reject(
                fields=fields)  # br.field = SessionRejectReason
            print "Creating reject - fields are %s" % str(fields)
            reject_string = self.session.compile_message(reject)
            self.transport.write(reject_string)
            # Spec says messages which fail business validation sholud be logged + sequence numbers
            # incremented
            self.session.persist_and_advance(msg.to_fix(),
                                             checkInSequence=True)
            return