-
Notifications
You must be signed in to change notification settings - Fork 554
Expand file tree
/
Copy pathSocket+Server.swift
More file actions
130 lines (120 loc) · 5.03 KB
/
Socket+Server.swift
File metadata and controls
130 lines (120 loc) · 5.03 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
//
// Socket+Server.swift
// Swifter
//
// Created by Damian Kolakowski on 13/07/16.
//
import Foundation
#if os(Windows)
import WinSDK
#endif
extension Socket {
// swiftlint:disable function_body_length
/// - Parameters:
/// - listenAddress: String representation of the address the socket should accept
/// connections from. It should be in IPv4 format if forceIPv4 == true,
/// otherwise - in IPv6.
public class func tcpSocketForListen(_ port: in_port_t, _ forceIPv4: Bool = false, _ maxPendingConnection: Int32 = SOMAXCONN, _ listenAddress: String? = nil) throws -> Socket {
#if os(Linux)
let socketFileDescriptor = socket(forceIPv4 ? AF_INET : AF_INET6, Int32(SOCK_STREAM.rawValue), 0)
#else
let socketFileDescriptor = socket(forceIPv4 ? AF_INET : AF_INET6, SOCK_STREAM, 0)
#endif
if socketFileDescriptor == invalidPlatformSocketFD {
throw SocketError.socketCreationFailed(Errno.description())
}
var value: Int32 = 1
if setsockopt(socketFileDescriptor, SOL_SOCKET, SO_REUSEADDR, &value, socklen_t(MemoryLayout<Int32>.size)) == -1 {
let details = Errno.description()
Socket.close(socketFileDescriptor)
throw SocketError.socketSettingReUseAddrFailed(details)
}
Socket.setNoSigPipe(socketFileDescriptor)
var bindResult: Int32 = -1
if forceIPv4 {
#if os(Linux)
var addr = sockaddr_in(
sin_family: sa_family_t(AF_INET),
sin_port: port.bigEndian,
sin_addr: in_addr(s_addr: in_addr_t(0)),
sin_zero: (0, 0, 0, 0, 0, 0, 0, 0))
#elseif os(Windows)
var addr = sockaddr_in(
sin_family: ADDRESS_FAMILY(AF_INET),
sin_port: port.bigEndian,
sin_addr: .init(),
sin_zero: (0, 0, 0, 0, 0, 0, 0, 0))
#else
var addr = sockaddr_in(
sin_len: UInt8(MemoryLayout<sockaddr_in>.stride),
sin_family: UInt8(AF_INET),
sin_port: port.bigEndian,
sin_addr: in_addr(s_addr: in_addr_t(0)),
sin_zero: (0, 0, 0, 0, 0, 0, 0, 0))
#endif
if let address = listenAddress {
if address.withCString({ cstring in inet_pton(AF_INET, cstring, &addr.sin_addr) }) == 1 {
// print("\(address) is converted to \(addr.sin_addr).")
} else {
// print("\(address) is not converted.")
}
}
bindResult = withUnsafePointer(to: &addr) {
bind(socketFileDescriptor, UnsafePointer<sockaddr>(OpaquePointer($0)), socklen_t(MemoryLayout<sockaddr_in>.size))
}
} else {
#if os(Linux)
var addr = sockaddr_in6(
sin6_family: sa_family_t(AF_INET6),
sin6_port: port.bigEndian,
sin6_flowinfo: 0,
sin6_addr: in6addr_any,
sin6_scope_id: 0)
#elseif os(Windows)
var addr = sockaddr_in6(
sin6_family: ADDRESS_FAMILY(AF_INET6),
sin6_port: port.bigEndian,
sin6_flowinfo: 0,
sin6_addr: in6addr_any,
sockaddr_in6.__Unnamed_union___Anonymous_field4())
#else
var addr = sockaddr_in6(
sin6_len: UInt8(MemoryLayout<sockaddr_in6>.stride),
sin6_family: UInt8(AF_INET6),
sin6_port: port.bigEndian,
sin6_flowinfo: 0,
sin6_addr: in6addr_any,
sin6_scope_id: 0)
#endif
if let address = listenAddress {
if address.withCString({ cstring in inet_pton(AF_INET6, cstring, &addr.sin6_addr) }) == 1 {
//print("\(address) is converted to \(addr.sin6_addr).")
} else {
//print("\(address) is not converted.")
}
}
bindResult = withUnsafePointer(to: &addr) {
bind(socketFileDescriptor, UnsafePointer<sockaddr>(OpaquePointer($0)), socklen_t(MemoryLayout<sockaddr_in6>.size))
}
}
if bindResult == -1 {
let details = Errno.description()
Socket.close(socketFileDescriptor)
throw SocketError.bindFailed(details)
}
if listen(socketFileDescriptor, maxPendingConnection) == -1 {
let details = Errno.description()
Socket.close(socketFileDescriptor)
throw SocketError.listenFailed(details)
}
return Socket(socketFileDescriptor: socketFileDescriptor)
}
public func acceptClientSocket() throws -> Socket {
let clientSocket = accept(self.socketFileDescriptor, nil, nil)
if clientSocket == invalidPlatformSocketFD {
throw SocketError.acceptFailed(Errno.description())
}
Socket.setNoSigPipe(clientSocket)
return Socket(socketFileDescriptor: clientSocket)
}
}