Skip to content

Commit 3dbeb33

Browse files
committed
Support for building on Android
Adds support for building using Swift Android SDK.
1 parent de184b0 commit 3dbeb33

9 files changed

+204
-6
lines changed

CSystemLinux/include/CSystemLinux.h

+7-3
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,14 @@
77
See https://swift.org/LICENSE.txt for license information
88
*/
99

10-
#ifdef __linux__
10+
#pragma once
11+
12+
#ifdef __ANDROID__
13+
#include <linux/eventpoll.h>
14+
#include <poll.h>
15+
#endif
1116

17+
#ifdef __linux__
1218
#include <sys/epoll.h>
1319
#include <sys/eventfd.h>
14-
1520
#endif
16-

FlyingSocks/Sources/Mutex.swift

+3-1
Original file line numberDiff line numberDiff line change
@@ -129,10 +129,12 @@ extension Mutex {
129129
}
130130
}
131131

132-
#elseif canImport(Glibc) || canImport(Musl)
132+
#elseif canImport(Glibc) || canImport(Musl) || canImport(Bionic)
133133

134134
#if canImport(Musl)
135135
import Musl
136+
#elseif canImport(Bionic)
137+
import Android
136138
#else
137139
import Glibc
138140
#endif
+180
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,180 @@
1+
//
2+
// Socket+Android.swift
3+
// FlyingFox
4+
//
5+
// Created by Simon Whitty on 26/09/2024.
6+
// Copyright © 2024 Simon Whitty. All rights reserved.
7+
//
8+
// Distributed under the permissive MIT license
9+
// Get the latest version from here:
10+
//
11+
// https://github.com/swhitty/FlyingFox
12+
//
13+
// Permission is hereby granted, free of charge, to any person obtaining a copy
14+
// of this software and associated documentation files (the "Software"), to deal
15+
// in the Software without restriction, including without limitation the rights
16+
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
17+
// copies of the Software, and to permit persons to whom the Software is
18+
// furnished to do so, subject to the following conditions:
19+
//
20+
// The above copyright notice and this permission notice shall be included in all
21+
// copies or substantial portions of the Software.
22+
//
23+
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24+
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25+
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
26+
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27+
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
28+
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
29+
// SOFTWARE.
30+
//
31+
32+
#if canImport(Android)
33+
import Android
34+
35+
// from linux/eventpoll.h, not imported by clang importer
36+
let EPOLLET: UInt32 = 1 << 31;
37+
38+
public extension Socket {
39+
typealias FileDescriptorType = Int32
40+
}
41+
42+
extension Socket.FileDescriptor {
43+
static let invalid = Socket.FileDescriptor(rawValue: -1)
44+
}
45+
46+
extension Socket {
47+
static let stream = Int32(SOCK_STREAM)
48+
static let in_addr_any = Android.in_addr(s_addr: Android.in_addr_t(0))
49+
50+
static func makeAddressINET(port: UInt16) -> Android.sockaddr_in {
51+
Android.sockaddr_in(
52+
sin_family: sa_family_t(AF_INET),
53+
sin_port: port.bigEndian,
54+
sin_addr: in_addr_any,
55+
__pad: (0, 0, 0, 0, 0, 0, 0, 0)
56+
)
57+
}
58+
59+
static func makeAddressINET6(port: UInt16) -> Android.sockaddr_in6 {
60+
Android.sockaddr_in6(
61+
sin6_family: sa_family_t(AF_INET6),
62+
sin6_port: port.bigEndian,
63+
sin6_flowinfo: 0,
64+
sin6_addr: in6addr_any,
65+
sin6_scope_id: 0
66+
)
67+
}
68+
69+
static func makeAddressLoopback(port: UInt16) -> Android.sockaddr_in6 {
70+
Android.sockaddr_in6(
71+
sin6_family: sa_family_t(AF_INET6),
72+
sin6_port: port.bigEndian,
73+
sin6_flowinfo: 0,
74+
sin6_addr: in6addr_loopback,
75+
sin6_scope_id: 0
76+
)
77+
}
78+
79+
static func makeAddressUnix(path: String) -> Android.sockaddr_un {
80+
var addr = Android.sockaddr_un()
81+
addr.sun_family = sa_family_t(AF_UNIX)
82+
let pathCount = min(path.utf8.count, 104)
83+
let len = UInt8(MemoryLayout<UInt8>.size + MemoryLayout<sa_family_t>.size + pathCount + 1)
84+
_ = withUnsafeMutablePointer(to: &addr.sun_path.0) { ptr in
85+
path.withCString {
86+
strncpy(ptr, $0, Int(len))
87+
}
88+
}
89+
return addr
90+
}
91+
92+
static func socket(_ domain: Int32, _ type: Int32, _ protocol: Int32) -> FileDescriptorType {
93+
Android.socket(domain, type, `protocol`)
94+
}
95+
96+
static func socketpair(_ domain: Int32, _ type: Int32, _ protocol: Int32) -> (FileDescriptorType, FileDescriptorType) {
97+
var sockets: [Int32] = [-1, -1]
98+
_ = Android.socketpair(domain, type, `protocol`, &sockets)
99+
return (sockets[0], sockets[1])
100+
}
101+
102+
static func fcntl(_ fd: Int32, _ cmd: Int32) -> Int32 {
103+
Android.fcntl(fd, cmd)
104+
}
105+
106+
static func fcntl(_ fd: Int32, _ cmd: Int32, _ value: Int32) -> Int32 {
107+
Android.fcntl(fd, cmd, value)
108+
}
109+
110+
static func setsockopt(_ fd: Int32, _ level: Int32, _ name: Int32,
111+
_ value: UnsafeRawPointer!, _ len: socklen_t) -> Int32 {
112+
Android.setsockopt(fd, level, name, value, len)
113+
}
114+
115+
static func getsockopt(_ fd: Int32, _ level: Int32, _ name: Int32,
116+
_ value: UnsafeMutableRawPointer!, _ len: UnsafeMutablePointer<socklen_t>!) -> Int32 {
117+
Android.getsockopt(fd, level, name, value, len)
118+
}
119+
120+
static func getpeername(_ fd: Int32, _ addr: UnsafeMutablePointer<sockaddr>!, _ len: UnsafeMutablePointer<socklen_t>!) -> Int32 {
121+
Android.getpeername(fd, addr, len)
122+
}
123+
124+
static func getsockname(_ fd: Int32, _ addr: UnsafeMutablePointer<sockaddr>!, _ len: UnsafeMutablePointer<socklen_t>!) -> Int32 {
125+
Android.getsockname(fd, addr, len)
126+
}
127+
128+
static func inet_ntop(_ domain: Int32, _ addr: UnsafeRawPointer!,
129+
_ buffer: UnsafeMutablePointer<CChar>!, _ addrLen: socklen_t) throws {
130+
if Android.inet_ntop(domain, addr, buffer, addrLen) == nil {
131+
throw SocketError.makeFailed("inet_ntop")
132+
}
133+
}
134+
135+
static func inet_pton(_ domain: Int32, _ buffer: UnsafePointer<CChar>!, _ addr: UnsafeMutableRawPointer!) -> Int32 {
136+
Android.inet_pton(domain, buffer, addr)
137+
}
138+
139+
static func bind(_ fd: Int32, _ addr: UnsafePointer<sockaddr>!, _ len: socklen_t) -> Int32 {
140+
Android.bind(fd, addr, len)
141+
}
142+
143+
static func listen(_ fd: Int32, _ backlog: Int32) -> Int32 {
144+
Android.listen(fd, backlog)
145+
}
146+
147+
static func accept(_ fd: Int32, _ addr: UnsafeMutablePointer<sockaddr>!, _ len: UnsafeMutablePointer<socklen_t>!) -> Int32 {
148+
Android.accept(fd, addr, len)
149+
}
150+
151+
static func connect(_ fd: Int32, _ addr: UnsafePointer<sockaddr>!, _ len: socklen_t) -> Int32 {
152+
Android.connect(fd, addr, len)
153+
}
154+
155+
static func read(_ fd: Int32, _ buffer: UnsafeMutableRawPointer!, _ nbyte: Int) -> Int {
156+
Android.read(fd, buffer, nbyte)
157+
}
158+
159+
static func write(_ fd: Int32, _ buffer: UnsafeRawPointer!, _ nbyte: Int) -> Int {
160+
Android.send(fd, buffer, nbyte, Int32(MSG_NOSIGNAL))
161+
}
162+
163+
static func close(_ fd: Int32) -> Int32 {
164+
Android.close(fd)
165+
}
166+
167+
static func unlink(_ addr: UnsafePointer<CChar>!) -> Int32 {
168+
Android.unlink(addr)
169+
}
170+
171+
static func poll(_ fds: UnsafeMutablePointer<pollfd>!, _ nfds: UInt32, _ tmo_p: Int32) -> Int32 {
172+
Android.poll(fds, nfds_t(nfds), tmo_p)
173+
}
174+
175+
static func pollfd(fd: FileDescriptorType, events: Int16, revents: Int16) -> Android.pollfd {
176+
Android.pollfd(fd: fd, events: events, revents: revents)
177+
}
178+
}
179+
180+
#endif

