ios networking topics

Click here to load reader

Post on 15-Dec-2015

297 views

Category:

Documents

1 download

Embed Size (px)

DESCRIPTION

IOS networking. It is topic on programming IOS networking.

TRANSCRIPT

  • NetworkingProgramming Topics

  • Contents

    Introduction 4How to Use This Document 4

    Prerequisites 5

    Using Sockets and Socket Streams 6Choosing an API Family 7

    Writing a TCP-Based Client 8

    Establishing a Connection 9

    Handling Events 10

    Closing the Connection 10

    For More Information 11

    Writing a TCP-Based Server 11

    Listening with Core Foundation 11

    Listening with POSIX Socket APIs 15

    Working with Packet-Based Sockets 18

    Obtaining the Native Socket Handle for a Socket Stream 20

    Resolving DNS Hostnames 22Resolving Hostnames with CFHost 22

    Resolving Hostnames with POSIX Calls 23

    Overriding TLS Chain Validation Correctly 25Manipulating Trust Objects 26

    Trust Objects and NSURLConnection 28

    Trust Objects and NSStream 31

    Document Revision History 35

    2012-12-13 | 2012 Apple Inc. All Rights Reserved.

    2

  • Listings

    Overriding TLS Chain Validation Correctly 25Listing 1 Adding an anchor to a SecTrustRef object 26

    Listing 2 Changing the remote hostname for a SecTrustRef object 27

    Listing 3 Overriding the trust object used by an NSURLConnection object 29

    Listing 4 Overriding the TLS hostname with NSStream 31

    Listing 5 Using custom TLS anchors with NSStream 32

    2012-12-13 | 2012 Apple Inc. All Rights Reserved.

    3

  • Important: This is a preliminary document. Although it has been reviewed for technical accuracy, it is notfinal. Apple is supplying this information to help you adopt the technologies and programming interfaces

    described herein. This information is subject to change, and software implemented according to this

    document should be vetted against final documentation. For information about updates to this document,

    go to the Apple Developer website. In the relevant reference library, enter the document's title in the

    Documents text field that appears.

    This document is a collection of highly specialized, task-based articles related to specific areas of networking.

    As with other programming topics documents in this developer library, this document assumes that you already

    have a deep familiarity with networking concepts.

    Important: Most developers do not need to read this document, and most networking software does notneed to do any of the things described in this document. Before you read this document, you should read

    Networking Overview to learn more about when you should perform the tasks described in these articles.

    How to Use This DocumentThis document includes the following articles:

    Using Sockets and Socket Streams (page 6)Describes how to use sockets and streams for low-level

    networking, from the POSIX layer up through the Foundation layer. This article explains how to write both

    client and server code using current best practices.

    Resolving DNS Hostnames (page 22)Explains how to resolve DNS hostnames in ways that avoid some

    of the common pitfalls associated with doing so.

    Overriding TLS Chain Validation Correctly (page 25)Tells how to safely alter the behavior of Transport

    Layer Security (TLS) chain validation without exposing your software to serious security risks. This article

    covers both TCP streams (using the CFStream or NSStream API) and URL requests (using the

    NSURLConnection API).

    Each article is intended to be read by developers who need to write code that performs the specified task.

    2012-12-13 | 2012 Apple Inc. All Rights Reserved.

    4

    Introduction

  • PrerequisitesThis document assumes you have already read or otherwise understand the subjects described in the following

    documents:

    Networking OverviewProvides a basic understanding of how networking software works, and how to

    avoid common mistakes.

    Networking ConceptsProvides a basic explanation of socket-based networking at a conceptual level.

    IntroductionPrerequisites

    2012-12-13 | 2012 Apple Inc. All Rights Reserved.

    5

  • This article explains how to work with sockets and socket streams at various levels, from POSIX through

    Foundation.

    Important: This article describes ways to make socket connections that are completely under the controlof your program. Most programs would be better served by higher-level APIs such as NSURLConnection.

    To learn more about these higher-level APIs, read Networking Overview .

    The APIs described in this article should be used only if you need to support some protocol other than the

    protocols supported by built-in Cocoa or Core Foundation functionality.

    At almost every level of networking, software can be divided into two categories: clients (programs that connect

    to other apps) and services (programs that other apps connect to). At a high level, these lines are clear. Most

    programs written using high-level APIs are purely clients. At a lower level, however, the lines are often blurry.

    Socket and stream programming generally falls into one of the following broad categories:

    Packet-based communicationPrograms that operate on one packet at a time, listening for incoming

    packets, then sending packets in reply.

    With packet-based communication, the only differences between clients and servers are the contents of

    the packets that each program sends and receives, and (presumably) what each program does with the

    data. The networking code itself is identical.

    Stream-based clientsPrograms that use TCP to send and receive data as two continuous streams of

    bytes, one in each direction.

    With stream-based communication, clients and servers are somewhat more distinct. The actual data

    handling part of clients and servers is similar, but the way that the program initially constructs the

    communication channel is very different.

    This chapter is divided into sections based on the above tasks:

    Choosing an API Family (page 7)Describes how to decide which API family to use when writing

    networking code.

    Writing a TCP-Based Client (page 8)Describes how to make outgoing TCP connections to existing

    servers and services.

    2012-12-13 | 2012 Apple Inc. All Rights Reserved.

    6

    Using Sockets and Socket Streams

  • Writing a TCP-Based Server (page 11)Describes how to listen for incoming TCP connections when

    writing servers and services.

    Working with Packet-Based Sockets (page 18)Describes how to work with non-TCP protocols, such

    as UDP.

    Choosing an API FamilyThe API you choose for socket-based connections depends on whether you are making a connection to another

    host or receiving a connection from another host. It also depends on whether you are using TCP or some other

    protocol. Here are a few factors to consider:

    In OS X, if you already have networking code that is shared with non-Apple platforms, you can use POSIX

    C networking APIs and continue to use your networking code as-is (on a separate thread). If your program

    is based on a Core Foundation or Cocoa (Foundation) run loop, you can also use the Core Foundation

    CFStream API to integrate the POSIX networking code into your overall architecture on the main thread.

    Alternatively, if you are using Grand Central Dispatch (GCD), you can add a socket as a dispatch source.

    In iOS, POSIX networking is discouraged because it does not activate the cellular radio or on-demand VPN.

    Thus, as a general rule, you should separate the networking code from any common data processing

    functionality and rewrite the networking code using higher-level APIs.

    Note: If you use POSIX networking code, you should be aware that the POSIX networking APIis not protocol-agnostic (you must handle some of the differences between IPv4 and IPv6

    yourself ). It is a connect-by-IP API rather than a connect-by-name API, which means that you

    must do a lot of extra work if you want to achieve the same initial-connection performance and

    robustness that higher-level APIs give you for free. Before you decide to reuse existing POSIX

    networking code, be sure to read Avoid Resolving DNS Names Before Connecting to a Host in

    Networking Overview .

    For daemons and services that listen on a port, or for non-TCP connections, use POSIX or Core Foundation

    (CFSocket) C networking APIs.

    For client code in Objective-C, use Foundation Objective-C networking APIs. Foundation defines high-level

    classes for managing URL connections, socket streams, network services, and other networking tasks. It is

    also the primary non-UI Objective-C framework in OS X and iOS, providing routines for run loops, string

    handling, collection objects, file access, and so on.

    For client code in C, use Core Foundation C networking APIs. The Core Foundation framework and the

    CFNetwork framework are two of the primary C-language frameworks in OS X and iOS. Together they

    define the functions and structures upon which the Foundation networking classes are built.

    Using Sockets and Socket StreamsChoosing an API Family

    2012-12-13 | 2012 Apple Inc. All Rights Reserved.

    7

  • Note: In OS X, CFNetwork is a subframework of the Core Services framework; in iOS, CFNetworkis a top-level framework.

    Writing a TCP-Based ClientThe way you make an outgoing connection depends on what programming language you are using, on the

    type of connection (TCP, UDP, and so forth), and on whether you are trying to share code with other (non-Mac,

    non-iOS) platforms.

    Use NSStream for outgoing connections in Objective-C.

    If you are connecting to a specific host, create a CFHost object (not NSHostthey are not toll-free

    bridged), then use CFStreamCreatePairWithSocketToHost or

    CFStreamCreatePairWithSocketToCFHost to open a socket connected to that host and port and

    associate a pair of CFStream objects with it. You can then cast these to an NSStream object.

    You can also use the CFStreamCreatePairWithSocketToNetService function with a

    CFNetServiceRef object to connect to a Bonjour service. Read Discovering and Advertising Network

    Services in Networking Overview for more information.

    Note: The getStreamsToHost:port:inputStream:outputStream: of NSNetService

    is nod available on iOS, and is discouraged on OS X for performance reasons. Specifically,

    NSNetService requires you to create an instance of NSHost. When you create the object, the

    lookup is performed synchronously. Thus, it is unsafe to construct an NSHost object on your

    main application thread. See NSNetService and Automatic Reference Counting (ARC) for details.

    Use CFStream for outgoing connections in C.

    If you are writing code that cannot include Objective-C, use the CFStream API. It integrates more easily

    with other Core Foundation APIs than CFSocket, and enables the cellular hardware on iOS (where

    applicable), unlike lower-level APIs. You can use CFStreamCreatePairWithSocketToHost or

    CFStreamCreatePairWithSocketToCFHost to open a socket connected to a given host and port and

    associate a pair of CFStream objects with it.

    You can also use the CFStreamCreatePairWithSocketToNetService function to connect to a Bonjour

    service. Read Discovering and Advertising Network Services in Networking Overview for more information.

    Use POSIX calls if cross-platform portability is required.

    Using Sockets and Socket StreamsWriting a TCP-Based Client

    2012-12-13 | 2012 Apple Inc. All Rights Reserved.

    8

  • If you are writing networking code that runs exclusively in OS X and iOS, you should generally avoid POSIX

    networking calls, because they are harder to work with than higher-level APIs. However, if you are writing

    networking code that must be shared with other platforms, you can use the POSIX networking APIs so

    that you can use the same code everywhere.

    Never use synchronous POSIX networking APIs on the main thread of a GUI application. If you use

    synchronous networking calls in a GUI application, you must do so on a separate thread.

    Note: POSIX networking does not activate the cellular radio on iOS. For this reason, the POSIXnetworking API is generally discouraged in iOS.

    The subsections below describe the use of NSStream. Except where noted, the CFStream API has functions

    with similar names, and behaves similarly.

    To learn more about the POSIX socket API, read the UNIX Socket FAQ at http://developerweb.net/.

    Establishing a ConnectionAs a rule, the recommended way to establish a TCP connection to a remote host is with streams. Streams

    automatically handle many of the challenges that TCP connections present. For example, streams provide the

    ability to connect by hostname, and in iOS, they automatically activate a devices cellular modem or on-demand

    VPN when needed (unlike CFSocket or BSD sockets). Streams are also a more Cocoa-like networking interface

    than lower-level protocols, behaving in a way that is largely compatible with the Cocoa file stream APIs.

    The way you obtain input and output streams for a host depends on whether you used service discovery to

    discover the host:

    If you already know the DNS name or IP address of the remote host, obtain Core Foundation read (input)

    and write (output) streams with the CFStreamCreatePairWithSocketToHost function. You can then

    take advantage of the toll-free bridge between CFStream and NSStream to cast your CFReadStreamRef

    and CFWriteStreamRef objects to NSInputStream and NSOutputStream objects.

    If you discovered the host by browsing for network services with a CFNetServiceBrowser object, you

    obtain input and output streams for the service with the

    CFStreamCreatePairWithSocketToNetService function. Read Discovering and Advertising Network

    Services in Networking Overview for more information.

    After you have obtained your input and output streams, you should retain them immediately if you are not

    using automatic reference counting. Then cast them to NSInputStream and NSOutputStream objects, set

    their delegate objects (which should conform to the NSStreamDelegate protocol), schedule them on the

    current run loop, and call their open methods.

    Using Sockets and Socket StreamsWriting a TCP-Based Client

    2012-12-13 | 2012 Apple Inc. All Rights Reserved.

    9

  • Note: If you are working with more than one connection at a time, you must also keep track ofwhich input stream is associated with a given output stream and vice versa. The most straightforward

    way to do this is to create your own connection object that holds references to both streams, and

    then set that object as the delegate for each stream.

    Handling EventsWhen the stream:handleEvent: method is called on the NSOutputStream objects delegate and the

    streamEvent parameters value is NSStreamEventHasSpaceAvailable, call write:maxLength: to send

    data. This method returns the number of bytes written or a negative number on error. If fewer bytes were

    written than you tried to send, you must queue up the remaining data and send it after the delegate method

    gets called again with an NSStreamEventHasSpaceAvailable event. If an error occurs, you should call

    streamError to find out what went wrong.

    When the stream:handleEvent: method is called on your NSInputStream objects delegate and the

    streamEvent parameters value is NSStreamEventHasBytesAvailable, your input stream has received

    data that you can read with the read:maxLength: method. This method returns the number of bytes read,

    or a negative number on error.

    If fewer bytes were read than you need, you must queue the data and wait until you receive another stream

    event with additional data. If an error occurs, you should call streamError to find out what went wrong.

    If the other end of the connection closes the connection:

    Your connection delegates stream:handleEvent: method is called with streamEvent set to

    NSStreamEventHasBytesAvailable. When you read from that stream, you get a length of zero (0).

    Your connection delegates stream:handleEvent: method is called with streamEvent set to

    NSStreamEventEndEncountered.

    When either of these two events occurs, the delegate method is responsible for detecting the end-of-file

    condition and cleaning up.

    Closing the ConnectionTo close your connection, unschedule it from the run loop, set the connections delegate to nil (the delegate

    is unretained), close both of the associated streams with the close method, and then release the streams

    themselves (if you are not using ARC) or set them to nil (if you are). By default, this closes the underlying

    socket connection. There are two situations in which you must close it yourself, however:

    If you previously set the kCFStreamPropertyShouldCloseNativeSocket to kCFBooleanFalse by

    calling setProperty:forKey: on the stream.

    Using Sockets and Socket StreamsWriting a TCP-Based Client

    2012-12-13 | 2012 Apple Inc. All Rights Reserved.

    10

  • If you created the streams based on an existing BSD socket by calling CFStreamCreatePairWithSocket.

    By default, streams created from an existing native socket do not close their underlying socket. However,

    you can enable automatic closing by setting the kCFStreamPropertyShouldCloseNativeSocket to

    kCFBooleanTrue with the setProperty:forKey: method.

    For More InformationTo learn more, read Setting Up Socket Streams in Stream Programming Guide , Using NSStreams For A TCP

    Connection Without NSHost , or see the SimpleNetworkStreams and RemoteCurrency sample code projects.

    Writing a TCP-Based ServerAs mentioned previously, a server and a client are similar once the connection is established. The main difference

    is that clients make outgoing connections, whereas servers create a listening socket (sometimes listen socket)asocket that listens for incoming connectionsthen accept connections on that socket. After that, each resulting

    connection behaves just like a connection you might make in a client.

    The API you should choose for your server depends primarily on whether you are trying to share the code with

    other (non-Mac, non-iOS) platforms. There are only two APIs that provide the ability to listen for incoming

    network connections: the Core Foundation socket API and the POSIX (BSD) socket API. Higher-level APIs cannot

    be used for accepting incoming connections.

    If you are writing code for OS X and iOS exclusively, use POSIX networking calls to set up your network

    sockets. Then, use GCD or CFSocket to integrate the sockets into your run loop.

    Use pure POSIX networking code with a POSIX-based run loop (select) if cross-platform portability with

    non-Apple platforms is required.

    If you are writing networking code that runs exclusively in OS X and iOS, you should generally avoid POSIX

    networking calls because they are harder to work with than higher level APIs. However, if you are writing

    networking code that must be shared with other platforms, you can use the POSIX networking APIs so

    that you can use the same code everywhere.

    Never use NSSocketPort or NSFileHandle for general socket communication. For details, see Do Not

    Use NSSocketPort (OS X) or NSFileHandle for General Socket Communication in Networking Overview .

    The following sections describe how to use these APIs to listen for incoming connections.

    Listening with Core FoundationTo use Core Foundation APIs to listen for incoming connections, you must do the following:

    Using Sockets and Socket StreamsWriting a TCP-Based Server

    2012-12-13 | 2012 Apple Inc. All Rights Reserved.

    11

  • 1. Add appropriate includes:

    #include

    #include

    #include

    2. Create socket objects (returned as a CFSocketRef object) with the CFSocketCreate or

    CFSocketCreateWithNative function. Specify kCFSocketAcceptCallBack as the callBackTypes

    parameter value. Provide a pointer to a CFSocketCallBack callback function as the callout parameter

    value.

    CFSocketRef myipv4cfsock = CFSocketCreate(

    kCFAllocatorDefault,

    PF_INET,

    SOCK_STREAM,

    IPPROTO_TCP,

    kCFSocketAcceptCallBack, handleConnect, NULL);

    CFSocketRef myipv6cfsock = CFSocketCreate(

    kCFAllocatorDefault,

    PF_INET6,

    SOCK_STREAM,

    IPPROTO_TCP,

    kCFSocketAcceptCallBack, handleConnect, NULL);

    3. Bind a socket with the CFSocketSetAddress function. Provide a CFData object containing a sockaddr

    struct that specifies information about the desired port and family.

    struct sockaddr_in sin;

    memset(&sin, 0, sizeof(sin));

    sin.sin_len = sizeof(sin);

    sin.sin_family = AF_INET; /* Address family */

    sin.sin_port = htons(0); /* Or a specific port */

    sin.sin_addr.s_addr= INADDR_ANY;

    Using Sockets and Socket StreamsWriting a TCP-Based Server

    2012-12-13 | 2012 Apple Inc. All Rights Reserved.

    12

  • CFDataRef sincfd = CFDataCreate(

    kCFAllocatorDefault,

    (UInt8 *)&sin,

    sizeof(sin));

    CFSocketSetAddress(myipv4cfsock, sincfd);

    CFRelease(sincfd);

    struct sockaddr_in6 sin6;

    memset(&sin6, 0, sizeof(sin6));

    sin6.sin6_len = sizeof(sin6);

    sin6.sin6_family = AF_INET6; /* Address family */

    sin6.sin6_port = htons(0); /* Or a specific port */

    sin6.sin6_addr = in6addr_any;

    CFDataRef sin6cfd = CFDataCreate(

    kCFAllocatorDefault,

    (UInt8 *)&sin6,

    sizeof(sin6));

    CFSocketSetAddress(myipv6cfsock, sin6cfd);

    CFRelease(sin6cfd);

    4. Begin listening on a socket by adding the socket to a run loop.

    Create a run-loop source for a socket with the CFSocketCreateRunLoopSource function. Then, add

    the socket to a run loop by providing its run-loop source to the CFRunLoopAddSource function.

    CFRunLoopSourceRef socketsource = CFSocketCreateRunLoopSource(

    kCFAllocatorDefault,

    myipv4cfsock,

    0);

    CFRunLoopAddSource(

    CFRunLoopGetCurrent(),

    Using Sockets and Socket StreamsWriting a TCP-Based Server

    2012-12-13 | 2012 Apple Inc. All Rights Reserved.

    13

  • socketsource,

    kCFRunLoopDefaultMode);

    CFRunLoopSourceRef socketsource6 = CFSocketCreateRunLoopSource(

    kCFAllocatorDefault,

    myipv6cfsock,

    0);

    CFRunLoopAddSource(

    CFRunLoopGetCurrent(),

    socketsource6,

    kCFRunLoopDefaultMode);

    After this, you can access the underlying BSD socket descriptor with the CFSocketGetNative function.

    When you are through with the socket, you must close it by calling CFSocketInvalidate.

    In your listening sockets callback function (handleConnect in this case), you should check to make sure the

    value of the callbackType parameter is kCFSocketAcceptCallBack, which means that a new connection

    has been accepted. In this case, the data parameter of the callback is a pointer to a CFSocketNativeHandle

    value (an integer socket number) representing the socket.

    To handle the new incoming connections, you can use the CFStream, NSStream, or CFSocket APIs. The

    stream-based APIs are strongly recommended.

    To do this:

    1. Create read and write streams for the socket with the CFStreamCreatePairWithSocket function.

    2. Cast the streams to an NSInputStream object and an NSOutputStream object if you are working in

    Cocoa.

    3. Use the streams as described in Writing a TCP-Based Client (page 8).

    For more information, see CFSocket Reference . For sample code, see the RemoteCurrency and WiTap sample

    code projects.

    Using Sockets and Socket StreamsWriting a TCP-Based Server

    2012-12-13 | 2012 Apple Inc. All Rights Reserved.

    14

  • Listening with POSIX Socket APIsPOSIX networking is fairly similar to the CFSocketAPI, except that you have to write your own run-loop-handling

    code.

    Important: Never use POSIX networking APIs on the main thread of a GUI application. If you use POSIXnetworking in a GUI application, you must either do so on a separate thread or use GCD.

    Here are the basic steps for creating a POSIX-level server:

    1. Create a socket by calling socket. For example:

    int ipv4_socket = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);

    int ipv6_socket = socket(PF_INET6, SOCK_STREAM, IPPROTO_TCP);

    2. Bind it to a port.

    If you have a specific port in mind, use that.

    If you dont have a specific port in mind, pass zero for the port number, and the operating system will

    assign you an ephemeral port. (If you are going to advertise your service with Bonjour, you should

    almost always use an ephemeral port.)

    For example:

    struct sockaddr_in sin;

    memset(&sin, 0, sizeof(sin));

    sin.sin_len = sizeof(sin);

    sin.sin_family = AF_INET; // or AF_INET6 (address family)

    sin.sin_port = htons(0);

    sin.sin_addr.s_addr= INADDR_ANY;

    if (bind(listen_sock, (struct sockaddr *)&sin, sizeof(sin)) < 0) {

    // Handle the error.

    }

    3. If you are using an ephemeral port, call getsockname to find out what port you are using. You can then

    register this port with Bonjour. For example:

    socklen_t len = sizeof(sin);

    Using Sockets and Socket StreamsWriting a TCP-Based Server

    2012-12-13 | 2012 Apple Inc. All Rights Reserved.

    15

  • if (getsockname(listen_sock, (struct sockaddr *)&sin, &len) < 0) {

    // Handle error here

    }

    // You can now get the port number with ntohs(sin.sin_port).

    4. Call listen to begin listening for incoming connections on that port.

    The next steps depend on whether you intend to use pure POSIX socket code or a higher level abstraction.

    Handling Events with Core Foundation

    Call CFSocketCreateWithNative. Then follow the directions in Listening with Core Foundation (page

    11), beginning at step 3.

    Handling Events with Grand Central Dispatch

    GCD allows you to perform operations asynchronously, and provides an event queue mechanism for determining

    when to read data from the socket. After creating the listening socket, a GCD-based server should:

    1. Call dispatch_source_create to create a dispatch source for the listening socket, specifying

    DISPATCH_SOURCE_TYPE_READ as the source type.

    2. Call dispatch_source_set_event_handler (or dispatch_source_set_event_handler_f and

    dispatch_set_context) to set a handler that gets called whenever a new connection arrives on the

    socket.

    3. When the listen socket handler is called (upon a new connection), it should:

    Call accept. This function fills a new sockaddr structure with information about the connection and

    returns a new socket for that connection.

    If desired, call ntohl(my_sockaddr_obj.sin_addr.s_addr) to determine the clients IP address.

    Call dispatch_source_create to create a dispatch source for the client socket, specifying

    DISPATCH_SOURCE_TYPE_READ as the source type.

    Call setsockopt to set the SO_NOSIGPIPE flag on the socket.

    Call dispatch_source_set_event_handler (or dispatch_source_set_event_handler_f

    and dispatch_set_context) to set a handler that gets called whenever the state of the connection

    changes.

    4. In the client socket handler, call dispatch_async or dispatch_async_f and pass a block that calls

    read on the socket to grab any new data, then handle that data appropriately. This block can also send

    responses by calling write on the socket.

    Using Sockets and Socket StreamsWriting a TCP-Based Server

    2012-12-13 | 2012 Apple Inc. All Rights Reserved.

    16

  • Handling Events with Pure POSIX Code1. Create a file descriptor set and add new sockets to that set as new connections come in.

    fd_set incoming_connections;

    memset(&incoming_connections, 0, sizeof(incoming_connections));

    2. If you need to perform actions periodically on your networking thread, construct a timeval structure for

    the select timeout.

    struct timeval tv;

    tv.tv_sec = 1; /* 1 second timeout */

    tv.tv_usec = 0; /* no microseconds. */

    It is important to choose a timeout that is reasonable. Short timeout values bog down the system by

    causing your process to run more frequently than is necessary. Unless you are doing something very

    unusual, your select loop should not wake more than a few times per second, at most, and on iOS, you

    should try to avoid doing this at all. For alternatives, read Common Networking Mistakes in Networking

    Overview .

    If you do not need to perform periodic actions, pass NULL.

    3. Call select in a loop, passing two separate copies of that file descriptor set (created by calling FD_COPY)

    for the read and write descriptor sets. The select system call modifies these descriptor sets, clearing any

    descriptors that are not ready for reading or writing.

    For the timeout parameter, pass the timeval structure you created earlier. Although OS X and iOS do

    not modify this structure, some other operating systems replace this value with the amount of time

    remaining. Thus, for cross-platform compatibility, you must reset this value each time you call select.

    For the nfds parameter, pass a number that is one higher than the highest-numbered file descriptor that

    is actually in use.

    4. Read data from sockets, calling FD_ISSET to determine if a given socket has pending data.

    Write data to calling FD_ISSET to determine if a given socket has room for new data.

    Maintain appropriate queues for incoming and outgoing data.

    As an alternative to the POSIX select function, the BSD-specific kqueueAPI can also be used to handle socket

    events.

    For More Information

    To learn more about POSIX networking, read the socket, listen, FD_SET, and select manual pages.

    Using Sockets and Socket StreamsWriting a TCP-Based Server

    2012-12-13 | 2012 Apple Inc. All Rights Reserved.

    17

  • Working with Packet-Based SocketsThe recommended way to send and receive UDP packets is by combining the POSIX API and either the CFSocket

    or GCD APIs. To use these APIs, you must perform the following steps:

    1. Create a socket by calling socket.

    2. Bind the socket by calling bind. Provide a sockaddr struct that specifies information about the desired

    port and family.

    3. Connect the socket by calling connect (optional).

    Note that a connected UDP socket is not a connection in the purest sense of the word. However, it provides

    two advantages over an unconnected socket. First, it removes the need to specify the destination address

    every time you send a new message. Second, your app may receive errors when a packet cannot be

    delivered. This error delivery is not guaranteed with UDP, however; it is dependent on network conditions

    that are beyond your apps control.

    From there, you can work with the connection in three ways:

    If you are using GCD for run loop integration (recommended), create a dispatch source by calling

    dispatch_source_create. Assign an event handler to the dispatch source. Optionally assign a

    cancellation handler. Finally, pass the dispatch source to the dispatch_resume function to begin handling

    events.

    If you are using CFSocket for integration, this technique is somewhat more complicated, but makes it

    easier to interface your code with some Cocoa APIs. However, CFSocket objects use a single object to

    represent a connection (much like sockets at the POSIX layer), whereas most Cocoa APIs are designed to

    interface with stream-based APIs that use separate objects for sending and receiving. As a result, some

    Cocoa APIs that expect read or write streams may be difficult to use in conjunction with CFSocketRef

    objects.

    To use CFSocket:

    1. Create an object to use for managing the connection. If you are writing Objective-C code, this can be

    a class. If you are writing pure C code, this should be a Core Foundation object, such as a mutable

    dictionary.

    2. Create a context object to describe that object.

    CFSocketContext ctxt;

    ctxt.version = 0;

    ctxt.info = my_context_object;

    Using Sockets and Socket StreamsWorking with Packet-Based Sockets

    2012-12-13 | 2012 Apple Inc. All Rights Reserved.

    18

  • ctxt.retain = CFRetain;

    ctxt.release = CFRelease;

    ctxt.copyDescription = NULL;

    3. Create a CFSocket object (CFSocketRef) for the CFSocketNativeHandle object by calling

    CFSocketCreateWithNative.

    Be sure to set (at minimum) the kCFSocketDataCallBack flag in your callBackTypes parameter

    value. Do not set the kCFSocketAcceptCallBack flag.

    Youll also need to provide a pointer to a CFSocketCallBack callback function as the callout

    parameter value.

    For example:

    CFSocketRef connection = CFSocketCreateWithNative(kCFAllocatorDefault,

    sock,

    kCFSocketDataCallBack,

    handleNetworkData,

    &ctxt);

    4. Tell Core Foundation that it is allowed to close the socket when the underlying Core Foundation

    object is invalidated.

    CFOptionFlags sockopt = CFSocketGetSocketFlags(connection);

    sockopt |= kCFSocketCloseOnInvalidate |kCFSocketAutomaticallyReenableReadCallBack;

    CFSocketSetSocketFlags(connection, sockopt);

    5. Create an event source for the socket and schedule it on your run loop.

    CFRunLoopSourceRef socketsource = CFSocketCreateRunLoopSource(

    kCFAllocatorDefault,

    connection,

    0);

    CFRunLoopAddSource(CFRunLoopGetCurrent(), socketsource,kCFRunLoopDefaultMode);

    Using Sockets and Socket StreamsWorking with Packet-Based Sockets

    2012-12-13 | 2012 Apple Inc. All Rights Reserved.

    19

  • Whenever new data becomes available, the data handler callback gets called. In your callback, if the value

    of the callbackType parameter is kCFSocketConnectCallBack, check the data parameter passed

    into the callback. If it is NULL, you have connected to the host. You can then send data using the

    CFSocketSendData function.

    When you are finished with the socket, close and invalidate it by calling the CFSocketInvalidate

    function.

    At any point, you can also access the underlying BSD socket by calling the CFSocketGetNative function.

    For more information, see CFSocket Reference . For sample code, see the UDPEcho sample code project.

    If you are using pure POSIX sockets, use the select system call to wait for data, then use the read and

    write system calls to perform I/O. To learn more about sending and receiving UDP packets with the POSIX

    socket API, read the UNIX Socket FAQ at http://developerweb.net/.

    Obtaining the Native Socket Handle for a Socket StreamSometimes when working with socket-based streams (NSInputStream, NSOutputStream, CFReadStream,

    or CFWriteStream), you may need to obtain the underlying socket handle associated with a stream. For

    example, you might want to find out the IP address and port number for each end of the stream with

    getsockname and getpeername, or set socket options with setsockopt.

    To obtain the native socket handle for an input stream, call the following method:

    -(int) socknumForNSInputStream: (NSStream *)stream

    {

    int sock = -1;

    NSData *sockObj = [stream propertyForKey:

    (__bridge NSString *)kCFStreamPropertySocketNativeHandle];

    if ([sockObj isKindOfClass:[NSData class]] &&

    ([sockObj length] == sizeof(int)) ) {

    const int *sockptr = (const int *)[sockObj bytes];

    sock = *sockptr;

    }

    return sock;

    }

    Using Sockets and Socket StreamsObtaining the Native Socket Handle for a Socket Stream

    2012-12-13 | 2012 Apple Inc. All Rights Reserved.

    20

  • You can do the same thing with an output stream, but you only need to do this with one or the other because

    the input and output streams for a given connection always share the same underlying native socket.

    Note: If you are working with a Core Foundation stream, you can do the same thing withCFReadStreamCopyProperty, CFDataGetLength, and CFDataGetBytes.

    Using Sockets and Socket StreamsObtaining the Native Socket Handle for a Socket Stream

    2012-12-13 | 2012 Apple Inc. All Rights Reserved.

    21

  • This article explains how to resolve a DNS hostname in a way that offers you maximum flexibility.

    Important: Most high-level OS X and iOS APIs allow you to connect to a host by its DNS name, and, as arule, you should do so. A hostname can map onto multiple IP addresses simultaneously. If you resolve the

    hostname yourself, you must choose which IP address to use when connecting to the remote host. By

    contrast, when you connect by name, you allow the operating system to choose the best way of connecting

    on your behalf. This is particularly true for Bonjour services because the IP address can change at any time.

    However, connecting by name is not always possible. If you must use APIs that require an IP address, OS X

    and iOS provide a number of ways to obtain one or more addresses for a DNS hostname. This appendix

    describes those techniques.

    Before you read this appendix, read Avoid Resolving DNS Names Before Connecting to a Host in Networking

    Overview to learn why you probably should not do the things described below.

    There are three primary APIs in OS X and iOS for resolving hostnames: NSHost (only in OS X), CFHost, and the

    POSIX resolver API.

    NSHostAlthough passing NSHost is a common way to pass hostnames to other APIs, using NSHost to

    resolve addresses yourself is generally discouraged because it is a synchronous API. Thus, using it on the

    main thread can cause serious performance degradation. Because this API is discouraged, its use is not

    described here.

    CFHostThe CFHost API allows you to perform resolution asynchronously, and is the preferred way to

    resolve hostnames if you must resolve them yourself.

    POSIXThe POSIX layer provides several functions for resolving hostnames. These functions should be

    used only if you are writing portable code that must be shared with non-Apple platforms or if you are

    integrating your code with existing POSIX networking code.

    Resolving Hostnames with CFHostTo resolve a host with CFHost:

    1. Create a CFHostRef object by calling CFHostCreateWithName.

    2012-12-13 | 2012 Apple Inc. All Rights Reserved.

    22

    Resolving DNS Hostnames

  • 2. Call CFHostSetClient and provide the context object of your choice and a callback function that will

    be called when resolution completes.

    3. Call CFHostScheduleWithRunLoop to schedule the resolver on your run loop.

    4. Call CFHostStartInfoResolution to tell the resolver to start resolving, passing kCFHostAddresses

    as the second parameter to indicate that you want it to return IP addresses.

    5. Wait for the resolver to call your callback. Within your callback, obtain the results by calling

    CFHostGetAddressing. This function returns an array of CFDataRef objects, each of which contains a

    POSIX sockaddr structure.

    The process for reverse name resolution (translating an IP address into a hostname) is similar, except that you

    callCFHostCreateWithAddress to create the object, passkCFHostNames toCFHostStartInfoResolution,

    and call CFHostGetNames to retrieve the results.

    Resolving Hostnames with POSIX CallsIf you intend to use POSIX calls to resolve hostnames, be aware that these calls are synchronous and should

    not be used on the main thread in a GUI app. Instead, you should either create a separate POSIX thread or a

    GCD task and perform these calls within that context.

    Important: Using POSIX calls to resolve a hostname on your main program thread in iOS will cause yourapplication to be killed if the resolution time out.

    POSIX defines three functions in for resolving hostnames:

    getaddrinfo

    Returns all the resolved addresses for a given hostname. This function is the preferred way to obtain

    address information at the POSIX level. You can find sample code in its man page (linked above).

    Important: Some older DNS servers do not reply to IPv6 lookup requests with an error. The POSIXgetaddrinfofunction attempts to hide this misbehavior by canceling outstanding IPv6 queries shortly after receiving a successfulIPv4 reply. If your app would benefit from continuing to receive IPv6 addresses until you connect successfully(rather than stopping as soon as you have an IPv4 address that might or might not work), then you should usean asynchronous API such as CFHost.

    gethostbyname

    Returns a single IPv4 address for a given hostname. This function is discouraged for new development

    because it is limited to IPv4 addresses.

    Resolving DNS HostnamesResolving Hostnames with POSIX Calls

    2012-12-13 | 2012 Apple Inc. All Rights Reserved.

    23

  • gethostbyname2

    Returns a single address for a given hostname in the specified address family (AF_INET, AF_INET6, and

    so on).

    Although this function allows you to get around the IPv4 limitations of gethostbyname, it still limits

    your ability to try multiple addresses at once and choose the fastest one. Thus, this function is primarily

    intended as a nearly drop-in replacement for gethostbyname in existing code. The getaddrinfo is

    preferred for use in new code.

    For reverse name resolution (translating an IP address into a hostname), POSIX provides getnameinfo and

    gethostbyaddr. The getnameinfo function is preferred because it is more flexible.

    To learn more about these functions, read their respective man pages, linked above.

    Resolving DNS HostnamesResolving Hostnames with POSIX Calls

    2012-12-13 | 2012 Apple Inc. All Rights Reserved.

    24

  • This article describes how to override the chain validation behavior of network connections secured with

    Transport Layer Security (TLS).

    Important: This article assumes you have already read Cryptographic Services in Security Overview or areotherwise familiar with the concepts of certificates, signatures, and chains of trust.

    Most production software should not override chain validation. However, it is common to do so during

    development. By using the techniques described here to override chain validation safely, your users will

    not be left unprotected if you inadvertently ship a version of your software without disabling that debugging

    code.

    When a TLS certificate is verified, the operating system verifies its chain of trust. If that chain of trust contains

    only valid certificates and ends at a known (trusted) anchor certificate, then the certificate is considered valid.

    If it does not, it is considered invalid. If you are using a commercially signed certificate from a major vendor,

    the certificate should just work.

    However, if you are doing something that falls outside the normcreating client certificates for your users,

    providing service for multiple domains with a single certificate that is not trusted for those domains, using a

    self-signed certificate, connecting to a host by IP address (where the networking stack cannot determine the

    servers hostname), and so onyou must take additional steps to convince the operating system to accept

    the certificate.

    At a high level, TLS chain validation is performed by a trust object (SecTrustRef). This object contains a

    number of flags that control what types of validation are performed. As a rule, you should not touch these

    flags, but you should be aware of their existence. In addition, the trust object contains a policy (SecPolicyRef)

    that allows you to provide the hostname that should be used when evaluating a TLS certificate. Finally, the

    trust object contains a list of trusted anchor certificates that your application can modify.

    This article is split into multiple parts. The first part, Manipulating Trust Objects (page 26), describes common

    ways to manipulate the trust object to change validation behavior. The remaining sections, Trust Objects and

    NSURLConnection (page 28) and Trust Objects and NSStream (page 31), show how to integrate those

    changes with various networking technologies.

    2012-12-13 | 2012 Apple Inc. All Rights Reserved.

    25

    Overriding TLS Chain Validation Correctly

  • Manipulating Trust ObjectsThe details of manipulating the trust object depend in large part on what youre trying to override. The two

    most common things to override are the hostname (which must match either the leaf certificates common

    name or one of the names in its Subject Alternate Name extension) and the set of anchors (which determine

    a set of trusted certificate authorities).

    To add a certificate to the list of trusted anchor certificates, you must copy the existing anchor certificates into

    an array, create a mutable version of that array, add the new anchor certificate to the mutable array, and tell

    the trust object to use that newly updated array for future evaluation of trust. A simple function to do this is

    listed in Listing 1.

    Listing 1 Adding an anchor to a SecTrustRef object

    SecTrustRef addAnchorToTrust(SecTrustRef trust, SecCertificateRef trustedCert)

    {

    CFArrayRef oldAnchorArray = NULL;

    if (SecTrustCopyAnchorCertificates(&oldAnchorArray) != errSecSuccess) {

    /* Something went wrong. */

    return NULL;

    }

    CFMutableArrayRef newAnchorArray = CFArrayCreateMutableCopy(

    kCFAllocatorDefault, 0, oldAnchorArray);

    CFRelease(oldAnchorArray);

    CFArrayAppendValue(newAnchorArray, trustedCert);

    SecTrustSetAnchorCertificates(trust, newAnchorArray);

    return trust;

    Overriding TLS Chain Validation CorrectlyManipulating Trust Objects

    2012-12-13 | 2012 Apple Inc. All Rights Reserved.

    26

  • Note: To construct a SecCertificateRef object for trustedCert, first load a DER-encoded certificate

    into a CFData object, then call SecCertificateCreateWithData.

    For more flexibility, including loading certificates in other encodings, you can also use

    SecItemImport function in OS X v10.7 and later.

    To override the hostname (to allow a certificate for one specific site to work for another specific site, or to allow

    a certificate to work when you connected to a host by its IP address), you must replace the policy object that

    the trust policy uses to determine how to interpret the certificate. To do this, first create a new TLS policy object

    for the desired hostname. Then create an array containing that policy. Finally, tell the trust object to use that

    array for future evaluation of trust. Listing 2 shows a function that does this.

    Listing 2 Changing the remote hostname for a SecTrustRef object

    SecTrustRef changeHostForTrust(SecTrustRef trust)

    {

    CFMutableArrayRef newTrustPolicies = CFArrayCreateMutable(

    kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);

    SecPolicyRef sslPolicy = SecPolicyCreateSSL(true, CFSTR("www.example.com"));

    CFArrayAppendValue(newTrustPolicies, sslPolicy);

    #ifdef MAC_BACKWARDS_COMPATIBILITY

    /* This technique works in OS X (v10.5 and later) */

    SecTrustSetPolicies(trust, newTrustPolicies);

    CFRelease(oldTrustPolicies);

    return trust;

    #else

    /* This technique works in iOS 2 and later, or

    OS X v10.7 and later */

    CFMutableArrayRef certificates = CFArrayCreateMutable(

    kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);

    Overriding TLS Chain Validation CorrectlyManipulating Trust Objects

    2012-12-13 | 2012 Apple Inc. All Rights Reserved.

    27

  • /* Copy the certificates from the original trust object */

    CFIndex count = SecTrustGetCertificateCount(trust);

    CFIndex i=0;

    for (i = 0; i < count; i++) {

    SecCertificateRef item = SecTrustGetCertificateAtIndex(trust, i);

    CFArrayAppendValue(certificates, item);

    }

    /* Create a new trust object */

    SecTrustRef newtrust = NULL;

    if (SecTrustCreateWithCertificates(certificates, newTrustPolicies, &newtrust)!= errSecSuccess) {

    /* Probably a good spot to log something. */

    return NULL;

    }

    return newtrust;

    #endif

    }

    Trust Objects and NSURLConnectionTo override the chain validation behavior of NSURLConnection, you must override two methods:

    connection:canAuthenticateAgainstProtectionSpace:

    This method tells NSURLConnection that it knows how to handle authentication of a particular type.

    When your application decides whether to trust a server certificate, it is considered a form of

    authenticationyour application authenticating the server.

    connection:didReceiveAuthenticationChallenge:

    In this method, your code needs to modify the trust policies, keys, or hostnames provided by the server

    or the client so that the trust policy evaluates successfully.

    Listing 3 shows an example of these two methods.

    Overriding TLS Chain Validation CorrectlyTrust Objects and NSURLConnection

    2012-12-13 | 2012 Apple Inc. All Rights Reserved.

    28

  • Listing 3 Overriding the trust object used by an NSURLConnection object

    // If you are building for OS X 10.7 and later or iOS 5 and later,

    // leave out the first method and use the second method as the

    // connection:willSendRequestForAuthenticationChallenge: method.

    // For earlier operating systems, include the first method, and

    // use the second method as the connection:didReceiveAuthenticationChallenge:

    // method.

    #ifndef NEW_STYLE

    - (BOOL)connection:(NSURLConnection *)connectioncanAuthenticateAgainstProtectionSpace:(NSURLProtectionSpace *)protectionSpace {

    #pragma unused(connection)

    NSString *method = [protectionSpace authenticationMethod];

    if (method == NSURLAuthenticationMethodServerTrust) {

    return YES;

    }

    return NO;

    }

    -(void)connection:(NSURLConnection *)connection

    didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge

    #else

    -(void)connection:(NSURLConnection *)connection

    willSendRequestForAuthenticationChallenge:(NSURLAuthenticationChallenge*)challenge

    #endif

    {

    NSURLProtectionSpace *protectionSpace = [challenge protectionSpace];

    if ([protectionSpace authenticationMethod] ==NSURLAuthenticationMethodServerTrust) {

    SecTrustRef trust = [protectionSpace serverTrust];

    /***** Make specific changes to the trust policy here. *****/

    /* Re-evaluate the trust policy. */

    Overriding TLS Chain Validation CorrectlyTrust Objects and NSURLConnection

    2012-12-13 | 2012 Apple Inc. All Rights Reserved.

    29

  • SecTrustResultType secresult = kSecTrustResultInvalid;

    if (SecTrustEvaluate(trust, &secresult) != errSecSuccess) {

    /* Trust evaluation failed. */

    [connection cancel];

    // Perform other cleanup here, as needed.

    return;

    }

    switch (secresult) {

    case kSecTrustResultUnspecified: // The OS trusts this certificateimplicitly.

    case kSecTrustResultProceed: // The user explicitly told the OS to trustit.

    {

    NSURLCredential *credential =

    [NSURLCredentialcredentialForTrust:challenge.protectionSpace.serverTrust];

    [challenge.sender useCredential:credentialforAuthenticationChallenge:challenge];

    return;

    }

    default:

    /* It's somebody else's key. Fall through. */

    }

    /* The server sent a key other than the trusted key. */

    [connection cancel];

    // Perform other cleanup here, as needed.

    }

    }

    Overriding TLS Chain Validation CorrectlyTrust Objects and NSURLConnection

    2012-12-13 | 2012 Apple Inc. All Rights Reserved.

    30

  • Trust Objects and NSStreamThe way you override trust for an NSStream depends on what you are trying to do.

    If all you need to do is specify a different TLS hostname, you can do this trivially by executing three lines of

    code before you open the streams:

    Listing 4 Overriding the TLS hostname with NSStream

    NSDictionary *sslSettings =

    [NSDictionary dictionaryWithObjectsAndKeys:

    @"www.gatwood.net",

    (__bridge id)kCFStreamSSLPeerName, nil];

    if (![myInputStream setProperty: sslSettings

    forKey: (__bridge NSString *)kCFStreamPropertySSLSettings]) {

    // Handle the error here.

    }

    This changes the streams notion of its hostname so that when the stream object later creates a trust object,

    it provides the new name.

    If you need to actually alter the list of trusted anchors, the process is somewhat more complex. As soon as the

    stream object creates a trust object, it evaluates it. If that trust evaluation fails, the stream is closed before your

    code has the opportunity to modify the trust object. Thus, to override trust evaluation, you must:

    Disable TLS chain validation. Because the stream never evaluates the TLS chain, the evaluation does not

    fail, and the stream does not close.

    Perform the chain validation yourself in the streams delegate (after modifying the trust object appropriately).

    By the time your stream delegates event handler gets called to indicate that there is space available on the

    socket, the operating system has already constructed a TLS channel, obtained a certificate chain from the other

    end of the connection, and created a trust object to evaluate it. At this point, you have an open TLS stream,

    but you have no idea whether you can trust the host at the other end. By disabling chain validation, it becomes

    your responsibility to verify that the host at the other end can be trusted. Among other things, this means:

    Do not disable hostname checking by creating a non-TLS policy or passing in a NULL pointer for the

    hostname. If you are intentionally connecting to a host using a hostname other than one of the names

    listed on its certificate, you should allow the operation only if the certificate you receive from that host is

    valid for some other domain that you control .

    Do not implicitly trust self-signed certificates as anchors (kSecTrustOptionImplicitAnchors). Instead,

    add your own (self-signed) CA certificate to the list of trusted anchors.

    Overriding TLS Chain Validation CorrectlyTrust Objects and NSStream

    2012-12-13 | 2012 Apple Inc. All Rights Reserved.

    31

  • Do not arbitrarily disable other security options, such as checking for expired certificates or roots. There

    are certain situations where doing so might make sense (such as verifying that a document signed back

    in 2001 was signed by a certificate that was valid back in 2001), but for networking purposes, the default

    options should generally be left alone.

    With those rules in mind, Listing 5 shows how to use custom TLS anchors with NSStream. This listing also uses

    the function addAnchorToTrust from Listing 1 (page 26).

    Listing 5 Using custom TLS anchors with NSStream

    /* Code executed after creating the socket: */

    [inStream setProperty:NSStreamSocketSecurityLevelNegotiatedSSL

    forKey:NSStreamSocketSecurityLevelKey];

    NSDictionary *sslSettings =

    [NSDictionary dictionaryWithObjectsAndKeys:

    (id)kCFBooleanFalse, (id)kCFStreamSSLValidatesCertificateChain,

    nil];

    [inStream setProperty: sslSettings forKey: (__bridge NSString*)kCFStreamPropertySSLSettings];

    ...

    /* Methods in your stream delegate class */

    NSString *kAnchorAlreadyAdded = @"AnchorAlreadyAdded";

    - (void)stream:(NSStream *)theStream handleEvent:(NSStreamEvent)streamEvent

    {

    if (streamEvent == NSStreamEventHasBytesAvailable || streamEvent ==NSStreamEventHasSpaceAvailable) {

    /* Check it. */

    Overriding TLS Chain Validation CorrectlyTrust Objects and NSStream

    2012-12-13 | 2012 Apple Inc. All Rights Reserved.

    32

  • NSArray *certs = [theStream propertyForKey: (__bridge NSString*)kCFStreamPropertySSLPeerCertificates];

    SecTrustRef trust = (SecTrustRef)[theStream propertyForKey: (__bridgeNSString *)kCFStreamPropertySSLPeerTrust];

    /* Because you don't want the array of certificates to keep

    growing, you should add the anchor to the trust list only

    upon the initial receipt of data (rather than every time).

    */

    NSNumber *alreadyAdded = [theStream propertyForKey: kAnchorAlreadyAdded];

    if (!alreadyAdded || ![alreadyAdded boolValue]) {

    trust = addAnchorToTrust(trust, self.trustedCert); // defined earlier.

    [theStream setProperty: [NSNumber numberWithBool: YES] forKey:kAnchorAlreadyAdded];

    }

    SecTrustResultType res = kSecTrustResultInvalid;

    if (SecTrustEvaluate(trust, &res)) {

    /* The trust evaluation failed for some reason.

    This probably means your certificate was broken

    in some way or your code is otherwise wrong. */

    /* Tear down the input stream. */

    [theStream removeFromRunLoop: ... forMode: ...];

    [theStream setDelegate: nil];

    [theStream close];

    /* Tear down the output stream. */

    ...

    return;

    }

    if (res != kSecTrustResultProceed && res != kSecTrustResultUnspecified) {

    /* The host is not trusted. */

    Overriding TLS Chain Validation CorrectlyTrust Objects and NSStream

    2012-12-13 | 2012 Apple Inc. All Rights Reserved.

    33

  • /* Tear down the input stream. */

    [theStream removeFromRunLoop: ... forMode: ...];

    [theStream setDelegate: nil];

    [theStream close];

    /* Tear down the output stream. */

    ...

    } else {

    // Host is trusted. Handle the data callback normally.

    }

    }

    }

    Overriding TLS Chain Validation CorrectlyTrust Objects and NSStream

    2012-12-13 | 2012 Apple Inc. All Rights Reserved.

    34

  • This table describes the changes to Networking Programming Topics .

    NotesDate

    Corrected the data type used for the length provided to getsockname,

    fixed missing ampersands in code snippets, and corrected sockaddr_in6

    initialization snippet.

    2012-12-13

    New document that explains how to perform certain networking tasks

    that although somewhat common, are beyond the scope of the overview

    documentation.

    2012-07-19

    2012-12-13 | 2012 Apple Inc. All Rights Reserved.

    35

    Document Revision History

  • Apple Inc. 2012 Apple Inc.All rights reserved.

    No part of this publication may be reproduced,stored in a retrieval system, or transmitted, in anyform or by any means, mechanical, electronic,photocopying, recording, or otherwise, withoutprior written permission of Apple Inc., with thefollowing exceptions: Any person is herebyauthorized to store documentation on a singlecomputer for personal use only and to printcopies of documentation for personal useprovided that the documentation containsApples copyright notice.

    No licenses, express or implied, are granted withrespect to any of the technology described in thisdocument. Apple retains all intellectual propertyrights associated with the technology describedin this document. This document is intended toassist application developers to developapplications only for Apple-labeled computers.

    Apple Inc.1 Infinite LoopCupertino, CA 95014408-996-1010

    Apple, the Apple logo, Bonjour, Cocoa, Mac,Objective-C, and OS X are trademarks of AppleInc., registered in the U.S. and other countries.

    UNIX is a registered trademark of The OpenGroup.

    iOS is a trademark or registered trademark ofCisco in the U.S. and other countries and is usedunder license.

    Even though Apple has reviewed this document,APPLE MAKES NO WARRANTY OR REPRESENTATION,EITHER EXPRESS OR IMPLIED, WITH RESPECT TO THISDOCUMENT, ITS QUALITY, ACCURACY,MERCHANTABILITY, OR FITNESS FOR A PARTICULARPURPOSE. AS A RESULT, THIS DOCUMENT IS PROVIDEDAS IS, AND YOU, THE READER, ARE ASSUMING THEENTIRE RISK AS TO ITS QUALITY AND ACCURACY.

    IN NO EVENT WILL APPLE BE LIABLE FOR DIRECT,INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIALDAMAGES RESULTING FROM ANY DEFECT ORINACCURACY IN THIS DOCUMENT, even if advised ofthe possibility of such damages.

    THE WARRANTY AND REMEDIES SET FORTH ABOVEARE EXCLUSIVE AND IN LIEU OF ALL OTHERS, ORALOR WRITTEN, EXPRESS OR IMPLIED. No Apple dealer,agent, or employee is authorized to make anymodification, extension, or addition to this warranty.

    Some states do not allow the exclusion or limitationof implied warranties or liability for incidental orconsequential damages, so the above limitation orexclusion may not apply to you. This warranty givesyou specific legal rights, and you may also have otherrights which vary from state to state.

    Networking Programming TopicsContentsListingsIntroductionUsing Sockets and Socket StreamsChoosing an API FamilyWriting a TCP-Based ClientEstablishing a ConnectionHandling EventsClosing the ConnectionFor More Information

    Writing a TCP-Based ServerListening with Core FoundationListening with POSIX Socket APIsHandling Events with Core FoundationHandling Events with Grand Central DispatchHandling Events with Pure POSIX CodeFor More Information

    Working with Packet-Based SocketsObtaining the Native Socket Handle for a Socket Stream

    Resolving DNS HostnamesResolving Hostnames with CFHostResolving Hostnames with POSIX Calls

    Overriding TLS Chain Validation CorrectlyManipulating Trust ObjectsTrust Objects and NSURLConnectionTrust Objects and NSStream

    Revision History