Skip to content

Commit b45bd38

Browse files
committed
add domain socket datagram client/server
1 parent 3b587ae commit b45bd38

File tree

4 files changed

+73
-34
lines changed

4 files changed

+73
-34
lines changed

Examples/IORingUDPClient/IORingUDPClient.swift renamed to Examples/IORingDatagramClient/IORingDatagramClient.swift

Lines changed: 36 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -17,39 +17,59 @@
1717
import AsyncExtensions
1818
import Glibc
1919
import IORing
20+
import IORingFoundation
2021
import IORingUtils
2122
import SocketAddress
2223
import struct SystemPackage.Errno
2324

25+
private func usage() -> Never {
26+
print("Usage: \(CommandLine.arguments[0]) [address:port|dg-path] [message]")
27+
exit(1)
28+
}
29+
2430
@main
25-
public struct IORingUDPClient {
31+
public struct IORingDatagramClient {
2632
private let socket: Socket
2733
private let ring: IORing
2834

2935
public static func main() async throws {
30-
guard CommandLine.arguments.count == 3,
31-
let address = try? sockaddr_storage(
32-
family: sa_family_t(AF_INET),
33-
presentationAddress: CommandLine.arguments[1]
34-
)
35-
else {
36-
print("Usage: \(CommandLine.arguments[0]) [address:port] [message]")
37-
exit(1)
38-
}
36+
guard CommandLine.arguments.count == 3 else { usage() }
3937

38+
let family = sa_family_t(CommandLine.arguments[1].hasPrefix("/") ? AF_LOCAL : AF_INET)
39+
guard let address = try? sockaddr_storage(
40+
family: family,
41+
presentationAddress: CommandLine.arguments[1]
42+
) else {
43+
usage()
44+
}
45+
let client = try Self(domain: family)
4046
let message = CommandLine.arguments[2]
41-
let client = try IORingUDPClient()
42-
try await client.connect(to: address)
43-
try await client.send(message: message)
47+
48+
do {
49+
if family == sa_family_t(AF_LOCAL) {
50+
try await client.bind(to: sockaddr_un.ephemeralDatagramDomainSocketName)
51+
}
52+
try await client.connect(to: address)
53+
try await client.send(message: message)
54+
} catch {
55+
print("error: \(error)")
56+
}
4457
}
4558

46-
init() throws {
59+
init(domain: sa_family_t) throws {
4760
ring = IORing.shared
48-
socket = try Socket(ring: ring, domain: sa_family_t(AF_INET), type: SOCK_DGRAM, protocol: 0)
61+
socket = try Socket(ring: ring, domain: domain, type: SOCK_DGRAM, protocol: 0)
62+
}
63+
64+
func bind(to address: any SocketAddress) async throws {
65+
debugPrint("binding to local address \(String(describing: try? address.presentationAddress))")
66+
try socket.bind(to: address)
4967
}
5068

5169
func connect(to address: any SocketAddress) async throws {
52-
debugPrint("connecting to address \(String(describing: try? address.presentationAddress))")
70+
debugPrint(
71+
"connecting to remote address \(String(describing: try? address.presentationAddress))"
72+
)
5373
try await socket.connect(to: address)
5474
}
5575

Examples/IORingUDPServer/IORingUDPServer.swift renamed to Examples/IORingDatagramServer/IORingDatagramServer.swift

Lines changed: 30 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
//
2-
// Copyright (c) 2023 PADL Software Pty Ltd
2+
// Copyright (c) 2023-2025 PADL Software Pty Ltd
33
//
44
// Licensed under the Apache License, Version 2.0 (the License);
55
// you may not use this file except in compliance with the License.
@@ -20,33 +20,52 @@ import IORing
2020
import IORingUtils
2121
import struct SystemPackage.Errno
2222

23+
private func usage() -> Never {
24+
print("Usage: \(CommandLine.arguments[0]) [port|dg-path]")
25+
exit(1)
26+
}
27+
2328
@main
24-
public struct IORingUDPServer {
29+
public struct IORingDatagramServer {
2530
private let socket: Socket
2631
private let ring: IORing
2732

2833
public static func main() async throws {
29-
guard CommandLine.arguments.count == 2,
30-
let port = UInt16(CommandLine.arguments[1])
31-
else {
32-
print("Usage: \(CommandLine.arguments[0]) [port]")
33-
exit(1)
34+
guard CommandLine.arguments.count == 2 else { usage() }
35+
36+
var path: String?
37+
var port: UInt16?
38+
39+
if CommandLine.arguments[1].hasPrefix("/") {
40+
path = CommandLine.arguments[1]
41+
} else if let p = UInt16(CommandLine.arguments[1]) {
42+
port = p
43+
} else {
44+
usage()
3445
}
3546

36-
let server = try IORingUDPServer()
37-
try await server.bind(port: port)
47+
let server = try Self(domain: sa_family_t(path != nil ? AF_LOCAL : AF_INET))
48+
if let path {
49+
try await server.bind(path: path)
50+
} else if let port {
51+
try await server.bind(port: port)
52+
}
3853
try await server.run()
3954
}
4055

41-
init() throws {
56+
init(domain: sa_family_t) throws {
4257
ring = IORing.shared
43-
socket = try Socket(ring: ring, domain: sa_family_t(AF_INET), type: SOCK_DGRAM, protocol: 0)
58+
socket = try Socket(ring: ring, domain: domain, type: SOCK_DGRAM, protocol: 0)
4459
}
4560

4661
func bind(port: UInt16) async throws {
4762
try socket.bind(port: port)
4863
}
4964

65+
func bind(path: String) async throws {
66+
try socket.bind(path: path)
67+
}
68+
5069
func run() async throws {
5170
repeat {
5271
do {

Package.resolved

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Package.swift

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -132,14 +132,14 @@ let package = Package(
132132
path: "Examples/IORingTCPEcho"
133133
),
134134
.executableTarget(
135-
name: "IORingUDPClient",
136-
dependencies: ["IORing", "IORingUtils"],
137-
path: "Examples/IORingUDPClient"
135+
name: "IORingDatagramClient",
136+
dependencies: ["IORing", "IORingUtils", "IORingFoundation"],
137+
path: "Examples/IORingDatagramClient"
138138
),
139139
.executableTarget(
140-
name: "IORingUDPServer",
140+
name: "IORingDatagramServer",
141141
dependencies: ["IORing", "IORingUtils"],
142-
path: "Examples/IORingUDPServer"
142+
path: "Examples/IORingDatagramServer"
143143
),
144144
.executableTarget(
145145
name: "IORingDeviceSpy",

0 commit comments

Comments
 (0)