In developing a RESTful API for IDA >= 7.5 [https://github.com/sfinktah/idarest75], I have observed that a standard threaded webserver does not release it's socket when IDA terminates, unless it is run as a plugin. This behaviour may extend to all threading, I have not tested.
If the code below is simply loaded as a script (or pasted into the CLI) it will actually cause IDA to invisibly hang when IDA is exited, i.e. IDA appears to close but can actually found to be still running in Task Explorer -> Details.
Is there perhaps an IDA-specific
atexit analog, as the builtin Python version certainly does not help.
Whilst the finished project is capable of running either as a plugin or a stand-alone script, the lack of any way to unload a python plugin requires keeping a reference to the class instance in order to call
.term(), which is contra-indicated if one actually expects destruction to occur correctly.
Sample code (paste, exit IDA, observe running tasks).
def ida_issue(): from http.server import BaseHTTPRequestHandler, HTTPServer from socketserver import ThreadingMixIn import threading class Handler(BaseHTTPRequestHandler): def do_GET(self): self.send_response(200) self.end_headers() class ThreadedHTTPServer(ThreadingMixIn, HTTPServer): allow_reuse_address = True class Worker(threading.Thread): def __init__(self, host, port): threading.Thread.__init__(self) self.httpd = ThreadedHTTPServer((host, port), Handler) self.host = host self.port = port def run(self): self.httpd.serve_forever() def stop(self): self.httpd.shutdown() self.httpd.server_close() class Master: def __init__(self): self.worker = Worker('127.0.0.1', 28612) self.worker.start() def main(): master = Master() return master return main() server = ida_issue()
How to re/unload [co-operative] IDAPython plugins.
class idarest_plugin_t(IdaRestConfiguration, ida_idaapi.plugin_t): flags = ida_idaapi.PLUGIN_UNL def run(self, *args): pass def reload_idarest(): l = ida_loader.load_plugin(sys.modules['__plugins__idarest_plugin'].__file__) ida_load.run_plugin(l, 0) # pip install exectools (or ida_idaapi.require would probably suffice) unload('idarest_plugin') # reload plugin (or not) l = ida_loader.load_plugin(sys.modules['__plugins__idarest_plugin'].__file__)