Skip to content

Commit 7e1174f

Browse files
committed
Added an option to set the address to listen to.
1 parent 7321632 commit 7e1174f

File tree

2 files changed

+59
-31
lines changed

2 files changed

+59
-31
lines changed

Sources/HttpServerIO.swift

Lines changed: 34 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ public protocol HttpServerIODelegate: class {
1515
public class HttpServerIO {
1616

1717
public weak var delegate : HttpServerIODelegate?
18-
18+
1919
private var socket = Socket(socketFileDescriptor: -1)
2020
private var sockets = Set<Socket>()
2121

@@ -25,9 +25,9 @@ public class HttpServerIO {
2525
case stopping
2626
case stopped
2727
}
28-
28+
2929
private var stateValue: Int32 = HttpServerIOState.stopped.rawValue
30-
30+
3131
public private(set) var state: HttpServerIOState {
3232
get {
3333
return HttpServerIOState(rawValue: stateValue)!
@@ -41,29 +41,40 @@ public class HttpServerIO {
4141
#endif
4242
}
4343
}
44-
44+
4545
public var operating: Bool { get { return self.state == .running } }
46-
46+
47+
/// String representation of the IPv4 address to receive requests from.
48+
/// It's only used when the server is started with `forceIPv4` option set to true.
49+
/// Otherwise, `listenAddressIPv6` will be used.
50+
public var listenAddressIPv4: String?
51+
52+
/// String representation of the IPv6 address to receive requests from.
53+
/// It's only used when the server is started with `forceIPv4` option set to false.
54+
/// Otherwise, `listenAddressIPv4` will be used.
55+
public var listenAddressIPv6: String?
56+
4757
private let queue = DispatchQueue(label: "swifter.httpserverio.clientsockets")
48-
58+
4959
public func port() throws -> Int {
5060
return Int(try socket.port())
5161
}
52-
62+
5363
public func isIPv4() throws -> Bool {
5464
return try socket.isIPv4()
5565
}
56-
66+
5767
deinit {
5868
stop()
5969
}
60-
70+
6171
@available(macOS 10.10, *)
6272
public func start(_ port: in_port_t = 8080, forceIPv4: Bool = false, priority: DispatchQoS.QoSClass = DispatchQoS.QoSClass.background) throws {
6373
guard !self.operating else { return }
6474
stop()
6575
self.state = .starting
66-
self.socket = try Socket.tcpSocketForListen(port, forceIPv4)
76+
let address = forceIPv4 ? listenAddressIPv4 : listenAddressIPv6
77+
self.socket = try Socket.tcpSocketForListen(port, forceIPv4, SOMAXCONN, address)
6778
DispatchQueue.global(qos: priority).async { [weak self] in
6879
guard let `self` = self else { return }
6980
guard self.operating else { return }
@@ -84,7 +95,7 @@ public class HttpServerIO {
8495
}
8596
self.state = .running
8697
}
87-
98+
8899
public func stop() {
89100
guard self.operating else { return }
90101
self.state = .stopping
@@ -98,11 +109,11 @@ public class HttpServerIO {
98109
socket.close()
99110
self.state = .stopped
100111
}
101-
112+
102113
public func dispatch(_ request: HttpRequest) -> ([String: String], (HttpRequest) -> HttpResponse) {
103114
return ([:], { _ in HttpResponse.notFound })
104115
}
105-
116+
106117
private func handleConnection(_ socket: Socket) {
107118
let parser = HttpParser()
108119
while self.operating, let request = try? parser.readHttpRequest(socket) {
@@ -129,7 +140,7 @@ public class HttpServerIO {
129140
}
130141
socket.close()
131142
}
132-
143+
133144
private struct InnerWriteContext: HttpResponseBodyWriter {
134145

135146
let socket: Socket
@@ -149,38 +160,38 @@ public class HttpServerIO {
149160
func write(_ data: NSData) throws {
150161
try socket.writeData(data)
151162
}
152-
163+
153164
func write(_ data: Data) throws {
154165
try socket.writeData(data)
155166
}
156167
}
157-
168+
158169
private func respond(_ socket: Socket, response: HttpResponse, keepAlive: Bool) throws -> Bool {
159170
guard self.operating else { return false }
160171

161172
try socket.writeUTF8("HTTP/1.1 \(response.statusCode()) \(response.reasonPhrase())\r\n")
162-
173+
163174
let content = response.content()
164-
175+
165176
if content.length >= 0 {
166177
try socket.writeUTF8("Content-Length: \(content.length)\r\n")
167178
}
168-
179+
169180
if keepAlive && content.length != -1 {
170181
try socket.writeUTF8("Connection: keep-alive\r\n")
171182
}
172-
183+
173184
for (name, value) in response.headers() {
174185
try socket.writeUTF8("\(name): \(value)\r\n")
175186
}
176-
187+
177188
try socket.writeUTF8("\r\n")
178-
189+
179190
if let writeClosure = content.write {
180191
let context = InnerWriteContext(socket: socket)
181192
try writeClosure(context)
182193
}
183-
194+
184195
return keepAlive && content.length != -1;
185196
}
186197
}

Sources/Socket+Server.swift

Lines changed: 25 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,27 +8,30 @@
88
import Foundation
99

1010
extension Socket {
11-
12-
public class func tcpSocketForListen(_ port: in_port_t, _ forceIPv4: Bool = false, _ maxPendingConnection: Int32 = SOMAXCONN) throws -> Socket {
13-
11+
12+
/// - Parameters:
13+
/// - listenAddress: String representation of the address the socket should accept
14+
/// connections from. It should be in IPv4 format if forceIPv4 == true,
15+
/// otherwise - in IPv6.
16+
public class func tcpSocketForListen(_ port: in_port_t, _ forceIPv4: Bool = false, _ maxPendingConnection: Int32 = SOMAXCONN, _ listenAddress: String? = nil) throws -> Socket {
17+
1418
#if os(Linux)
1519
let socketFileDescriptor = socket(forceIPv4 ? AF_INET : AF_INET6, Int32(SOCK_STREAM.rawValue), 0)
1620
#else
1721
let socketFileDescriptor = socket(forceIPv4 ? AF_INET : AF_INET6, SOCK_STREAM, 0)
1822
#endif
19-
23+
2024
if socketFileDescriptor == -1 {
2125
throw SocketError.socketCreationFailed(Errno.description())
2226
}
23-
27+
2428
var value: Int32 = 1
2529
if setsockopt(socketFileDescriptor, SOL_SOCKET, SO_REUSEADDR, &value, socklen_t(MemoryLayout<Int32>.size)) == -1 {
2630
let details = Errno.description()
2731
Socket.close(socketFileDescriptor)
2832
throw SocketError.socketSettingReUseAddrFailed(details)
2933
}
3034
Socket.setNoSigPipe(socketFileDescriptor)
31-
3235

3336
var bindResult: Int32 = -1
3437
if forceIPv4 {
@@ -46,6 +49,13 @@ extension Socket {
4649
sin_addr: in_addr(s_addr: in_addr_t(0)),
4750
sin_zero:(0, 0, 0, 0, 0, 0, 0, 0))
4851
#endif
52+
if let address = listenAddress {
53+
if address.withCString({ cstring in inet_pton(AF_INET, cstring, &addr.sin_addr) }) == 1 {
54+
// print("\(address) is converted to \(addr.sin_addr).")
55+
} else {
56+
// print("\(address) is not converted.")
57+
}
58+
}
4959
bindResult = withUnsafePointer(to: &addr) {
5060
bind(socketFileDescriptor, UnsafePointer<sockaddr>(OpaquePointer($0)), socklen_t(MemoryLayout<sockaddr_in>.size))
5161
}
@@ -66,17 +76,24 @@ extension Socket {
6676
sin6_addr: in6addr_any,
6777
sin6_scope_id: 0)
6878
#endif
79+
if let address = listenAddress {
80+
if address.withCString({ cstring in inet_pton(AF_INET6, cstring, &addr.sin6_addr) }) == 1 {
81+
//print("\(address) is converted to \(addr.sin6_addr).")
82+
} else {
83+
//print("\(address) is not converted.")
84+
}
85+
}
6986
bindResult = withUnsafePointer(to: &addr) {
7087
bind(socketFileDescriptor, UnsafePointer<sockaddr>(OpaquePointer($0)), socklen_t(MemoryLayout<sockaddr_in6>.size))
7188
}
7289
}
73-
90+
7491
if bindResult == -1 {
7592
let details = Errno.description()
7693
Socket.close(socketFileDescriptor)
7794
throw SocketError.bindFailed(details)
7895
}
79-
96+
8097
if listen(socketFileDescriptor, maxPendingConnection) == -1 {
8198
let details = Errno.description()
8299
Socket.close(socketFileDescriptor)

0 commit comments

Comments
 (0)