Thursday, August 27, 2009

How to use iPhone with Network Status Functions: A Tutorial for Software Developers

How to use iPhone with Network Status Functions: A Tutorial for Software Developers


Norman McEntire

Version 1.2 January 19

Copyright © 2009 Servin Corporation. http://servin.com


Introduction

The iPhone OS, like Mac OS X, provides both Apple specific networking functions, and Unix-type networking functions.

There are Apple specific networking functions that are prefixed with SCNetwork. For example, you can use SCNetworkReachabilityGetFlags() to return status flags as to how you can reach the network.

Another example is the Unix function call gethostbyname(). You can issue this same call on the iPhone to convert a host name into an IP address.

In this Servin Mini-Course, you will learn how to use both Apple-specific and Unix-type function calls to get network information.


iPhone Software Skills You Will Learn

  • How to use Xcode to create a Window-Based App.
  • How to display text output in a UITextView control.
  • How to use SCNetworkReachabilityCreateWithAddress().
  • How to use SCNetworkReachabilityGetFlags().
  • How to use gethostbyname().

Prerequisites


Startup Xcode

If Xcode is not already running, start it up:

  1. On the Mac Desktop, double-click on the Finder icon (the icon with the face on it).
  2. On the left-side of the Finder window, click on Macintosh HD.
  3. On the right-side of the Finder window, click on the Developer folder.
  4. Click on the Applications folder.
  5. Double-click on the Xcode icon.

At this point, you should see the Xcode menu at the top of your desktop.


Create New Xcode Project

With Xcode running, create a new Xcode project:

  1. File > New Project.
  2. On the left-side of the New Project window, select Application under iPhone OS.
  3. On the right-side of the New Project window, select Window-Based Application.
  4. Click on the Choose button.
  5. Enter NetStatus for the project name.
  6. Click on Save button.

At this point, you should see Xcode open a new window that shows a number of files.


Build Default App

Go ahead and build the default application:

  1. Click on the Build and Go button.
  2. After a brief moment, you should see the code running in the iPhone Simulator.
  3. Observe the status bar at the top of the window, and a white window everywhere else.
  4. In the iPhone Simulator, press the Home button to stop the application.

Edit NetStatusAppDelegate to Add UITextView as Subview to UIWindow

In this exercise, you will edit NetStatusAppDelegate.h and NetStatusAppDelegate.m to add a UITextView as a subview to the UIWindow.

  1. In Xcode, in the Groups & Files window on the left-side, click on the Classes folder.
  2. You should see the following files on the right-side of the window:
    NetStatusAppDelegate.h
    NetStatusAppDelegate.m
  3. Select NetStatusAppDelegate.h so that it appears in the Xcode editor window.
  4. Edit the code to match the following:
    #import 

    @interface NetStatusAppDelegate : NSObject {
    UIWindow *window;

    UITextView *textView;

    }
    @property (nonatomic, retain) IBOutlet UIWindow *window;

    @property (nonatomic, retain) UITextView *textView;

    @end
  5. The above code adds a member variable named textView, which is a pointer to an object of type UITextView. Our goal is to use the UITextView control to display the output.
  6. We will not use Interface Builder for this demo, so we did not add the IBOutlet to the code that we entered.
  7. Select NetStatusAppDelegate.m into the Xcode editor window.
  8. Edit the code to match the following:
    #import 

    @implementation NetStatusAppDelegate

    @synthesize window;

    @synthesize textView;


    - (void)applicationDidFinishLaunching:(UIApplication *)application {

    // Create instance of UITextView
    self.textView = [[UITextView alloc]
    initWithFrame:[[UIScreen mainScreen] applicationFrame]];

    // Add text
    self.textView.text = @"Output will go here...";

    // Make non-editable
    self.textView.editable = NO;

    // Add as subview to window
    [window addSubview:self.textView];

    // Decrement our usage count
    [self.textView release];

    [window makeKeyAndVisible];
    }
  9. Build and Go.
  10. You should see your app running, with the text "Output will go here..." displayed in the window.
  11. Press Home in iPhone Simulator to stop the application.

As a review, in this exercise you added code to the NetStatusAppDelegate class to create a UITextView, setting it so that it cannot be edited. You also added text to the UITextView, and then added the UITextView to the subview of the window.


SystemConfiguration.framework

In this exercise, you will add the SystemConfiguration.framework to your project. This framework is needed, for it holds the SCNetwork functions, along with other functions related to system configuration.

  1. In Xcode, in the Groups & Files window on the left-side, click on the Frameworks folder.
  2. You should see the following frameworks:
    - CoreGraphics.framework
    - Foundation.framework
    - UIKit.framework
  3. Control+click on the Frameworks folder.
  4. Select Add from the popup menu.
  5. Select Existing Frameworks.
  6. Select Frameworks folder. (This may already be selected.)
  7. Select SystemConfiguration.framework.
  8. Click on Add.
  9. When prompted, confirm that you want to add the framework.
  10. The result is that you will now have the following frameworks listed in your Frameworks folder:
    - CoreGraphics.framework
    - Foundation.framework
    - SystemConfiguration.framework
    - UIKit.framework

