Пример #1
0
    def on_binary(self, buf, handler):
        try:
            l = len(buf)

            if self.padding_length > l:
                self.tmpfile.write(buf)
                self.padding_length -= l

            else:
                if self.padding_length == l:
                    self.tmpfile.write(buf)
                else:
                    self.tmpfile.write(buf[:self.padding_length])
                    logger.error("Recv data length error")

                handler.binary_mode = False

                logger.info("New firmware received")
                self.tmpfile.file.flush()
                self.tmpfile.seek(0)
                s = Storage("update_fw")
                with s.open("upload.fxfw", "wb") as f:
                    f.write(self.tmpfile.read())

                proc = Popen(["fxupdate.py", "--dryrun", self.tmpfile.name])
                self.subwatcher = self.stack.loop.child(
                    proc.pid, False, self.on_verified, (handler, proc))
                self.subwatcher.start()

        except RuntimeError as e:
            handler.send_text(("error %s" % e.args[0]).encode())
        except Exception:
            logger.exception("Unhandle Error")
            handler.send_text("error %s" % UNKNOWN_ERROR)
Пример #2
0
    def on_binary(self, buf, handler):
        try:
            l = len(buf)

            if self.padding_length > l:
                self.tmpfile.write(buf)
                self.padding_length -= l

            else:
                if self.padding_length == l:
                    self.tmpfile.write(buf)
                else:
                    self.tmpfile.write(buf[:self.padding_length])
                handler.binary_mode = False

                self.tmpfile.seek(0)
                s = Storage("update_fw")

                with s.open("mainboard.bin", "wb") as f:
                    f.write(self.tmpfile.read())

                logging.warn("Fireware uploaded, start processing")
                self.send_upload_request()
                handler.send_text("ok")

                self.stack.exit_task(self, True)
        except RuntimeError as e:
            handler.send_text(("error %s" % e.args[0]).encode())
        except Exception:
            logger.exception("Unhandle Error")
            handler.send_text("error %s" % UNKNOWN_ERROR)
Пример #3
0
    def on_binary(self, buf, handler):
        try:
            l = len(buf)

            if self.padding_length > l:
                self.tmpfile.write(buf)
                self.padding_length -= l

            else:
                if self.padding_length == l:
                    self.tmpfile.write(buf)
                else:
                    self.tmpfile.write(buf[:self.padding_length])
                handler.binary_mode = False

                self.tmpfile.seek(0)
                s = Storage("update_fw")

                with s.open("head.bin", "wb") as f:
                    f.write(self.tmpfile.read())

                logger.info("Head fireware uploaded, start processing")
                handler.send_text("ok")
                self.process_update(handler)
                # Note: self.process_update will invoke self.stack.exit_task
        except RuntimeError as e:
            handler.send_text(("error %s" % e.args[0]).encode())
        except Exception:
            logger.exception("Unhandle Error")
            handler.send_text("error " + UNKNOWN_ERROR)
Пример #4
0
    def start(self):
        GPIOUtils.setup()
        hwprofile = GPIOUtils.get_hardware_profile()

        while hwprofile is None or "HARDWARE_VERSION" not in hwprofile:
            logger.error("Fetch hardware profile failed: %s", hwprofile)

            try:
                logger.error("Re-burn firmware")
                fsrc = resource_stream("fluxmonitor", "data/mainboard.bin")
                storage = Storage("update_fw")
                with storage.open("mainboard.bin", "wb") as fdst:
                    copyfileobj(fsrc, fdst)
                GPIOUtils.update_mbfw()
            except RuntimeWarning as e:
                logger.error("%s", e.args[0])
            except Exception:
                logger.exception("Re-burn firmware failed")

            sleep(3.0)
            hwprofile = GPIOUtils.get_hardware_profile()

        self.hwprofile = hwprofile

        if get_model_id() == MODEL_D1P:
            self.gpio = PinMappingV1(self.meta)
        else:
            self.gpio = PinMappingV0(self.meta)

        self.btn_monitor = FrontButtonMonitor(self.gpio, self.kernel.loop,
                                              self.send_button_event)
        self.connect_uart()
Пример #5
0
    def update_mbfw(cls):
        cls.reset_mainboard()
        sleep(1.0)

        storage = Storage("update_fw")
        tty = cls.get_mainboard_port()

        if not storage.exists("mainboard.bin"):
            raise RuntimeWarning("mainboard.bin not found")

        if os.system("stty -F %s 1200" % tty) != 0:
            raise RuntimeWarning("stty exec failed")

        sleep(2.0)

        fw_path = storage.get_path("mainboard.bin")
        if os.system("bossac -p %s -e -w -v -b %s" %
                     (tty.split("/")[-1], fw_path)) != 0:
            raise RuntimeWarning("bossac exec failed")

        os.rename(fw_path, fw_path + ".updated")
        os.system("sync")
        sleep(0.75)
        cls.reset_mainboard()
        sleep(0.75)
Пример #6
0
    def autoplay(self):
        storage = Storage("general", "meta")

        if storage["replay"] != "N":
            pathlist = (("USB", "autoplay.fc"), (
                "SD",
                "autoplay.fc",
            ), (
                "SD",
                "Recent/recent-1.fc",
            ))
        else:
            pathlist = (("USB", "autoplay.fc"), (
                "SD",
                "autoplay.fc",
            ))

        us = UserSpace()

        for candidate in pathlist:
            try:
                abspath = us.get_path(*candidate, require_file=True)
                logger.debug("Autoplay: %s", abspath)

                pm = PlayerManager(self.loop, abspath, self.release_exclusive)
                self.exclusive(pm)
                return
            except RuntimeError:
                continue

        logger.debug("Autoplay failed")
