def __handle_find_by_type_req(self, op, pdu): if len(pdu) < 7: return att_pdu.new_error_resp(op, 0, att.ECODE_INVALID_PDU) _, startHandle, endHandle, uuid, value = \ att_pdu.parse_find_by_type_req(pdu) if startHandle == 0 or startHandle > endHandle: return att_pdu.new_error_resp(op, startHandle, att.ECODE_INVALID_HANDLE) respCount = 0 resp = bytearray([att.OP_FIND_BY_TYPE_RESP]) for handle in self._handles[startHandle:endHandle+1]: if handle._uuid != uuid: continue if handle._read() != value: continue if len(resp) + 4 > self._socket.sendMTU: break resp += handle._get_handle_as_bytearray() resp += handle._owner._get_end_group_handle()._get_handle_as_bytearray() respCount += 1 if respCount == 0: return att_pdu.new_error_resp(op, startHandle, \ att.ECODE_ATTR_NOT_FOUND) else: return resp
def __handle_find_info_req(self, op, pdu): if len(pdu) != 5: return att_pdu.new_error_resp(op, 0, att.ECODE_INVALID_PDU) _, startHandle, endHandle = att_pdu.parse_find_info_req(pdu) if startHandle == 0 or startHandle > endHandle: return att_pdu.new_error_resp(op, startHandle, att.ECODE_INVALID_HANDLE) respCount = 0 resp = bytearray([att.OP_FIND_INFO_RESP]) respFmt = None for handle in self._handles[startHandle:endHandle+1]: if respFmt is None: respFmt = len(handle._uuid) resp.append(1 if respFmt == 2 else 2) if len(handle._uuid) != respFmt: break if len(resp) + 2 + respFmt > self._socket.sendMTU: break resp += handle._get_handle_as_bytearray() resp += handle._uuid.raw[::-1] respCount += 1 if respCount == 0: return att_pdu.new_error_resp(op, startHandle, \ att.ECODE_ATTR_NOT_FOUND) else: return resp
def __recv_single(self): """Read and handle a single packet""" if self._stream: # Stream mode n = self._sock.recv(1) if n == "": raise RuntimeError("socket connection broken") received = 0 n = ord(n) if n == 0: return pdu = bytearray() while received < n: chunk = self._sock.recv(n - received) if chunk == "": raise RuntimeError("socket connection broken") received += len(chunk) pdu += bytearray(ord(x) for x in chunk) else: # Seqpacket mode pdu = self._sock.recv() if pdu == "": raise RuntimeError("socket connection broken") pdu = bytearray(ord(x) for x in pdu) op = pdu[0] if op == att.OP_MTU_REQ: resp = bytearray(3) resp[0] = att.OP_MTU_RESP resp[1] = self._recv_mtu & 0xFF resp[2] = (self._recv_mtu >> 8) & 0xFF self._send(resp) elif (att.isRequest(op) or op == att.OP_WRITE_CMD or op == att.OP_SIGNED_WRITE_CMD or op == att.OP_HANDLE_CNF): if self._server is not None: resp = self._server._handle_packet(pdu) if resp is not None: self._send(resp) elif att.isRequest(op): warnings.warn("server not supported") resp = att_pdu.new_error_resp(op, 0, att.ECODE_REQ_NOT_SUPP) self._send(resp) elif (att.isResponse(op) or (op == att.OP_ERROR and len(pdu) >= 2 and att.isRequest(pdu[1])) or op == att.OP_HANDLE_NOTIFY or op == att.OP_HANDLE_IND): if self._client is not None: resp = self._client._handle_packet(pdu) if resp is not None: self._send(resp) else: warnings.warn("unknown opcode: " + str(op))
def __handle_read_by_group_req(self, op, pdu): if len(pdu) != 7 and len(pdu) != 21: return att_pdu.new_error_resp(op, 0, att.ECODE_INVALID_PDU) _, startHandle, endHandle, uuid = \ att_pdu.parse_read_by_group_req(pdu) if startHandle == 0 or startHandle > endHandle: return att_pdu.new_error_resp(op, startHandle, att.ECODE_INVALID_HANDLE) respCount = 0 resp = bytearray([att.OP_READ_BY_GROUP_RESP, 0]) # 0 is placeholder valLen = None for handle in self._handles[startHandle:endHandle+1]: if handle._uuid != uuid: continue valRead = handle._read() if valRead is None: return att_pdu.new_error_resp(op, startHandle, att.ECODE_READ_NOT_PERM) assert isinstance(valRead, bytearray) if not valLen: assert len(valRead) <= 0xFF - 4 valLen = len(valRead) resp[1] = valLen + 4 if valLen != len(valRead): break if len(resp) + 4 + valLen > self._socket.sendMTU: break resp += handle._get_handle_as_bytearray() resp += handle._owner._get_end_group_handle()._get_handle_as_bytearray() resp += valRead respCount += 1 if respCount == 0: return att_pdu.new_error_resp(op, startHandle, att.ECODE_ATTR_NOT_FOUND) else: return resp
def __handle_read_req(self, op, pdu): if len(pdu) < 3: return att_pdu.new_error_resp(op, 0, att.ECODE_INVALID_PDU) _, handleNo = att_pdu.parse_read_req(pdu) if not self.__is_valid_handle(handleNo): return att_pdu.new_error_resp(op, handleNo, att.ECODE_INVALID_HANDLE) if self._handles[handleNo]._read_callback: try: value = self._handles[handleNo]._read_callback() resp = bytearray([att.OP_READ_RESP]) resp += value return resp except int, ecode: return att_pdu.new_error_resp(op, handleNo, ecode) except ServerError: return att_pdu.new_error_resp(op, handleNo, att.ECODE_UNLIKELY)
def __handle_write_cmd_req(self, op, pdu): if len(pdu) < 3: return att_pdu.new_error_resp(op, 0, att.ECODE_INVALID_PDU) _, handleNo, value = att_pdu.parse_write(pdu) if not self.__is_valid_handle(handleNo): if op == att.OP_WRITE_REQ: return att_pdu.new_error_resp(op, handleNo, att.ECODE_INVALID_HANDLE) else: return None if self._handles[handleNo]._write_callback: try: self._handles[handleNo]._write_callback(value) return bytearray([att.OP_WRITE_RESP]) except int, ecode: return att_pdu.new_error_resp(op, handleNo, ecode) except ServerError: return att_pdu.new_error_resp(op, handleNo, att.ECODE_UNLIKELY)
def _handle_packet(self, pdu): op = pdu[0] if op == att.OP_FIND_INFO_REQ: return self.__handle_find_info_req(op, pdu) elif op == att.OP_FIND_BY_TYPE_REQ: return self.__handle_find_by_type_req(op, pdu) elif op == att.OP_READ_BY_TYPE_REQ: return self.__handle_read_by_type_req(op, pdu) elif op == att.OP_READ_BY_GROUP_REQ: return self.__handle_read_by_group_req(op, pdu) elif op == att.OP_READ_REQ: return self.__handle_read_req(op, pdu) elif op == att.OP_WRITE_REQ or op == att.OP_WRITE_CMD: return self.__handle_write_cmd_req(op, pdu) elif op == att.OP_HANDLE_CNF: self.__handle_confirm(op, pdu) return None else: return att_pdu.new_error_resp(op, 0, att.ECODE_REQ_NOT_SUPP)
def _handle_packet(self, pdu): op = pdu[0] if (att.isResponse(op) or (op == att.OP_ERROR and self._currentRequest and self._currentResponse is None and pdu[1] == self._currentRequest[0])): self._currentResponse = pdu self._responseEvent.set() return None if op == att.OP_HANDLE_NOTIFY or op == att.OP_HANDLE_IND: if len(pdu) < 3: return att_pdu.new_error_resp(op, 0, att.ECODE_INVALID_PDU) _, handleNo, value = att_pdu.parse_notify_indicate(pdu) if handleNo not in self._valHandles: if op == att.OP_HANDLE_NOTIFY: warnings.warn("notification on unknown handle") else: warnings.warn("indication on unknown handle") return None charac = self._valHandles[handleNo] if charac._subscribeCallback is not None: try: charac._subscribeCallback(value) except ClientError, err: warnings.warn(err) else: warnings.warn("unsolicited notification or indication") if op == att.OP_HANDLE_IND: return bytearray([att.OP_HANDLE_CNF]) else: return None
return att_pdu.new_error_resp(op, handleNo, att.ECODE_INVALID_HANDLE) if self._handles[handleNo]._read_callback: try: value = self._handles[handleNo]._read_callback() resp = bytearray([att.OP_READ_RESP]) resp += value return resp except int, ecode: return att_pdu.new_error_resp(op, handleNo, ecode) except ServerError: return att_pdu.new_error_resp(op, handleNo, att.ECODE_UNLIKELY) else: return att_pdu.new_error_resp(op, 0, att.ECODE_READ_NOT_PERM) def __handle_write_cmd_req(self, op, pdu): if len(pdu) < 3: return att_pdu.new_error_resp(op, 0, att.ECODE_INVALID_PDU) _, handleNo, value = att_pdu.parse_write(pdu) if not self.__is_valid_handle(handleNo): if op == att.OP_WRITE_REQ: return att_pdu.new_error_resp(op, handleNo, att.ECODE_INVALID_HANDLE) else: return None if self._handles[handleNo]._write_callback: