Home > AIR, Actionscript, Source > mDNS daap announce AIR 2.0

mDNS daap announce AIR 2.0

June 30th, 2010

This morning I woke up with the need to try something new.
Never had the time to play with the new AIR 2.0 features or most of the new FP 10.1 features.
So I had to create something that is useful (for me at least) and uses some (in this case just one :P ) new feature of AIR 2.0.
This nice new class is called DatagramSocket. With this class you can send UDP packages... wait... UDP :D

To make a long story short... I've read some RFC pages (not the whole document) about mDNS and used wireshark to analyze some mDNS packages.
The result is a class which you can use to announce a daap share in your local network.
For me this is very handy because I now can listen to my home iTunes at any location.

The class:

 
package nl.debit.net.bonjour
{
	import flash.events.TimerEvent;
	import flash.net.DatagramSocket;
	import flash.utils.ByteArray;
	import flash.utils.Timer;
 
	public class DaapAnnouncer
	{
		private var _aSocket:DatagramSocket;
		private var _ip:String;
		private var _port:int;
		private var _ttl:int;
 
		private var _name:String;
		private var _timer:Timer;
 
		public function DaapAnnouncer(name:String, ip:String, port:int = 3689, ttl:int = 120)
		{
			_name = name;
			_ip = ip;
			_port = port;
			_ttl = ttl;
 
			init();
		}
 
		private function init():void
		{
			_aSocket = new DatagramSocket();
 
			_timer = new Timer((_ttl / 2) * 1000);
			_timer.addEventListener(TimerEvent.TIMER, sendAnnounceData);
			_timer.start();
			sendAnnounceData(null);
		}
 
		private function sendAnnounceData(event:TimerEvent):void
		{
			_aSocket.send(getAnnounceBytes(_ttl),0,0,"224.0.0.251",5353);
		}
 
		public function start():void
		{
			if(_timer.running)
				return;
 
			_timer.start();
			sendAnnounceData(null);
		}
 
		public function stop():void
		{
			_timer.stop();
			_aSocket.send(getAnnounceBytes(0),0,0,"224.0.0.251",5353);
		}
 
		public function dispose():void
		{
			stop();
			_timer.removeEventListener(TimerEvent.TIMER, sendAnnounceData);
			_timer = null;
			_aSocket = null;
		}
 
		private function getAnnounceBytes(ttl:int):ByteArray
		{
			var bytes:ByteArray = new ByteArray();
 
			bytes.writeShort(0x00); // Transaction ID: 0x0000
			bytes.writeShort(0x8400); // Flags
			bytes.writeShort(0x00); // Question
			bytes.writeShort(0x03); // Answer RRs
			bytes.writeShort(0x00); // Authority RRs
			bytes.writeShort(0x01); // Additional RRs
 
			writeString(bytes, _name + "._daap._tcp.local");
			bytes.writeByte(0x00);
 
			//SRV record
			bytes.writeShort(0x21); //Type
			bytes.writeByte(0x80); // FlushCache
			bytes.writeByte(0x01); // Class IN
			bytes.writeUnsignedInt(ttl); //Time to live
			bytes.writeShort(8 + _ip.length); //Data length
			bytes.writeShort(0x00); //priority
			bytes.writeShort(0x00); //weight
			bytes.writeShort(_port); //port
			writeString(bytes, _ip);
			bytes.writeByte(0x00); //end
 
			//TXT Record
			bytes.writeShort(0xC00C); //Name ^^^
			bytes.writeShort(0x10); //Type TXT
			bytes.writeByte(0x80); //Flush Cache
			bytes.writeByte(0x01); // Class IN
			bytes.writeUnsignedInt(ttl);//TTL
			bytes.writeShort(0x01); //Data length
			bytes.writeByte(0x00); //Data
 
			//PTR Record
			bytes.writeByte(0xC0);
			bytes.writeByte(0x0D + _name.length);
			bytes.writeShort(0x0C); //Type PTR
			bytes.writeByte(0x00); //Flush Cache
			bytes.writeByte(0x01); // Class IN
			bytes.writeUnsignedInt(ttl);//TTL
			bytes.writeShort(0x02); //Data length
			bytes.writeShort(0xC00C); //Data 
 
			//Additional Record
			bytes.writeShort(0xC00C); //Name ^^^
			bytes.writeShort(0x2F); //Type NSEC
			bytes.writeByte(0x80); //Flush Cache
			bytes.writeByte(0x01); // Class IN
			bytes.writeUnsignedInt(ttl); //TTL
			bytes.writeShort(0x09); //Data length
			bytes.writeShort(0xC00C); //Data Next domain name
			bytes.writeUnsignedInt(0x50000); //Dunno
			bytes.writeByte(0x80); // RR type TXT
			bytes.writeByte(0x00);
			bytes.writeByte(0x40); // RR type SRV
 
			return bytes;
		}
 
		private function writeString(bytes:ByteArray, string:String):void
		{
			var ar:Array = string.split(".");
			var len:int = ar.length;
 
			for (var i:int = 0; i < len; i++)
			{
				bytes.writeByte((ar[i] as String).length);
				bytes.writeUTFBytes(ar[i]);
			}
		}
	}
}
 

The code needs some cleaning but I think the idea is obvious.

A Simple AIR example: download

Bernard AIR, Actionscript, Source

  1. hakha
    November 29th, 2011 at 01:02 | #1

    great example!

    I’m currently trying to Broadcast simple mDNS/Zeroconf service.
    but dont have a clue when it comes to bytecode madness. I’ve tried to run wireshark on my mac. But not sure whats going on tho.

  1. No trackbacks yet.