from subprocess import Popen, PIPE from signal import alarm, signal, SIGALRM class Alarm(Exception): pass def handler(signum, frame): # map the signal to an exception raise Alarm def dnssd(params, pattern='local.', timeout=3): h = Popen('dns-sd %s' % params, shell=True, stdout=PIPE) # set up a timeout if timeout: signal(SIGALRM, handler) alarm(timeout) result = [] try: # readline will block when dns-sd enters its loop while True: line = h.stdout.readline() if pattern in line: result.append(line) except Alarm: h.kill() return result # grab all instances of _ipp._tcp services printers = map( lambda entry: entry.split('_ipp._tcp.')[1].strip(), dnssd('-B _ipp._tcp.', 'local.', 3) ) # tack on 'URF=none' to each service info entries = [] for p in printers: entries.extend(map( lambda record: (p.split("@")[0].split(' ')[0], record.strip() + ' URF=none'), dnssd('-L "%s" _ipp' % p, 'txtvers', 1) )) # now advertise the first entry (advertising more than one would require # something like multiprocessing.Pool() or just plain exec(), and I have # just the one printer...) dnssd('-R "%s AirPrint" _ipp._tcp,_universal local. 631 %s' % entries[0], timeout=0)