Skip to content

Commit fdefc8f

Browse files
Fixed bugs on connect and sockaddr
1 parent 86fe4cb commit fdefc8f

File tree

5 files changed

+153
-29
lines changed

5 files changed

+153
-29
lines changed

.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata

Lines changed: 7 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<Scheme
3+
LastUpgradeVersion = "1230"
4+
version = "1.3">
5+
<BuildAction
6+
parallelizeBuildables = "YES"
7+
buildImplicitDependencies = "YES">
8+
<BuildActionEntries>
9+
<BuildActionEntry
10+
buildForTesting = "YES"
11+
buildForRunning = "YES"
12+
buildForProfiling = "YES"
13+
buildForArchiving = "YES"
14+
buildForAnalyzing = "YES">
15+
<BuildableReference
16+
BuildableIdentifier = "primary"
17+
BlueprintIdentifier = "Socket"
18+
BuildableName = "Socket"
19+
BlueprintName = "Socket"
20+
ReferencedContainer = "container:">
21+
</BuildableReference>
22+
</BuildActionEntry>
23+
<BuildActionEntry
24+
buildForTesting = "YES"
25+
buildForRunning = "YES"
26+
buildForProfiling = "NO"
27+
buildForArchiving = "NO"
28+
buildForAnalyzing = "YES">
29+
<BuildableReference
30+
BuildableIdentifier = "primary"
31+
BlueprintIdentifier = "SocketTests"
32+
BuildableName = "SocketTests"
33+
BlueprintName = "SocketTests"
34+
ReferencedContainer = "container:">
35+
</BuildableReference>
36+
</BuildActionEntry>
37+
</BuildActionEntries>
38+
</BuildAction>
39+
<TestAction
40+
buildConfiguration = "Debug"
41+
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
42+
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
43+
shouldUseLaunchSchemeArgsEnv = "YES">
44+
<Testables>
45+
<TestableReference
46+
skipped = "NO">
47+
<BuildableReference
48+
BuildableIdentifier = "primary"
49+
BlueprintIdentifier = "SocketTests"
50+
BuildableName = "SocketTests"
51+
BlueprintName = "SocketTests"
52+
ReferencedContainer = "container:">
53+
</BuildableReference>
54+
</TestableReference>
55+
</Testables>
56+
</TestAction>
57+
<LaunchAction
58+
buildConfiguration = "Debug"
59+
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
60+
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
61+
launchStyle = "0"
62+
useCustomWorkingDirectory = "NO"
63+
ignoresPersistentStateOnLaunch = "NO"
64+
debugDocumentVersioning = "YES"
65+
debugServiceExtension = "internal"
66+
allowLocationSimulation = "YES">
67+
</LaunchAction>
68+
<ProfileAction
69+
buildConfiguration = "Release"
70+
shouldUseLaunchSchemeArgsEnv = "YES"
71+
savedToolIdentifier = ""
72+
useCustomWorkingDirectory = "NO"
73+
debugDocumentVersioning = "YES">
74+
<MacroExpansion>
75+
<BuildableReference
76+
BuildableIdentifier = "primary"
77+
BlueprintIdentifier = "Socket"
78+
BuildableName = "Socket"
79+
BlueprintName = "Socket"
80+
ReferencedContainer = "container:">
81+
</BuildableReference>
82+
</MacroExpansion>
83+
</ProfileAction>
84+
<AnalyzeAction
85+
buildConfiguration = "Debug">
86+
</AnalyzeAction>
87+
<ArchiveAction
88+
buildConfiguration = "Release"
89+
revealArchiveInOrganizer = "YES">
90+
</ArchiveAction>
91+
</Scheme>

Sources/Socket/Socket.swift

Lines changed: 33 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -2,21 +2,23 @@ import Foundation
22