As a review, in this exercise you added the SystemConfiguration.framework to your project. This is needed, because the SCNetwork functions you will use later are in this framework.


SystemConfiguration/SystemConfiguration.h, netinet/in.h

In this exercise, you will add the two additional header files needed for this project:

- SystemConfiguration/SystemConfiguration.h
- netinet/in.h
  1. In Xcode, in the Groups & Files window on the left-side, click on the Other Sources folder.
  2. You should see the following files:
    - main.m
    - NetStatus_Prefix.pch
  3. Click on NetStatus_Prefix.pch to select it into the Xcode editor.
  4. Edit the code to match the following:
    #ifdef __OBJC__
    #import
    #import

    #import
    #import

    #endif

As a review, in this exercise you added the additional header files needed for this project.


SCNetworkReachabilityGetFlags()

In this exercise, you will use the SCNetworkReachabilityGetFlags() function to determine:

- Is the network reachable
- Is the network a cell phone network
  1. In Xcode, in the Groups & Files window on the left-side, click on the Classes folder.
  2. You should see the following files on the right-side of the window:
    NetStatusAppDelegate.h
    NetStatusAppDelegate.m
  3. Select NetStatusAppDelegate.m so that it appears in the Xcode editor window.
  4. The function we need to call is SCNetworkReachabilityGetFlags(), which has the following prototype:
    Boolean
    SCNetworkReachabilityGetFlags(
    SCNetworkReachabilityRef target,
    SCNetworkReachabilityFlags *flags);
  5. As shown by the function prototype, the flags are returned using a pointer in the second parameter. However, the first parameter is a SCNetworkReachabilityRef, so we need to initialize that parameter.
  6. Use the SCNetworkReachabilityCreateWithAddress() to create the first parameter required by the SCNetworkReachabilityGetFlags():
    SCNetworkReachabilityRef
    SCNetworkReachabilityCreateWithAddress(
    CFAllocatorRef allocator,
    const struct sockaddr *address)
  7. You can set the allocator parameter to NULL to use the default allocator.
  8. You can set the address parameter to a zero socket address to use the local machine.
  9. Using the previous information as a guide, now edit NetStatusAppDelegate.m to match the following:
    #import 

    @implementation NetStatusAppDelegate

    @synthesize window;
    @synthesize textView;

    - (void)applicationDidFinishLaunching:(UIApplication *)application {

    // Create instance of UITextView
    self.textView = [[UITextView alloc]
    initWithFrame:[[UIScreen mainScreen] applicationFrame]];

    // Part 1 - Create Internet socket addr of zero
    struct sockaddr_in zeroAddr;
    bzero(&zeroAddr, sizeof(zeroAddr));
    zeroAddr.sin_len = sizeof(zeroAddr);
    zeroAddr.sin_family = AF_INET;

    // Part 2- Create target in format need by SCNetwork
    SCNetworkReachabilityRef target =
    SCNetworkReachabilityCreateWithAddress(NULL, (struct sockaddr *) &zeroAddr);

    // Part 3 - Get the flags
    SCNetworkReachabilityFlags flags;
    SCNetworkReachabilityGetFlags(target, &flags);

    // Part 4 - Create output
    NSString *sNetworkReachable;
    if (flags & kSCNetworkFlagsReachable)
    sNetworkReachable = @"YES";
    else
    sNetworkReachable = @"NO";

    NSString *sCellNetwork;
    if (flags & kSCNetworkReachabilityFlagsIsWWAN)
    sCellNetwork = @"YES";
    else
    sCellNetwork = @"NO";

    NSString *s = [[NSString alloc]
    initWithFormat:
    @"Network Reachable: %@\n"
    @"Cell Network: %@\n",
    sNetworkReachable,
    sCellNetwork];

    // Add text
    self.textView.text = s;
    [sCellNetwork release];
    [sNetworkReachable release];
    [s release];

    // Make non-editable
    self.textView.editable = NO;

    // Add as subview to window
    [window addSubview:self.textView];

    // Decrement our usage count
    [self.textView release];
    [window makeKeyAndVisible];
    }
  10. Build and Go.
  11. When your application runs, you should see the following displayed on the iPhone screen:
    Network Reachable: YES
    Cell Network: NO

As a review, in this exercise you used the SCNetworkReachabilityGetFlags() function to get status related to network reachability.


Unix gethostbyname(3)

