Transcript
Page 1: IOS Networking Topics

NetworkingProgramming Topics

Page 2: IOS Networking Topics

Contents

Introduction 4How to Use This Document 4Prerequisites 5

Using Sockets and Socket Streams 6Choosing an API Family 7Writing a TCP-Based Client 8

Establishing a Connection 9Handling Events 10Closing the Connection 10For More Information 11

Writing a TCP-Based Server 11Listening with Core Foundation 11Listening with POSIX Socket APIs 15

Working with Packet-Based Sockets 18Obtaining the Native Socket Handle for a Socket Stream 20

Resolving DNS Hostnames 22Resolving Hostnames with CFHost 22Resolving Hostnames with POSIX Calls 23

Overriding TLS Chain Validation Correctly 25Manipulating Trust Objects 26Trust Objects and NSURLConnection 28Trust Objects and NSStream 31

Document Revision History 35

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

2

Page 3: IOS Networking Topics

Listings

Overriding TLS Chain Validation Correctly 25Listing 1 Adding an anchor to a SecTrustRef object 26Listing 2 Changing the remote hostname for a SecTrustRef object 27Listing 3 Overriding the trust object used by an NSURLConnection object 29Listing 4 Overriding the TLS hostname with NSStream 31Listing 5 Using custom TLS anchors with NSStream 32

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

3

Page 4: IOS Networking Topics

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 interfacesdescribed herein. This information is subject to change, and software implemented according to thisdocument 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 theDocuments 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 alreadyhave 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 readNetworking 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-levelnetworking, from the POSIX layer up through the Foundation layer. This article explains how to write bothclient and server code using current best practices.

● “Resolving DNS Hostnames” (page 22)—Explains how to resolve DNS hostnames in ways that avoid someof the common pitfalls associated with doing so.

● “Overriding TLS Chain Validation Correctly” (page 25)—Tells how to safely alter the behavior of TransportLayer Security (TLS) chain validation without exposing your software to serious security risks. This articlecovers both TCP streams (using the CFStream or NSStream API) and URL requests (using theNSURLConnection 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

Page 5: IOS Networking Topics

PrerequisitesThis document assumes you have already read or otherwise understand the subjects described in the followingdocuments:

● Networking Overview—Provides a basic understanding of how networking software works, and how toavoid common mistakes.

● Networking Concepts—Provides a basic explanation of socket-based networking at a conceptual level.

IntroductionPrerequisites

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

5

Page 6: IOS Networking Topics

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

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 theprotocols 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 connectto other apps) and services (programs that other apps connect to). At a high level, these lines are clear. Mostprograms 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 communication—Programs that operate on one packet at a time, listening for incomingpackets, then sending packets in reply.

With packet-based communication, the only differences between clients and servers are the contents ofthe packets that each program sends and receives, and (presumably) what each program does with thedata. The networking code itself is identical.

● Stream-based clients—Programs that use TCP to send and receive data as two continuous streams ofbytes, one in each direction.

With stream-based communication, clients and servers are somewhat more distinct. The actual datahandling part of clients and servers is similar, but the way that the program initially constructs thecommunication 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 writingnetworking code.

● “Writing a TCP-Based Client” (page 8)—Describes how to make outgoing TCP connections to existingservers and services.

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

6

Using Sockets and Socket Streams

Page 7: IOS Networking Topics

● “Writing a TCP-Based Server” (page 11)—Describes how to listen for incoming TCP connections whenwriting servers and services.

● “Working with Packet-Based Sockets” (page 18)—Describes how to work with non-TCP protocols, suchas UDP.

Choosing an API FamilyThe API you choose for socket-based connections depends on whether you are making a connection to anotherhost or receiving a connection from another host. It also depends on whether you are using TCP or some otherprotocol. 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 POSIXC networking APIs and continue to use your networking code as-is (on a separate thread). If your programis based on a Core Foundation or Cocoa (Foundation) run loop, you can also use the Core FoundationCFStream 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 processingfunctionality 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 IPv6yourself ). It is a connect-by-IP API rather than a connect-by-name API, which means that youmust do a lot of extra work if you want to achieve the same initial-connection performance androbustness that higher-level APIs give you for free. Before you decide to reuse existing POSIXnetworking code, be sure to read “Avoid Resolving DNS Names Before Connecting to a Host” inNetworking 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-levelclasses for managing URL connections, socket streams, network services, and other networking tasks. It isalso the primary non-UI Objective-C framework in OS X and iOS, providing routines for run loops, stringhandling, collection objects, file access, and so on.

