Skip to content

Commit f0ff99b

Browse files
committed
WIP: send/recv
1 parent 8d7a7ef commit f0ff99b

File tree

4 files changed

+106
-5
lines changed

4 files changed

+106
-5
lines changed

Sources/System/Internals/Syscalls.swift

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,3 +136,21 @@ internal func system_listen(_ socket: CInt, _ backlog: CInt) -> CInt {
136136
#endif
137137
return listen(socket, backlog)
138138
}
139+
140+
internal func system_send(
141+
_ socket: Int32, _ buffer: UnsafeRawPointer!, _ len: Int, _ flags: Int32
142+
) -> Int {
143+
#if ENABLE_MOCKING
144+
if mockingEnabled { return _mockInt(socket, buffer, len, flags) }
145+
#endif
146+
return send(socket, buffer, len, flags)
147+
}
148+
149+
internal func system_recv(
150+
_ socket: Int32, _ buffer: UnsafeMutableRawPointer!, _ len: Int, _ flags: Int32
151+
) -> Int {
152+
#if ENABLE_MOCKING
153+
if mockingEnabled { return _mockInt(socket, buffer, len, flags) }
154+
#endif
155+
return recv(socket, buffer, len, flags)
156+
}

Sources/System/Sockets/SocketDescriptor.swift

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -150,8 +150,7 @@ extension SocketDescriptor {
150150

151151
// TODO: option flags (SO_DEBUG)?
152152

153-
// TODO: address families? Should we jus do INET and INET6?
154-
153+
// TODO:
155154
@frozen
156155
public struct MessageFlags: OptionSet {
157156
@_alwaysEmitIntoClient
@@ -163,6 +162,9 @@ extension SocketDescriptor {
163162
@_alwaysEmitIntoClient
164163
private init(_ raw: CInt) { self.init(rawValue: raw) }
165164

165+
@_alwaysEmitIntoClient
166+
public static var none: MessageFlags { MessageFlags(0) }
167+
166168
// MSG_OOB: process out-of-band data
167169
@_alwaysEmitIntoClient
168170
public static var outOfBand: MessageFlags { MessageFlags(_MSG_OOB) }
@@ -179,9 +181,7 @@ extension SocketDescriptor {
179181
@_alwaysEmitIntoClient
180182
public static var waitForAll: MessageFlags { MessageFlags(_MSG_WAITALL) }
181183

182-
// TODO: MSG_EOR MSG_TRUNC MSG_CTRUNC MSG_DONTWAIT MSG_EOF MSG_WAITSTREAM
183-
// TODO: MSG_FLUSH MSG_HOLD MSG_SEND MSG_HAVEMORE MSG_RCVMORE MSG_NEEDSA
184-
// TODO: MSG_NOSIGNAL
184+
// TODO: any of the others? I'm going off of man pagees...
185185
}
186186

187187
public struct ShutdownKind: RawRepresentable, Hashable, Codable {

Sources/System/Sockets/SocketOperations.swift

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,69 @@ extension SocketDescriptor {
7979
nothingOrErrno(system_listen(self.rawValue, CInt(backlog)))
8080
}
8181

82+
/// Send a message from a socket
83+
///
84+
/// - Parameters:
85+
/// - buffear: The region of memory that contains the data being sent.
86+
/// - flags: see `send(2)`
87+
/// - retryOnInterrupt: Whether to retry the send operation
88+
/// if it throws ``Errno/interrupted``.
89+
/// The default is `true`.
90+
/// Pass `false` to try only once and throw an error upon interruption.
91+
/// - Returns: The number of bytes that were sent.
92+
///
93+
/// The corresponding C function is `send`
94+
public func send(
95+
_ buffer: UnsafeRawBufferPointer,
96+
flags: MessageFlags = .none,
97+
retryOnInterrupt: Bool = true
98+
) throws -> Int {
99+
try _send(buffer, flags: flags, retryOnInterrupt: retryOnInterrupt).get()
100+
}
82101

102+
@usableFromInline
103+
internal func _send(
104+
_ buffer: UnsafeRawBufferPointer,
105+
flags: MessageFlags,
106+
retryOnInterrupt: Bool
107+
) -> Result<Int, Errno> {
108+
valueOrErrno(retryOnInterrupt: retryOnInterrupt) {
109+
system_send(self.rawValue, buffer.baseAddress!, buffer.count, flags.rawValue)
110+
}
111+
}
112+
113+
/// Receive a message from a socket
114+
///
115+
/// - Parameters:
116+
/// - buffer: The region of memory to receive into.
117+
/// - flags: see `recv(2)`
118+
/// - retryOnInterrupt: Whether to retry the receive operation
119+
/// if it throws ``Errno/interrupted``.
120+
/// The default is `true`.
121+
/// Pass `false` to try only once and throw an error upon interruption.
122+
/// - Returns: The number of bytes that were received.
123+
///
124+
/// The corresponding C function is `recv`
125+
public func receive(
126+
into buffer: UnsafeMutableRawBufferPointer,
127+
flags: MessageFlags = .none,
128+
retryOnInterrupt: Bool = true
129+
) throws -> Int {
130+
try _receive(
131+
into: buffer, flags: flags, retryOnInterrupt: retryOnInterrupt
132+
).get()
133+
}
134+
135+
@usableFromInline
136+
internal func _receive(
137+
into buffer: UnsafeMutableRawBufferPointer,
138+
flags: MessageFlags,
139+
retryOnInterrupt: Bool
140+
) -> Result<Int, Errno> {
141+
valueOrErrno(retryOnInterrupt: retryOnInterrupt) {
142+
system_recv(self.rawValue, buffer.baseAddress!, buffer.count, flags.rawValue)
143+
}
144+
}
83145
}
84146

85147
// MARK: - Forward FileDescriptor methods

Tests/SystemTests/SocketTest.swift

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,12 @@ final class SocketTest: XCTestCase {
2222

2323
let socket = SocketDescriptor(rawValue: 3)
2424
let rawSocket = socket.rawValue
25+
let rawBuf = UnsafeMutableRawBufferPointer.allocate(byteCount: 100, alignment: 4)
26+
defer { rawBuf.deallocate() }
27+
let bufAddr = rawBuf.baseAddress
28+
let bufCount = rawBuf.count
29+
let writeBuf = UnsafeRawBufferPointer(rawBuf)
30+
let writeBufAddr = writeBuf.baseAddress
2531

2632
let syscallTestCases: Array<MockTestCase> = [
2733
MockTestCase(name: "socket", PF_INET6, SOCK_STREAM, 0, interruptable: true) {
@@ -36,6 +42,21 @@ final class SocketTest: XCTestCase {
3642
retryOnInterrupt in
3743
_ = try socket.listen(backlog: 999)
3844
},
45+
MockTestCase(
46+
name: "recv", rawSocket, bufAddr, bufCount, MSG_PEEK, interruptable: true
47+
) {
48+
retryOnInterrupt in
49+
_ = try socket.receive(
50+
into: rawBuf, flags: .peek, retryOnInterrupt: retryOnInterrupt)
51+
},
52+
MockTestCase(
53+
name: "send", rawSocket, writeBufAddr, bufCount, MSG_DONTROUTE,
54+
interruptable: true
55+
) {
56+
retryOnInterrupt in
57+
_ = try socket.send(
58+
writeBuf, flags: .doNotRoute, retryOnInterrupt: retryOnInterrupt)
59+
},
3960
]
4061

4162
syscallTestCases.forEach { $0.runAllTests() }

0 commit comments

Comments
 (0)