Пример #7
0
    def setup_upnp_sock(self):
        try:
            logger.info("Upnp going UP")

            storage = Storage("general", "meta")
            bare = storage["bare"] == "Y"
            bcst_config = storage["broadcast"]

            mcst_if = create_interface_v2(MulticaseNotifyInterface)(
                self) if bare else MulticaseNotifyInterface(self)  # noqa
            mcst_watcher = self.loop.io(mcst_if, pyev.EV_READ,
                                        mcst_if.on_message)
            mcst_watcher.start()
            self.mcst = (mcst_if, mcst_watcher)

            ucst_if = create_interface_v2(UnicasetInterface)(
                self) if bare else UnicasetInterface(self)  # noqa
            ucst_watcher = self.loop.io(ucst_if, pyev.EV_READ,
                                        ucst_if.on_message)
            ucst_watcher.start()
            self.ucst = (ucst_if, ucst_watcher)

            if bcst_config != "N":
                bcst_if = create_interface_v2(BroadcaseNotifyInterface)(
                    self, bcst_config) if bare else BroadcaseNotifyInterface(
                        self, bcst_config)  # noqa
                bcst_watcher = self.loop.io(bcst_if, pyev.EV_READ,
                                            bcst_if.on_message)
                self.bcst = (bcst_if, bcst_watcher)

            self.mversion = self.meta.mversion
        except socket.error:
            logger.exception("Error while upnp going UP")
            self.teardown_upnp_sock()
Пример #8
0
    def setUp(self):
        host = socket.socket()
        host.bind(("127.0.0.1", 0))
        host.listen(1)

        self.client_sock = cs = socket.socket()
        cs.setblocking(False)
        cs.connect_ex(host.getsockname())
        self.serverSock, self.clientEndpoint = host.accept()
        host.close()

        self.loop = pyev.Loop()
        _prepare_cert()
        s = Storage("security", "private")
        self.certfile = s.get_path("cert.pem")
        self.keyfile = s.get_path("sslkey.pem")
Пример #9
0
    def dispatch_cmd(self, handler, cmd, *args):
        try:
            if cmd == "player":
                return self.dispatch_playmanage_cmd(handler, *args)
            elif cmd == "file":
                return self.dispatch_filemanage_cmd(handler, *args)
            elif cmd == "task":
                return self.dispatch_task_cmd(handler, *args)
            elif cmd == "config":
                return self.dispatch_config_cmd(handler, *args)

        except TypeError:
            tb = sys.exc_info()[2]
            if tb.tb_next is None or tb.tb_next.tb_next is None:
                raise RuntimeError(BAD_PARAMS)
            else:
                raise

        try:
            if cmd == "update_fw":
                mimetype, filesize, upload_to = args
                if mimetype != mimetypes.MIMETYPE_FLUX_FIRMWARE:
                    raise RuntimeError(BAD_FILE_FORMAT)
                self.update_fw(handler, int(filesize, 10))
            elif cmd == "kick":
                self.stack.kernel.destory_exclusive()
                handler.send_text("ok")
            elif cmd == "update_mbfw" and allow_god_mode():
                mimetype, filesize, upload_to = args
                return self.update_mbfw(handler, int(filesize, 10))
            elif cmd == "deviceinfo":
                self.deviceinfo(handler)
            elif cmd == "scan":
                # TODO: going tobe remove
                self.dispatch_task_cmd(handler, "scan")
            elif cmd == "start":
                # TODO: going tobe removed
                self.dispatch_playmanage_cmd(handler, "start")
                self.play(handler)
            elif cmd == "maintain":
                # TODO: going tobe removed
                self.dispatch_task_cmd(handler, "maintain")
            elif cmd == "cloud_validation_code":
                self.cloud_validation_code(handler)
            elif cmd == "oracle":
                s = Storage("general", "meta")
                s["debug"] = args[0].encode("utf8")
                handler.send_text("oracle")
            elif cmd == "fetch_log":
                self.fetch_log(handler, *args)
            else:
                logger.debug("Can not handle: %s" % repr(cmd))
                raise RuntimeError(UNKNOWN_COMMAND)

        except TypeError:
            tb = sys.exc_info()[2]
            if tb.tb_next is None:
                raise RuntimeError(BAD_PARAMS)
            else:
                raise
Пример #10
0
    def __init__(self, loop, taskfile, terminated_callback=None):
        storage = Storage("run")

        oldpid = load_pid(storage.get_path("fluxplayerd.pid"))
        if oldpid is not None:
            try:
                os.kill(oldpid, SIGKILL)
                logger.error("Kill old player process: %i", oldpid)
            except Exception:
                logger.exception("Error while kill old process: %i", oldpid)

        s = create_mainboard_socket()
        try:
            s.send("\n@DISABLE_LINECHECK\nX5S115\n")

            if os.path.exists(PLAY_ENDPOINT):
                os.unlink(PLAY_ENDPOINT)
            ff = FCodeFile(taskfile)

            self.playinfo = ff.metadata, ff.image_buf

            cmd = [
                "fluxplayer", "-c", PLAY_ENDPOINT, "--task", taskfile, "--log",
                storage.get_path("fluxplayerd.log"), "--pid",
                storage.get_path("fluxplayerd.pid")
            ]
            if logger.getEffectiveLevel() <= 10:
                cmd += ["--debug"]

            f = open(storage.get_path("fluxplayerd.err.log"), "a")
            proc = Popen(cmd, stdin=PIPE, stderr=f.fileno())
            child_watcher = loop.child(proc.pid, False, self.on_process_dead,
                                       terminated_callback)
            child_watcher.start()
            metadata.update_device_status(1, 0, "N/A", err_label="")

            self.child_watcher = child_watcher
            self.proc = proc

        except FCodeError as e:
            s.send("X5S0\n")
            raise RuntimeError(FILE_BROKEN, *e.args)
        except Exception as e:
            s.send("X5S0\n")
            raise RuntimeError(UNKNOWN_ERROR)
        finally:
            s.close()