● For client code in C, use Core Foundation C networking APIs. The Core Foundation framework and theCFNetwork framework are two of the primary C-language frameworks in OS X and iOS. Together theydefine 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

Page 8: IOS Networking Topics

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 thetype 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 NSHost—they are not toll-freebridged), then use CFStreamCreatePairWithSocketToHost orCFStreamCreatePairWithSocketToCFHost to open a socket connected to that host and port andassociate a pair of CFStream objects with it. You can then cast these to an NSStream object.

You can also use the CFStreamCreatePairWithSocketToNetService function with aCFNetServiceRef 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 NSNetServiceis 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, thelookup is performed synchronously. Thus, it is unsafe to construct an NSHost object on yourmain 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 easilywith other Core Foundation APIs than CFSocket, and enables the cellular hardware on iOS (whereapplicable), unlike lower-level APIs. You can use CFStreamCreatePairWithSocketToHost orCFStreamCreatePairWithSocketToCFHost to open a socket connected to a given host and port andassociate a pair of CFStream objects with it.

You can also use the CFStreamCreatePairWithSocketToNetService function to connect to a Bonjourservice. 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

Page 9: IOS Networking Topics

If you are writing networking code that runs exclusively in OS X and iOS, you should generally avoid POSIXnetworking calls, because they are harder to work with than higher-level APIs. However, if you are writingnetworking code that must be shared with other platforms, you can use the POSIX networking APIs sothat you can use the same code everywhere.

Never use synchronous POSIX networking APIs on the main thread of a GUI application. If you usesynchronous 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 functionswith 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. Streamsautomatically handle many of the challenges that TCP connections present. For example, streams provide theability to connect by hostname, and in iOS, they automatically activate a device’s cellular modem or on-demandVPN when needed (unlike CFSocket or BSD sockets). Streams are also a more Cocoa-like networking interfacethan 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 todiscover 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 thentake advantage of the toll-free bridge between CFStream and NSStream to cast your CFReadStreamRefand CFWriteStreamRef objects to NSInputStream and NSOutputStream objects.

● If you discovered the host by browsing for network services with a CFNetServiceBrowser object, youobtain input and output streams for the service with theCFStreamCreatePairWithSocketToNetService 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 notusing automatic reference counting. Then cast them to NSInputStream and NSOutputStream objects, settheir delegate objects (which should conform to the NSStreamDelegate protocol), schedule them on thecurrent 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

Page 10: IOS Networking Topics

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 straightforwardway to do this is to create your own connection object that holds references to both streams, andthen set that object as the delegate for each stream.

Handling EventsWhen the stream:handleEvent: method is called on the NSOutputStream object’s delegate and thestreamEvent parameter’s value is NSStreamEventHasSpaceAvailable, call write:maxLength: to senddata. This method returns the number of bytes written or a negative number on error. If fewer bytes werewritten than you tried to send, you must queue up the remaining data and send it after the delegate methodgets called again with an NSStreamEventHasSpaceAvailable event. If an error occurs, you should callstreamError to find out what went wrong.

When the stream:handleEvent: method is called on your NSInputStream object’s delegate and thestreamEvent parameter’s value is NSStreamEventHasBytesAvailable, your input stream has receiveddata 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 streamevent 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 delegate’s stream:handleEvent: method is called with streamEvent set toNSStreamEventHasBytesAvailable. When you read from that stream, you get a length of zero (0).

● Your connection delegate’s stream:handleEvent: method is called with streamEvent set toNSStreamEventEndEncountered.

When either of these two events occurs, the delegate method is responsible for detecting the end-of-filecondition and cleaning up.

Closing the ConnectionTo close your connection, unschedule it from the run loop, set the connection’s delegate to nil (the delegateis unretained), close both of the associated streams with the close method, and then release the streamsthemselves (if you are not using ARC) or set them to nil (if you are). By default, this closes the underlyingsocket connection. There are two situations in which you must close it yourself, however:

● If you previously set the kCFStreamPropertyShouldCloseNativeSocket to kCFBooleanFalse bycalling setProperty:forKey: on the stream.

