def _onDataTransmissionRecv(self, xAsyncTCPClient, data, arg): if arg: tot = arg uid = data.tobytes() else: tot, rte = IoTSocketStruct.DecodeDataTRHdr(data) if rte: self._recv(16, self._onDataTransmissionRecv, tot) return uid = None if tot == IoTSocketStruct.TOT_ACL and self._isCentral: self._recv(4, self._onACLItemsCountRecv) elif tot == IoTSocketStruct.TOT_PING: self._router.Log('SESSION %s > PING RECEIVED' % self._getSessionName()) self.Send(IoTSocketStruct.MakePongTR()) self._waitDataTransmission() elif tot == IoTSocketStruct.TOT_PONG: self._router.Log('SESSION %s > PONG RECEIVED' % self._getSessionName()) self._waitDataTransmission() elif tot == IoTSocketStruct.TOT_REQUEST: self._recv(5, self._onRequestRecv, (uid, )) elif tot == IoTSocketStruct.TOT_RESPONSE: self._recv(6, self._onResponseRecv, (uid, )) elif tot == IoTSocketStruct.TOT_CLOSE_CONN: self._recv(1, self._onCloseConnCodeRecv) else: self.Send( IoTSocketStruct.MakeCloseConnTR( IoTSocketStruct.CLOSE_CODE_PROTO_ERR)) self.Close()
def _onDataTransmissionRecv(self, xAsyncTCPClient, data, arg) : if arg : tot = arg uid = data.tobytes() else : tot, rte = IoTSocketStruct.DecodeDataTRHdr(data) if rte : self._recv(16, self._onDataTransmissionRecv, tot) return uid = None if tot == IoTSocketStruct.TOT_PING : self._send(IoTSocketStruct.MakePongTR()) self._waitDataTransmission() elif tot == IoTSocketStruct.TOT_PONG : self._waitDataTransmission() elif tot == IoTSocketStruct.TOT_REQUEST : self._recv(5, self._onRequestRecv, (uid, )) elif tot == IoTSocketStruct.TOT_RESPONSE : self._recv(6, self._onResponseRecv, (uid, )) elif tot == IoTSocketStruct.TOT_TELTOKEN : self._recv(8, self._onTelemetryTokenRecv) elif tot == IoTSocketStruct.TOT_CLOSE_CONN : self._recv(1, self._onCloseConnCodeRecv) else : self._send(IoTSocketStruct.MakeCloseConnTR(IoTSocketStruct.CLOSE_CODE_PROTO_ERR)) self.Close()
def RouteTelemetry(self, token, dataFormat, formatOpt, data): if token and data: uid, exp = self._telemetryTokens.get(token, (None, None)) if uid: self.Log( 'ROUTER > TELEMETRY RECEIVED FROM {%s} WITH TOKEN %s' % (IoTSocketStruct.UIDFromBin128(uid), self.TelemetryTokenToStr(token))) if self.CentralSessionExists(): session = self._centralSession if session: data = IoTSocketStruct.MakeIdentTelemetryTRHdr( uid, dataFormat, formatOpt, len(data) ) \ + data if session.Send(data): return True elif self._onGetWebHookTelemetry: plFormat, plObject = IoTSocketStruct.DecodeJSONPayload( data, dataFormat) if plFormat is not None and plObject is not None: webHook = self._onGetWebHookTelemetry(self) if webHook: webHook.Post(self._centralAuthKeyHex, uid, plObject, plFormat) return True self.Log('ROUTER > ERROR TO OPEN WEBHOOK OF TELEMETRY') self.Log('ROUTER > NO DESTINATION FOR TELEMETRY') return False
def _processPOSTACL(self, content): try: o = self._getJSONContent(content) except Exception as ex: self._logRefused('BAD REQUEST, %s' % ex) self._sendHTTPResponse(400, '400 : Bad Request (%s)' % ex) return try: acl = [] ok = True for ac in o: groupID = IoTSocketStruct.GroupNameToBin128(ac['GroupName']) uid = IoTSocketStruct.UIDToBin128(ac['UID']) authKey = unhexlify(ac['AuthKey']) if groupID and uid and authKey and len(authKey) == 16: acl.append((groupID, uid, authKey)) else: ok = False break if ok: self._router.ClearACL() for ac in acl: self._router.AddACLAccess(*ac) self._router.SaveACL() self._log('%s ACL SETUP RECEIVED' % len(acl)) self._sendHTTPResponse(200) return except: pass self._logRefused('BAD REQUEST, INCORRECT JSON DATA') self._sendHTTPResponse(400, '400 : Bad Request (incorrect json data)')
def _processPOSTRequest(self, content): try: o = self._getJSONContent(content) except Exception as ex: self._logRefused('BAD REQUEST, %s' % ex) self._sendHTTPResponse(400, '400 : Bad Request (%s)' % ex) return try: uid = IoTSocketStruct.UIDToBin128(o['UID']) timeout = int(o.get('Timeout', self._maxSecWaitResponse)) fmt, data = IoTSocketStruct.EncodeJSONPayload( o['Payload'], o['Format']) if uid and timeout > 0 and fmt is not None and data is not None: if timeout > self._maxSecWaitResponse: timeout = self._maxSecWaitResponse exp = time() + timeout self._trackingNbr = self._router.AddCentralHTTPRequest( self, exp) strUID = ('{%s}' % IoTSocketStruct.UIDFromBin128(uid)) self._log('REQUEST TO %s RECEIVED (#%s)' % (strUID, self._trackingNbr)) if not self._router.RouteRequest( fromUID=None, toUID=uid, trackingNbr=self._trackingNbr, dataFormat=fmt, formatOpt=IoTSocketStruct.PLDATA_FMT_OPT_NONE, data=data): self._router.RemoveCentralHTTPRequest(self) self.SendResponseErrNoDest() return except: pass self._logRefused('BAD REQUEST, INCORRECT JSON DATA') self._sendHTTPResponse(400, '400 : Bad Request (incorrect json data)')
def RouteResponse(self, fromUID, toUID, trackingNbr, code, dataFormat, formatOpt, data): if toUID or self.CentralSessionExists(): if toUID: session = self._objectsSessions.get(toUID, None) else: session = self._centralSession if session: session.EndTrackingRequest(trackingNbr) data = IoTSocketStruct.MakeResponseTRHdr( fromUID, trackingNbr, code, dataFormat, formatOpt, len(data) ) \ + data return session.Send(data) else: httpReq, exp = self._centralHTTPRequests.get( trackingNbr, (None, None)) if httpReq: plFormat, plObject = IoTSocketStruct.DecodeJSONPayload( data, dataFormat) if plFormat is not None and plObject is not None: self.RemoveCentralHTTPRequest(httpReq) return httpReq.SendResponse(code, plObject, plFormat) self.Log('ROUTER > NO DESTINATION FOR RESPONSE (#%s)' % trackingNbr) return False
def AuthenticateSession(self, session, token128, hmac256): if session.UID == IoTSocketStruct.CENTRAL_EMPTY_UID: central = True authKey = self._centralAuthKey else: groupID, authKey = self.GetACLAccess(session.UID) central = False if authKey: hmac256srv = hmac.new(authKey, token128, hashlib.sha256).digest() if hmac.compare_digest(hmac256, hmac256srv): if central: if self._centralSession: self._centralSession.Close() self._centralSession = session else: existingSession = self._objectsSessions.get( session.UID, None) if existingSession: existingSession.Close() self._objectsSessions[session.UID] = session session.Send(IoTSocketStruct.MakeAuthValidation(True)) with self._lock: sessionData, exp = self._keepSessionsData.get( session.UID, (None, None)) if sessionData is not None: for data in sessionData: session.Send(data) del self._keepSessionsData[session.UID] return True session.Send(IoTSocketStruct.MakeAuthValidation(False)) session.Close() return False
def _onResponseRecv(self, xAsyncTCPClient, data, arg): uid = arg[0] if len(arg) == 2: trackingNbr, code, dataFormat, formatOpt, dataLen = arg[1] data = data.tobytes() else: hdr = IoTSocketStruct.DecodeResponseHdr(data.tobytes()) trackingNbr, code, dataFormat, formatOpt, dataLen = hdr if dataLen > 0: self._recv(dataLen, self._onResponseRecv, (uid, hdr)) return data = b'' if uid: strUID = ('{%s}' % IoTSocketStruct.UIDFromBin128(uid)) else: strUID = 'CENTRAL' self._router.Log('SESSION %s > RESPONSE TO %s RECEIVED (#%s)' % (self._getSessionName(), strUID, trackingNbr)) self._router.RouteResponse( fromUID=None if self._isCentral else self._uid, toUID=uid, trackingNbr=trackingNbr, code=code, dataFormat=dataFormat, formatOpt=formatOpt, data=data) self._waitDataTransmission()
def _onInitiationReqRecv(self, xAsyncTCPClient, data, arg): tls, ver, opt, maxTrLen = IoTSocketStruct.DecodeInitiationReq(data) ok = (ver == self.IOTSOCKET_VER and (not tls or self._sslContext is not None)) data = IoTSocketStruct.MakeInitiationResp( ok=ok, ruleType=IoTSocketStruct.INIT_NO_RULE) if ok: self.Send(data, self._onInitiationRespSent, tls) else: self.Send(data) self.Close()
def _onRequestRecv(self, xAsyncTCPClient, data, arg) : uid = arg[0] if len(arg) == 2 : trackingNbr, dataFormat, formatOpt, dataLen = arg[1] data = data.tobytes() else : hdr = IoTSocketStruct.DecodeRequestHdr(data.tobytes()) trackingNbr, dataFormat, formatOpt, dataLen = hdr if dataLen > 0 : self._recv(dataLen, self._onRequestRecv, (uid, hdr)) return data = b'' print('ON REQUEST [%s] RECV' % trackingNbr) self._send(IoTSocketStruct.MakeResponseTRHdr(uid, trackingNbr, 0, dataFormat, 0, dataLen) + data) self._waitDataTransmission()
def SaveACL(self): try: o = {} with self._lock: for uid in self._acl: o[IoTSocketStruct.UIDFromBin128(uid)] = { "GroupName": IoTSocketStruct.GroupNameFromBin128(self._acl[uid][0]), "AuthKey": hexlify(self._acl[uid][1]).decode() } with open(self._aclFilename, 'wb') as file: file.write(json.dumps(o).encode('UTF-8')) return True except: return False
def _doInitiationReq(self) : data = IoTSocketStruct.MakeInitiationReq( tls = True, ver = self.IOTSOCKET_VER, opt = 0x00, maxTrLen = self.MAX_TR_LEN ) self._send(data) self._recv(2, self._onInitiationRespRecv)
def AddGroup(self, groupName, options={}): if groupName and type(options) is dict: groupID = IoTSocketStruct.GroupNameToBin128(groupName) if groupID: self._groups[groupID] = options return True return False
def _onAuthValidationRecv(self, xAsyncTCPClient, data, arg) : if IoTSocketStruct.DecodeAuthValidation(data) : print('Authentication ok') self._startSession() else : print('Authentication error') self.Close()
def _startSession(self): self._authenticated = True self._isCentral = (self._uid == IoTSocketStruct.CENTRAL_EMPTY_UID) if not self._isCentral: self._strUID = IoTSocketStruct.UIDFromBin128(self._uid) self._router.Log('SESSION %s STARTED FROM %s' % (self._getSessionName(), self._xasTCPCli.CliAddr[0])) if not self._isCentral: self._groupID = self._router.GetACLAccess(self._uid)[0] if self._router.GetGroupOption(self._groupID, 'Telemetry'): expMin = self._router.GetGroupOption(self._groupID, 'TelemetryTokenExpMin') self._telemetryToken = self._router.GetNewTelemetryToken( self._uid, expMin) tr = IoTSocketStruct.MakeTelemetryTokenTR(self._telemetryToken) self.Send(tr) self._waitDataTransmission()
def SendTelemetryData(data) : if telemetryToken and data : datagram = IoTSocketStruct.MakeTelemetryPacket( token = telemetryToken, dataFormat = IoTSocketStruct.PLDATA_FORMAT_BIN, formatOpt = IoTSocketStruct.PLDATA_FMT_OPT_NONE, data = data ) return xasUDPCli.AsyncSendDatagram(datagram, udpSrvAddr) return False
def _onChallengeRecv(self, xAsyncTCPClient, data, arg) : #uid = IoTSocketStruct.CENTRAL_EMPTY_UID #key = b'\x00\x11\x22\x33\x44\x55\x66\x77\x88\x99\xAA\xBB\xCC\xDD\xEE\xFF' uid = IoTSocketStruct.UIDToBin128("ObjTest") authKey = b'CCCCCCCCDDDDDDDD' hmac256 = hmac.new(authKey, data, hashlib.sha256).digest() self._send(uid + hmac256) self._recv(1, self._onAuthValidationRecv)
def _onACLItemRecv(self, xAsyncTCPClient, data, arg): groupID, uid, authKey = IoTSocketStruct.DecodeACLItem(data.tobytes()) self._router.AddACLAccess(groupID, uid, authKey) if arg > 1: self._recv(48, self._onACLItemRecv, arg - 1) else: self._router.SaveACL() self._waitDataTransmission()
def _onWebHookClosed(self, centralHTTPWebHook): uid, trackingNbr = centralHTTPWebHook.ObjRef if uid and trackingNbr: session = self._objectsSessions.get(uid, None) if session: session.EndTrackingRequest(trackingNbr) data = IoTSocketStruct.MakeResponseErrTR( None, trackingNbr, IoTSocketStruct.RESP_CODE_REQ_NOK) session.Send(data)
def LoadACL(self): try: with open(self._aclFilename, 'r') as file: o = json.load(file) acl = {} for strUID in o: uid = IoTSocketStruct.UIDToBin128(strUID) groupID = IoTSocketStruct.GroupNameToBin128( o[strUID]["GroupName"]) authKey = unhexlify(o[strUID]["AuthKey"]) if not uid or not groupID or len(authKey) != 16 or \ not groupID in self._groups : return False acl[uid] = (groupID, authKey) with self._lock: self._acl = acl return True except: return False
def _onInitiationRespRecv(self, xAsyncTCPClient, data, arg) : ok, ruleType, ruleFlags = IoTSocketStruct.DecodeInitiationResp(data) if ok and ruleType == IoTSocketStruct.INIT_NO_RULE : try : self._xasTCPCli.StartSSL() self._recv(16, self._onChallengeRecv) return except : pass self.Close()
def SendBinaryRequest(data) : if data : data = IoTSocketStruct.MakeRequestTRHdr( uid = None, trackingNbr = 30303, dataFormat = IoTSocketStruct.PLDATA_FORMAT_BIN, formatOpt = IoTSocketStruct.PLDATA_FMT_OPT_NONE, dataLen = len(data) ) \ + data return xasTCPCli.AsyncSendData(data) return False
def _onRequestRecv(self, xAsyncTCPClient, data, arg): uid = arg[0] if len(arg) == 2: trackingNbr, dataFormat, formatOpt, dataLen = arg[1] data = data.tobytes() else: hdr = IoTSocketStruct.DecodeRequestHdr(data.tobytes()) trackingNbr, dataFormat, formatOpt, dataLen = hdr if dataLen > 0: self._recv(dataLen, self._onRequestRecv, (uid, hdr)) return data = b'' if uid: strUID = ('{%s}' % IoTSocketStruct.UIDFromBin128(uid)) else: strUID = 'CENTRAL' errCode = None with self._requestsLock: self._router.Log('SESSION %s > REQUEST TO %s RECEIVED (#%s)' % (self._getSessionName(), strUID, trackingNbr)) if not trackingNbr in self._requests: if self._router.RouteRequest( fromUID=None if self._isCentral else self._uid, toUID=uid, trackingNbr=trackingNbr, dataFormat=dataFormat, formatOpt=formatOpt, data=data): exp = time() + self._reqTimeout self._requests[trackingNbr] = (uid, exp) else: errCode = IoTSocketStruct.RESP_CODE_ERR_NO_DEST else: self._router.Log( 'SESSION %s > TRACKING NUMBER #%s ALREADY EXISTS' % (self._getSessionName(), trackingNbr)) errCode = IoTSocketStruct.RESP_CODE_ERR_SAME_TRK_NBR if errCode: self.Send( IoTSocketStruct.MakeResponseErrTR(uid, trackingNbr, errCode)) self._waitDataTransmission()
def CheckRequestsTimeout(self, nowSec): if self._requests: with self._requestsLock: for trackingNbr in list(self._requests): uid, exp = self._requests[trackingNbr] if nowSec >= exp: del self._requests[trackingNbr] self.Send( IoTSocketStruct.MakeResponseErrTR( uid, trackingNbr, IoTSocketStruct.RESP_CODE_ERR_TIMEOUT)) self._router.Log('SESSION %s > REQUEST TIMEOUT (#%s)' % (self._getSessionName(), trackingNbr))
def _onWebHookResponseOk(self, centralHTTPWebHook, o): if o: uid, trackingNbr = centralHTTPWebHook.ObjRef try: code = int(o['Code']) fmt, data = IoTSocketStruct.EncodeJSONPayload( o['Payload'], o['Format']) if fmt is not None and data is not None: centralHTTPWebHook.ObjRef = (None, None) session = self._objectsSessions.get(uid, None) if session: session.EndTrackingRequest(trackingNbr) data = IoTSocketStruct.MakeResponseTRHdr( None, trackingNbr, code, fmt, IoTSocketStruct.PLDATA_FMT_OPT_NONE, len(data) ) \ + data session.Send(data) except: pass
def RouteRequest(self, fromUID, toUID, trackingNbr, dataFormat, formatOpt, data): if toUID or self.CentralSessionExists(): if toUID: session = self._objectsSessions.get(toUID, None) else: session = self._centralSession data = IoTSocketStruct.MakeRequestTRHdr( fromUID, trackingNbr, dataFormat, formatOpt, len(data) ) \ + data if session and session.Send(data): return True if not toUID: toUID = IoTSocketStruct.CENTRAL_EMPTY_UID sessionData, exp = self._keepSessionsData.get(toUID, (None, None)) if sessionData is not None: sessionData.append(data) self.Log('ROUTER > REQUEST KEPT (#%s)' % trackingNbr) return True else: if self._onGetWebHookRequest: plFormat, plObject = IoTSocketStruct.DecodeJSONPayload( data, dataFormat) if plFormat is not None and plObject is not None: webHook = self._onGetWebHookRequest(self) if webHook: webHook.ObjRef = (fromUID, trackingNbr) webHook.OnResponseOk = self._onWebHookResponseOk webHook.OnClosed = self._onWebHookClosed webHook.Post(self._centralAuthKeyHex, fromUID, plObject, plFormat) return True self.Log('ROUTER > ERROR TO OPEN WEBHOOK OF REQUEST') self.Log('ROUTER > NO DESTINATION FOR REQUEST (#%s)' % trackingNbr) return False
def _onResponseRecv(self, xAsyncTCPClient, data, arg) : uid = arg[0] if len(arg) == 2 : trackingNbr, code, dataFormat, formatOpt, dataLen = arg[1] data = data.tobytes() else : hdr = IoTSocketStruct.DecodeResponseHdr(data.tobytes()) trackingNbr, code, dataFormat, formatOpt, dataLen = hdr if dataLen > 0 : self._recv(dataLen, self._onResponseRecv, (uid, hdr)) return data = b'' print('ON RESPONSE [%s] RECV (%s)' % (trackingNbr, code)) self._waitDataTransmission()
def Post(self, centralAuthKeyHex, uid, plObject, plFormat): o = { "UID": IoTSocketStruct.UIDFromBin128(uid), "Payload": plObject, "Format": plFormat } data = json.dumps(o).encode('UTF-8') self._sendLine('POST %s HTTP/1.0' % self._url.Path) self._sendLine('Host: %s' % self._url.Host) self._sendLine('Authorization: Bearer %s' % centralAuthKeyHex) self._sendLine('Content-Type: application/json; charset=UTF-8') self._sendLine('Content-Length: %s' % len(data)) self._sendLine() self._send(data) self._recvResponseFirstLine(self._onFirstLineRecv)
def GetNewTelemetryToken(self, uid, expirationMin): with self._lock: while True: token = token_bytes(8) if not token in self._telemetryTokens: if isinstance(expirationMin, int) and expirationMin > 0: exp = time() + (expirationMin * 60) else: exp = None self._telemetryTokens[token] = (uid, exp) break self.Log('NEW TELEMETRY TOKEN FOR {%s} EXPIRING IN %s MIN (%s)' % (IoTSocketStruct.UIDFromBin128(uid), expirationMin, self.TelemetryTokenToStr(token))) return token
def OnUDPSrvDataRecv(xAsyncUDPDatagram, remoteAddr, datagram) : token, dataFormat, formatOpt, data = IoTSocketStruct.DecodeTelemetryPacket(datagram.tobytes()) router.RouteTelemetry(token, dataFormat, formatOpt, data)