Пример #11
0
 def __config_del(self, key):
     storage = Storage("general", "meta")
     if key in self.__VALUES:
         struct = self.__VALUES[key]
         if hasattr(metadata, struct["key"]):
             delattr(metadata, struct["key"])
         else:
             del storage[struct["key"]]
     else:
         raise RuntimeError(BAD_PARAMS)
Пример #12
0
    def __init__(self, options):
        super(CloudService, self).__init__(logger, options)

        mqttlogger = logging.getLogger(
            "AWSIoTPythonSDK.core.protocol.mqttCore")
        if logger.getEffectiveLevel() < logging.INFO:
            mqttlogger.setLevel(logging.DEBUG)
        else:
            mqttlogger.setLevel(logging.WARNING)

        self.storage = Storage("cloud")
        self.uuidhex = security.get_uuid()

        if options.cloud.endswith("/"):
            self.cloud_netloc = options.cloud[:-1]
        else:
            self.cloud_netloc = options.cloud

        self.diagnosis()
Пример #13
0
 def postback_status(self, st_id):
     url = Storage("general", "meta")["player_postback_url"]
     if url:
         try:
             if '"' in url or '\\' in url:
                 logger.error("Bad url: %r", url)
             else:
                 url = url % {"st_id": st_id}
                 os.system("curl -s -o /dev/null \"%s\"" % url)
         except Exception:
             logger.exception("Error while post back status, url: %s", url)
Пример #14
0
    def __config_set(self, key, val):
        storage = Storage("general", "meta")
        if key in self.__VALUES:
            struct = self.__VALUES[key]

            # Check input correct
            cval = struct["type"](val)
            # Check enum
            if "enum" in struct and cval not in struct["enum"]:
                raise RuntimeError(BAD_PARAMS)
            if "min" in struct and cval < struct["min"]:
                raise RuntimeError(BAD_PARAMS)
            if "max" in struct and cval > struct["max"]:
                raise RuntimeError(BAD_PARAMS)
            if "maxlen" in struct and len(cval) > struct["maxlen"]:
                raise RuntimeError(BAD_PARAMS)

            if hasattr(metadata, struct["key"]):
                setattr(metadata, struct["key"], val)
            else:
                storage[struct["key"]] = val
        elif key == "backlash":
            d = {}
            for kv in val.split(" "):
                if ":" in kv:
                    k, sv = kv.split(":")
                    try:
                        v = float(sv)
                        if k in "ABC" and v >= 0 and v <= 100:
                            d[k] = v
                    except ValueError:
                        pass
            Preference.instance().backlash = d

        elif key == "leveling":
            d = {}
            for kv in val.split(" "):
                if ":" in kv:
                    k, sv = kv.split(":")
                    try:
                        v = float(sv)
                        if k in "XYZ" and v <= 0 and v >= -2:
                            d[k] = v
                        elif k in "R" and v <= 101 and v >= 92:
                            d[k] = v
                        elif k == "H" and v > 120 and v < 243:
                            d[k] = v
                    except ValueError:
                        pass
            Preference.instance().plate_correction = d
        else:
            raise RuntimeError(BAD_PARAMS)
Пример #15
0
def allow_god_mode():
    from fluxmonitor.security._security import is_dev_model
    from fluxmonitor.storage import Storage

    if is_dev_model():
        return True
    else:
        s = Storage("general", "meta")
        magic_str = s["debug"]
        if magic_str:
            return sha1(magic_str).hexdigest() == DEBUG_STR
        else:
            return False
Пример #16
0
def get_cert():
    from binascii import b2a_base64 as to_base64
    from OpenSSL import crypto
    from fluxmonitor.storage import Storage
    s = Storage("security", "private")

    try:
        key = crypto.load_privatekey(crypto.FILETYPE_PEM, s["sslkey.pem"])
    except (crypto.Error, TypeError):
        pkey = get_private_key()
        s["sslkey.pem"] = pem = pkey.export_pem()
        key = crypto.load_privatekey(crypto.FILETYPE_PEM, pem)

    try:
        cert = crypto.load_certificate(crypto.FILETYPE_PEM, s["cert2.pem"])
    except (crypto.Error, TypeError):
        issuersubj = crypto.X509Name(crypto.X509().get_subject())
        issuersubj.C = "TW"
        issuersubj.L = "Taipei"
        issuersubj.O = "FLUX Inc."

        cert = crypto.X509()
        subj = cert.get_subject()

        subj.O = "FLUX 3D Delta Printer"
        subj.CN = (get_uuid() + ":" + get_serial() + ":")
        ext = crypto.X509Extension("nsComment", True,
                                   to_base64(get_identify()))
        cert.add_extensions((ext, ))

        cert.set_serial_number(1001)
        cert.gmtime_adj_notBefore(0)
        cert.gmtime_adj_notAfter(60 * 365 * 24 * 60 * 60)
        cert.set_issuer(cert.get_subject())
        cert.set_pubkey(key)
        cert.sign(key, 'sha512')
        s["cert2.pem"] = crypto.dump_certificate(crypto.FILETYPE_PEM, cert)

    return s.get_path("cert2.pem"), s.get_path("sslkey.pem")
