0001 https://github.com/johnno1962/Dynamo
0013 import Foundation
0014
0015 #if os(Linux)
0016 import Glibc
0017 import NSLinux
0018 #endif
0019
0020
0022
0025
0026 public class ProxySwiftlet| Proxies.swift:82 | public class SSLProxySwiftlet: ProxySwiftlet { |
: _NSObject_, DynamoSwiftlet {
0027
0028 var logger| Proxies.swift:32 | self.logger = logger |
| Proxies.swift:66 | DynamoSelector.relay( host, from: httpClient, to: remoteConnection, logger ) |
| Proxies.swift:92 | DynamoSelector.relay( httpClient.path, from: httpClient, to: remoteConnection, logger ) |
: ((String) -> ())?
0029
0030
0031 public init( logger: ((String) -> ())? = nil ) {
0032 self.logger = logger
0033 }
0034
0035
0036 public func present( httpClient: DynamoHTTPConnection ) -> DynamoProcessed {
0037
0038 if httpClient.url.host == dummyBase.host {
0039 return .NotProcessed
0040 }
0041
0042 if let host = httpClient.url.host {
0043 if let remoteConnection = DynamoHTTPConnection( url: httpClient.url ) {
0044
0045 var remotePath = httpClient.url.path ?? "/"
0046 if !remotePath.hasSuffix( "/" ) && (httpClient.path.hasSuffix( "/" ) || httpClient.path.rangeOfString( "/?" ) != nil) {
0047 remotePath += "/"
0048 }
0049 if let query = httpClient.url.query {
0050 remotePath += "?"+query
0051 }
0052
0053 remoteConnection.rawPrint( "\(httpClient.method) \(remotePath) \(httpClient.version)\r\n" )
0054 for (name, value) in httpClient.requestHeaders {
0055 remoteConnection.rawPrint( "\(name): \(value)\r\n" )
0056 }
0057 remoteConnection.rawPrint( "\r\n" )
0058
0059 if httpClient.readBuffer.length != 0 {
0060 let readBuffer = httpClient.readBuffer
0061 remoteConnection.write( readBuffer.bytes, count: readBuffer.length )
0062 readBuffer.replaceBytesInRange( NSMakeRange( 0, readBuffer.length ), withBytes: nil, length: 0 )
0063 }
0064 remoteConnection.flush()
0065
0066 DynamoSelector.relay( host, from: httpClient, to: remoteConnection, logger )
0067 }
0068 else {
0069 httpClient.sendResponse( .OK( html: "Unable to resolve host \(host)" ) )
0070 }
0071 }
0072 return .Processed
0073 }
0074
0075 }
0076
0077
0081
0082 public class SSLProxySwiftlet: ProxySwiftlet {
0083
0084
0085 public override func present( httpClient: DynamoHTTPConnection ) -> DynamoProcessed {
0086 if httpClient.method == "CONNECT" {
0087
0088 if let urlForDestination = NSURL( string: "https://\(httpClient.path)" ),
0089 remoteConnection = DynamoHTTPConnection( url: urlForDestination ) {
0090 httpClient.rawPrint( "HTTP/1.0 200 Connection established\r\nProxy-agent: Dynamo/1.0\r\n\r\n" )
0091 httpClient.flush()
0092 DynamoSelector.relay( httpClient.path, from: httpClient, to: remoteConnection, logger )
0093 }
0094
0095 return .Processed
0096 }
0097
0098 return .NotProcessed
0099 }
0100
0101 }
0102
0103
0105 var dynamoSelector| Proxies.swift:154 | if dynamoSelector == nil { |
| Proxies.swift:155 | dynamoSelector = DynamoSelector() |
| Proxies.swift:157 | dynamoSelector!.selectLoop( logger ) |
| Proxies.swift:161 | dynamoSelector!.queue.append( (label,from,to) ) |
: DynamoSelector?
0106 private let selectBitsPerFlag: Int32 = 32
0107 private let selectShift| Proxies.swift:108 | private let selectBitMask: Int32 = (1<<selectShift)-1 |
| Proxies.swift:122 | let set = flags + Int( fd>>selectShift ) |
| Proxies.swift:127 | let set = flags + Int( fd>>selectShift ) |
| Proxies.swift:132 | let set = flags + Int( fd>>selectShift ) |
: Int32 = 5
0108 private let selectBitMask| Proxies.swift:123 | set.memory &= ~(1<<(fd&selectBitMask)) |
| Proxies.swift:128 | set.memory |= 1<<(fd&selectBitMask) |
| Proxies.swift:133 | return (set.memory & (1<<(fd&selectBitMask))) != 0 |
: Int32 = (1<<selectShift)-1
0109 private var dynamoQueueLock| Proxies.swift:152 | dynamoQueueLock.lock() |
| Proxies.swift:162 | dynamoQueueLock.unlock() |
| Proxies.swift:176 | dynamoQueueLock.lock() |
| Proxies.swift:193 | dynamoQueueLock.unlock() |
= NSLock()
0110 private let dynamoProxyQueue| Proxies.swift:156 | dispatch_async( dynamoProxyQueue, { |
= dispatch_queue_create( "DynamoProxyThread", DISPATCH_QUEUE_CONCURRENT )
0111
0112
0113 public var dynamoPollingUsec| Proxies.swift:225 | timeout.tv_usec = dynamoPollingUsec |
: Int32 = 100*1000
0114 private var maxReadAhead| Proxies.swift:201 | if writer.readBuffer.length < maxReadAhead { |
= 10*1024*1024
0115 private var maxPacket| Proxies.swift:171 | var buffer = [Int8](count: maxPacket, repeatedValue: 0) |
= 2*1024
0116
0117 func FD_ZERO| Proxies.swift:195 | FD_ZERO( readFlags ) |
| Proxies.swift:196 | FD_ZERO( writeFlags ) |
| Proxies.swift:197 | FD_ZERO( errorFlags ) |
| Proxies.swift:238 | FD_ZERO( readFlags ) |
| Proxies.swift:247 | FD_ZERO( readFlags ) |
( flags: UnsafeMutablePointer<Int32> ) {
0118 memset( flags, 0, sizeof(fd_set) )
0119 }
0120
0121 func FD_CLR( fd: Int32, _ flags: UnsafeMutablePointer<Int32> ) {
0122 let set = flags + Int( fd>>selectShift )
0123 set.memory &= ~(1<<(fd&selectBitMask))
0124 }
0125
0126 func FD_SET| Proxies.swift:202 | FD_SET( fd, readFlags ) |
| Proxies.swift:204 | FD_SET( fd, errorFlags ) |
| Proxies.swift:213 | FD_SET( fd, writeFlags ) |
| Proxies.swift:214 | FD_SET( fd, errorFlags ) |
| Proxies.swift:239 | FD_SET( fd, readFlags ) |
| Proxies.swift:248 | FD_SET( fd, readFlags ) |
( fd: Int32, _ flags: UnsafeMutablePointer<Int32> ) {
0127 let set = flags + Int( fd>>selectShift )
0128 set.memory |= 1<<(fd&selectBitMask)
0129 }
0130
0131 func FD_ISSET| Proxies.swift:265 | where FD_ISSET( readFD, readFlags ) || writer.readTotal != 0 && reader.hasBytesAvailable { |
| Proxies.swift:288 | if FD_ISSET( writeFD, writeFlags ) { |
| Proxies.swift:309 | if FD_ISSET( errorFD, errorFlags ) { |
( fd: Int32, _ flags: UnsafeMutablePointer<Int32> ) -> Bool {
0132 let set = flags + Int( fd>>selectShift )
0133 return (set.memory & (1<<(fd&selectBitMask))) != 0
0134 }
0135
0136
0141
0144
0145 final class DynamoSelector| Proxies.swift:66 | DynamoSelector.relay( host, from: httpClient, to: remoteConnection, logger ) |
| Proxies.swift:92 | DynamoSelector.relay( httpClient.path, from: httpClient, to: remoteConnection, logger ) |
| Proxies.swift:105 | var dynamoSelector: DynamoSelector? |
| Proxies.swift:155 | dynamoSelector = DynamoSelector() |
| Servers.swift:213 | DynamoSelector.relay( "surrogate", from: sslConnection, to: surrogateConnection, dynamoTrace ) |
{
0146
0147 var readMap| Proxies.swift:190 | readMap[from.clientSocket] = to |
| Proxies.swift:191 | readMap[to.clientSocket] = from |
| Proxies.swift:200 | for (fd,writer) in readMap { |
| Proxies.swift:235 | dynamoStrerror( "Select error \(readMap) \(writeMap)" ) |
| Proxies.swift:237 | for (fd,_) in readMap { |
| Proxies.swift:264 | if let writer = readMap[readFD], reader = readMap[writer.clientSocket] |
| Proxies.swift:264 | if let writer = readMap[readFD], reader = readMap[writer.clientSocket] |
| Proxies.swift:270 | logger?( "\(writer.label) \(writer.readTotal)+\(readBuffer.length)+\(bytesRead) bytes (\(readFD)/\(readMap.count)/\(fdcount))" ) |
| Proxies.swift:319 | if let writer = readMap[fd] { |
| Proxies.swift:320 | readMap.removeValueForKey( writer.clientSocket ) |
| Proxies.swift:322 | readMap.removeValueForKey( fd ) |
= [Int32:DynamoHTTPConnection]()
0148 var writeMap| Proxies.swift:212 | for (fd,_) in writeMap { |
| Proxies.swift:235 | dynamoStrerror( "Select error \(readMap) \(writeMap)" ) |
| Proxies.swift:246 | for (fd,writer) in writeMap { |
| Proxies.swift:250 | writeMap.removeValueForKey( writer.clientSocket ) |
| Proxies.swift:281 | writeMap[writer.clientSocket] = writer |
| Proxies.swift:287 | for (writeFD,writer) in writeMap { |
| Proxies.swift:293 | writeMap.removeValueForKey( writer.clientSocket ) |
| Proxies.swift:302 | writeMap.removeValueForKey( writer.clientSocket ) |
| Proxies.swift:310 | writeMap.removeValueForKey( errorFD ) |
= [Int32:DynamoHTTPConnection]()
0149 var queue| Proxies.swift:161 | dynamoSelector!.queue.append( (label,from,to) ) |
| Proxies.swift:177 | while queue.count != 0 { |
| Proxies.swift:178 | let (label,from,to) = queue.removeAtIndex(0) |
= [(String,DynamoHTTPConnection,DynamoHTTPConnection)]()
0150
0151 class func relay| Proxies.swift:66 | DynamoSelector.relay( host, from: httpClient, to: remoteConnection, logger ) |
| Proxies.swift:92 | DynamoSelector.relay( httpClient.path, from: httpClient, to: remoteConnection, logger ) |
| Servers.swift:213 | DynamoSelector.relay( "surrogate", from: sslConnection, to: surrogateConnection, dynamoTrace ) |
( label: String, from: DynamoHTTPConnection, to: DynamoHTTPConnection, _ logger: ((String) -> ())? ) {
0152 dynamoQueueLock.lock()
0153
0154 if dynamoSelector == nil {
0155 dynamoSelector = DynamoSelector()
0156 dispatch_async( dynamoProxyQueue, {
0157 dynamoSelector!.selectLoop( logger )
0158 } )
0159 }
0160
0161 dynamoSelector!.queue.append( (label,from,to) )
0162 dynamoQueueLock.unlock()
0163 }
0164
0165 func selectLoop| Proxies.swift:157 | dynamoSelector!.selectLoop( logger ) |
( logger: ((String) -> Void)? = nil ) {
0166
0167 let readFlags = UnsafeMutablePointer<Int32>( malloc( sizeof(fd_set) ) )
0168 let writeFlags = UnsafeMutablePointer<Int32>( malloc( sizeof(fd_set) ) )
0169 let errorFlags = UnsafeMutablePointer<Int32>( malloc( sizeof(fd_set) ) )
0170
0171 var buffer = [Int8](count: maxPacket, repeatedValue: 0)
0172 var timeout = timeval()
0173
0174 while true {
0175
0176 dynamoQueueLock.lock()
0177 while queue.count != 0 {
0178 let (label,from,to) = queue.removeAtIndex(0)
0179 to.label = "-> \(label)"
0180 from.label = "<- \(label)"
0181
0182
0190 readMap[from.clientSocket] = to
0191 readMap[to.clientSocket] = from
0192 }
0193 dynamoQueueLock.unlock()
0194
0195 FD_ZERO( readFlags )
0196 FD_ZERO( writeFlags )
0197 FD_ZERO( errorFlags )
0198
0199 var maxfd: Int32 = -1, fdcount = 0
0200 for (fd,writer) in readMap {
0201 if writer.readBuffer.length < maxReadAhead {
0202 FD_SET( fd, readFlags )
0203 }
0204 FD_SET( fd, errorFlags )
0205 if maxfd < fd {
0206 maxfd = fd
0207 }
0208 fdcount += 1
0209 }
0210
0211 var hasWrite = false
0212 for (fd,_) in writeMap {
0213 FD_SET( fd, writeFlags )
0214 FD_SET( fd, errorFlags )
0215 if maxfd < fd {
0216 maxfd = fd
0217 }
0218 hasWrite = true
0219 }
0220
0221 timeout.tv_sec = 0
0222 #if os(Linux)
0223 timeout.tv_usec = Int(dynamoPollingUsec)
0224 #else
0225 timeout.tv_usec = dynamoPollingUsec
0226 #endif
0227
0228 if select( maxfd+1,
0229 UnsafeMutablePointer<fd_set>( readFlags ),
0230 hasWrite ? UnsafeMutablePointer<fd_set>( writeFlags ) : nil,
0231 UnsafeMutablePointer<fd_set>( errorFlags ), &timeout ) < 0 {
0232
0233 timeout.tv_sec = 0
0234 timeout.tv_usec = 0
0235 dynamoStrerror( "Select error \(readMap) \(writeMap)" )
0236
0237 for (fd,_) in readMap {
0238 FD_ZERO( readFlags )
0239 FD_SET( fd, readFlags )
0240 if select( fd+1, UnsafeMutablePointer<fd_set>( readFlags ), nil, nil, &timeout ) < 0 {
0241 dynamoLog( "Closing reader: \(fd)" )
0242 close( fd )
0243 }
0244 }
0245
0246 for (fd,writer) in writeMap {
0247 FD_ZERO( readFlags )
0248 FD_SET( fd, readFlags )
0249 if select( fd+1, UnsafeMutablePointer<fd_set>( readFlags ), nil, nil, &timeout ) < 0 {
0250 writeMap.removeValueForKey( writer.clientSocket )
0251 dynamoLog( "Closing writer: \(fd)" )
0252 close( fd )
0253 }
0254 }
0255
0256 continue
0257 }
0258
0259 if maxfd < 0 {
0260 continue
0261 }
0262
0263 for readFD in 0...maxfd {
0264 if let writer = readMap[readFD], reader = readMap[writer.clientSocket]
0265 where FD_ISSET( readFD, readFlags ) || writer.readTotal != 0 && reader.hasBytesAvailable {
0266
0267 if let bytesRead = reader.receive( &buffer, count: buffer.count ) {
0268 let readBuffer = writer.readBuffer
0269
0270 logger?( "\(writer.label) \(writer.readTotal)+\(readBuffer.length)+\(bytesRead) bytes (\(readFD)/\(readMap.count)/\(fdcount))" )
0271
0272 if bytesRead <= 0 {
0273 close( readFD )
0274 }
0275 else {
0276 readBuffer.appendBytes( buffer, length: bytesRead )
0277 writer.readTotal += bytesRead
0278 }
0279
0280 if readBuffer.length != 0 {
0281 writeMap[writer.clientSocket] = writer
0282 }
0283 }
0284 }
0285 }
0286
0287 for (writeFD,writer) in writeMap {
0288 if FD_ISSET( writeFD, writeFlags ) {
0289 let readBuffer = writer.readBuffer
0290
0291 if let bytesWritten = writer.forward( readBuffer.bytes, count: readBuffer.length ) {
0292 if bytesWritten <= 0 {
0293 writeMap.removeValueForKey( writer.clientSocket )
0294 dynamoLog( "Short write on relay \(writer.label)" )
0295 close( writeFD )
0296 }
0297 else {
0298 readBuffer.replaceBytesInRange( NSMakeRange( 0, bytesWritten ), withBytes: nil, length: 0 )
0299 }
0300
0301 if readBuffer.length == 0 {
0302 writeMap.removeValueForKey( writer.clientSocket )
0303 }
0304 }
0305 }
0306 }
0307
0308 for errorFD in 0..<maxfd {
0309 if FD_ISSET( errorFD, errorFlags ) {
0310 writeMap.removeValueForKey( errorFD )
0311 dynamoLog( "ERROR from select on relay" )
0312 close( errorFD )
0313 }
0314 }
0315 }
0316 }
0317
0318 private func close| Proxies.swift:242 | close( fd ) |
| Proxies.swift:252 | close( fd ) |
| Proxies.swift:273 | close( readFD ) |
| Proxies.swift:295 | close( writeFD ) |
| Proxies.swift:312 | close( errorFD ) |
( fd: Int32 ) {
0319 if let writer = readMap[fd] {
0320 readMap.removeValueForKey( writer.clientSocket )
0321 }
0322 readMap.removeValueForKey( fd )
0323 }
0324
0325 }
0326