TCP/TCPListener.h
author Jens Alfke <jens@mooseyard.com>
Sun May 24 15:03:39 2009 -0700 (2009-05-24)
changeset 49 20cccc7c26ee
parent 22 8b883753394a
permissions -rwxr-xr-x
Misc. tweaks made while porting Chatty to use MYNetwork.
* Allow -[BLIPConnection sendRequest:] to re-send an already-sent or received request.
* Allow use of the basic -init method for BLIPConnection.
* Some new convenience factory methods.
* Broke dependencies on Security.framework out into new TCPEndpoint+Certs.m source file, so client apps aren't forced to link against Security.
jens@0
     1
//
jens@0
     2
//  TCPListener.m
jens@0
     3
//  MYNetwork
jens@0
     4
//
jens@0
     5
//  Created by Jens Alfke on 5/10/08.
jens@0
     6
//  Copyright 2008 Jens Alfke. All rights reserved.
jens@0
     7
jens@0
     8
#import "TCPEndpoint.h"
jens@0
     9
@class TCPConnection, IPAddress;
jens@0
    10
@protocol TCPListenerDelegate;
jens@0
    11
jens@0
    12
jens@0
    13
/** Generic TCP-based server that listens for incoming connections on a port.
jens@2
    14
jens@0
    15
    For each incoming connection, it creates an instance of (a subclass of) the generic TCP
jens@0
    16
    client class TCPClient. The -connectionClass property lets you customize which subclass
jens@0
    17
    to use.
jens@2
    18
 
jens@2
    19
    TCPListener supports SSL, Bonjour advertisements for the service, and automatic port renumbering
jens@2
    20
    if there are conflicts. (The SSL related methods are inherited from TCPEndpoint.) 
jens@2
    21
 
jens@2
    22
    You will almost always need to implement the TCPListenerDelegate protocol in your own
jens@2
    23
    code, and set an instance as the listener's delegate property, in order to be informed
jens@2
    24
    of important events such as incoming connections. */
jens@0
    25
@interface TCPListener : TCPEndpoint 
jens@0
    26
{
jens@0
    27
    @private
jens@0
    28
    uint16_t _port;
jens@0
    29
    BOOL _pickAvailablePort;
jens@0
    30
    BOOL _useIPv6;
jens@0
    31
    CFSocketRef _ipv4socket;
jens@0
    32
    CFSocketRef _ipv6socket;
jens@0
    33
    
jens@0
    34
    NSString *_bonjourServiceType, *_bonjourServiceName;
jens@44
    35
    NSNetServiceOptions _bonjourServiceOptions;
jens@0
    36
    NSNetService *_netService;
jens@0
    37
    NSDictionary *_bonjourTXTRecord;
jens@0
    38
    BOOL _bonjourPublished;
jens@0
    39
    NSInteger /*NSNetServicesError*/ _bonjourError;
jens@0
    40
jens@0
    41
    Class _connectionClass;
jens@0
    42
}
jens@0
    43
jens@0
    44
/** Initializes a new TCPListener that will listen on the given port when opened. */
jens@0
    45
- (id) initWithPort: (UInt16)port;
jens@0
    46
jens@0
    47
/** The subclass of TCPConnection that will be instantiated. */
jens@0
    48
@property Class connectionClass;
jens@0
    49
jens@2
    50
/** Delegate object that will be called when interesting things happen to the listener --
jens@2
    51
    most importantly, when a new incoming connection is accepted. */
jens@0
    52
@property (assign) id<TCPListenerDelegate> delegate;
jens@0
    53
jens@0
    54
/** Should the server listen for IPv6 connections (on the same port number)? Defaults to NO. */
jens@0
    55
@property BOOL useIPv6;
jens@0
    56
jens@0
    57
/** The port number to listen on.
jens@0
    58
    If the pickAvailablePort property is enabled, this value may be updated after the server opens
jens@0
    59
    to reflect the actual port number being used. */
jens@0
    60
@property uint16_t port;
jens@0
    61
jens@0
    62
/** Should the server pick a higher port number if the desired port is already in use?
jens@0
    63
    Defaults to NO. If enabled, the port number will be incremented until a free port is found. */
jens@0
    64
@property BOOL pickAvailablePort;
jens@0
    65
jens@0
    66
/** Opens the server. You must call this after configuring all desired properties (property
jens@0
    67
    changes are ignored while the server is open.) */
jens@0
    68