Пример #17
0
 def __config_get(self, key):
     storage = Storage("general", "meta")
     if key in self.__VALUES:
         struct = self.__VALUES[key]
         if hasattr(metadata, struct["key"]):
             return getattr(metadata, struct["key"])
         else:
             return storage[struct["key"]]
     elif key == "backlash":
         return " ".join("%s:%.4f" % (k, v)
                         for k, v in Preference.instance().backlash.items())
     elif key == "leveling":
         return " ".join(
             "%s:%.4f" % (k, v)
             for k, v in Preference.instance().plate_correction.items()
             if k in "XYZRH")
     else:
         raise RuntimeError(BAD_PARAMS)
Пример #18
0
    def __init__(self):
        camera_model = halprofile.PROFILE.get("scan_camera_model")
        if camera_model == 2:
            self._camera = Camera(0, width=1280, height=720)
            self.rotate = 1
        else:
            global delta_camera_option

            if delta_camera_option is None:
                from fluxmonitor.storage import Storage
                storage = Storage("general", "meta")
                delta_camera_option = 1 if storage["camera_version"] == "1" \
                    else 0

            if delta_camera_option == 1:
                self._camera = Camera(0, width=1280, height=720)
                self.rotate = 1
            else:
                self._camera = Camera(0)
Пример #19
0
 def on_compute_cab(step, m):
     m = m.split()[1]
     data["calibrate_param"].append(m)
     if len(data["calibrate_param"]) < 3:
         begin_compute_cab()
     else:
         if 'fail' in data["calibrate_param"]:
             output = ' '.join(data["calibrate_param"])
             on_loop('fail laser ' + output)
         elif all(abs(float(r) - float(data["calibrate_param"][0])) < 72
                  for r in data["calibrate_param"][1:]):
             # so naive check
             s = Storage('camera')
             s['calibration'] = ' '.join(
                 map(lambda x: str(round(float(x))),
                     data["calibrate_param"]))
             output = ' '.join(data["calibrate_param"])
             on_loop(output)
         else:
             output = ' '.join(data["calibrate_param"])
             on_loop('fail laser ' + output)
Пример #20
0
    def __init__(self, options):
        ServiceBase.__init__(self, logger, options)

        self.internl_interface = RobotUnixStreamInterface(self)

        if Storage("general", "meta")["bare"] == "Y":
            self.tcp_interface = RobotSSLInterface(self)
        else:
            self.tcp_interface = RobotTcpInterface(self)
        self._hal_reset_timer = self.loop.timer(5, 0, self._connect2hal)
        self._cloud_conn = set()

        try:
            if options.taskfile:
                logger.debug("Autoplay: %s", options.taskfile)
                pm = PlayerManager(self.loop, options.taskfile,
                                   self.release_exclusive)
                self.exclusive(pm)
            elif options.autoplay:
                self.autoplay()
        except Exception:
            logger.exception("Error while setting task at init")
Пример #21
0
    def __init__(self, taskloader=None, head=None):
        storage = Storage("general", "meta")
        metadata = taskloader.metadata if taskloader else {}
        self.additional_macros = []

        self._setup_toolhead(head, metadata)
        self._setup_leveling(storage, metadata)
        self._setup_filament_detect(storage, metadata)
        self._setup_toolhead_error_level(storage, metadata)
        self._setup_backlash(storage, metadata)
        self._setup_max_xyzr(metadata)
        self._setup_common(storage)
        self._setup_fcode_special_request(metadata)

        # ALL DIRTY THINGS START FROM HERE
        # TODO: enable hardware error for toolhead pwm issue
        self.head_error_level |= 64

        if self.head != "EXTRUDER":
            # Only EXTRUDER need filament detect
            self.filament_detect = False
            # Only EXTRUDER allowed correction
            self.correction = "N"
            self.movement_test = False
Пример #22
0
 def cloud_validation_code(self, handler):
     handler.send_text("ok %s %s" % (Storage("cloud")["token"],
                                     b2a_base64(metadata.cloud_hash)))