33
public class Socket {
44
let socket : Int32
5-
let addressFamily : Int32
6-
let socketType : Int32
7-
let socketProtocol : Int32
5+
let host : String?
86

9-
var port : UInt16
10-
var infos : addrinfo = addrinfo()
7+
public let addressFamily : Int32
8+
public let socketType : Int32
9+
public let socketProtocol : Int32
10+
11+
public var port : UInt16
1112

1213
var maxConnections : Int32 = 1
1314

14-
public init(host : String, port : UInt16, addressFamily : Int32, socketType : Int32, socketProtocol : Int32, maxConnections : Int32 = 1) throws {
15-
// Create socket
15+
public init(host : String?, port : UInt16, addressFamily : Int32, socketType : Int32, socketProtocol : Int32, maxConnections : Int32 = 1) throws {
16+
self.host = host
1617
self.addressFamily = addressFamily
1718
self.socketType = socketType
1819
self.socketProtocol = socketProtocol
1920

21+
// Create socket
2022
socket = Darwin.socket(addressFamily, socketType, socketProtocol)
2123
guard self.socket != -1 else {
2224
throw SocketError.socketCreationFailed(String(cString: strerror(errno)))
@@ -25,27 +27,27 @@ public class Socket {
2527
// Initialize parameters
2628
self.port = port
2729
self.maxConnections = maxConnections
28-
29-
// Socket infos
30-
self.infos = try getAddrInfo(host)
31-
32-
// MARK: SQL server only!
33-
// Set socket options
34-
var value : Int32 = 1;
35-
try setOption(level: SOL_SOCKET, option: SO_REUSEADDR, value: &value, length: socklen_t(MemoryLayout<Int32>.size))
36-
try setOption(level: SOL_SOCKET, option: SO_KEEPALIVE, value: &value, length: socklen_t(MemoryLayout<Int32>.size))
37-
try setOption(level: SOL_SOCKET, option: SO_NOSIGPIPE, value: &value, length: socklen_t(MemoryLayout<Int32>.size))
3830
}
3931

4032
/// Connect client socket to server.
41-
public func connect() throws {
33+
public func connect(infos : addrinfo) throws {
4234
guard Darwin.connect(socket, infos.ai_addr, socklen_t(infos.ai_addrlen)) != -1 else {
4335
throw SocketError.connectFailed(String(cString: strerror(errno)))
4436
}
4537
}
4638

39+
public func connectAll(infos : [addrinfo]) throws {
40+
for info in infos {
41+
do {
42+
try connect(infos: info)
43+
return
44+
}
45+
catch {}
46+
}
47+
}
48+
4749
/// Bind server to an address.
48-
public func bind() throws {
50+
public func bind(infos : addrinfo) throws {
4951
guard Darwin.bind(socket, infos.ai_addr, socklen_t(infos.ai_addrlen)) != -1 else {
5052
throw SocketError.bindFailed(String(cString: strerror(errno)))
5153
}
@@ -82,27 +84,32 @@ public class Socket {
8284
}
8385
}
8486

85-
// -- Utility --
8687
/// Get server address infos from host for socket connection.
87-
private func getAddrInfo(_ host : String) throws -> addrinfo {
88+
public func getAddressInfos() throws -> [addrinfo] {
89+
var result : [addrinfo] = []
8890
var hints : addrinfo = addrinfo(
89-
ai_flags: AI_ALL,
91+
ai_flags: AI_ADDRCONFIG,
9092
ai_family: addressFamily,
9193
ai_socktype: socketType,
92-
ai_protocol: 0,
94+
ai_protocol: socketProtocol,
9395
ai_addrlen: 0,
9496
ai_canonname: nil,
9597
ai_addr: nil,
9698
ai_next: nil
9799
)
98-
var serverInfos : UnsafeMutablePointer<addrinfo>? = nil
100+
var infos : UnsafeMutablePointer<addrinfo>? = nil
99101

100102
// Get infos
101-
if (getaddrinfo(nil, String(port), &hints, &serverInfos) != 0) {
103+
if (getaddrinfo(host, String(port), &hints, &infos) != 0) {
102104
throw SocketError.getAddressInfoFailed(errno)
103105
}
104106

105-
return serverInfos!.pointee
107+
while (infos != nil) {
108+
result.append(infos!.pointee)
109+
infos = infos!.pointee.ai_next
110+
}
111+
112+
return result
106113
}
107114
}
108115

Sources/Socket/Utilities.swift

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import Foundation
2+
3+
extension sockaddr_in {
4+
init(_ from: sockaddr, port : UInt16) {
5+
self.init()
6+
7+
// Init from sockaddr
8+
self.sin_family = from.sa_family
9+
self.sin_port = port.bigEndian
10+
}
11+
}

Tests/SocketTests/SocketTests.swift

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,21 @@ class SocketTests : XCTestCase {
1414

1515
override func setUpWithError() throws {
1616
socket = try Socket(
17-
host: "eu-cdbr-west-03.cleardb.net",
18-
port: 3306,
17+
host: "echo.websocket.org",
18+
port: 80,
1919
addressFamily: AF_INET,
2020
socketType: SOCK_STREAM,
2121
socketProtocol: 0
2222
)
23-
try socket!.connect()
23+
24+
// Set socket options
25+
var value : Int32 = 1;
26+
try socket!.setOption(level: SOL_SOCKET, option: SO_REUSEADDR, value: &value, length: socklen_t(MemoryLayout<Int32>.size))
27+
try socket!.setOption(level: SOL_SOCKET, option: SO_KEEPALIVE, value: &value, length: socklen_t(MemoryLayout<Int32>.size))
28+
try socket!.setOption(level: SOL_SOCKET, option: SO_NOSIGPIPE, value: &value, length: socklen_t(MemoryLayout<Int32>.size))
29+
30+
// Try all connections
31+
try socket!.connectAll(infos: try socket!.getAddressInfos())
2432
}
2533

2634
override func tearDownWithError() throws {

0 commit comments

Comments
 (0)