Using Sockets and Socket StreamsWriting a TCP-Based Client

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

10

Page 11: IOS Networking Topics

● 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 tokCFBooleanTrue with the setProperty:forKey: method.

For More InformationTo learn more, read “Setting Up Socket Streams” in Stream Programming Guide , Using NSStreams For A TCPConnection 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 differenceis that clients make outgoing connections, whereas servers create a listening socket (sometimes listen socket)—asocket that listens for incoming connections—then accept connections on that socket. After that, each resultingconnection 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 withother (non-Mac, non-iOS) platforms. There are only two APIs that provide the ability to listen for incomingnetwork connections: the Core Foundation socket API and the POSIX (BSD) socket API. Higher-level APIs cannotbe used for accepting incoming connections.

● If you are writing code for OS X and iOS exclusively, use POSIX networking calls to set up your networksockets. 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 withnon-Apple platforms is required.

If you are writing networking code that runs exclusively in OS X and iOS, you should generally avoid POSIXnetworking calls because they are harder to work with than higher level APIs. However, if you are writingnetworking code that must be shared with other platforms, you can use the POSIX networking APIs sothat 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

Page 12: IOS Networking Topics

1. Add appropriate includes:

#include <CoreFoundation/CoreFoundation.h>

#include <sys/socket.h>

#include <netinet/in.h>

2. Create socket objects (returned as a CFSocketRef object) with the CFSocketCreate orCFSocketCreateWithNative function. Specify kCFSocketAcceptCallBack as the callBackTypesparameter value. Provide a pointer to a CFSocketCallBack callback function as the callout parametervalue.

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 sockaddrstruct 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

Page 13: IOS Networking Topics

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, addthe 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

Page 14: IOS Networking Topics

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 socket’s callback function (handleConnect in this case), you should check to make sure thevalue of the callbackType parameter is kCFSocketAcceptCallBack, which means that a new connectionhas been accepted. In this case, the data parameter of the callback is a pointer to a CFSocketNativeHandlevalue (an integer socket number) representing the socket.

To handle the new incoming connections, you can use the CFStream, NSStream, or CFSocket APIs. Thestream-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 inCocoa.

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 samplecode projects.

Using Sockets and Socket StreamsWriting a TCP-Based Server

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

14

Page 15: IOS Networking Topics

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

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 don’t have a specific port in mind, pass zero for the port number, and the operating system willassign you an ephemeral port. (If you are going to advertise your service with Bonjour, you shouldalmost 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 thenregister 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

Page 16: IOS Networking Topics

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 FoundationCall CFSocketCreateWithNative. Then follow the directions in “Listening with Core Foundation” (page11), beginning at step 3.

Handling Events with Grand Central DispatchGCD allows you to perform operations asynchronously, and provides an event queue mechanism for determiningwhen 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, specifyingDISPATCH_SOURCE_TYPE_READ as the source type.

2. Call dispatch_source_set_event_handler (or dispatch_source_set_event_handler_f anddispatch_set_context) to set a handler that gets called whenever a new connection arrives on thesocket.

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 andreturns a new socket for that connection.

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

● Call dispatch_source_create to create a dispatch source for the client socket, specifyingDISPATCH_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_fand dispatch_set_context) to set a handler that gets called whenever the state of the connectionchanges.

4. In the client socket handler, call dispatch_async or dispatch_async_f and pass a block that callsread on the socket to grab any new data, then handle that data appropriately. This block can also sendresponses 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

Page 17: IOS Networking Topics

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 forthe 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 bycausing your process to run more frequently than is necessary. Unless you are doing something veryunusual, your select loop should not wake more than a few times per second, at most, and on iOS, youshould try to avoid doing this at all. For alternatives, read “Common Networking Mistakes” in NetworkingOverview .

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 anydescriptors that are not ready for reading or writing.

For the timeout parameter, pass the timeval structure you created earlier. Although OS X and iOS donot modify this structure, some other operating systems replace this value with the amount of timeremaining. 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 thatis 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 socketevents.

For More InformationTo 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

Page 18: IOS Networking Topics