Пример #23
0
class CloudService(ServiceBase):
    config_ts = -1
    error_counter = 0
    config_enable = None
    cloud_netloc = None
    storage = None

    _notify_up_required = False
    _notify_last_st = {"st_id": None}
    _notify_last_ts = 0
    _notify_aggressive = 0
    _notify_retry_counter = 0
    aws_client = None
    postback_url = None

    def __init__(self, options):
        super(CloudService, self).__init__(logger, options)

        mqttlogger = logging.getLogger(
            "AWSIoTPythonSDK.core.protocol.mqttCore")
        if logger.getEffectiveLevel() < logging.INFO:
            mqttlogger.setLevel(logging.DEBUG)
        else:
            mqttlogger.setLevel(logging.WARNING)

        self.storage = Storage("cloud")
        self.uuidhex = security.get_uuid()

        if options.cloud.endswith("/"):
            self.cloud_netloc = options.cloud[:-1]
        else:
            self.cloud_netloc = options.cloud

        self.diagnosis()

    def on_start(self):
        logger.info("Cloud service started (version=%s)", __version__)
        if security.get_serial() == "XXXXXXXXXX":
            logger.error("Serial invalid, cloud deamon will be silenced.")
        else:
            self.timer = self.loop.timer(3., 3., self.on_timer)
            self.timer.start()

    def require_identify(self):
        logger.debug("Require identify")

        url = urlparse("%s/axon/require_identify" % self.cloud_netloc)

        pkey = security.get_private_key()
        publickey_base64 = b2a_base64(pkey.export_pubkey_der())
        serial = security.get_serial()
        model = get_model_id()
        identify_base64 = b2a_base64(security.get_identify())

        try:
            conn = get_connection(url)
            logger.debug("Require identify request sent")
            conn.post_request(
                url.path, {
                    "serial": serial,
                    "uuid": self.uuidhex,
                    "model": model,
                    "version": __version__,
                    "publickey": publickey_base64,
                    "signature": identify_base64
                })
            resp = conn.get_json_response()

            if resp.get("status") == "ok":
                return resp["token"].encode(), resp["subject"]
            elif resp.get("status") == "error":
                raise RuntimeWarning(*resp["error"])
            else:
                logger.error("require_identify response unknown response: %s",
                             resp)
                raise RuntimeWarning("RESPONSE_ERROR")
        except socket.gaierror as e:
            raise RuntimeError("REQUIRE_IDENTIFY", "DNS_ERROR", e)
        except socket.error as e:
            raise RuntimeError("REQUIRE_IDENTIFY", "CONNECTION_ERROR", e)
        except RuntimeWarning as e:
            raise RuntimeError("REQUIRE_IDENTIFY", *e.args)
        except Exception as e:
            logger.exception("Error in require identify")
            raise RuntimeError("REQUIRE_IDENTIFY", "UNKNOWN_ERROR", e)

    def get_identify(self, token, request_asn1):
        logger.debug("Get identify")

        url = urlparse("%s/axon/identify" % self.cloud_netloc)
        uuidhex = security.get_uuid()

        try:
            conn = get_connection(url)
            logger.debug("Get identify request sent")
            conn.post_request(
                url.path, {
                    "uuid": uuidhex,
                    "token": token,
                    "x509_request": request_asn1,
                    "metadata": {
                        "version": __version__
                    }
                })
            resp = conn.get_json_response()

            if resp.get("status") == "ok":
                return resp
            elif resp.get("status") == "error":
                raise RuntimeWarning(*resp["error"])
            else:
                logger.error("get identify response unknown response: %s",
                             resp)
                raise RuntimeWarning("RESPONSE_ERROR")
        except socket.gaierror as e:
            raise RuntimeError("GET_IDENTIFY", "DNS_ERROR", e)
        except socket.error as e:
            raise RuntimeError("GET_IDENTIFY", "CONNECTION_ERROR", e)
        except RuntimeWarning as e:
            raise RuntimeError("GET_IDENTIFY", *e.args)
        except Exception as e:
            logger.exception("Error in get identify")
            raise RuntimeError("GET_IDENTIFY", "UNKNOWN_ERROR", e)

    def generate_certificate_request(self, subject_list):
        from subprocess import Popen, PIPE

        fxkey = security.get_private_key()
        self.storage["key.pem"] = fxkey.export_pem()
        subject_str = "/" + "/".join(("=".join(i) for i in subject_list))

        proc = Popen([
            "openssl", "req", "-new", "-key",
            self.storage.get_path("key.pem"), "-subj", subject_str, "-keyform",
            "pem", "-nodes", "-sha256"
        ],
                     stdin=PIPE,
                     stderr=PIPE,
                     stdout=PIPE)
        stdoutdata, stderrdata = proc.communicate(input="")

        while proc.poll() is None:
            pass
        if proc.returncode > 0:
            error = stdoutdata if stdoutdata else stderrdata
            if error:
                error = error.decode("utf8")
            else:
                error = "Process return %i" % proc.returncode
            raise SystemError(error)
        else:
            return stdoutdata
        # csr = crypto.X509Req()
        # subj = csr.get_subject()
        # for name, value in subject_list:
        #     if name == "CN":
        #         add_result = crypto._lib.X509_NAME_add_entry_by_NID(
        #             subj._name, 13, crypto._lib.MBSTRING_UTF8,
        #             value.encode('utf-8'), -1, -1, 0)
        #         if not add_result:
        #             crypto._raise_current_error()
        #     else:
        #         setattr(subj, name, value)

        # fxkey = security.get_private_key()
        # opensslkey = crypto.load_privatekey(crypto.FILETYPE_ASN1,
        #                                     fxkey.export_der())
        # self.storage["key.pem"] = fxkey.export_pem()
        # csr.set_pubkey(opensslkey)
        # csr.sign(opensslkey, "sha256")
        # return crypto.dump_certificate_request(crypto.FILETYPE_PEM, csr)

    def fetch_identify(self):
        logger.info("Fetch identify")

        token, subject_list = self.require_identify()
        logger.info("Require identify return token=%s, subject=%s", token,
                    subject_list)

        request_asn1 = self.generate_certificate_request(subject_list)
        doc = self.get_identify(token, request_asn1)
        logger.info("Get identify return %s", doc["status"])

        self.storage["token"] = token
        self.storage["endpoint"] = doc["endpoint"]
        self.storage["client_id"] = doc["client_id"]
        self.storage["certificate_reqs.pem"] = doc["certificate_reqs"]
        self.storage["certificate.pem"] = doc["certificate"]

    def notify_up(self, c):
        payload = json.dumps({
            "state": {
                "reported": {
                    "version": __version__,
                    "token": self.storage["token"],
                    "nickname": metadata.nickname
                }
            }
        })
        c.publish(self._notify_topic, payload, 1)

    def postback_status(self, st_id):
        url = Storage("general", "meta")["player_postback_url"]
        if url:
            try:
                if '"' in url or '\\' in url:
                    logger.error("Bad url: %r", url)
                else:
                    url = url % {"st_id": st_id}
                    os.system("curl -s -o /dev/null \"%s\"" % url)
            except Exception:
                logger.exception("Error while post back status, url: %s", url)

    def notify_update(self, new_st, now):
        if metadata.verify_mversion() is False:
            self._notify_up_required = True

        new_st_id = new_st["st_id"]

        if self._notify_last_st["st_id"] == new_st_id:
            if self._notify_last_ts > self._notify_aggressive:
                # notify aggressive is invalid
                if now - self._notify_last_ts < 1200:
                    # update every 1200 seconds
                    return
            else:
                # notify aggressive is valid
                if new_st_id <= 0 and now - self._notify_last_ts < 1200:
                    # update every 1200 seconds if device is idle or occupy
                    return
        elif new_st_id in (48, 64, 128):  # paused, completed, aborted
            self.postback_status(new_st_id)

        c = self.aws_client.getMQTTConnection()

        payload = json.dumps({"state": {"reported": new_st}})

        if self._notify_up_required:
            self.notify_up(c)
            self._notify_up_required = False
        c.publish(self._notify_topic, payload, 0)
        self._notify_last_st = new_st
        self._notify_last_ts = now

    def aws_on_request_callback(self, client, userdata, message):
        # incommint topic format: "device/{token}/request/{action}"
        # response topic format: "device/{token}/response/{action}"

        action = message.topic.split("/", 3)[-1]
        logger.debug("IoT request: %s", action)
        response_topic = "device/%s/response/%s" % (self.aws_token, action)

        try:
            payload = json.loads(message.payload)
        except ValueError:
            logger.error("IoT request payload error: %s", message.payload)
            client.publish(response_topic, message.payload)
            return

        if payload.get("uuid") != self.uuidhex:
            client.publish(
                response_topic,
                json.dumps({
                    "status": "reject",
                    "cmd_index": payload.get("cmd_index")
                }))
            return

        cmd_index = payload.get("cmd_index")

        try:
            if action == "getchu":
                try:
                    current_hash = metadata.cloud_hash
                    access_id, signature = payload.get("validate_message")
                    client_key = security.get_keyobj(access_id=access_id)
                    if client_key.verify(current_hash, a2b_base64(signature)):
                        client.publish(
                            response_topic,
                            json.dumps({
                                "status": "ok",
                                "cmd_index": cmd_index
                            }))
                    else:
                        client.publish(
                            response_topic,
                            json.dumps({
                                "status": "reject",
                                "cmd_index": cmd_index
                            }))
                finally:
                    metadata.cloud_hash = os.urandom(32)
            elif action == "monitor":
                self._notify_aggressive = time() + 180
                self._notify_last_st["st_id"] = None
                client.publish(
                    response_topic,
                    json.dumps({
                        "status": "ok",
                        "cmd_index": cmd_index
                    }))
            elif action == "camera":
                self.require_camera(payload["camera_id"], payload["endpoint"],
                                    payload["token"])
                client.publish(
                    response_topic,
                    json.dumps({
                        "status": "ok",
                        "cmd_index": cmd_index
                    }))
            elif action == "control":
                self.require_control(payload["endpoint"], payload["token"])
                client.publish(
                    response_topic,
                    json.dumps({
                        "status": "ok",
                        "cmd_index": cmd_index
                    }))
            else:
                client.publish(
                    response_topic,
                    json.dumps({
                        "status": "error",
                        "cmd_index": cmd_index
                    }))
        except Exception:
            logger.exception("Handle aws request error")
            client.publish(
                response_topic,
                json.dumps({
                    "status": "error",
                    "cmd_index": cmd_index
                }))

    def begin_session(self):
        logger.info("Begin Session")
        if not self.storage["certificate.pem"]:
            metadata.cloud_status = (False, ("INIT", ))
            self.fetch_identify()

        self.setup_session()
        metadata.cloud_status = (True, ())

    def setup_session(self):
        logger.info("Setup session")
        from AWSIoTPythonSDK.MQTTLib import AWSIoTMQTTShadowClient
        from AWSIoTPythonSDK.core.protocol.mqttCore import (
            connectTimeoutException)

        client_id, token = self.storage["client_id"], self.storage["token"]
        if not client_id or not token:
            raise SystemError("client_id or token error")

        try:
            ipaddr, port = self.storage["endpoint"].split(":")
        except (AttributeError, ValueError):
            raise SystemError("endpoint error")

        cafile = self.storage.get_path("certificate_reqs.pem")
        cert = self.storage.get_path("certificate.pem")
        key = self.storage.get_path("key.pem")

        if False in map(lambda p: os.path.exists(p), (cafile, cert, key)):
            raise SystemError("cafile or cert or key not exist")

        client = AWSIoTMQTTShadowClient(client_id)
        client.configureEndpoint(ipaddr, int(port))
        client.configureCredentials(cafile, key, cert)
        client.configureConnectDisconnectTimeout(10)
        client.configureMQTTOperationTimeout(5)

        try:
            client.connect()
        except SSLError as e:
            raise RuntimeError("SESSION", "TLS_ERROR", "%s" % e.reason)
        except (connectTimeoutException, socket.gaierror, socket.error):
            raise RuntimeError("SESSION", "CONNECTION_ERROR")

        conn = client.getMQTTConnection()
        conn.subscribe("device/%s/request/+" % self.storage["token"], 1,
                       self.aws_on_request_callback)

        self.aws_client = client
        self.aws_token = token
        self._notify_topic = "$aws/things/%s/shadow/update" % (
            self.storage["client_id"])
        self.notify_up(conn)
        metadata.cloud_hash = os.urandom(32)
        logger.info("Session ready")

    def teardown_session(self):
        if self.aws_client:
            aws_client = self.aws_client
            self.aws_client = None

            conn = aws_client.getMQTTConnection()
            try:
                if conn._mqttCore._pahoClient._thread.isAlive():
                    aws_client.disconnect()
                else:
                    logger.error("MQTT thread closed, remove directly")

            except Exception:
                logger.exception("AWS panic while disconnect from aws, "
                                 "make a ugly bugfix")
                try:
                    conn._mqttCore._pahoClient._thread_terminate = True
                    if conn._mqttCore._pahoClient._sock:
                        conn._mqttCore._pahoClient._sock.close()
                    return
                except Exception:
                    logger.exception("AWS panic ugly bugfix failed")

    def on_timer(self, watcher, revent):
        try:
            if self.config_ts != metadata.mversion:
                self.error_counter = 0

                if metadata.enable_cloud == "R":
                    logger.warning("Refetch required")
                    if self.aws_client:
                        self.teardown_session()
                    metadata.enable_cloud = "A"
                    metadata.cloud_status = (False, ("INIT", ))
                    self.fetch_identify()

                self.config_ts = metadata.mversion
                self.config_enable = (metadata.enable_cloud == "A")
                if self.config_enable is False:
                    metadata.cloud_status = (False, ("DISABLE", ))

            if self.config_enable:
                if self.aws_client:
                    self.notify_update(metadata.format_device_status, time())
                    self.error_counter = max(self.error_counter - 1, 0)
                else:
                    if self.error_counter in ERROR_COUNTER_MATCH:
                        self.begin_session()
                        self.error_counter = max(self.error_counter - 1, 0)
                    elif self.error_counter > ERROR_COUNTER_MATCH[-1]:
                        self.error_counter = ERROR_COUNTER_MATCH[-2]
                    else:
                        self.error_counter += 1

            else:
                if self.aws_client:
                    self.teardown_session()

            self._notify_retry_counter = 0
        except publishQueueDisabledException:
            metadata.cloud_status = (False, ("SESSION", "CONNECTION_ERROR"))
            self._notify_retry_counter += 1
            logger.exception("publishQueueDisabledException raise in notify")
            if self._notify_retry_counter > 10:
                self.teardown_session()
            self.error_counter += 1
        except RuntimeError as e:
            logger.error(e)
            metadata.cloud_status = (False, e.args)
            self.error_counter += 1

            self.diagnosis()
        except Exception:
            logger.exception("Unhandle error")
            metadata.cloud_status = (False, ("UNKNOWN_ERROR", ))
            self.error_counter += 1

    def on_shutdown(self):
        pass

    def require_camera(self, camera_id, endpoint, token):
        payload = msgpack.packb((0x80, camera_id, endpoint, token))
        s = socket.socket(socket.AF_UNIX)
        s.connect(CAMERA_ENDPOINT)
        s.send(payload)
        rl = select((s, ), (), (), 0.25)[0]
        if rl:
            logger.debug("Require camera return %s",
                         msgpack.unpackb(s.recv(4096)))
        s.close()

    def require_control(self, endpoint, token):
        payload = msgpack.packb((0x80, endpoint, token))
        s = socket.socket(socket.AF_UNIX)
        s.connect(ROBOT_ENDPOINT)
        s.send(payload)
        rl = select((s, ), (), (), 0.25)[0]
        if rl:
            logger.debug("Require robot return %s",
                         msgpack.unpackb(s.recv(4096)))
        s.close()

    def diagnosis(self):
        from fluxmonitor.misc._process import Process
        from time import time as epoch
        logger.info("Diagnosis...")

        try:
            logger.info(
                'ntp dns testing...\n%s\n%s',
                Process.call_with_output('getent', 'hosts',
                                         '0.debian.pool.ntp.org'),
                Process.call_with_output('getent', 'hosts',
                                         '1.debian.pool.ntp.org'))
        except Exception:
            logger.exception('ntp dns testing failed')

        try:
            logger.info('ntp service status...\n%s',
                        Process.call_with_output('service', 'ntp', 'status'))
        except Exception:
            logger.exception('fetch ntp service status failed')

        try:
            if epoch() < 1505720271:
                logger.error(
                    "System time error, fixing...\n%s",
                    Process.call_with_output('ntp-wait', '-s', '1', '-n', '1'))
                if epoch() < 1505720271:
                    logger.error("System time sync failed")

        except Exception:
            logger.exception("cloud diagnosis error")