- (BOOL) open: (NSError **)error;
jens@0
    69
jens@2
    70
/** Opens the server, without returning a specific error code.
jens@2
    71
    (In case of error the delegate's -listener:failedToOpen: method will be called with the
jens@2
    72
    error code, anyway.) */
jens@0
    73
- (BOOL) open;
jens@0
    74
jens@0
    75
/** Closes the server. */
jens@0
    76
- (void) close;
jens@0
    77
jens@0
    78
/** Is the server currently open? */
jens@0
    79
@property (readonly) BOOL isOpen;
jens@0
    80
jens@0
    81
jens@0
    82
#pragma mark BONJOUR:
jens@0
    83
jens@0
    84
/** The Bonjour service type to advertise. Defaults to nil; setting it implicitly enables Bonjour.
jens@0
    85
    The value should look like e.g. "_http._tcp."; for details, see the NSNetService documentation. */
jens@0
    86
@property (copy) NSString *bonjourServiceType;
jens@0
    87
jens@0
    88
/** The Bonjour service name to advertise. Defaults to nil, meaning that a default name will be
jens@0
    89
    automatically generated if Bonjour is enabled (by setting -bonjourServiceType). */
jens@0
    90
@property (copy) NSString *bonjourServiceName;
jens@0
    91
jens@44
    92
/** Options to use when publishing the Bonjour service. */
jens@44
    93
@property NSNetServiceOptions bonjourServiceOptions;
jens@44
    94
jens@0
    95
/** The dictionary form of the Bonjour TXT record: metadata about the service that can be browsed
jens@0
    96
    by peers. Changes to this dictionary will be pushed in near-real-time to interested peers. */
jens@0
    97
@property (copy) NSDictionary *bonjourTXTRecord;
jens@0
    98
jens@0
    99
/** Is this service currently published/advertised via Bonjour? */
jens@0
   100
@property (readonly) BOOL bonjourPublished;
jens@0
   101
jens@0
   102
/** Current error status of Bonjour service advertising. See NSNetServicesError for error codes. */
jens@0
   103
@property (readonly) NSInteger /*NSNetServicesError*/ bonjourError;
jens@0
   104
jens@22
   105
/** The NSNetService being published. */
jens@22
   106
@property (readonly) NSNetService* bonjourService;
jens@22
   107
jens@0
   108
jens@0
   109
@end
jens@0
   110
jens@0
   111
jens@0
   112
jens@0
   113
#pragma mark -
jens@0
   114
jens@2
   115
/** The delegate messages sent by TCPListener.
jens@2
   116
    All are optional except -listener:didAcceptConnection:. */
jens@0
   117
@protocol TCPListenerDelegate <NSObject>
jens@0
   118
jens@2
   119
/** Called after an incoming connection arrives and is opened;
jens@2
   120
    the connection is now ready to send and receive data.
jens@2
   121
    To control whether or not a connection should be accepted, implement the
jens@2
   122
    -listener:shouldAcceptConnectionFrom: method.
jens@2
   123
    To use a different class than TCPConnection, set the listener's -connectionClass property.
jens@2
   124
    (This is the only required delegate method; the others are optional to implement.) */
jens@0
   125
- (void) listener: (TCPListener*)listener didAcceptConnection: (TCPConnection*)connection;
jens@0
   126
jens@0
   127
@optional
jens@2
   128
/** Called after the listener successfully opens. */
jens@0
   129
- (void) listenerDidOpen: (TCPListener*)listener;
jens@2
   130
/** Called if the listener fails to open due to an error. */
jens@0
   131
- (void) listener: (TCPListener*)listener failedToOpen: (NSError*)error;
jens@2
   132
/** Called after the listener closes. */
jens@0
   133
- (void) listenerDidClose: (TCPListener*)listener;
jens@2
   134
/** Called when an incoming connection request arrives, but before the conncetion is opened;
jens@2
   135
    return YES to accept the connection, NO to refuse it.
jens@2
   136
    This method can only use criteria like the peer IP address, or the number of currently
jens@2
   137
    open connections, to determine whether to accept. If you also want to check the
jens@2
   138
    peer's SSL certificate, then return YES from this method, and use the TCPConnection
jens@2
   139
    delegate method -connection:authorizeSSLPeer: to examine the certificate. */
jens@0
   140
- (BOOL) listener: (TCPListener*)listener shouldAcceptConnectionFrom: (IPAddress*)address;
jens@0
   141
@end