FlyingSocks/Sources/Socket.swift

+2
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@
3131

3232
#if canImport(WinSDK)
3333
import WinSDK.WinSock2
34+
#elseif canImport(Android)
35+
@_exported import Android
3436
#endif
3537
import Foundation
3638

FlyingSocks/Sources/SocketAddress.swift

+5
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,13 @@
3232
import Foundation
3333
#if canImport(WinSDK)
3434
import WinSDK.WinSock2
35+
#elseif canImport(Android)
36+
import Android
3537
#endif
3638

39+
#if canImport(CSystemLinux)
40+
import CSystemLinux
41+
#endif
3742

3843
public protocol SocketAddress: Sendable {
3944
static var family: sa_family_t { get }

FlyingSocks/Sources/SocketError.swift

+3
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,9 @@
3030
//
3131

3232
import Foundation
33+
#if canImport(Android)
34+
import Android
35+
#endif
3336

3437
public enum SocketError: LocalizedError, Equatable {
3538
case failed(type: String, errno: Int32, message: String)

FlyingSocks/Sources/SocketPool+Poll.swift

+2
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@
3131

3232
#if canImport(WinSDK)
3333
import WinSDK.WinSock2
34+
#elseif canImport(Android)
35+
import Android
3436
#endif
3537
import Foundation
3638

FlyingSocks/Sources/SocketPool+ePoll.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -219,7 +219,7 @@ extension EventNotification {
219219
private struct EPOLLEvents: OptionSet, Hashable {
220220
var rawValue: UInt32
221221

222-
#if canImport(Musl)
222+
#if canImport(Musl) || canImport(Android)
223223
static let read = EPOLLEvents(rawValue: UInt32(EPOLLIN))
224224
static let write = EPOLLEvents(rawValue: UInt32(EPOLLOUT))
225225
static let hup = EPOLLEvents(rawValue: UInt32(EPOLLHUP))

Package.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ let package = Package(
2626
),
2727
.target(
2828
name: "FlyingSocks",
29-
dependencies: [.target(name: "CSystemLinux", condition: .when(platforms: [.linux]))],
29+
dependencies: [.target(name: "CSystemLinux", condition: .when(platforms: [.linux, .android]))],
3030
path: "FlyingSocks/Sources",
3131
swiftSettings: .upcomingFeatures
3232
),

0 commit comments

Comments
 (0)