Пример #24
0
 def __init__(self, storage=None):
     from fluxmonitor.storage import Storage
     self.storage = storage if storage else Storage("security", "pub")
Пример #25
0
    def update_hbfw(self, stage_cb=lambda m: None):
        raspi_uart = Serial(port="/dev/ttyAMA0",
                            baudrate=115200,
                            stopbits=1,
                            xonxoff=0,
                            rtscts=0,
                            timeout=0)

        def wait_ack(stage):
            t = time()
            while time() - t < 5.0:
                rl = select((raspi_uart, ), (), (), 5.0)[0]
                if rl:
                    ret = raspi_uart.read(1)
                    if ret == 'y':
                        return
                    elif ret == '\x1f':
                        raise RuntimeError(SUBSYSTEM_ERROR, "HEAD RETURN 0x1f")
                    else:
                        raise RuntimeError(UNKNOWN_ERROR,
                                           "HEAD RETURN %s" % repr(ret))
            raise RuntimeError(NO_RESPONSE, stage)

        def send_cmd(cmd, stage):
            raspi_uart.write(chr(cmd))
            raspi_uart.write(chr(cmd ^ 0xFF))
            wait_ack(stage)
            sleep(0.1)

        def crc8(msg, init=0):
            crc = init
            for c in msg:
                crc = crc ^ ord(c)
            return chr(crc)

        def bootloader_hello():
            raspi_uart.write('\x7f')
            wait_ack("HELLO")

        logger.debug("Update head fw")
        storage = Storage("update_fw")
        if not storage.exists("head.bin"):
            raise RuntimeError(NOT_FOUND)

        with storage.open("head.bin", "rb") as f:
            fw = f.read()

        size = len(fw)
        pages = size // 2048
        if size % 2048 > 0:
            pages += 1
        logger.debug("Fw size=%i, use page=%i", size, pages)

        try:
            # Bootstrap
            stage_cb(b"B")

            raspi_uart.parity = PARITY_EVEN

            GPIO.output(self.TOOLHEAD_POWER, self.TOOLHEAD_POWER_OFF)
            GPIO.output(self.TOOLHEAD_BOOT, GPIO.HIGH)
            sleep(0.5)

            GPIO.output(self.TOOLHEAD_POWER, self.TOOLHEAD_POWER_ON)
            sleep(0.5)

            raspi_uart.setRTS(0)
            raspi_uart.setDTR(0)
            sleep(0.1)
            raspi_uart.setDTR(1)
            sleep(0.5)

            # Hello
            stage_cb(b"H")

            try:
                bootloader_hello()
            except Exception:
                sleep(0.5)
                bootloader_hello()

            send_cmd(0x00, "G_VR")
            l = ord(raspi_uart.read())
            version = raspi_uart.read(1)
            a = raspi_uart.read(l)
            logger.debug("VER %s", repr(a))
            wait_ack("G_VRL")
            logger.debug("Update head: bootloader ver=%s", version)
            if version != '1':
                raise RuntimeError(NOT_SUPPORT)

            # Earse
            stage_cb(b"E")

            send_cmd(0x44, "G_ERASE")
            cmd = struct.pack(">H", pages - 1)
            cmd += "".join([struct.pack(">H", i) for i in xrange(pages)])
            raspi_uart.write(cmd)
            raspi_uart.write(crc8(cmd))
            wait_ack("G_E")

            # Write
            stage_cb(b"W")
            offset = 0
            while offset < size:
                stage_cb(("%07x" % (size - offset)).encode())
                l = min(size - offset, 128)
                send_cmd(0x31, "G_WINIT")
                addr = struct.pack(">I", 0x08000000 + offset)
                raspi_uart.write(addr)
                raspi_uart.write(crc8(addr))
                wait_ack("G_WREADY")
                payload = chr(l - 1) + fw[offset:offset + l]
                raspi_uart.write(payload)
                raspi_uart.write(crc8(payload))
                wait_ack("G_WDONE")
                offset += l

            stage_cb("00000000")
        finally:
            GPIO.output(self.TOOLHEAD_BOOT, GPIO.LOW)
            GPIO.output(self.TOOLHEAD_POWER, self.TOOLHEAD_POWER_OFF)
            sleep(0.5)
            GPIO.output(self.TOOLHEAD_POWER, self._head_power_stat)
            raspi_uart.parity = PARITY_NONE
            raspi_uart.close()

        logger.debug("Update fw end")
