0001    //
0002    //  Servers.swift
0003    //  Dynamo
0004    //
0005    //  Created by John Holdsworth on 11/06/2015.
0006    //  Copyright (c) 2015 John Holdsworth. All rights reserved.
0007    //
0008    //  $Id: //depot/Dynamo/Sources/Servers.swift#16 $
0009    //
0010    //  Repo: https://github.com/johnno1962/Dynamo
0011    //
0012    
0013    import Foundation
0014    
0015    #if os(Linux)
0016    import Glibc
0017    import NSLinux
0018    #endif
0019    
0020    // MARK: Private queues and missing IP functions
0021    
0022    let dynamoRequestQueue
Servers.swift:109
                dispatch_async( dynamoRequestQueue, {
= dispatch_queue_create( "DynamoRequestThread", DISPATCH_QUEUE_CONCURRENT ) 0023 0024 // MARK: Basic http: Web server 0025 0026 /** 0027 Basic http protocol web server running on the specified port. Requests are presented to each of a set 0028 of swiftlets provided in a connecton thread until one is encountered that has processed the request. 0029 */ 0030 0031 public class DynamoWebServer
Servers.swift:190
public class DynamoSSLWebServer: DynamoWebServer {
: _NSObject_ { 0032 0033 private let swiftlets
Servers.swift:55
        self.swiftlets = swiftlets
Servers.swift:130
                for swiftlet in swiftlets {
: [DynamoSwiftlet] 0034 private let serverSocket
Servers.swift:70
        serverSocket = socket( Int32(ip4addr.sin_family), sockType, 0 )
Servers.swift:77
        if serverSocket < 0 {
Servers.swift:80
        else if setsockopt( serverSocket, SOL_SOCKET, SO_REUSEADDR, &yes, yeslen ) < 0 {
Servers.swift:83
        else if bind( serverSocket, sockaddr_cast(&ip4addr), addrLen ) < 0 {
Servers.swift:86
        else if listen( serverSocket, 100 ) < 0 {
Servers.swift:89
        else if getsockname( serverSocket, sockaddr_cast(&ip4addr), &addrLen ) == 0 {
Servers.swift:104
        while self.serverSocket >= 0 {
Servers.swift:106
            let clientSocket = accept( self.serverSocket, nil, nil )
: Int32 0035 0036 /** port allocated for server if specified as 0 */ 0037 public var serverPort
Servers.swift:90
            serverPort = ntohs( ip4addr.sin_port )
Servers.swift:96
            dynamoLog( "Server available on http\(s)://localhost:\(serverPort)" )
: UInt16 = 0 0038 0039 /** basic initialiser for Swift web server processing using array of swiftlets */ 0040 public convenience init?( portNumber: UInt16, swiftlets: [DynamoSwiftlet], localhostOnly: Bool = false ) { 0041 0042 self.init( portNumber, swiftlets: swiftlets, localhostOnly: localhostOnly ) 0043 0044 dispatch_async( dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), { 0045 self.runConnectionHandler( self.httpConnectionHandler ) 0046 } ) 0047 } 0048 0049 init
Servers.swift:42
        self.init( portNumber, swiftlets: swiftlets, localhostOnly: localhostOnly )
Servers.swift:201
        super.init( portNumber, swiftlets: swiftlets, localhostOnly: false )
?( _ portNumber: UInt16, swiftlets: [DynamoSwiftlet], localhostOnly: Bool ) { 0050 0051 #if os(Linux) 0052 signal( SIGPIPE, SIG_IGN ) 0053 #endif 0054 0055 self.swiftlets = swiftlets 0056 0057 var ip4addr = sockaddr_in() 0058 0059 #if !os(Linux) 0060 ip4addr.sin_len = UInt8(sizeof(sockaddr_in)) 0061 #endif 0062 ip4addr.sin_family = sa_family_t(AF_INET) 0063 ip4addr.sin_port = htons( portNumber ) 0064 ip4addr.sin_addr = in_addr( s_addr: INADDR_ANY ) 0065 0066 if localhostOnly { 0067 inet_aton( "127.0.0.1", &ip4addr.sin_addr ) 0068 } 0069 0070 serverSocket = socket( Int32(ip4addr.sin_family), sockType, 0 ) 0071 0072 var yes: u_int = 1, yeslen = socklen_t(sizeof(yes.dynamicType)) 0073 var addrLen = socklen_t(sizeof(ip4addr.dynamicType)) 0074 0075 super.init() 0076 0077 if serverSocket < 0 { 0078 dynamoStrerror( "Could not get server socket" ) 0079 } 0080 else if setsockopt( serverSocket, SOL_SOCKET, SO_REUSEADDR, &yes, yeslen ) < 0 { 0081 dynamoStrerror( "Could not set SO_REUSEADDR" ) 0082 } 0083 else if bind( serverSocket, sockaddr_cast(&ip4addr), addrLen ) < 0 { 0084 dynamoStrerror( "Could not bind service socket on port \(portNumber)" ) 0085 } 0086 else if listen( serverSocket, 100 ) < 0 { 0087 dynamoStrerror( "Server socket would not listen" ) 0088 } 0089 else if getsockname( serverSocket, sockaddr_cast(&ip4addr), &addrLen ) == 0 { 0090 serverPort = ntohs( ip4addr.sin_port ) 0091 #if os(Linux) 0092 let s = "" 0093 #else 0094 let s = self.dynamicType === DynamoSSLWebServer.self ? "s" : "" 0095 #endif 0096 dynamoLog( "Server available on http\(s)://localhost:\(serverPort)" ) 0097 return 0098 } 0099 0100 return nil 0101 } 0102 0103 func runConnectionHandler
Servers.swift:45
            self.runConnectionHandler( self.httpConnectionHandler )
Servers.swift:205
                self.runConnectionHandler( self.httpConnectionHandler )
Servers.swift:209
            runConnectionHandler( {
( connectionHandler: (Int32) -> Void ) { 0104 while self.serverSocket >= 0 { 0105 0106 let clientSocket = accept( self.serverSocket, nil, nil ) 0107 0108 if clientSocket >= 0 { 0109 dispatch_async( dynamoRequestQueue, { 0110 connectionHandler( clientSocket ) 0111 } ) 0112 } 0113 else { 0114 NSThread.sleepForTimeInterval( 0.5 ) 0115 } 0116 } 0117 } 0118 0119 func wrapConnection
Servers.swift:125
        if let httpClient = self.wrapConnection( clientSocket ) {
( clientSocket: Int32 ) -> DynamoHTTPConnection? { 0120 return DynamoHTTPConnection( clientSocket: clientSocket ) 0121 } 0122 0123 public func httpConnectionHandler
Servers.swift:45
            self.runConnectionHandler( self.httpConnectionHandler )
Servers.swift:205
                self.runConnectionHandler( self.httpConnectionHandler )
( clientSocket: Int32 ) { 0124 0125 if let httpClient = self.wrapConnection( clientSocket ) { 0126 0127 while httpClient.readHeaders() { 0128 var processed = false 0129 0130 for swiftlet in swiftlets { 0131 0132 switch swiftlet.present( httpClient ) { 0133 case .NotProcessed: 0134 continue 0135 case .Processed: 0136 return 0137 case .ProcessedAndReusable: 0138 httpClient.flush() 0139 processed = true 0140 break 0141 } 0142 0143 break 0144 } 0145 0146 if !processed { 0147 httpClient.status = 400 0148 httpClient.response( "Invalid request: \(httpClient.method) \(httpClient.path) \(httpClient.version)" ) 0149 return 0150 } 0151 } 0152 } 0153 } 0154 0155 } 0156 0157 #if os(Linux) 0158 /** 0159 Pre-forked worker model version e.g. https://github.com/kylef/Curassow 0160 */ 0161 0162 public class DynamoWorkerServer : DynamoWebServer { 0163 0164 public init?( portNumber: UInt16, swiftlets: [DynamoSwiftlet], workers: Int, localhostOnly: Bool = false ) { 0165 0166 super.init( portNumber, swiftlets: swiftlets, localhostOnly: localhostOnly ) 0167 0168 dispatch_async( dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), { 0169 var wcount = 0 0170 while true { 0171 let status = __WAIT_STATUS() 0172 if (wcount < workers || wait( status ) != 0) && fork() == 0 { 0173 self.runConnectionHandler( self.httpConnectionHandler ) 0174 } 0175 wcount += 1 0176 } 0177 } ) 0178 } 0179 0180 } 0181 #else 0182 0183 // MARK: SSL https: Web Server 0184 0185 /** 0186 Subclass of DynamoWebServer for accepting https: SSL encoded requests. Create a proxy on the provided 0187 port to a surrogate DynamoWebServer on a random port on the localhost to actually process the requests. 0188 */ 0189 0190 public class DynamoSSLWebServer
Servers.swift:94
            let s = self.dynamicType === DynamoSSLWebServer.self ? "s" : ""
: DynamoWebServer { 0191 0192 private let certs
Servers.swift:199
        self.certs = certs
Servers.swift:223
        return DynamoSSLConnection( sslSocket: clientSocket, certs: certs )
: [AnyObject] 0193 0194 /** 0195 default initialiser for SSL server. Can proxy a "surrogate" non-SSL server given it's URL 0196 */ 0197 public init?( portNumber: UInt16, swiftlets: [DynamoSwiftlet] = [], certs: [AnyObject], surrogate: String? = nil ) { 0198 0199 self.certs = certs 0200 0201 super.init( portNumber, swiftlets: swiftlets, localhostOnly: false ) 0202 0203 if surrogate == nil { 0204 dispatch_async( dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), { 0205 self.runConnectionHandler( self.httpConnectionHandler ) 0206 } ) 0207 } 0208 else if let surrogateURL = NSURL( string: surrogate! ) { 0209 runConnectionHandler( { 0210 (clientSocket: Int32) in 0211 if let sslConnection = self.wrapConnection( clientSocket ), 0212 surrogateConnection = DynamoHTTPConnection( url: surrogateURL ) { 0213 DynamoSelector.relay( "surrogate", from: sslConnection, to: surrogateConnection, dynamoTrace ) 0214 } 0215 } ) 0216 } 0217 else { 0218 dynamoLog( "Invalid surrogate URL: \(surrogate)" ) 0219 } 0220 } 0221 0222 override func wrapConnection
Servers.swift:211
                if let sslConnection = self.wrapConnection( clientSocket ),
( clientSocket: Int32 ) -> DynamoHTTPConnection? { 0223 return DynamoSSLConnection( sslSocket: clientSocket, certs: certs ) 0224 } 0225 0226 } 0227 0228 class DynamoSSLConnection
Servers.swift:223
        return DynamoSSLConnection( sslSocket: clientSocket, certs: certs )
: DynamoHTTPConnection { 0229 0230 let inputStream
Servers.swift:240
        inputStream = readStream!.takeRetainedValue()
Servers.swift:245
        inputStream.open()
Servers.swift:255
            CFReadStreamSetProperty( inputStream, kCFStreamPropertySSLSettings, sslSettings )
Servers.swift:261
        return inputStream.hasBytesAvailable
Servers.swift:265
        return inputStream.read( UnsafeMutablePointer<UInt8>(buffer), maxLength: count )
Servers.swift:273
        return inputStream.hasBytesAvailable ? _read( buffer, count: count ) :  nil
Servers.swift:283
        inputStream.close()
: NSInputStream 0231 let outputStream
Servers.swift:241
        outputStream = writeStream!.takeRetainedValue()
Servers.swift:246
        outputStream.open()
Servers.swift:256
            CFWriteStreamSetProperty( outputStream, kCFStreamPropertySSLSettings, sslSettings )
Servers.swift:269
        return outputStream.write( UnsafePointer<UInt8>(buffer), maxLength: count )
Servers.swift:277
        return outputStream.hasSpaceAvailable ? _write( buffer, count: count ) : nil
Servers.swift:282
        outputStream.close()
: NSOutputStream 0232 0233 init
Servers.swift:223
        return DynamoSSLConnection( sslSocket: clientSocket, certs: certs )
?( sslSocket: Int32, certs: [AnyObject]? ) { 0234 0235 var readStream: Unmanaged<CFReadStream>? 0236 var writeStream: Unmanaged<CFWriteStream>? 0237 0238 CFStreamCreatePairWithSocket( nil, sslSocket, &readStream, &writeStream ) 0239 0240 inputStream = readStream!.takeRetainedValue() 0241 outputStream = writeStream!.takeRetainedValue() 0242 0243 super.init( clientSocket: sslSocket ) 0244 0245 inputStream.open() 0246 outputStream.open() 0247 0248 if certs != nil { 0249 let sslSettings: [NSString:AnyObject] = [ 0250 kCFStreamSSLIsServer: NSNumber( bool: true ), 0251 kCFStreamSSLLevel: kCFStreamSSLLevel, 0252 kCFStreamSSLCertificates: certs! 0253 ] 0254 0255 CFReadStreamSetProperty( inputStream, kCFStreamPropertySSLSettings, sslSettings ) 0256 CFWriteStreamSetProperty( outputStream, kCFStreamPropertySSLSettings, sslSettings ) 0257 } 0258 } 0259 0260 override var hasBytesAvailable: Bool { 0261 return inputStream.hasBytesAvailable 0262 } 0263 0264 override func _read
Servers.swift:273
        return inputStream.hasBytesAvailable ? _read( buffer, count: count ) :  nil
( buffer: UnsafeMutablePointer<Void>, count: Int ) -> Int { 0265 return inputStream.read( UnsafeMutablePointer<UInt8>(buffer), maxLength: count ) 0266 } 0267 0268 override func _write
Servers.swift:277
        return outputStream.hasSpaceAvailable ? _write( buffer, count: count ) : nil
( buffer: UnsafePointer<Void>, count: Int ) -> Int { 0269 return outputStream.write( UnsafePointer<UInt8>(buffer), maxLength: count ) 0270 } 0271 0272 override func receive( buffer: UnsafeMutablePointer<Void>, count: Int ) -> Int? { 0273 return inputStream.hasBytesAvailable ? _read( buffer, count: count ) : nil 0274 } 0275 0276 override func forward( buffer: UnsafePointer<Void>, count: Int ) -> Int? { 0277 return outputStream.hasSpaceAvailable ? _write( buffer, count: count ) : nil 0278 } 0279 0280 deinit { 0281 flush() 0282 outputStream.close() 0283 inputStream.close() 0284 } 0285 0286 } 0287 0288 #endif 0289 0290