vicco
vicco

Reputation: 1089

queue.get() returns only one item

I'm building a little sniffer to receive answers of a device in my network. I would rather solve the thing by implementing the answers() method of Scapys Packet class, but that doesn't work as expected. I'm trying to bypass this by first creating a sniffing-thread, then sending a packet to the device and waiting for an answer.

import threading
from scapy.all import sniff
class SnifferThread(threading.Thread):

    """ Thread that sniffs for incoming packets
    """

    def __init__(self, queue, timeout=1, checkFunction=None, filter=None):
        """ Initialization method """
        if queue is None:
            raise Exception, "queue must not be None"

        self.q = queue
        self.filter = filter
        self.timeout = timeout
        self.checkFunction = checkFunction

        threading.Thread.__init__(self)


    def putInQueue(self, packet):
        """ Checks packet and puts it into the queue if it matches """
        if self.checkFunction:
            if self.checkFunction(packet):
                self.q.put(packet)
                print "put"
        else:
            self.q.put(packet)


    def run(self):
        """ Executes the sniffing """
        sniff(
            timeout=self.timeout,
            filter=self.filter,
            prn=lambda pkt: self.putInQueue(pkt)
        )

def has_IAm(packet):
    """ Checks whether the packet contains an IAm """
    if packet.haslayer(APDU):
        if (packet[APDU].serviceChoice\
                == BACNetAPDUUnconfirmedServiceChoice.I_AM):
            print "has I_AM"
            return True


def discoverDevices():
    """ Sends WhoIs packet and prints answers """

    bindBACNetLayers()

    myQ = Queue.Queue()

    sniffer = SnifferThread(
        queue=myQ,
        checkFunction=has_IAm,
        filter=FILTER_BACNET
    )
    sniffer.start()

    sendp(
        getBACNetWhoIsPacket(
            "192.168.1.1",
            "192.168.1.255"
        ),
        verbose=False
    )

    while sniffer.isAlive():
        print "still alive"
    print myQ.qsize()
    answers = PacketList()
    answers.append(myQ.get())

    answers.show()

discoverDevices()

When executing it I can see in Wireshark that two devices are responding by sending an I_AM packet. I can also see that there are two items in the queue because at the end print myQ.qsize() prints 2. So I expect myQ.get() to return two packets objects which should then be displayed in the terminal when answers.show() is executed, but somehow only one packet - the first to be received - is displayed. Am I using myQ.get() incorrectly?


I solved it like that

while sniffer.isAlive():
    pass
answers = PacketList()
for _ in range(myQ.qsize()):
    answers.append(myQ.get())

Upvotes: 2

Views: 3516

Answers (1)

Daniel Roseman
Daniel Roseman

Reputation: 599628

get will always return a single item, as the documentation says:

Remove and return an item from the queue.

You should call get repeatedly until the queue is empty.

Upvotes: 5

Related Questions