In this exercise, you will use the Unix C library function gethostbyname(3) to display the IP address of a remote host.

  1. In Xcode, select Help > Open man page. In the world of Unix, a man page is a manual page that documents Unix commands, system calls, and other info.
  2. When you see the Open man Page window, enter gethostbyname, then click on OK.
  3. In the documentation window, observe the "Name" field:
    endhostent, gethostbyaddr, gethostbyname - get network host entry
  4. Observe the information shown in the Synopsis section:
    #include 

    struct hostent *
    gethostbyname(const char *name);
  5. In our case, we will use gethostbyname() to return the IP address of the host servin.com:
    struct hostent *remoteHostEnt = gethostbyname("servin.com");
  6. Scroll down further in the documentation, in the section titled Description, and find the definition of struct hostent:
    struct hostent {
    char *h_name; /* official name of host */
    char **h_aliases; /* alias list */
    int h_addrtype; /* host addr type */
    int h_length; /* length of address */
    char **h_addr_list; /* list of addresses from the name server */
    }
  7. Our goal is to display the IP address for servin.com, so we need to convert from the generic h_addr_list to a specific Internet address format:
    struct in_addr *remoteInAddr = (struct in_addr *) remoteHostEnt->h_addr_list[0];
  8. To display the output, we need string data, so we convert from an Internet address to an ASCII string:
    #include 

    char *
    inet_ntoa(struct in_addr in);
  9. This leads to the following code:
    char *sRemoteInAddr = inet_ntoa(*remoteInAddr);
  10. Putting all the previous comments together, you are now ready to edit the code.
  11. In Xcode, in the Groups & Files window on the left-side, click on the Other Sources folder.
  12. You should see the following files on the right-side of the window:
    main.m
    NetStatus_Prefix.pch
  13. Select NetStatus_Prefix.pch so that it appears in the Xcode editor window.
  14. Edit the code to match the following:
    #ifdef __OBJC__
    #import
    #import
    #import
    #import

    #include
    #include

    #endif
  15. In Xcode, in the Groups & Files window on the left-side, click on the Classes folder.
  16. You should see the following files on the right-side of the window:
    NetStatusAppDelegate.h
    NetStatusAppDelegate.m
  17. Select NetStatusAppDelegate.m into the Xcode editor.
  18. Edit the code to match the following:
    - (void)applicationDidFinishLaunching:(UIApplication *)application {

    // Create instance of UITextView
    self.textView = [[UITextView alloc]
    initWithFrame:[[UIScreen mainScreen] applicationFrame]];

    // Part 1 - Create Internet socket addr of zero
    struct sockaddr_in zeroAddr;
    bzero(&zeroAddr, sizeof(zeroAddr));
    zeroAddr.sin_len = sizeof(zeroAddr);
    zeroAddr.sin_family = AF_INET;

    // Part 2- Create target in format need by SCNetwork
    SCNetworkReachabilityRef target =
    SCNetworkReachabilityCreateWithAddress(NULL, (struct sockaddr *) &zeroAddr);

    // Part 3 - Get the flags
    SCNetworkReachabilityFlags flags;
    SCNetworkReachabilityGetFlags(target, &flags);

    // Part 4 - Create output
    NSString *sNetworkReachable;
    if (flags & kSCNetworkFlagsReachable)
    sNetworkReachable = @"YES";
    else
    sNetworkReachable = @"NO";

    NSString *sCellNetwork;
    if (flags & kSCNetworkReachabilityFlagsIsWWAN)
    sCellNetwork = @"YES";
    else
    sCellNetwork = @"NO";


    // Get host entry info for given host
    struct hostent *remoteHostEnt = gethostbyname("servin.com");

    // Get address info from host entry
    struct in_addr *remoteInAddr = (struct in_addr *) remoteHostEnt->h_addr_list[0];

    // Convert numeric addr to ASCII string
    char *sRemoteInAddr = inet_ntoa(*remoteInAddr);

    NSString *s = [[NSString alloc]
    initWithFormat:
    @"Network Reachable: %@\n"
    @"Cell Network: %@\n"
    @"Remote IP: %s\n",
    sNetworkReachable,
    sCellNetwork,
    sRemoteInAddr];


    // Add text
    self.textView.text = s;
    [sCellNetwork release];
    [sNetworkReachable release];
    [s release];
    // Make non-editable
    self.textView.editable = NO;

    // Add as subview to window
    [window addSubview:self.textView];

    // Decrement our usage count
    [self.textView release];
    [window makeKeyAndVisible];
    }
  19. Build and Go.
  20. When your application runs, you should see an output on the screen similar to the following:
    Network Reachable: YES
    Cell Network: NO
    Remote IP: 216.75.35.182

As a review, in this exercise you used the Unix man pages to display information about the gethostbyname(3) C-language library call, and you used the function to resolve a name to an IP address.

No comments: