Wednesday, May 30, 2018

Restarting an AirPort via AppleScript

Apples airports are great devices, but like so many “appliances” they need a restart once in a while. Apple has the newer models pretty well locked down. There is no web interface, nothing you can hit with a curl command and no SNMP or anything else to talk to to tell it to restart itself.

After I lost my entire wifi network the other day and I had to restart it manually I decided it was time to tackle the AirPort Utility via User Interface Scripting. It turns out you can do this, sort of... There are either bugs in the AirPort utility and it’s implementation of user interface scripting, even though you’re not supposed to have to implement it, it’s just there because of the OS, or there are some limitations to it that aren’t clearly documented.

The applescript to restart an airport is pretty simple actually, this handler will do it, sometimes:

on restartAirportByName(theName)
tell application "System Events"
tell process "AirPort Utility"
click (first image of group 1 of scroll area 1 of window 1 where its name starts with theName)
click menu item "Restart…" of menu "Base Station" of menu bar 1
end tell
end tell

end restartAirportByName

Note that handler doesn’t actually launch the AirPort Utility first, You should do something like:

launch application “AirPort Utility”
delay( 5)

Before calling that.

There are some gotchas right away, the ellipsis in the Restart menu item name is a UTF8 ellipsis character and not just three periods. If you use three periods it won’t be able to find the menu to click.

It won’t work if the application is hidden or the main window minimized. It does not have to be frontmost, but it cannot be hidden in any way.

The name of the “process” is case sensitive. It must have the same case as the actual application in order to match, even though much else of AppleScript is not case sensitive this is. It must be “AirPort Utility” or it won’t work.

Next the script or the host of the script must have assistive access turned on in order to use the UI scripting at all. You have to do that in the System Preferences, Privacy & Security pane under Assistive Access. This will also break if you are saving the script as an application and make any edits to it. You must go in and uncheck and recheck the checkbox next to the application you created or it will know that you changed it and won’t let it access the UI. Again, you don’t get the helpful error message that you’d get if you hadn’t added it to the list at all telling you that assistive access is not enabled for this program, it just fails to be able to do anything.

Beyond that there is something weird about how AirPort Utility processes the event, or there is a limitation for processes not specifically started by a user which may be the case. I would expect those to generate an error specifically telling you that you don’t have privs. Sometimes, or all the time depending on the OS version you get an error about a bad index when trying to get a reference to window 1. I’ve tried accessing the window by name and several other hacky work arounds but it doesn’t seem to matter. If you run the script from a program that has assistive access turned on, but wasn’t launched by the user you’ll definitely get this error at least once, and then it might start working for the second time. Or it might not.

In my testing the best solution is to embed that bit of script into an applescript saved as an application. Then you can give it privs to use assistive access and just launch it, or use some other system to launch the app. That seems to work. At least on OSX 10.13. There still seem to be problems doing these things on 10.12.

I’ve wrapped that and a whole lot more scanning and checking code including the ability to monitor your internet connection and get your external IP address into a larger script that talks to my home automation software of choice XTension (well it should be my choice as I’m one of the developers) which will definitely be useful for other XTension users as long as they are running an OS version that includes a less buggy AirPort Utility. That code is free and open and if you are interested in how to get the rest of that info out of it it’s also fully documented with comments in the code here.

Tuesday, May 22, 2018

A fix for Stupidly Slow VNC performance on the Mac

On and off I’ve had a problem with my house server where the remote desktop or VNC connection was just so slow that it was almost unusable. I normally load test versions of XTension by dragging them and dropping them onto the VNC window. This was also excruciatingly slow. Like 200k a second slow rather than the 60 or 70 megs a second I would expect.

I’ve spent months fighting with it, restarting seems to help for a few minutes but it comes right back. I’ve run new ethernet cables, I’ve tried plugging directly into the switch. Of course it never occurred to me to test other throughput to the server. Connecting over regular SMB file sharing to it results in more than 70 meg a second throughput. So it had to be something with VNC.

Just gazing at my system logs the other day I watched 3 or 4 zombied windows machines trying to log into my VNC server as it’s exposed to the internet. I have the ports for VNC passed through my router so I can log in remotely if I ever needed to. They are just running through the list of most common passwords and dictionary words hoping that my password is just “secret” and I’ve just ignored them up until now.

Just as a test I turned the VNC passthrough off on my router and guess what? I can now VNC like I could before and I can get 70meg a second throughput when dragging large files onto the VNC window! It was truly awful to try to type in an edit script window on the machine remotely, but now it’s wonderful again.

It seems that a failed password attempt causes the VNC server to hang up for a fraction of a second. Multiply that by 2 or 3 attempts a second from different infected windows machines and it comes to a screeching halt.

For myself I’ll just leave those passthroughs off unless I specifically think I’m going to need them. Moving your VNC install to a higher random port would solve the problem from just the hacked windows machines as they won’t bother to do a full port scan on your machine, but it won’t protect you from someone targeting you specifically as they will do a port scan and find it no matter where you put it. It would definitely help though.

OSX is supposed to have an adaptive firewall that you can turn on that watches the log files for those failed password attempts and if someone has more than a certain number it will temporarily block them. I can’t get this to actually work on my machine though. Much info out there suggests that this is broken on OSX but I will experiment further with it.

Saturday, January 6, 2018

Copper Veneer Is Beautiful

I am in the middle of a project building floor to ceiling bookshelves across one wall of our living room. It’s a rather larger project than I normally take on and has provided many unique and stimulating challenges both in design and fabrication... We decided on a gentle arch at the top of each book case and in order for them not to look ordinary and drab I’m experimenting with some antiqued copper veneers that I got from Veneer The same place I got the wonderful dark burl I used to make our Veneered Mantle. I chickened out and didn’t buy any of the really weird and wonderful copper patinas available, but opted for a sheet of just the antiqued stuff to experiment with.  this stuff is beautiful.

This is just a test run to hang one up so that She Who Must Be Obeyed can get a feel for it and make sure that it’s what she wants before I commit to making a dozen of these things. There are only 6 bookshelves, but there will be an arch at the top section, and an arch below the library ladder rail 8 feet up. With each part of this project I keep thinking that won’t be a lot of extra work, and then I remember that oh, there are six bookshelves so I have to do it six times. And then with these I have to make twice that number. But it will be worth it, these look fantastic.

Now if only I could make the stain on the routed edge look a bit more even. I will have to sand that a lot more aggressively to smooth out the wood before applying the stain on the real ones.

Dont worry about the slightly funky edges. I made it an inch or so wider than it needs to be and will trim those off to perfection on the table saw before putting it into place.

Friday, January 5, 2018

High Sierra hangs your main thread when the screen is asleep!

Thanks to Ben Bird of bensoftware and SecuritySpy fame I was able to work around the problem in High Sierra. If any Mac users are interested in really good DVR software I can whole heartedly recommend his Security Spy app. It works great with XTension and we even have an interface that will let you get motion data out of the program and assigned to units in XTension for taking other actions based on that.

The problem is evident in Mac OS version 10.13.2 and may actually have been introduced in the .2 update as I don’t recall having this problem immediately upon my updating to High Sierra but only more recently. I could be completely wrong about that though.

It turns out it has nothing to do with App Nap at all, I was barking up the wrong tree about that completely. It’s a rather nasty bug in some of Apple's screen drawing code. If you have an app that has an interface and it causes interface elements to update once the screen goes to sleep High Sierra will eventually just hang. Something causes a thread contention with the screen drawing. This might not be a big problem for most user apps as if the screen is asleep then you’re not using them. They will wake up along with the screen as soon as you touch the computer again. For an app that needs to keep doing things while you’re not there like XTension does this is tragic.

My first attempt at a fix was not successful. You can subscribe to events to tell you when the screen is put to sleep or woken up. In the event where the screen is going to sleep I hid all my open windows and in the event waking up the screen I showed them again. This was not enough to stop the thread contention issue. Possibly even drawing the menu is enough to cause the problem. I am not able to disable all the drawing in the app as far as I know. Though there are calls for windows to defer updates. There may be a Cocoa way to disable all screen drawing and I’ll have a look at that later. The pressure is off right now because I was able to get it working with a background helper app to check for the the main thread hanging in the app.

Ben had suggested a thread that pinged or otherwise checked on the regular spinning of the apps main thread. I tried this, but since I’m working in Xojo I’m limited to cooperative threads. If you block the main thread in a Xojo app you also block any other threads. Which is important to know if you’re working with threads and using semaphores to manage access to resources between the threads and the main thread. So I wasn’t very confident that the pinging thread would be effective since I expected that thread to get hung as well. That was indeed the case, the second thread stopped as well and so was never able to wake the screen.

The solution, hopefully temporary until Apple fixes this, was to create a separate terminal app to do the waking of the screen. Since command line apps have no GUI they aren’t affected by the problem. The background app just listens for a single character to arrive via STDIN. If it doesn’t get one from the main app at least every 5 seconds it makes a call to the Power Manager to assert a User Activity. Using the MBS plugins for Xojo this is easy, but I suspect it could fairly easily be done with a declare or external method call to the right library.  To wake the screen I just did this:

Dim userActivityID as integer

Dim err As Integer = IOPMAssertionMBS.DeclareUserActivity( "waking screen for thread contention", IOPMAssertionMBS.kIOPMUserActiveLocal, userActivityID)
You’re supposed to keep that userActivityID around and re-use it for any previous calls, so don’t just reset it to 0 each time you make this call. Though I’m not sure if thats really necessary.