Working with Packet-Based SocketsThe recommended way to send and receive UDP packets is by combining the POSIX API and either the CFSocketor 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 desiredport 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 providestwo advantages over an unconnected socket. First, it removes the need to specify the destination addressevery time you send a new message. Second, your app may receive errors when a packet cannot bedelivered. This error delivery is not guaranteed with UDP, however; it is dependent on network conditionsthat are beyond your app’s 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 callingdispatch_source_create. Assign an event handler to the dispatch source. Optionally assign acancellation handler. Finally, pass the dispatch source to the dispatch_resume function to begin handlingevents.

● If you are using CFSocket for integration, this technique is somewhat more complicated, but makes iteasier to interface your code with some Cocoa APIs. However, CFSocket objects use a single object torepresent a connection (much like sockets at the POSIX layer), whereas most Cocoa APIs are designed tointerface with stream-based APIs that use separate objects for sending and receiving. As a result, someCocoa APIs that expect read or write streams may be difficult to use in conjunction with CFSocketRefobjects.

To use CFSocket:

1. Create an object to use for managing the connection. If you are writing Objective-C code, this can bea class. If you are writing pure C code, this should be a Core Foundation object, such as a mutabledictionary.

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

Page 19: IOS Networking Topics

ctxt.retain = CFRetain;

ctxt.release = CFRelease;

ctxt.copyDescription = NULL;

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

Be sure to set (at minimum) the kCFSocketDataCallBack flag in your callBackTypes parametervalue. Do not set the kCFSocketAcceptCallBack flag.

You’ll also need to provide a pointer to a CFSocketCallBack callback function as the calloutparameter 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 Foundationobject 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

Page 20: IOS Networking Topics

Whenever new data becomes available, the data handler callback gets called. In your callback, if the valueof the callbackType parameter is kCFSocketConnectCallBack, check the data parameter passedinto the callback. If it is NULL, you have connected to the host. You can then send data using theCFSocketSendData function.

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

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 andwrite system calls to perform I/O. To learn more about sending and receiving UDP packets with the POSIXsocket 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. Forexample, you might want to find out the IP address and port number for each end of the stream withgetsockname 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

Page 21: IOS Networking Topics

You can do the same thing with an output stream, but you only need to do this with one or the other becausethe 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

Page 22: IOS Networking Topics

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 thehostname yourself, you must choose which IP address to use when connecting to the remote host. Bycontrast, when you connect by name, you allow the operating system to choose the best way of connectingon 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 Xand iOS provide a number of ways to obtain one or more addresses for a DNS hostname. This appendixdescribes those techniques.

Before you read this appendix, read “Avoid Resolving DNS Names Before Connecting to a Host” in NetworkingOverview 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 thePOSIX resolver API.

● NSHost—Although passing NSHost is a common way to pass hostnames to other APIs, using NSHost toresolve addresses yourself is generally discouraged because it is a synchronous API. Thus, using it on themain thread can cause serious performance degradation. Because this API is discouraged, its use is notdescribed here.

● CFHost—The CFHost API allows you to perform resolution asynchronously, and is the preferred way toresolve hostnames if you must resolve them yourself.

● POSIX—The POSIX layer provides several functions for resolving hostnames. These functions should beused only if you are writing portable code that must be shared with non-Apple platforms or if you areintegrating 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

Page 23: IOS Networking Topics

2. Call CFHostSetClient and provide the context object of your choice and a callback function that willbe 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 kCFHostAddressesas 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 callingCFHostGetAddressing. This function returns an array of CFDataRef objects, each of which contains aPOSIX sockaddr structure.

The process for reverse name resolution (translating an IP address into a hostname) is similar, except that youcallCFHostCreateWithAddress 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 shouldnot be used on the main thread in a GUI app. Instead, you should either create a separate POSIX thread or aGCD 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 <netdb.h> for resolving hostnames:

getaddrinfoReturns all the resolved addresses for a given hostname. This function is the preferred way to obtainaddress 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.

gethostbynameReturns a single IPv4 address for a given hostname. This function is discouraged for new developmentbecause it is limited to IPv4 addresses.

Resolving DNS HostnamesResolving Hostnames with POSIX Calls

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

23

Page 24: IOS Networking Topics

gethostbyname2Returns a single address for a given hostname in the specified address family (AF_INET, AF_INET6, andso on).

Although this function allows you to get around the IPv4 limitations of gethostbyname, it still limitsyour ability to try multiple addresses at once and choose the fastest one. Thus, this function is primarilyintended as a nearly drop-in replacement for gethostbyname in existing code. The getaddrinfo ispreferred for use in new code.

