The Dark Depths of iOS

CodeMash starts Wednesday in Sandusky, with half-day iOS tutorials from Daniel Steinberg and myself, followed by two days of sessions. My Thursday session is The Dark Depths of iOS, and is a rapid-fire tour of the non-obvious parts of the iOS APIs.

Researching for this has proven an interesting exercise. I had the idea for the talk from the occasional dive into Core Foundation for functionality that is not exposed at higher levels of the iOS and Mac stacks. A simple example of this is the CFUUID, the Universally unique identifier defined by RFC 4122. More than once, I’ve needed an arbitrary unique ID (other than, say, the device ID), and am happy to use the industry standard. But it’s not defined in Foundation or Cocoa, so you need to use Core Foundation and its C API.

Another example I knew about before starting this talk was the CFNetwork sub-framework, which provides a much more complete networking stack than is available in Cocoa’s URL Loading System. CFNetwork allows you make arbitrary socket connections, work with hosts (e.g., to do DNS lookups), accept connections, etc. Basically, if what you need from the network can’t be expressed as a URL, you need to drop down at least to this level. It has an advantage over traditional BSD sockets in that it integrates with the Core Foundation view of the world, most importantly in that its reading and writing APIs use the asynchronous callback design patterns common to Apple’s frameworks, rather than blocking as the traditional C APIs would.

Stuff like those, along with Accelerate and Keychain, are things I knew I wanted to talk about, and did the first few slides on Core Media and Core Services by pointing out reasonably findable information from Apple’s architecture docs.

The eye-openers for me were down in the “System” level of Core OS… the various C APIs that iOS inherits from its open-source roots in FreeBSD and NetBSD (i.e., Darwin). These aren’t substantially documented in Xcode (though they do enjoy syntax highlighting and sometimes code-completion). The documentation for these is in the man pages, which of course makes sense for long-time Unix programmers, but maybe less so today… if I’m writing in Xcode for a separate iOS device, the Mac command-line is a rather counterintuitive location to look for API documentation, isn’t it?

So the trick with calling the standard C libraries is finding out just what’s available to you. Apple has links to iOS Manual Pages that collect a lot of these APIs in one place, but they are largely unordered (beyond the historical Unix man page sections), and being programmatically generated, Apple can only offer a warning that while some APIs known to be unavailable on iOS have been filtered out, the list isn’t guaranteed to be completely accurate. There’s also a consideration that some of these APIs, while they may exist, are not particularly useful given the limitations under which third-party iOS applications operate. For example, all the APIs involving processes (e.g., getting your PID and EUID) and inter-process communication are presumably only of academic interest — the iPhone is not the campus timeshare mainframe from 1988. Similarly, ncurses is probably not going to do much for you on a touch display. OK, maybe if you’re writing an ssh client. Or if you really need to prove that Angry Birds could have worked on a VT100.

Another way of figuring out what’s there — if less so how to actually call it — is to go spelunking down in <iOS_SDK>/usr/lib and <iOS_SDK>/usr/include to get an idea of the organization and packaging of the standard libraries. Had I not done this, I might not have realized that there is a C API for regular expression matching (regex.h), XML parsing with libxml2 (both DOM and SAX), zip and tar, MD5 and SHA (in CommonCrypto/) and other interesting stuff.

On the other hand, there are cases where code libraries are available but don’t have public headers. For example, libbz2.dylib are libtidy.dylib are in usr/lib but don’t seem to have corresponding entries in usr/include. That begs the question of whether you could call into these BZip and Tidy libraries and remain “App Store safe”, given the apparent lack of a “public” API, even though you could easily get the headers for these open-source libraries from their host projects. Heck, kebernet pointed out to me that tidy.h and bzlib.h are available in the iPhoneSimulator.platform path, just not iPhoneOS.platform.

It would be nice if there were better visibility into these libraries, though their nature as unrepentant C probably scares off a lot of developers, who will be just as well off scouring Google Code for a nice Objective-C alternative (provided the license they find is compatible with their own). My takeaway is that there’s even more functionality at these low levels than I expected to find. I’ll probably at least consider using stuff like libxml2 and regex.h in the future.

Comment (1)

  1. steve mcfarlin

    I copied network headers from the OS-X sdk over to /usr/include so I could get access to sysctlbyname for the purpose of getting the tcpcb structure from the kernel. My app made it through no problems. With this said the tcp statistics and some vars in tcpcb are garbage on iOS, or at the very least inaccurate.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.