Commit 4eb0af89 authored by Bruno Laurencich's avatar Bruno Laurencich

modal working but crash on restart

parent 011e76d1
bl_info = {
"name": "Test_addon",
"category": "Object",
"name": "Chordata mocap",
"category": "Rigging",
}
# To support reload properly, try to access a package var,
# if it's there, reload everything
if "bpy" in locals():
import imp
# imp.reload(mysphere)
imp.reload(mdns)
else:
pass
from . import mdns
# pass
# from . import mysphere
from sys import path
from os.path import join, abspath, dirname
path.append(join(dirname(abspath(__file__)), "dnspython"))
from dns.resolver import Resolver
import bpy
import threading
class Chord_Get_Ip(bpy.types.Operator):
"""Tries to get the ip of the notochord"""
bl_idname = "chordata.get_ip"
bl_label = "Chordata: get notochord ip"
bl_options = {'REGISTER'}
def modal(self, context, event):
if event.type in {'RIGHTMOUSE', 'ESC'}:
self.cancel(context)
return {'CANCELLED'}
if event.type == 'TIMER':
if self.query_thread.is_alive():
print("ip query ongoing..")
else:
with self.query_lock:
print("IP found :", self.found_ip)
# self.cancel(context)
# return {'FINISHED'}
return {'PASS_THROUGH'}
def do_query(self):
print("query thread running")
ip = mdns.get_ip()
while not ip and mdns.timeout < 10:
mdns.set_timeout(mdns.timeout + 2)
print("*** new timeout ", mdns.timeout)
if mdns.timeout >= 10:
mdns.set_nameserver()
ip = mdns.get_ip()
with self.query_lock:
self.found_ip = ip
print("*** Thread terminating..")
return
class Zeroconf_Explore(bpy.types.Operator):
"""TODO Add description"""
bl_idname = "object.test_addon"
bl_label = "Test Addon"
bl_options = {'REGISTER', 'UNDO'}
def execute(self, context):
myRes=Resolver()
myRes.nameservers=['224.0.0.251'] #mdns multicast address
myRes.port=5353 #mdns port
a=myRes.query('raspberrypi.local','A')
print( "FOUND IP:)",a[0].to_text())
# print("test addon.")
wm = context.window_manager
self._timer = wm.event_timer_add(0.5, context.window)
wm.modal_handler_add(self)
print(mdns.myRes)
self.query_lock = threading.Lock()
self.found_ip = False
self.query_thread = threading.Thread(target=self.do_query,
name="mdns_query")
self.query_thread.start()
return {'FINISHED'}
def cancel(self, context):
wm = context.window_manager
wm.event_timer_remove(self._timer)
# print("waiting thread..")
# self.query_thread.join()
# print("thread joined..")
def register():
bpy.utils.register_class(Zeroconf_Explore)
bpy.utils.register_class(Chord_Get_Ip)
def unregister():
bpy.utils.unregister_class(Zeroconf_Explore)
bpy.utils.unregister_class(Chord_Get_Ip)
if __name__ == "__main__":
register()
register()
from sys import path
from os.path import join, abspath, dirname
path.append(join(dirname(abspath(__file__)), "dnspython"))
from dns.resolver import Resolver
from dns.exception import Timeout
#Naive mDNS resolution by "NameOfTheRose" working only on avahi running targets
#from https://stackoverflow.com/a/35853322
#(full answer containing a more complete yet NOT COMPILANT implementation at the end)
myRes=Resolver()
myRes.nameservers=['224.0.0.252'] #mdns multicast address
myRes.port=5353 #mdns port
timeout = myRes.lifetime
def set_timeout(time = 3):
global myRes
global timeout
timeout = time
myRes.timeout = time
myRes.lifetime = time
set_timeout()
def set_nameserver(name = '224.0.0.251', port=5353):
global myRes
# if name not in myRes.nameservers:
# myRes.nameservers.append(name)
myRes.nameservers = [name]
myRes.port = port
def query(host = 'raspberrypi.local', field = "A"):
return myRes.query(host,field)
def get_ip(host = 'raspberrypi.local'):
try:
return query(host)[0].to_text()
except Timeout as e:
print(e)
return False
except Exception as e:
print(e)
return False
# This code works when the target computer runs avahi, but fails when the target runs python zeroconf or the esp8266 mdns implementation. Interestingly Linux systems running avahi successfully resolve such targets (avahi apparently implementing nssswitch.conf mdns plugin and being a fuller implementation of the mdns protocol)
# In case of a naive mdns responder which, contrary to the rfc, sends its response via the mdns port, the following code (run on linux and windows and resolving linux avahi, hp printer and esp8266 targets) works for me: (and is also non-compliant as it uses the MDNS port to send the query while it is obviously NOT a full implementation)
# ```
# import socket
# import struct
# import dpkt, dpkt.dns
# UDP_IP="0.0.0.0"
# UDP_PORT=5353
# MCAST_GRP = '224.0.0.251'
# sock = socket.socket( socket.AF_INET, socket.SOCK_DGRAM )
# sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
# sock.bind( (UDP_IP,UDP_PORT) )
# #join the multicast group
# mreq = struct.pack("4sl", socket.inet_aton(MCAST_GRP), socket.INADDR_ANY)
# sock.setsockopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP, mreq)
# for host in ['esp01','microknoppix','pvknoppix','hprinter'][::-1]:
# # the string in the following statement is an empty query packet
# dns = dpkt.dns.DNS('\x00\x00\x01\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x01')
# dns.qd[0].name=host+'.local'
# sock.sendto(dns.pack(),(MCAST_GRP,UDP_PORT))
# sock.settimeout(5)
# while True:
# try:
# m=sock.recvfrom( 1024 );#print '%r'%m[0],m[1]
# dns = dpkt.dns.DNS(m[0])
# if len(dns.qd)>0:print dns.__repr__(),dns.qd[0].name
# if len(dns.an)>0 and dns.an[0].type == dpkt.dns.DNS_A:print dns.__repr__(),dns.an[0].name,socket.inet_ntoa(dns.an[0].rdata)
# except socket.timeout:
# break
# #DNS(qd=[Q(name='hprinter.local')]) hprinter.local
# #DNS(qd=[Q(name='pvknoppix.local')]) pvknoppix.local
# #DNS(qd=[Q(name='microknoppix.local')]) microknoppix.local
# #DNS(qd=[Q(name='esp01.local')]) esp01.local
# #DNS(an=[RR(name='esp01.local', rdata='\n\x00\x00\x04', ttl=120, cls=32769)], op=33792) esp01.local 10.0.0.4
# #DNS(an=[RR(name='PVknoppix.local', rdata='\n\x00\x00\xc2', ttl=120, cls=32769)], op=33792) PVknoppix.local 10.0.0.194
# ```
# The empty dns object was created in the above code by passing the constructor a string collected from the network using
# ```
# m0=sock.recvfrom( 1024 );print '%r'%m0[0]
# #'\xf6\xe8\x01\x00\x00\x01\x00\x00\x00\x00\x00\x00\x05esp01\x05local\x00\x00\x01\x00\x01'
# ```
# This query was produced by nslookup so its id was non-zero (in this case \xf6\xe8) trying to resolve esp01.local. An dns object containing an empty query was then created by:
# ```
# dns = dpkt.dns.DNS(m0[0])
# dns.id=0
# dns.qd[0].name=''
# print '%r'%dns.pack()
# #'\x00\x00\x01\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x01'
# ```
# The same result could also be created by:
# ```
# dns=dpkt.dns.DNS(qd=[dpkt.dns.DNS.Q(name='')])
# ```
# The dns object could also be created with non-empty query:
# ```
# dns=dpkt.dns.DNS(qd=[dpkt.dns.DNS.Q(name='esp01.local')])
# ```
# or even with multiple queries:
# ```
# dns=dpkt.dns.DNS(qd=[dpkt.dns.DNS.Q(name='esp01.local'),dpkt.dns.DNS.Q(name='esp02.local')])
# ```
# but minimal responders may fail to handle dns messages containing multiple queries
# I am also unhappy with the python zeroconf documentation. From a casual reading of the code and packet monitoring using tcpdump, it seems that (when the registration example is running) zeroconf will respond to address queries but nslookup ignores (or does not receive) the answer.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment