added test case and fixed incomplete data
This commit is contained in:
230
zk/base.py
230
zk/base.py
@@ -958,88 +958,6 @@ class ZK(object):
|
||||
else:
|
||||
if self.verbose: print ("can't read/find finger")
|
||||
return None
|
||||
#-----------------------------------------------------------------
|
||||
if not cmd_response.get('status'):
|
||||
return None #("can't get user template")
|
||||
#else
|
||||
if cmd_response.get('code') == const.CMD_DATA: # less than 1024!!!
|
||||
resp = self.__data[:-1]
|
||||
if self.tcp:
|
||||
if resp[-6:] == b'\x00\x00\x00\x00\x00\x00': # padding? bug?
|
||||
resp = resp[:-6]
|
||||
if self.verbose: print("tcp too small!")
|
||||
return Finger(uid, temp_id, 1, resp)
|
||||
if cmd_response.get('code') == const.CMD_PREPARE_DATA:
|
||||
data = []
|
||||
bytes = self.__get_data_size() #TODO: check with size
|
||||
size = bytes
|
||||
if self.tcp:
|
||||
data_recv = self.__sock.recv(bytes + 32)
|
||||
tcp_length = self.__test_tcp_top(data_recv)
|
||||
if tcp_length == 0:
|
||||
print ("Incorrect tcp packet")
|
||||
return None
|
||||
recieved = len(data_recv)
|
||||
if self.verbose: print ("recieved {}, size {} rec {}".format(recieved, size, data_recv.encode('hex'))) #todo python3
|
||||
tcp_length = unpack('<HHI', data_recv[:8])[2] #bytes+8
|
||||
if tcp_length < (bytes + 8):
|
||||
if self.verbose: print ("request chunk too big!")
|
||||
response = unpack('HHHH', data_recv[8:16])[0]
|
||||
if recieved >= (bytes + 32): #complete
|
||||
if response == const.CMD_DATA:
|
||||
resp = data_recv[16:bytes+16][:size-1] # no ack?
|
||||
if resp[-6:] == b'\x00\x00\x00\x00\x00\x00': # padding? bug?
|
||||
if self.verbose: print ("cutting from",len(resp))
|
||||
resp = resp[:-6]
|
||||
if self.verbose: print ("resp len1", len(resp))
|
||||
return Finger(uid, temp_id, 1, resp) #mistery
|
||||
else:
|
||||
if self.verbose: print("broken packet!!!")
|
||||
return None #broken
|
||||
else: # incomplete
|
||||
if self.verbose: print ("try incomplete")
|
||||
data.append(data_recv[16:]) # w/o tcp and header
|
||||
bytes -= recieved-16
|
||||
while bytes>0: #jic
|
||||
data_recv = self.__sock.recv(bytes) #ideal limit?
|
||||
recieved = len(data_recv)
|
||||
if self.verbose: print ("partial recv {}".format(recieved))
|
||||
data.append(data_recv) # w/o tcp and header
|
||||
bytes -= recieved
|
||||
data_recv = self.__sock.recv(16)
|
||||
response = unpack('<4H', data_recv[8:16])[0]
|
||||
if response == const.CMD_ACK_OK:
|
||||
resp = b''.join(data)[:size-1] # testing
|
||||
if resp[-6:] == b'\x00\x00\x00\x00\x00\x00':
|
||||
resp = resp[:-6]
|
||||
if self.verbose: print ("resp len2", len(resp))
|
||||
return Finger(uid, temp_id, 1, resp)
|
||||
#data_recv[bytes+16:].encode('hex') #included CMD_ACK_OK
|
||||
if self.verbose: print("bad response %s" % data_recv)
|
||||
if self.verbose: print(data)
|
||||
return None
|
||||
#else udp
|
||||
size = bytes
|
||||
while True: #limitado por respuesta no por tamaño
|
||||
data_recv = self.__sock.recv(response_size)
|
||||
response = unpack('<4H', data_recv[:8])[0]
|
||||
if self.verbose: print("# packet response is: {}".format(response))
|
||||
if response == const.CMD_DATA:
|
||||
data.append(data_recv[8:]) #header turncated
|
||||
bytes -= 1024
|
||||
elif response == const.CMD_ACK_OK:
|
||||
break #without problem.
|
||||
else:
|
||||
#truncado! continuar?
|
||||
if self.verbose: print("broken!")
|
||||
break
|
||||
if self.verbose: print("still needs %s" % bytes)
|
||||
data = b''.join(data)[:-1]
|
||||
if data[-6:] == b'\x00\x00\x00\x00\x00\x00': # padding? bug?
|
||||
data = data[:-6]
|
||||
#uid 32 fing 03, starts with 4d-9b-53-53-32-31
|
||||
#CMD_USERTEMP_RRQ desn't need [:-1]
|
||||
return Finger(uid, temp_id, 1, data)
|
||||
|
||||
def get_templates(self):
|
||||
""" return array of all fingers """
|
||||
@@ -1073,7 +991,7 @@ class ZK(object):
|
||||
users = []
|
||||
max_uid = 0
|
||||
userdata, size = self.read_with_buffer(const.CMD_USERTEMP_RRQ, const.FCT_USER)
|
||||
if self.verbose: print("user size %i" % size)
|
||||
if self.verbose: print("user size {} (= {})".format(size, len(userdata)))
|
||||
if size <= 4:
|
||||
print("WRN: missing user data")# debug
|
||||
return []
|
||||
@@ -1342,6 +1260,73 @@ class ZK(object):
|
||||
else:
|
||||
raise ZKErrorResponse("can't clear data")
|
||||
|
||||
def __recieve_tcp_data(self, data_recv, size):
|
||||
""" data_recv, raw tcp packet
|
||||
must analyze tcp_length
|
||||
|
||||
must return data, broken
|
||||
"""
|
||||
data = []
|
||||
tcp_length = self.__test_tcp_top(data_recv) # tcp header
|
||||
if self.verbose: print ("tcp_length {}, size {}".format(tcp_length, size))
|
||||
if tcp_length <= 0:
|
||||
if self.verbose: print ("Incorrect tcp packet")
|
||||
return None, b""
|
||||
if (tcp_length - 8) < size: #broken on smaller DATAs
|
||||
if self.verbose: print ("tcp length too small... retrying")
|
||||
resp, bh = self.__recieve_tcp_data(data_recv, tcp_length - 8)
|
||||
data.append(resp)
|
||||
size -= len(resp)
|
||||
if self.verbose: print ("new tcp DATA packet to fill misssing {}".format(size))
|
||||
data_recv = bh + self.__sock.recv(size) #ideal limit?
|
||||
resp, bh = self.__recieve_tcp_data(data_recv, size)
|
||||
data.append(resp)
|
||||
if self.verbose: print ("for misssing {} recieved {} with extra {}".format(size, len(resp), len(bh)))
|
||||
return b''.join(data), bh
|
||||
recieved = len(data_recv)
|
||||
if self.verbose: print ("recieved {}, size {}".format(recieved, size))
|
||||
#if (tcp_length - 16) > (recieved - 16): #broken first DATA
|
||||
# #reparse as more data packets?
|
||||
# if self.verbose: print ("trying".format(recieved, size))
|
||||
# _data, bh = self.__recieve_tcp_data(data_recv, tcp_length-16)
|
||||
#analize first response
|
||||
response = unpack('HHHH', data_recv[8:16])[0]
|
||||
if recieved >= (size + 32): #complete with ACK_OK included
|
||||
if response == const.CMD_DATA:
|
||||
resp = data_recv[16 : size + 16] # no ack?
|
||||
if self.verbose: print ("resp complete len {}".format(len(resp)))
|
||||
return resp, data_recv[size + 16:]
|
||||
else:
|
||||
if self.verbose: print("incorrect response!!! {}".format(response))
|
||||
return None, b"" #broken
|
||||
else: # response DATA incomplete (or missing ACK_OK)
|
||||
if self.verbose: print ("try DATA incomplete (actual valid {})".format(recieved-16))
|
||||
data.append(data_recv[16 : size + 16 ]) # w/o DATA tcp and header
|
||||
size -= recieved - 16 # w/o DATA tcp and header
|
||||
broken_header = b""
|
||||
if size < 0: #broken ack header?
|
||||
broken_header = data_recv[size:]
|
||||
if self.verbose: print ("broken", (broken_header).encode('hex')) #TODO python3
|
||||
if size > 0: #need raw data to complete
|
||||
data_recv = self.__recieve_raw_data(size)
|
||||
data.append(data_recv) # w/o tcp and header
|
||||
return b''.join(data), broken_header
|
||||
#get cmd_ack_ok on __rchunk
|
||||
|
||||
|
||||
def __recieve_raw_data(self, size):
|
||||
""" partial data ? """
|
||||
data = []
|
||||
if self.verbose: print ("expecting {} bytes raw data".format(size))
|
||||
while size > 0:
|
||||
data_recv = self.__sock.recv(size) #ideal limit?
|
||||
recieved = len(data_recv)
|
||||
if self.verbose: print ("partial recv {}".format(recieved))
|
||||
data.append(data_recv) # w/o tcp and header
|
||||
size -= recieved
|
||||
if self.verbose: print ("still need {}".format(size))
|
||||
return b''.join(data)
|
||||
|
||||
def __recieve_chunk(self):
|
||||
""" recieve a chunk """
|
||||
if self.__response == const.CMD_DATA: # less than 1024!!!
|
||||
@@ -1350,61 +1335,36 @@ class ZK(object):
|
||||
elif self.__response == const.CMD_PREPARE_DATA:
|
||||
data = []
|
||||
size = self.__get_data_size()
|
||||
if self.verbose: print ("recieve chunk:data size is", size)
|
||||
if self.verbose: print ("recieve chunk: prepare data size is {}".format(size))
|
||||
if self.tcp:
|
||||
if len(self.__data)>=(8+size): #prepare data with actual data! should be 8+size+32
|
||||
if len(self.__data) >= (8 + size): #prepare data with actual data! should be 8+size+32
|
||||
data_recv = self.__data[8:] # test, maybe -32
|
||||
else:
|
||||
data_recv = self.__sock.recv(size + 32)
|
||||
tcp_length = self.__test_tcp_top(data_recv)
|
||||
if tcp_length == 0:
|
||||
print ("Incorrect tcp packet")
|
||||
return None
|
||||
recieved = len(data_recv)
|
||||
if self.verbose: print ("recieved {}, size {}".format(recieved, size))
|
||||
if tcp_length < (size + 8):
|
||||
if self.verbose: print ("request chunk too big!")
|
||||
response = unpack('HHHH', data_recv[8:16])[0]
|
||||
if recieved >= (size + 32): #complete with ACK_OK included
|
||||
if response == const.CMD_DATA:
|
||||
resp = data_recv[16 : size + 16] # no ack?
|
||||
if self.verbose: print ("resp complete len", len(resp))
|
||||
return resp
|
||||
else:
|
||||
if self.verbose: print("broken packet!!! {}".format(response))
|
||||
return None #broken
|
||||
else: # incomplete
|
||||
if self.verbose: print ("try incomplete (actual valid {})".format(recieved-16))
|
||||
data.append(data_recv[16 : size+ 16 ]) # w/o DATA tcp and header
|
||||
size -= recieved-16 # w/o DATA tcp and header
|
||||
broken_header = b""
|
||||
if size < 0: #broken ack header?
|
||||
broken_header = data_recv[size:]
|
||||
if self.verbose: print ("broken", (broken_header).encode('hex')) #TODO python3
|
||||
while size>0: #jic
|
||||
if self.verbose: print ("still need {}".format(size))
|
||||
data_recv = self.__sock.recv(size) #ideal limit?
|
||||
recieved = len(data_recv)
|
||||
if self.verbose: print ("partial recv {}".format(recieved))
|
||||
data.append(data_recv) # w/o tcp and header
|
||||
size -= recieved
|
||||
#get cmd_ack_ok
|
||||
data_recv = self.__sock.recv(size + 32) #could have two commands
|
||||
resp, broken_header = self.__recieve_tcp_data(data_recv, size)
|
||||
data.append(resp)
|
||||
# get CMD_ACK_OK
|
||||
if len(broken_header) < 16:
|
||||
data_recv = broken_header + self.__sock.recv(16)
|
||||
#could be broken
|
||||
if len(data_recv) < 16:
|
||||
print ("trying to complete broken ACK %s /16" % len(data_recv))
|
||||
if self.verbose: print (data_recv.encode('hex')) #todo python3
|
||||
data_recv += self.__sock.recv(16 - len(data_recv)) #TODO: CHECK HERE_!
|
||||
if not self.__test_tcp_top(data_recv):
|
||||
if self.verbose: print ("invalid tcp ACK OK")
|
||||
return None #b''.join(data) # incomplete?
|
||||
response = unpack('HHHH', data_recv[8:16])[0]
|
||||
if response == const.CMD_ACK_OK:
|
||||
return b''.join(data)
|
||||
#data_recv[bytes+16:].encode('hex') #included CMD_ACK_OK
|
||||
if self.verbose: print("bad response %s" % data_recv)
|
||||
if self.verbose: print (data)
|
||||
return None
|
||||
else:
|
||||
data_recv = broken_header
|
||||
#could be broken
|
||||
if len(data_recv) < 16:
|
||||
print ("trying to complete broken ACK %s /16" % len(data_recv))
|
||||
if self.verbose: print (data_recv.encode('hex')) #todo python3
|
||||
data_recv += self.__sock.recv(16 - len(data_recv)) #TODO: CHECK HERE_!
|
||||
if not self.__test_tcp_top(data_recv):
|
||||
if self.verbose: print ("invalid chunk tcp ACK OK")
|
||||
return None #b''.join(data) # incomplete?
|
||||
response = unpack('HHHH', data_recv[8:16])[0]
|
||||
if response == const.CMD_ACK_OK:
|
||||
if self.verbose: print ("chunk tcp ACK OK!")
|
||||
return b''.join(data)
|
||||
if self.verbose: print("bad response %s" % data_recv)
|
||||
if self.verbose: print (codecs.encode(data,'hex'))
|
||||
return None
|
||||
|
||||
return resp
|
||||
#else udp
|
||||
while True: #limitado por respuesta no por tamaño
|
||||
data_recv = self.__sock.recv(1024+8)
|
||||
@@ -1459,10 +1419,12 @@ class ZK(object):
|
||||
#direct!!! small!!!
|
||||
size = len(self.__data)
|
||||
return self.__data, size
|
||||
#else ACK_OK with size
|
||||
size = unpack('I', self.__data[1:5])[0] # extra info???
|
||||
if self.verbose: print ("size fill be %i" % size)
|
||||
remain = size % MAX_CHUNK
|
||||
packets = (size-remain) // MAX_CHUNK # should be size /16k
|
||||
if self.verbose: print ("rwb: #{} packets of max {} bytes, and extra {} bytes remain".format(packets, MAX_CHUNK, remain))
|
||||
for _wlk in range(packets):
|
||||
data.append(self.__read_chunk(start,MAX_CHUNK))
|
||||
start += MAX_CHUNK
|
||||
|
||||
Reference in New Issue
Block a user