For reverse name resolution (translating an IP address into a hostname), POSIX provides getnameinfo andgethostbyaddr. 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

Page 25: IOS Networking Topics

This article describes how to override the chain validation behavior of network connections secured withTransport 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 duringdevelopment. By using the techniques described here to override chain validation safely, your users willnot be left unprotected if you inadvertently ship a version of your software without disabling that debuggingcode.

When a TLS certificate is verified, the operating system verifies its chain of trust. If that chain of trust containsonly 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 norm—creating client certificates for your users,providing service for multiple domains with a single certificate that is not trusted for those domains, using aself-signed certificate, connecting to a host by IP address (where the networking stack cannot determine theserver’s hostname), and so on—you must take additional steps to convince the operating system to acceptthe certificate.

At a high level, TLS chain validation is performed by a trust object (SecTrustRef). This object contains anumber of flags that control what types of validation are performed. As a rule, you should not touch theseflags, 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, thetrust 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 commonways to manipulate the trust object to change validation behavior. The remaining sections, “Trust Objects andNSURLConnection” (page 28) and “Trust Objects and NSStream” (page 31), show how to integrate thosechanges with various networking technologies.

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

25

Overriding TLS Chain Validation Correctly

Page 26: IOS Networking Topics

Manipulating Trust ObjectsThe details of manipulating the trust object depend in large part on what you’re trying to override. The twomost common things to override are the hostname (which must match either the leaf certificate’s commonname or one of the names in its Subject Alternate Name extension) and the set of anchors (which determinea set of trusted certificate authorities).

To add a certificate to the list of trusted anchor certificates, you must copy the existing anchor certificates intoan array, create a mutable version of that array, add the new anchor certificate to the mutable array, and tellthe trust object to use that newly updated array for future evaluation of trust. A simple function to do this islisted 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

Page 27: IOS Networking Topics

Note: To construct a SecCertificateRef object for trustedCert, first load a DER-encoded certificateinto a CFData object, then call SecCertificateCreateWithData.

For more flexibility, including loading certificates in other encodings, you can also useSecItemImport 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 allowa certificate to work when you connected to a host by its IP address), you must replace the policy object thatthe trust policy uses to determine how to interpret the certificate. To do this, first create a new TLS policy objectfor the desired hostname. Then create an array containing that policy. Finally, tell the trust object to use thatarray 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

Page 28: IOS Networking Topics

/* 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 ofauthentication—your application authenticating the server.

● connection:didReceiveAuthenticationChallenge:

In this method, your code needs to modify the trust policies, keys, or hostnames provided by the serveror 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

Page 29: IOS Networking Topics

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

Page 30: IOS Networking Topics

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

Page 31: IOS Networking Topics

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 ofcode 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 stream’s 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 thestream object creates a trust object, it evaluates it. If that trust evaluation fails, the stream is closed before yourcode 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 notfail, and the stream does not close.

● Perform the chain validation yourself in the stream’s delegate (after modifying the trust object appropriately).

By the time your stream delegate’s event handler gets called to indicate that there is space available on thesocket, the operating system has already constructed a TLS channel, obtained a certificate chain from the otherend 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 becomesyour 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 thehostname. If you are intentionally connecting to a host using a hostname other than one of the nameslisted on its certificate, you should allow the operation only if the certificate you receive from that host isvalid 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

Page 32: IOS Networking Topics

● Do not arbitrarily disable other security options, such as checking for expired certificates or roots. Thereare certain situations where doing so might make sense (such as verifying that a document signed backin 2001 was signed by a certificate that was valid back in 2001), but for networking purposes, the defaultoptions should generally be left alone.

With those rules in mind, Listing 5 shows how to use custom TLS anchors with NSStream. This listing also usesthe 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

Page 33: IOS Networking Topics

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

Page 34: IOS Networking Topics

/* 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

Page 35: IOS Networking Topics

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_in6initialization snippet.

2012-12-13

New document that explains how to perform certain networking tasksthat although somewhat common, are beyond the scope of the overviewdocumentation.

2012-07-19

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

35

Document Revision History

Page 36: IOS Networking Topics

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 containsApple’s 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 PROVIDED“AS 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.


Top Related