Пример #26
0
 def get_cab(self, handler):
     s = Storage('camera')
     a = s.readall('calibration')
     if a is None:
         a = '320 320 320'
     handler.send_text("ok " + a)
Пример #27
0
 def storage(self):
     return Storage("net")
Пример #28
0
def get_storage():
    from fluxmonitor.storage import Storage
    return Storage("security", "private")
Пример #29
0
def try_config_network(dryrun=False):
    anti_garbage_usb_mass_storage()
    if os.path.exists("/media/usb/config_flux.txt"):
        print("USB Disk found")

        from ConfigParser import RawConfigParser
        from fluxmonitor.security import get_serial
        from fluxmonitor.storage import Storage
        from hashlib import md5

        storage = Storage("general", "meta")
        with open("/media/usb/config_flux.txt") as f:
            h = md5(f.read()).hexdigest()
            print("Fingerprint local=%s, disk=%s" %
                  (storage["flashconfig_history"], h))

            if storage["flashconfig_history"] == h:
                print("This config file is already done, ignore")
                return

        c = RawConfigParser()
        c.read("/media/usb/config_flux.txt")

        if "device" in c.sections():
            device = dict(c.items("device"))
            s = device.get("serial")
            if s and get_serial() != s:
                print("Device serial not match")
                return
        else:
            print("Device section not found, ignore")

        if "general" in c.sections():
            general_config = dict(c.items("general"))

            name = general_config.get("name")
            if name:
                if dryrun:
                    print("[Dryrun] Config name to: %s" % name)
                else:
                    from fluxmonitor.storage import Metadata
                    m = Metadata()
                    m.nickname = general_config["name"]

            password = general_config.get("password")
            if password:
                if dryrun:
                    print("[Dryrun] Set password to: ***")
                else:
                    from fluxmonitor.security import set_password
                    set_password(general_config["password"])

        if "network" in c.sections():
            network_config = dict(c.items("network"))

            if dryrun:
                print("[Dryrun] Config network: %s" % network_config)
            else:
                from fluxmonitor.misc import network_config_encoder as NCE  # noqa
                from fluxmonitor.config import NETWORK_MANAGE_ENDPOINT
                import socket
                s = socket.socket(socket.AF_UNIX, socket.SOCK_DGRAM)
                s.connect(NETWORK_MANAGE_ENDPOINT)
                s.send(b"%s\x00%s" %
                       (b"config_network", NCE.to_bytes(network_config)))

        storage["flashconfig_history"] = h