Determining Reachability and Getting Connected
This chapter describes the System Configuration reachability and connection APIs. You use the reachability API to determine if data destined for a remote host can leave the local machine. To start or stop a PPP connection, you use the connection API.
It is not necessary to have an in-depth understanding of the System Configuration architecture to determine reachability or start a PPP connection. The reachability and connection APIs provide a layer of abstraction that allows an application to make connections without worrying about the state of the network stack.
Scope of the Reachability and Connection APIs
Many types of applications need to find out if a remote host is reachable or to start a PPP-based connection. For example, an application might need to check for software updates that are available from a remote server. In OS X version 10.3 and later, the System Configuration framework provides APIs to accomplish these tasks quickly and easily, without requiring a detailed knowledge of System Configuration architecture. In particular, the reachability and connection APIs do much of their work behind the scenes, so the application does not have to poll for status changes or watch specific keys in the dynamic store.
The System Configuration reachability API helps an application determine if a remote host is reachable. A remote host is considered reachable if a data packet sent to the host can leave the local computer, regardless of what ultimately happens to the packet. In other words, the reachability of a remote host does not guarantee that the host will receive the data.
In practice, when a remote host is deemed reachable, but the packets you send to it fail to arrive, the myriad possible reasons for the failure fall into two broad categories:
A part of the Internet connection over which you have no control is broken. For example, the remote host’s server is down.
A part of your local network infrastructure over which you might have control is broken. For example, your modem hasn’t dialed or your AirPort base station is turned off.
The reachability API cannot help you with problems in the first category. As long as data packets can leave the local machine, the remote host is considered reachable. What the reachability API can provide is help diagnosing some of the problems in the second category. If, for example, the modem is currently disconnected, the API can tell you this.
To further define the scope of the System Configuration reachability and connection APIs, this document uses the following phrases to distinguish between two different types of network connection:
Network transport connection. This is a TCP-based connection you initiate using, for example, BSD sockets.
Network link connection. This is a PPP-based connection you initiate by, for example, telling the modem to dial.
The reachability API helps you determine if a remote host is reachable by examining the status of the local network link connection. The connection API allows you to start a network link connection. After you successfully start a network link connection, you use different API (such as Core Foundation networking API) to establish a network transport connection.
A Reachability and Connection Example
Determining reachability and requesting a network link connection often go hand in hand. As an example, consider the running of an email application. The sequence of events might go like this:
The user launches the email application to check her email.
The email application uses the reachability API to find out if the POP server is reachable.
The reachability API tells the application that the POP server is reachable, but that a network link connection must first be made.
The email application asks the user if she wants to dial the modem and she clicks “OK”. (The application might skip this step if the user has set a preference that tells the modem to dial automatically when the email application is launched.)
The email application uses the connection API to start a PPP connection, which causes the modem to dial. At this point, the email application can return to its work.
The reachability API notifies the email application that the network link connection is up and the email application then uses a network transport connection to fetch the email.
After the email application delivers the email to the user, it might or might not cause the PPP connection to drop, depending on the user’s preferences. Either way, when the email application quits, the PPP connection is dropped and, if the email application held the last reference to the connection, the modem disconnects. For more information on connection references, see Starting and Stopping a Connection.
Using the Reachability API
In versions of OS X prior to 10.3, the System Configuration reachability API consisted of two functions. The functions,
SCNetworkCheckReachabilityByName, supply information about the reachability of a remote host by providing a set of flags. The flags (defined in
SCNetwork.h) indicate, for example, that the specified remote host could be reached using the current network configuration. Unfortunately, these functions encouraged polling because they did not support notifications.
In OS X version 10.3, the System Configuration framework introduced the SCNetworkReachability API which supports asynchronous notifications of changes in the connection to a remote host. You still get the same set of connection-status flags the previous reachability functions supplied to determine if a connection is required, but you no longer have to poll to find out if a connection attempt is successful.
Most functions in the new API rely on an
SCNetworkReachabilityRef (defined in
SCNetworkReachability.h) you use to identify the remote target. You create this reference for a specific address or hostname and use it to add the reference to your run loop and set up a callback function. You can use the information in the connection-status flags to request a network link connection and the new reachability API notifies you when the connection is established.
You can use the new reachability functions in your application to perform the following tasks:
Create a reference for your target remote host you can use in other reachability functions.
Add the target to your run loop.
Provide a callback function that’s called when the reachability status of your target changes.
Determine if the target is reachable.
The following sections describe how to use the SCNetworkReachability functions to perform these tasks. For a code example demonstrating how to use the SCNetworkReachability API, see SimpleReach.
Creating a Reference
The SCNetworkReachability API provides three functions that create a target reference you can use to monitor the reachability of a remote host:
If you are interested in the reachability of only the remote host, you can use either
SCNetworkReachabilityCreateWithAddress, you supply a remote host address in a
sockaddr structure. For more information on the
sockaddr structure, see the networking
man page at http://developer.apple.com/documentation/Darwin/Reference/ManPages/man4/netintro.4.html. For
SCNetworkReachabilityCreateWithName, you supply a remote host name, such as www.apple.com.
If you need to monitor possible changes to both the local and remote host addresses, you use the
SCNetworkReachabilityCreateWithAddressPair function. This function returns a reference you can use to find out if:
The address of your local host changes
The remote address becomes unreachable
The network route associated with the remote host changes
All three functions return an object of type
SCNetworkReachabilityRef for the remote host, which you can use in any of the other SCNetworkReachability functions.
Adding a Target to a Run Loop
To ensure that your application receives notification when the reachability status of the target remote host changes, you add the target’s
SCNetworkReachabilityRef to your application’s run loop. A run loop monitors sources of input to an application. When an input source becomes ready for processing (because some activity occurs), the run loop dispatches control to a callback function associated with the input source. For more information on run loops and modes, see Run Loops.
For a network-aware application, the input source is the
SCNetworkReachabilityRef, the activity is a change in the target’s connection status, and the callback function is one you provide. Thus, by using the reachability API to add your target to your application’s run loop and to provide a callback function (described in Associating a Callback Function With the Target), you ensure your application will be notified of changes in the target’s reachability.
To add an
SCNetworkReachabilityRef to your application’s run loop, you use the
SCNetworkReachabilityScheduleWithRunLoop function. You provide the
SCNetworkReachabilityRef, a reference to your application’s run loop, and the mode in which the run loop should run, typically the default mode.
To remove an
SCNetworkReachabilityRef from your application’s run loop, you use the
SCNetworkReachabilityUnscheduleFromRunLoop function, which requires the same parameters as the
Associating a Callback Function With the Target
To make use of the notifications the reachability API provides, you should associate a callback function with the
SCNetworkReachabilityRef representing the remote host you’re interested in. The callback function might display the change in the connection to the user or perform some other task.
To associate a callback function with your target, you first define a function of type
SCNetworkReachabilityCallBack (this type is defined in
SCNetworkReachability.h). To pass contextual information about the changes to your callback function, you define a structure of type
SCNetworkReachabilityContext. You use the
info argument to contain the context information (you can also specify NULL, if context information is unnecessary). Finally, you pass the callback function, the
SCNetworkReachabilityRef representing the remote host, and the context to the
The SCNetworkReachability API provides the
SCNetworkReachabilityGetFlags function you can use to determine the reachability of a remote host. This function supplies the same connection-status flags the older reachability functions defined in
To use this function, you supply the
SCNetworkReachabilityRef for your remote host and the address of the variable you declare to contain the flags. The flags you can receive are listed in Table 4-1.
The target is reachable through a transient connection (for example, PPP).
The target is reachable using the current network configuration.
The target is reachable using the current network configuration, but a connection must be established first. For example, a suitable dialup connection exists, but it is not active.
The target is reachable using the current network configuration, but a connection must be established first. Further, any traffic directed to the target will automatically initiate the connection.
The target is reachable using the current network configuration, but a connection must be established first. Further, some user action is required to establish connection (for example, providing a password).
The target is associated with a network interface on the current system. For example, the target address is one of the IP addresses assigned to the system.
Network traffic to the target will not pass through a router because the destination address is on a network that’s directly connected to one of the local machine’s interfaces (for example, it’s on the same subnet as the local machine).
Using the Network Connection API
In OS X version 10.3, the System Configuration framework introduced the SCNetworkConnection API. This API allows an application to control connection-oriented services already defined in the system. Currently, an application can control only PPP services with this API.
In addition to controlling an existing service, an application can use the SCNetworkConnection API to get information about the connection. The API provides connection-status information on two levels:
High-level, generic information that describes the status of the network connection, such as connected or disconnected
Detailed, PPP-specific information that describes the status of the PPP stack
These two levels of status information target different types of applications. A network-aware application might want to display whether or not a network link connection is live, but is probably uninterested in knowing if the PPP controller is currently configuring the link layer. A complex dialer application, on the other hand, might need to know exactly what the PPP controller is doing at each step of the connection process.
Although these functions are defined in the same header file, this chapter does not describe the PPP-specific connection-status functions in
SCNetworkConnection.h. For more information on how to use these functions and how to use the System Configuration schema to interpret the results, see The System Configuration Schema. Instead, this chapter focuses on the remainder of the SCNetworkConnection API, describing how an application can use it to accomplish the following tasks:
Create a reference representing the connection you can use with other connection functions.
Add the connection reference to your application’s run loop.
Start a connection.
Get the status of a connection.
Stop an existing connection.
For a code example demonstrating the use of the SCNetworkConnection API, see SimpleDial.
Creating a Connection Reference
The SCNetworkConnection API provides one function you can use to create a connection reference:
SCNetworkConnectionCreateWithServiceID. To use this function, you supply a service ID and a callback function, along with a couple of other parameters, and you receive an object of type
SCNetworkConnectionRef. You use this object to represent the connection in the other SCNetworkConnection functions.
Because you’ll be using the
SCNetworkConnectionRef to refer to a specific PPP connection, you must supply a unique service ID to identify it. There are two ways to get this service ID. One way is to look in the dynamic store for available services and choose one. The second way is for your application to use the
SCNetworkConnectionCopyUserPreferences function to get the default service ID (the one the Internet Connect application uses).
Although you can pass NULL for the callback function parameter, it is not recommended. If you don’t define a callback function, your application will not receive status-change notifications and will have to poll for updates.
Adding a Connection Reference to a Run Loop
To ensure your application gets notified of changes in a specific connection’s status, you can add the
SCNetworkConnectionRef representing the connection to your application’s run loop. When the connection’s status changes, the
SCNetworkConnectionRef alerts the run loop and the run loop passes control to the callback function you provide.
To add an
SCNetworkConnectionRef to your application’s run loop, you use the
SCNetworkConnectionScheduleWithRunLoop function. You provide the
SCNetworkConnectionRef, a reference to your application’s run loop, and the mode in which the run loop should run (in most cases, the default mode). For more information on run loops and modes, see Introduction to Run Loops in the Core Foundation Reference Library.
To remove the
SCNetworkConnectionRef from your application’s run loop, you use the
SCNetworkConnectionUnscheduleFromRunLoop function. Like the
SCNetworkConnectionScheduleWithRunLoop function, this function expects the
SCNetworkConnectionRef, a reference to your application’s run loop, and the run loop mode.
Starting and Stopping a Connection
The SCNetworkConnection API provides two functions your application can use to control a connection using an
Both functions return immediately while the connection or disconnection process they initiate proceeds asynchronously. If you add the connection’s
SCNetworkConnectionRef to your application’s run loop and provide a callback function, your application is notified when the status of the connection changes. Your application can then check the status to determine if the connection process is complete. If you don’t add the connection reference to the run loop, you will have to poll to discover the connection status, and this is not recommended.
By default, the
SCNetworkConnectionStart function uses the user’s preferred connection settings to start the connection. You can, however, provide a dictionary of values to override some of these settings for the duration of the connection.
If you do provide a dictionary of additional settings be aware that:
The dictionary must be in the correct format for a network service dictionary (described in The NetworkServices Dictionary). If you do not follow this format precisely, the PPP controller may ignore the dictionary.
The PPP controller merges the settings you provide with the user’s existing settings before the connection is established, ignoring any inappropriate values in your dictionary.
Starting and stopping a connection are implicitly arbitrated. This means that the interest other applications may have in a connection is taken into account before the connection is stopped. For example, application “B” can start a connection that has already been started by application “A”. Application “A” may choose to stop the connection but the system should not stop the connection until “B” is finished with it. Using the SCNetworkConnection functions, application “A” can call
SCNetworkConnectionStop on the connection and the function will return success, but the connection will not stop until “B” calls
SCNetworkConnectionStop. An application can also use the
linger parameter (discussed below) to register interest.
SCNetworkConnectionStart function allows an application to indicate an interest in a connection. In this way, an application can request that the existence of the connection be tied to actions the application takes. In the simplest case, an application might want a connection to start when the application calls
SCNetworkConnectionStart and stop when any of the following events occur:
The application quits.
The application releases the
SCNetworkConnectionRefrepresenting the connection.
The application calls
To indicate interest in a connection, an application can use the
linger parameter of the
SCNetworkConnectionStart function. An application, such as an email client, that needs to get connected, perform its tasks, and get disconnected, sets the parameter to
FALSE. This indicates that the connection should stop when the application quits or releases the connection reference. A PPP dialer application, on the other hand, might choose to set the parameter to
TRUE so that the user has control over the modem. The
TRUE value indicates the connection should not stop when the application quits or releases the connection reference.
It’s important to note, however, that several concurrent applications might register interest in the same connection. When this is the case, the System Configuration framework keeps track of the references to the connection, stopping it when the last reference is released (or the last application holding a reference quits).
SCNetworkConnectionStop function performs an arbitrated stop of the connection. In other words, it closes the connection if:
There are no other interested applications currently running or holding references to the connection. If there are, the
SCNetworkConnectionStopfunction returns success to the calling application, but the connection will persist until all interested applications terminate or release their references to the connection.
An application calls
forceDisconnectparameter. This stops the connection regardless of the interest of other currently running applications. Most applications do not need to force a connection to stop in this way. A PPP dialer application, however, would probably choose to do this because it ensures that the connection stops when the user wants it to.
Getting the Status of a Connection
An application can use the
SCNetworkConnectionGetStatus function to get the high-level status of the connection. You pass the
SCNetworkConnectionRef representing the connection to the function and you receive one of the constants shown in Introduction to System Configuration Programming Guidelines.
The network connection refers to an invalid service.
The network connection is disconnected.
The network connection is connecting.
The network connection is connected.
The network connection is disconnecting.
If your application needs to know more about the PPP connection, such as when the PPP controller is authenticating to the server, you should use the
SCNetworkConnectionCopyExtendedStatus function. You pass the
SCNetworkConnectionRef representing the connection to the function and you receive a dictionary that contains subdictionaries for each subcomponent of the service, such as PPP, IPv4, and Modem. The PPP connection status is represented by a constant defined in the SCNetworkConnection API. Table 4-3 shows the current set of constants. Note that additional status values might be defined in the future, so your application should be able to handle an unknown value.
PPP is disconnected.
PPP is initializing.
PPP is connecting the lower layer (as when, for example, the modem is dialing out).
PPP is waiting for networking traffic to automatically establish the connection.
The PPP lower layer is connected and PPP is negotiating the link layer (the LCP protocol).
PPP is authenticating to the server (using PAP, CHAP, MSCHAP, or EAP protocol).
PPP is waiting for the server to call back. Note: this state is defined but will not occur because CallBack is not supported in OS X version 10.3.
PPP is authenticated and is now negotiating the networking layer (using IPCP or IPv6CP protocol).
PPP is fully connected for at least one networking layer. Additional networking protocols might still be negotiating.
PPP networking and link protocols are terminating.
PPP is disconnecting the lower connection layer (as when, for example, the modem is hanging up).
PPP is disconnected and maintaining the link temporarily “off”.
PPP is suspended as the result of the “suspend” command as when, for example, a V92 Modem is “On Hold”.
PPP found a busy server and is waiting for redial.
For more information on why you might choose to use the
SCNetworkConnectionCopyExtendedStatus function, see Getting Detailed PPP Connection-Status Information.