Apple Bonjour for .Net Core (Part 2)

In part 1, I wrote a simple Core console app that could log the multicast requests it received. Running the simple Bonjour Browser utility, I could see this being logged

The lines  _services_dns-sd seems to indicate some sort of services request being made, which made sense, given that Bonjour’s purpose for existing is to advertise services on a network. A quick Google for _services_dns-sd lead me to this Apple article https://developer.apple.com/library/content/qa/qa1337/_index.html.

This confirmed my hunch.

 Devices running mDNSResponder-58.6 (Mac OS X 10.3.4) or later will respond to the “Service Type Enumeration” meta-query described in Section 10 of the DNS-SD specification. Issuing a Multicast DNS PTR record query for the name “_services._dns-sd._udp.local.” will return a list of service types being advertised on the local network.

Aside from the full stops being displayed as question mark characters, this looked pretty sensible.

First order of business was to actually parse the byte[] into its parts and display them. Back to RFC 6762.

Section 18 talks about the message format, but deals a lot in bits, rather than bytes. To help me understand the values a bit better, I decided to write each request out as bits.

I got something like this (each byte in its own line)

00000000
00000000
00000000
00000000
00000000
00000001
00000000
00000000
00000000
00000000
00000000
00000000
00001001
01011111
01110011
01100101
01110010
01110110
01101001
01100011
01100101
01110011
00000111
01011111
01100100
01101110
01110011
00101101
01110011
01100100
00000100
01011111
01110101
01100100
01110000
00000101
01101100
01101111
01100011
01100001
01101100
00000000
00000000
00001100
00000000
00000001