The terminal app is copied into XTension’s resources folder during compilation and I’ve created an interactive shell class in XTension that is very simple. It just launches the app and starts a timer that sends a “P” to the shells stdin every second. Since timers fire on the main thread they are all silenced by the thread contention issue and so it stops sending that ping. 5 seconds later the screen wakes up and all starts working again. If I set the timing to much less than 5 seconds then I seem to get a lot of wakeups for slightly longer program operations like regular database saves and such. The 5 seconds seems a good compromise between having it hang all the time and just keeping the screen awake all the time.

Which is the other solution. You could just call that user activity constantly or tell your users to not let the screen go to sleep at all. Both things also “solve” the problem. Interestingly enough making the request to stop app nap and adding the flag for stopping idle sleeping of the screen did not solve the problem. So App Nap is not keeping the screen awake in those cases, or perhaps the screen saver is starting or something I don’t know, but just doing that did not solve the problem.

Sunday, December 24, 2017

App Nap in High Sierra

Update: 1/5/2018 It turns out this problem had nothing to do with app nap at all. It’s a thread contention issue in the screen drawing code in High Sierra and there is a very nasty workaround you can do to get it working. I’ve written about it Here

There is an undocumented change to how App Nap is handled in the latest build of the High Sierra operating system. In past OS versions the operating system actually believed you when you said you were executing a user initiated process and let your app continue to operate as normal even when the user wasn’t using your app. That seems no longer to be the case with High Sierra.

App Nap is a great idea overall. If your app isn’t being used it can be put to sleep and we can not waste the battery or the power to keep it doing all it’s interface animation and what now while the user isn’t using it. Unfortunately apps like my day job at XTension need to remain responsive to incoming data or connections even when the user has been absent for months. In the past this was no problem! MacOS was efficient and my app managed it’s memory carefully and didn’t leak and so for 6 months or more you could run in the background and keep doing all you needed to do.

That is no longer the case with High Sierra. If the user isn’t there and the screen goes to sleep then ALL the user apps will go to sleep. Even if they have done what apple suggested and register a “user initiated action” that should continue to work even while the user wanders off. High Sierra seems to decide that if the user has let the screen go to sleep then no user tasks need to be of high priority. This is remarkably frustrating as there are definitely apps that want to run while there is no user sitting at the machine.

The officially documented way to disable app nap does NOT work with High Sierra.

The only work around that I’ve been able to figure out is to disable putting the screen sleep. You can do this manually in the energy saver preferences just set the screen to never go to sleep. If you’re doing the official apple way of doing things then you can set the disable Idle Screen Sleep flag when you create your action.

Or you can just tell your users to set their energy saver preferences to never shut off the screen... This is a completely undocumented change that makes a huge difference to us developers of apps that run without the user sitting in front of the machine. I am very frustrated.

Sunday, October 8, 2017

SSL Secure Communications in XTension

My day job remains, happily, the Home Automation software XTension. We’ve managed to avoid creating a “cloud” for ourselves and yet have to weather lots of questions about data security. Especially for the Web Interfaces that we have customized for mobile clients or desktop clients. The truth is, if you’re willing to write a few numbers on a card in your wallet you can verify the serial number of the certificate from a public computer, and if you’re connecting from your own laptop or phone then your keychain will do that for you and it’s trivially simple to know if someone is performing a man-in-the-middle type attack despite the horrible brimstone and everybody is going to die warnings from your browser. Secure Communications in XTension

Friday, September 22, 2017

cMediaFile a Xojo class for serving video or audio files to Safari on MacOS and iOS

My day job is as a developer for XTension a Mac based home automation system.

Some years ago something changed in Safari and it stopped playing the video clips that XTension saves off in response to motion or other perimeter violations. I could never get it to work on iOS either. This was remarkably frustrating to have to tell people that to view the video archives in the Web Interface they had to use a different browser. It continued to work just fine in Chrome and Firefox. I thought at first that it had to do with using a self signed certificate but it turns out that Safari absolutely requires you to support the Range header and to properly reply. The other browsers were happy with my response of the entirety of the file even though they also initially ask for a smaller range of bytes. Safari was not happy with that and flatly refused to load the files at all unless I supported their range request.

The Web Remote and Mobile Web Remote in XTension are developed with Xojo and the built in webFile class does not support range requests. Since figuring this out I’ve been able to implement a replacement class that does support them. Should any other Xojo developers need to serve up video or audio files to Safari or Mobile Safari they are free (as in beer) to use the cMediaFile class and even to improve it and make new submissions at the github repository.

Download the class and example project:

Here’s an example of XTension’s Video Archive page now working again in Safari!