def main(self): devices = eval(self.config.get("settings", "devices")) self.add_outgoing_paths(self.config.get("settings", "id"), devices) try: acceptnet = eval(self.config.get("settings", "acceptnet")) netport = int(self.config.get("settings", "netport")) gpsport = int(self.config.get("settings", "gpsport")) idfreq = self.config.get("settings", "idfreq") if idfreq == "Never": idfreq = 0 else: idfreq = int(idfreq) except Exception as e: printlog("Repeater : Failed to parse network info: %s" % e) acceptnet = False if acceptnet: self.repeater.socket = self.repeater.listen_on(netport) self.repeater.gps_socket = self.repeater.listen_on(gpsport) self.repeater.repeat() while True: try: time.sleep(0.25) except KeyboardInterrupt: self.repeater.stop() break
def handler(frame): self.condition.acquire() try: self.__repeat(transport, frame) except Exception as e: printlog("Repeater : Exception during __repeat: %s" % e) self.condition.release()
def load_devices(self): try: l = eval(self.config.get("settings", "devices")) for d, r in l: self.dev_list.add_item(d, r) except Exception as e: printlog(("Unable to load devices: %s" % e))
def __init__(self): RepeaterUI.__init__(self) self.window = gtk.Window(gtk.WINDOW_TOPLEVEL) self.window.set_default_size(450, 380) self.window.connect("delete_event", self.ev_delete) self.window.connect("destroy", self.sig_destroy) self.window.set_title("D-RATS Repeater Proxy") vbox = gtk.VBox(False, 5) self.tabs = gtk.Notebook() self.tabs.append_page(self.make_settings(), gtk.Label("Settings")) # FIXME: later # self.tabs.append_page(self.make_monitor(), gtk.Label("Monitor")) self.tabs.show() vbox.pack_start(self.tabs, 1, 1, 1) vbox.pack_start(self.make_bottom_buttons(), 0, 0, 0) vbox.show() self.window.add(vbox) self.window.show() #gobject.timeout_add(1000, self.update) try: if self.config.get("settings", "state") == "True": self.button_on(None, None) except Exception as e: printlog(e)
def __send_job(self, job, id): printlog( "RPC", " : Sending job `%s' to %s" % (job.get_desc(), job.get_dest())) frame = self.__job_to_frame(job, id) job.frame = frame self._sm.outgoing(self, frame) printlog("RPC", " : Job sent")
def write_raw(self, data): f = DDT2RawData() f.data = data f.type = self.T_DEF printlog("Chat"," : Sending raw: %s" % data) self._sm.outgoing(self, f)
def __job_state(self, job, state, _result, id): printlog("RPC"," : Job state: %s for %i: %s" % (state, id, _result)) if state == "running": return result = encode_dict(_result) f = self.__send_job_status(id, job.get_dest(), state, result) self._sm.outgoing(self, f)
def ping_station(self, station): f = DDT2EncodedFrame() f.d_station = station f.type = self.T_PNG_REQ f.data = "Ping Request" f.set_compress(False) self._sm.outgoing(self, f) printlog("Chat"," : pinging %s" % f.d_station) self._emit("ping-request", f.s_station, f.d_station, "Request")
def _repeat(self): while self.enabled: self.condition.acquire() self.accept_new() self.accept_new_gps() self.condition.release() time.sleep(0.5) printlog("Repeater : Repeater thread ended")
def __worker(self): for id, (ts, att, job) in self.__jobs.items(): if job.frame and not job.frame.sent_event.isSet(): # Reset timer until the block is sent self.__jobs[id] = (time.time(), att, job) elif (time.time() - ts) > self.__t_retry: printlog("RPC"," : Cancelling job %i due to timeout" % id) del self.__jobs[id] job.set_state("timeout") return True
def accept_new_gps(self): if not self.gps_socket: return try: (csocket, addr) = self.gps_socket.accept() except: return printlog("Repeater : Accepted new GPS client %s:%i" % addr) self.gps_sockets.append(csocket)
def RPC_get_version(self, job): result = {} result["version"] = DRATS_VERSION result["os"] = self.__config.platform.os_version_string() result["pyver"] = ".".join([str(x) for x in sys.version_info[:3]]) try: import gtk result["pygtkver"] = ".".join([str(x) for x in gtk.pygtk_version]) result["gtkver"] = ".".join([str(x) for x in gtk.gtk_version]) except ImportError: result["pygtkver"] = result["gtkver"] = "Unknown" printlog("RPC", " : RPC_get_version: %s" % result) return result
def auth_exchange(self, pipe): username = password = None count = 0 def readline(_s): data = "" while "\r\n" not in data: try: _d = _s.read(32) except socket.timeout: continue if _d == "": break data += _d return data.strip() while (not username or not password) and count < 3: line = readline(pipe) if not line: continue try: cmd, value = line.split(" ", 1) except Exception as e: printlog("Repeater : Unable to read auth command: `%s': %s" % (line, e)) pipe.write("501 Invalid Syntax\r\n") break cmd = cmd.upper() if cmd == "USER" and not username and not password: username = value elif cmd == "PASS" and username and not password: password = value else: pipe.write("201 Protocol violation\r\n") break if username and not password: pipe.write("102 %s okay\r\n" % cmd) if not username or not password: printlog("Repeater : Negotiation failed with client") return username, password
def accept_new(self): if not self.socket: return try: (csocket, addr) = self.socket.accept() except: return printlog("Repeater : Accepted new client %s:%i" % addr) path = comm.SocketDataPath(csocket) tport = transport.Transporter(path, authfn=self.auth_user, warmup_timeout=0) self.add_new_transport(tport)
def handle_exception(exctyp, value, tb): # this eventually starts the initial window with the list of errors and the # buttons to open log or ignore errors global IGNORE_ALL if exctyp is KeyboardInterrupt or IGNORE_ALL: return original_excepthook(exctyp, value, tb) gtk.gdk.pointer_ungrab() gtk.gdk.keyboard_ungrab() _trace = traceback.format_exception(exctyp, value, tb) trace = os.linesep.join(_trace) printlog("D-Rats", "---- GUI Exception ----\n%s\n---- End ----\n" % trace) msg = """ <b><big>D-RATS has encountered an error.</big></b> This may be non-fatal, so you may click <b>Ignore</b> below to attempt to continue running. Otherwise, click 'Quit' to terminate D-RATS now. If you are planning to file a bug for this issue, please click <b>Debug Log</b> below and include the contents in the bug tracker. If you need to ignore all additional warnings for this session, click <b>Ignore All</b>. However, please reproduce and report the issue when possible. """ def extra(dialog): dialog.add_button(_("Debug Log"), gtk.RESPONSE_HELP) dialog.add_button(_("Ignore"), gtk.RESPONSE_CLOSE) dialog.add_button(_("Ignore All"), -1) dialog.add_button(gtk.STOCK_QUIT, gtk.RESPONSE_CANCEL) dialog.set_default_response(gtk.RESPONSE_CANCEL) while True: r = utils.make_error_dialog(msg, trace, gtk.BUTTONS_NONE, gtk.MESSAGE_ERROR, extra=extra) if r == gtk.RESPONSE_CANCEL: sys.exit(1) elif r == gtk.RESPONSE_CLOSE: break elif r == -1: IGNORE_ALL = True break elif r == gtk.RESPONSE_HELP: p = dplatform.get_platform() p.open_text_file(p.config_file("debug.log"))
def stop(self): self.enabled = False self.condition.acquire() self.condition.notify() self.condition.release() if self.repeat_thread: printlog("Repeater : Stopping repeater") self.repeat_thread.join() for p in self.paths: printlog("Repeater : Stopping") p.disable() if self.socket: self.socket.close()
def incoming_data(self, frame): if frame.type == self.T_RPCREQ: try: job = self.__decode_rpccall(frame) except UnknownRPCCall as e: printlog( "RPC", " : incoming data : unable to execute RPC from %s: %s" % (frame.s_station, e)) return job.connect("state-change", self.__job_state, frame.seq) result = job.do(self.__rpcactions) if result is not None: job.set_state("complete", result) elif frame.type == self.T_RPCACK: if frame.seq in self.__jobs: ts, att, job = self.__jobs[frame.seq] del self.__jobs[frame.seq] job.set_state("complete", decode_dict(frame.data)) else: printlog("RPC", " : incoming data : Unknown job %i" % frame.seq) else: printlog( "RPC", " : incoming data : Unknown RPC frame type %i" % frame.type)
def RPC_file_pull(self, job): result = {} if not self.__config.getboolean("prefs", "allow_remote_files"): result["rc"] = "Remote file transfers not enabled" return result dir = self.__config.get("prefs", "download_dir") path = os.path.join(dir, job.get_file()) printlog("RPC", " : Remote requested %s" % path) if os.path.exists(path): result["rc"] = "OK" self.emit("rpc-send-file", job.get_dest(), self.__port, path, job.get_file()) else: result["rc"] = "File not found" event = main_events.Event(None, job.get_dest() + " " + \ _("Requested file %s") % job.get_file()) self.emit("event", event) return result
def auth_user(self, pipe): host, port = pipe._socket.getpeername() if not self.reqauth: pipe.write("100 Authentication not required\r\n") return True elif self.trustlocal and host == "127.0.0.1": pipe.write("100 Authentication not required for localhost\r\n") return True auth_fn = dplatform.get_platform().config_file("users.txt") try: auth = open(auth_fn) lines = auth.readlines() auth.close() except Exception as e: printlog("Repeater : Failed to open %s: %s" % (auth_fn, e)) pipe.write("101 Authorization required\r\n") username, password = self.auth_exchange(pipe) lno = 1 for line in lines: line = line.strip() try: u, p = line.split(" ", 1) u = u.upper() except Exception as e: printlog( "Repeater : Failed to parse line %i in users.txt: %s" % (lno, line)) continue if u == username and p == password: printlog(("Authorized user %s" % u)) pipe.write("200 Authorized\r\n") return True printlog("Repeater : User %s failed to authenticate" % username) pipe.write("500 Not authorized\r\n") return False
if __name__ == "__main__": import sys if not opts.debug: if opts.logpath: f = open(opts.logpath + "/repeater.log", "a", 0) else: p = dplatform.get_platform() #f = file(p.config_file("repeater.log"), "w", 0) f = open(p.config_file("repeater.log"), "a", 0) if f: sys.stdout = f sys.stderr = f else: printlog("Repeater : Failed to open log") if opts.console: r = RepeaterConsole() r.main() else: import gtk import gobject from d_rats.miscwidgets import make_choice from d_rats import miscwidgets from d_rats.config import prompt_for_port gobject.threads_init() g = RepeaterGUI() gtk.main()
def add_outgoing_paths(self, id, paths): reqauth = self.config.get("settings", "require_auth") == "True" trustlocal = self.config.get("settings", "trust_local") == "True" gps_okay_ports = self.config.get("tweaks", "allow_gps").split(",") printlog("Repeater : Repeater id is %s" % id) self.repeater = Repeater(id, reqauth, trustlocal, gps_okay_ports) for dev, param in paths: to = 0 if dev.startswith("net:"): try: net, host, port = dev.split(":", 2) port = int(port) except Exception as e: printlog(("Invalid net string: %s (%s)" % (dev, e))) continue printlog("Repeater : Socket %s %i (%s)" % (host, port, param)) if param: path = comm.SocketDataPath((host, port, id, param)) else: path = comm.SocketDataPath((host, port)) elif dev.startswith("tnc:"): try: tnc, port, device = dev.split(":", 2) device = int(device) except Exception as e: printlog("Repeater : Invalid tnc string: %s (%s)" % (dev, e)) continue printlog("Repeater : TNC %s %i" % (dev.replace("tnc:", ""), int(param))) path = comm.TNCDataPath((dev.replace("tnc:", ""), int(param))) else: printlog("Repeater : Serial: %s %i" % (dev, int(param))) path = comm.SerialDataPath((dev, int(param))) to = 3 path.connect() tport = transport.Transporter(path, warmup_timout=to, name=dev) self.repeater.add_new_transport(tport)
o.add_option("-c", "--config", dest="config", help="Use alternate configuration directory") o.add_option("-p", "--profile", dest="profile", action="store_true", help="Enable profiling") (opts, args) = o.parse_args() # import the platform module - this will setup all the proper parameters for the different OSs from d_rats import dplatform if opts.config: printlog("D-Rats", " : re-config option found -- Reconfigure D-rats") dplatform.get_platform(opts.config) # import the D-Rats main application from d_rats import mainapp #stores away the value of sys.excepthook install_excepthook() import libxml2 libxml2.debugMemory(1) # create the mainapp with the basic options app = mainapp.MainApp(safe=opts.safe) printlog("D-Rats", " : reloading app\n\n")
def RPC_pos_report(self, job): result = {} mycall = self.__config.get("user", "callsign") rqcall = job.get_station() printlog("RPC", " : Position request for `%s'" % rqcall) printlog("RPC", " : Self=%s" % format(self)) if rqcall == mycall or rqcall == ".": rqcall = None try: #obtaining current position from config or local gps fix = self.emit("get-current-position", rqcall) #result = fix.to_NMEA_GGA() result["rc"] = "True" result["msg"] = fix.to_APRS( symtab=self.__config.get("settings", "aprssymtab"), symbol=self.__config.get("settings", "aprssymbol")) except Exception as e: printlog( "RPC", " : Case KO : Exception while getting position of %s: " % rqcall) log_exception() fix = None result["rc"] = "False" result["msg"] = " No data for station '%s'" % job.get_station() if fix: #sending the position to transport // but this is broken!! printlog("RPC", " : port is : %s" % self.__port) printlog("RPC", " : fix is : %s" % fix) printlog("RPC", " : fix in NMEA GGA is: %s" % fix.to_NMEA_GGA()) printlog("RPC", " : fix in APRS is: %s" % result) #self.emit("user-send-chat","CQCQCQ", self.__port, fix.to_NMEA_GGA(), True) self.emit("user-send-chat", "CQCQCQ", self.__port, result["msg"], True) return None
def handler(obj, *args): printlog("RPC", " : Proxy emit %s: %s" % (signal, args)) gobject.idle_add(self.emit, signal, *args)
def incoming_data(self, frame): printlog("Chat"," : Got chat frame: %s" % frame) if frame.type == self.T_DEF: fix = gps.parse_GPS(frame.data) if fix and fix.valid: self._incoming_gps(fix) else: self._incoming_chat(frame) elif frame.type == self.T_PNG_REQ: self._emit("ping-request", frame.s_station, frame.d_station, "Request") if frame.d_station == "CQCQCQ": delay = random.randint(0,50) / 10.0 printlog("Chat"," : Broadcast ping, waiting %.1f sec" % delay) time.sleep(delay) elif frame.d_station != self._sm.station: return # Not for us frame.d_station = frame.s_station frame.type = self.T_PNG_RSP try: frame.data = self.pingfn() except Exception as e: printlog("Chat"," : Ping function failed: %s" % e) return self._sm.outgoing(self, frame) try: s, m = self.emit("get-current-status") self.advertise_status(s, m) except Exception as e: printlog("Chat"," : Exception while getting status for ping reply:") utils.log_exception() self._emit("ping-response", frame.s_station, frame.d_station, six.text_type(frame.data, "utf-8")) elif frame.type == self.T_PNG_RSP: printlog("Chat"," : PING OUT") self._emit("ping-response", frame.s_station, frame.d_station, frame.data) elif frame.type == self.T_PNG_ERQ: self._emit("ping-request", frame.s_station, frame.d_station, "%s %i %s" % (_("Echo request of"), len(frame.data), _("bytes"))) if frame.d_station == "CQCQCQ": delay = random.randint(0, 100) / 10.0 printlog("Chat"," : Broadcast ping echo, waiting %.1f sec" % delay) time.sleep(delay) elif frame.d_station != self._sm.station: return # Not for us frame.d_station = frame.s_station frame.type = self.T_PNG_ERS self._sm.outgoing(self, frame) self._emit("ping-response", frame.s_station, frame.d_station, "%s %i %s" % (_("Echo of"), len(frame.data), _("bytes"))) elif frame.type == self.T_PNG_ERS: self._emit("ping-response", frame.s_station, frame.d_station, "%s %i %s" % (_("Echo of"), len(frame.data), _("bytes"))) if frame.s_station in self.__ping_handlers: cb, data = self.__ping_handlers[frame.s_station] try: cb(*data) except Exception: printlog("Chat"," : Exception while running ping callback") utils.log_exception() elif frame.type == self.T_STATUS: try: s = int(frame.data[0]) except Exception: printlog("Chat"," : Unable to parse station status: %s" % {frame.s_station : frame.data}) s = 0 self._emit("station-status", frame.s_station, s, frame.data[1:])
def __repeat(self, transport, frame): if frame.d_station == "!": return if frame.s_station == frame.d_station == "CQCQCQ" and \ frame.session == 1 and \ frame.data.startswith("$") and \ self.__should_repeat_gps(transport, frame): for s in self.gps_sockets: s.send(frame.data) srcinfo = self.calls.get(frame.s_station, None) if srcinfo is None and frame.s_station != "CQCQCQ": printlog("Repeater : Adding new station %s to port %s" % (frame.s_station, transport)) self.calls[frame.s_station] = CallInfo(frame.s_station, transport) elif srcinfo: if srcinfo.last_transport() != transport: printlog("Repeater : Station %s moved to port %s" % (frame.s_station, transport)) srcinfo.just_heard(transport) dstinfo = self.calls.get(frame.d_station, None) if dstinfo is not None: if not dstinfo.last_transport().enabled: printlog("Repeater : Last transport for %s is dead" % frame.d_station) elif dstinfo.last_heard() < self.__call_timeout: printlog("Repeater : Delivering frame to %s at %s" % (frame.d_station, dstinfo.last_transport())) dstinfo.last_transport().send_frame(frame.get_copy()) return else: printlog("Repeater : Last port for %s was %i sec ago (>%i sec)" % \ (frame.d_station, dstinfo.last_heard(), self.__call_timeout)) printlog("Repeater : Repeating frame to %s on all ports" % frame.d_station) for path in self.paths[:]: if path == transport: continue if not path.enabled: printlog("Repeater : Found a stale path, removing...") path.disable() self.paths.remove(path) else: path.send_frame(frame.get_copy())