I started by trying to compare each part to the corresponding bit outline in the RFC. Nothing matched, so I went back to Google and found this piece on Wikipedia (https://en.wikipedia.org/wiki/Multicast_DNS). A quick read and the first example looked like that I wanted.

00 00 Transaction ID
00 00 Flags
00 01 Number of questions
00 00 Number of answers
00 00 Number of authority resource records
00 00 Number of additional resource records
07 61 70 70 6c 65 74 76 “appletv”
05 6c 6f 63 61 6c “local”
00 Terminator
00 01 Type (A record)
00 01 Class

To confirm, I went back to my C# and modified it to show the data in a similar shape.

Working with the first 12 bytes, I saw this in the console’s output

00 00
00 00
00 01
00 00
00 00
00 00

This looked identical to the example in Wikipedia. I then went about look for the null terminator. After some tricking around I ended up with this

00 00 Transaction ID
00 00 Flags
00 01 Number of questions
00 00 Number of answers
00 00 Number of authority resource records
00 00 Number of additional resource records
09 5F 73 65 72 76 69 63 65 73 07 5F 64 6E 73 2D 73 64 04 5F 75 64 70 05 6C 6F 63 61 6C _services_dns-sd_udplocal
00 Terminator
00 0C Type
00 01 Class

This is a near perfect match to the Wikipedia entry. The primary difference is the “Type” value (and the actual request content (_services_dns instead of appletv.local)

Type value of 0x0C is obviously different, so I hit Google again and found this lovely Microsoft article. https://docs.microsoft.com/en-us/previous-versions/windows/it-pro/windows-server-2008-R2-and-2008/dd197470(v=ws.10)

It explains the various parts of the request/response and the 0C type is a PTR request. This seems appropriate for DNS service discovery! Huzzah.

Next step is to now respond with some data, probably in the form of a TXT record.

 

Apple Bonjour for .Net Core

As part of my work on building a .Net implementation of Apple Homekit protocol, I want to have it run on a Raspberry Pi. My plan is to accomplish this using Windows 10 for IoT. This is basically a cut down version of Windows 10, designed to run .Net Core and UWP apps. I haven’t really explored it very much, but it seems to suit my needs. I can deploy my Homekit service and put the Raspberry Pi in the cupboard.

The first piece of functionality I need for my Homekit implementation is the broadcasting of the accessories using Bonjour. Bonjour is apple’s zero configuration protocol implementation. It is available on Windows, via Apple’s SDK, but unfortunately, it’s a COM component, so running it on Raspberry Pi is a non-starter. I searched around on the internet for a few hours and discovered, to my immense disappointment, that there are no Nuget packages for advertising services over Bonjour. Lots of ones for browsing and searching, but none for advertising.

These kind of situations, whilst annoying, do provide an opportunity to learn something new. What would it take to create a simple implementation of Bonjour that would run on .Net Core, on a Raspberry Pi. Let’s find out 🙂

To get the ball rolling, I created a .Net Core console application in Visual Studio. This doesn’t achieve anything in and of itself, but makes me feel like I’m making progress 🙂

A read through a few articles on Bonjour;

and I was ready to start. General searching around the web, led me to RFC-6762 (https://tools.ietf.org/html/rfc6762), which describes Multicast DNS or mDNS. This is used by Bonjour. I do love a good RFC.

After reading the first few pages, I established the following facts; mDNS, in essence, works by resolving .local addresses e.g. computer.local or hap.local. It does this by sending requests over multicast to the group 224.0.0.251 on the port 5353. I had come across the multicast technology (my router didn’t support it) a few years ago, so I was familiar with the main concepts.

Converting this into code, I came up with

public void Start()
{
 try
 {
 UdpClient udpClient = new UdpClient();

udpClient.ExclusiveAddressUse = false;
 IPEndPoint localEndpoint = new IPEndPoint(IPAddress.Any, 5353);

udpClient.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
 udpClient.ExclusiveAddressUse = false;

udpClient.Client.Bind(localEndpoint);

IPAddress multicastaddress = IPAddress.Parse("224.0.0.251");
 udpClient.JoinMulticastGroup(multicastaddress);

while (true)
 {
 Byte[] data = udpClient.Receive(ref localEndpoint);
 string dataAsString = Encoding.UTF8.GetString(data);
 Console.WriteLine(dataAsString);
 }
 }
 catch (Exception exp)
 {
 Console.WriteLine(exp.Message);
 }
 }

This code essentially listens on port 5353 for broadcasts to the group 224.0.0.251.

When I fire up the console app, I just see this

Console

Not much to see. In order to generate some Bonjour traffic, I use an app called Bonjour Browser

I launch this and again, I don’t see much:

Bonjour

However, a few lines appear in my console app:

Console with data

Right now I don’t have a clue what these are, but I can see what might be dns requests.

More detail to follow!

 

Rebuilding CommuterPal with Azure Functions and CosmosDB

A few years ago I built an iOS called Commuter Pal. I never actually launched the app, since I tried to do *way* too much in terms of route planning and intelligent alerting. Since I didn’t actually commute myself, it was not something I could field test.

Fast forward to 2017 and I’ve been commuting for about six months now. I’ve tried a few different apps to help keep me ahead of delays, but most of the apps are aimed at the entire network and have loads of bells and whistles, so I gave up using them as they just didn’t help. Most of the time I’m already on the platform before I learn of a signal failure or ill passenger.

To coincide with the fact I’ve started wearing my Apple Watch again, I’ve decided to try and bring Commuter Pal back to life with a more simple goal; a watch complication that tells me if my route is clear or blocked.

My choice of tech is predictable – iOS (Objective-C) and .Net. This time, instead of my usual WebAPI approach, I’m going to try and build the whole thing with CosmosDB and Azure Functions. I’m not really sure how it will work, but I think that all phone interactions can be powered by HTTP bound Functions and calls to TFL for updates can be done using Timer based Functions. Throw in a queue here or there and an Azure Notification hub and we should be in business.

I’ll try and document the process as I go along.

If you’re an iOS user and commute using the London Underground, I’ll be making this app available for beta testing, so if you’re interested in taking a look, let me know!

Roomr 4.1 – Search has arrived!

I’ve just submitted Roomr 4.1 to the App Store for approval. This version brings my first attempt at a search feature.

A few weeks back I was contacted by a user in the Netherlands, who wanted to use Roomr to improve the way they booking parking spaces at their company. They had an existing Exchange installation that used individual calendars for individual parking spaces. The then grouped this parking spaces into buildings using Room Lists. They found that searching and booking was quite difficult from Outlook.

Search was something that has been on the Roomr roadmap for quite some time, but I never got around to implementing it, simply because Exchange’s API don’t really allow for a general search. However,  with this request focused on Room Lists, I had a very clear requirement to work with.

After a few rounds of beta testing, I’m pleased to report that I have submitted Roomr 4.1 to Apple!

Simulator Screen Shot 23 Mar 2017, 13.23.24

This search UI allows you to choose a Room List, date and a time range. All the rooms contained with the Room List are checked for availability. Once a match is found, the user can choose one of the rooms and open its calendar. As a shortcut, the date & time they searched for will be displayed within the calendar.

Simulator Screen Shot 23 Mar 2017, 14.59.38.

Booking then works as normal.

This Search feature is also available with G Suite, so Google users haven’t been left out. It obviously doesn’t rely on Room Lists. Instead, all rooms with the domain’s Resources are searched to see if they are free at the specified time.

Roomr 4.1 should be available to buy from the App Store in the next couple of days.

Azure Functions and ServiceBus gotcha

Okay, so this might not be a gotcha, but I lost an hour early this morning trying to diagnose a problem with an Azure Function I’m writing. I’m using ServiceBus triggers and outputs to form a processing pipeline using the functions. One function reads the messages on a queue and then puts another message on a queue for another function to handle.

I was getting this non descriptive error when running locally.

error

After much experimentation I realised that the ServiceBus queue in the function.json must actually exist 🙂 For some reason I assumed the host would create them as required! Anyway.

Might be of use to somebody else.

Roomr 4.0 is out and on sale!

To celebrate the release of Roomr 4.0 on iOS, I’ve decided to drop the price to $0.99 (£0.79) from now, until the 14th of May.

Roomr 4 includes some improvements and new features.

  • The UI has been updated so it’s cleaner and better organised.
  • It’s now possible to browse the Address Lists (if you’re using Exchange 2013 or Office365).
  • You can now search Global Address List.
  • When creating bookings, you can invite people to the meetings.
  • Browsing is now unlocked in the free version, so it’s easier to evaluate.
  • When you’re looking at a shared calendar, you can view the details of appointments.
  • Fixed lots of bugs around AutoDiscovery for Office365 and Exchange Online

In addition to adding features, I’ve also removed some. MobileIron AppConnect integration is no longer present and MDM configuration is no longer supported either. These two features were added to help make a sale to a large enterprise, which, unfortunately, never came to fruition.

The free version of Roomr now allows booking and browsing, without needing to upgrade. I hope these changes will make it easier for users to evaluate Roomr. The limit of one favourite will remain in place and QR scanning will still require the Pro version. The new Invitees feature in booking will also require the Pro upgrade.

I hope you will download it and try it out. If you’re already a Roomr user, I hope you like these changes!

You can download the free version of Roomr from here https://itunes.apple.com/us/app/roomr-check-meeting-room-availability/id722842404?ls=1&mt=8.  This version offers an In-App purchase

You can download the Pro version from here https://itunes.apple.com/us/app/roomr-pro-check-meeting-room/id929725634?ls=1&mt=8

Back to basics

Tempus Fugit. As a developer, one of the things that causes me to stress the most, is a simple lack of time.

I have so many ideas (mostly useless) floating around in my head that I would like to turn into reality. I have three apps in the App Store, which I don’t really update. I also have a day job.

Faced with so many things to do, I really struggle to focus. I can lock in on something for a week or two, but a customer email will arrive, or a new idea will pop into my head, and my priorities change, leaving something half done.

This excellent Commit Strip is basically my product range – http://www.commitstrip.com/en/2014/11/25/west-side-project-story/

Strip-Side-project-650-finalenglish

My iOS app, Roomr, is a good example of this.

What started out as a simple app for viewing the availablility of meeting rooms morphed into something more complicated, but which wasn’t *more* useful. I kept reacting to user’s feature requests, without keeping an eye on the growing complexity. Complexity, I said to myself, is natural as a product evolves.

Roomr doesn’t make much money. I’ve sold a few thousand units over the years, which I’m very thankful for, but it’s never actually been worth my time. Rather than maintaining that app, I’d have been better building an app for somebody else and getting paid.

It took me a long time to accept this simple truth.

Uncontrolled feature creep is the biggest issue I face.

I recently had a user state, in an email, that if I added feature X, they’d buy ten units of the app. I knew it would take me 20+ hours to implement this and that ten sales hardly covered 1/2 an hour of my time, but I went ahead anyway, knowing full well, that I’d probably never see a return on this investment. I justified it by saying “if I add feature X, more people will buy it”.

The fact of the matter is, it won’t make a blind bit of difference. I’ve had this request from two or three other users in the past three years.

Another justification for adding complexity is that by adding feature X, a large company will buy many, many licenses i.e. £££ for me. Again, reailty has taught me otherwise. I’ve had large multinationals inquire about the app and large scale deployments, but none of them ever made a purchase, despite many changes. An app with just one developer behind it, presents too much risk for companies, which I understand.

I’ve come to realise that, when you’re on your own building apps, simplicity is probably best. My iOS apps, Roomr and Peopler started with a very narrow focus on doing one thing and doing it well. Somewhere along the road, I lost focus on that. Sure, it was fun and interesting working on the complex stuff, but in the end, I think my nerves and customers, suffered.

I had planned on Roomr 4.0 being more complex than the previous versions, but I think it’s time to start ripping stuff out and making the app more focused than before. I’m also going to try ad support. If I can generate more revenue, it will be easier for me to update the apps.

This will, I suspect, upset some existing customers, but I would rather try a new approach, then kill the app off completely.

Roomr 4.0–Inviting people

My work on Roomr 4.0 continues! One of the most requested features when creating meetings is the ability to invite other people.

Starting with Roomr 4.0, this will now be possible. The UI is still evolving, but here is an early look.

Simulator Screen Shot 6 Apr 2016, 10.01.08

You just type the name of person you want to invite to the meeting and Roomr will search Exchange for any matches. You can select multiple people to invite and the UI is similar to the iOS native calendar, so it should be pretty easy to use.

It’s a work in progress, but if you’d like to try Roomr 4.0 whilst it’s in beta, please drop me an email (tomas@coldbear.co.uk) or message me on Twitter (@tomasmcguinness)

Roomr 4.0, the first beta

This morning I submitted the first build of Roomr 4.0 to Apple for Beta Testing.

I know it has only been three months since I released 3.0, but I’ve decided that since I’ll adding two or three large new features, that 4.0 seemed more appropriate.

So what is coming in 4.0?

With Roomr, there have been a few consistent feature requests.

  1. Browse all the rooms like I do in Outlook.
  2. Invite people to meetings.
  3. View the details of a meeting.

I’ve resisted implementing some of these (2 & 3) because I felt they were in keeping with the spirit of the app.  Request 1 was due to sheer complexity. Roomr uses Exchange Web Services for availability, but this doesn’t offer any access to the Address Book within Exchange.

Browse all the things!

After pushing back, I decided to roll up my sleeves and try to tackle request 1. Lots of people had written to me asking why they couldn’t browse rooms. When I explained that you could using Exchange Room Lists, I was met with blank stares and comments like “My IT guys won’t do that”. I took the stance of “sorry, but hard cheese”.

On reflection, this wasn’t the best idea I ever had.

You see, Browse required an upgrade to Pro or the purchase of the Pro version.

You can imagine that a lot of people were quite pissed off that, having upgraded, they still couldn’t browse. I’ve seen quite a few refunds issued because of this. I mean, I don’t blame people, in spite of the fact it was clearly stated in the description of the app that Room Lists were required. People see it work in one bit of software and expect it to work like that everywhere.

I rolled up my sleeves.

Exchange implements a protocol named MAPI. This, traditionally, is accessed using RPC. RPC is hard and really low level (we’re talking TCP streams).  I wrote RPC implementations in C back in 2002, so I was no stranger to it.

Thankfully, Microsoft have “upgraded” this over time, offering RPC over HTTP. I read the specification. Twice. And decided that wasn’t going to happen anytime soon. With Exchange 2013, Microsoft added MAPI over HTTP. Not exactly JSON based, but doable. It was still binary, just blobs of bytes sent over HTTP, which, in reality, is no different from a JSON based request. Old School.

I read the docs and set about building an implementation in C# that used lots and lots of Byte[]. After lots of short bursts of work spanning a few weeks, I got it working. I then ported it to Objective-C and, after more trickery, I got it working with Roomr.

Simulator Screen Shot 29 Mar 2016, 09.31.04

This screen shot shows the updated Browse view, where you can see the All Rooms address list and the Room Lists.

Expanding the All Rooms list shows all the meeting rooms within Exchange.

Simulator Screen Shot 29 Mar 2016, 09.31.09

I’m pretty proud of myself right now.

I hope this will make Roomr much more useful to people, since they won’t be replying on their IT guys to create and maintain Room Lists. I also hope it’s more accessible.

I’m planning on making Browse “free”, so it won’t require the upgrade.  I hope this will encourage more use and by making other features premium ones, such as booking and opening appointments, I’ll encourage more conversions.

I will only know if I try.

If you’d like get an early look at Roomr 4.0, please get in touch and I’ll invite you to the Beta. This

This stuff is all quite new, so the more instances of Exchange it is tested against, the better.

Thanks for reading,

Tom

PS I’ll be writing up a post on how I got MAPI over HTTP working. I’m sure about four people in the world will find it interesting, but it’s been an experience trawling through 9 different PDFs and reading hex code Smile