Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Port Swifter to Windows #548

Open
wants to merge 2 commits into
base: stable
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 7 additions & 2 deletions Xcode/Sources/HttpServerIO.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,11 @@
import Foundation
import Dispatch

#if os(Windows)
import WinSDK
public typealias in_port_t = UInt16
#endif

public protocol HttpServerIODelegate: AnyObject {
func socketConnectionReceived(_ socket: Socket)
}
Expand All @@ -16,7 +21,7 @@ open class HttpServerIO {

public weak var delegate: HttpServerIODelegate?

private var socket = Socket(socketFileDescriptor: -1)
private var socket = Socket(socketFileDescriptor: invalidPlatformSocketFD)
private var sockets = Set<Socket>()

public enum HttpServerIOState: Int32 {
Expand All @@ -33,7 +38,7 @@ open class HttpServerIO {
return HttpServerIOState(rawValue: stateValue)!
}
set(state) {
#if !os(Linux)
#if !os(Linux) && !os(Windows)
OSAtomicCompareAndSwapInt(self.state.rawValue, state.rawValue, &stateValue)
#else
self.stateValue = state.rawValue
Expand Down
13 changes: 12 additions & 1 deletion Xcode/Sources/Process.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@

import Foundation

#if os(Windows)
import WinSDK
#endif

public class Process {

public static var pid: Int {
Expand All @@ -16,6 +20,8 @@ public class Process {
public static var tid: UInt64 {
#if os(Linux)
return UInt64(pthread_self())
#elseif os(Windows)
return UInt64(GetCurrentThreadId())
#else
var tid: __uint64_t = 0
pthread_threadid_np(nil, &tid)
Expand All @@ -28,7 +34,12 @@ public class Process {

public static func watchSignals(_ callback: @escaping (Int32) -> Void) {
if !signalsObserved {
[SIGTERM, SIGHUP, SIGSTOP, SIGINT].forEach { item in
#if os(Windows)
let signals = [SIGTERM, SIGINT]
#else
let signals = [SIGTERM, SIGHUP, SIGSTOP, SIGINT]
#endif
signals.forEach { item in
signal(item) { signum in
Process.signalsWatchers.forEach { $0(signum) }
}
Expand Down
12 changes: 9 additions & 3 deletions Xcode/Sources/Socket+File.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,15 @@

import Foundation

#if os(iOS) || os(tvOS) || os (Linux)
#if os(Windows)
import WinSDK
#endif

#if os(iOS) || os(tvOS) || os (Linux) || os(Windows)
// swiftlint:disable type_name function_parameter_count
struct sf_hdtr { }

private func sendfileImpl(_ source: UnsafeMutablePointer<FILE>, _ target: Int32, _: off_t, _: UnsafeMutablePointer<off_t>, _: UnsafeMutablePointer<sf_hdtr>, _: Int32) -> Int32 {
private func sendfileImpl(_ source: UnsafeMutablePointer<FILE>, _ target: PlatformSocketFD, _: off_t, _: UnsafeMutablePointer<off_t>, _: UnsafeMutablePointer<sf_hdtr>, _: Int32) -> Int32 {
var buffer = [UInt8](repeating: 0, count: 1024)
while true {
let readResult = fread(&buffer, 1, buffer.count, source)
Expand All @@ -25,6 +29,8 @@ import Foundation
let len = readResult - writeCounter
#if os(Linux)
return send(target, start, len, Int32(MSG_NOSIGNAL))
#elseif os(Windows)
return Int(send(target, start, Int32(len), 0))
#else
return write(target, start, len)
#endif
Expand All @@ -44,7 +50,7 @@ extension Socket {
var offset: off_t = 0
var sf: sf_hdtr = sf_hdtr()

#if os(iOS) || os(tvOS) || os (Linux)
#if os(iOS) || os(tvOS) || os (Linux) || os(Windows)
let result = sendfileImpl(file.pointer, self.socketFileDescriptor, 0, &offset, &sf, 0)
#else
let result = sendfile(fileno(file.pointer), self.socketFileDescriptor, 0, &offset, &sf, 0)
Expand Down
26 changes: 20 additions & 6 deletions Xcode/Sources/Socket+Server.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@

import Foundation

#if os(Windows)
import WinSDK
#endif

extension Socket {

// swiftlint:disable function_body_length
Expand All @@ -15,14 +19,13 @@ extension Socket {
/// 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 == -1 {
if socketFileDescriptor == invalidPlatformSocketFD {
throw SocketError.socketCreationFailed(Errno.description())
}

Expand All @@ -42,6 +45,12 @@ extension Socket {
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),
Expand All @@ -68,6 +77,13 @@ extension Socket {
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),
Expand Down Expand Up @@ -104,10 +120,8 @@ extension Socket {
}

public func acceptClientSocket() throws -> Socket {
var addr = sockaddr()
var len: socklen_t = 0
let clientSocket = accept(self.socketFileDescriptor, &addr, &len)
if clientSocket == -1 {
let clientSocket = accept(self.socketFileDescriptor, nil, nil)
if clientSocket == invalidPlatformSocketFD {
throw SocketError.acceptFailed(Errno.description())
}
Socket.setNoSigPipe(clientSocket)
Expand Down
40 changes: 32 additions & 8 deletions Xcode/Sources/Socket.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,18 @@

import Foundation

#if os(Windows)
import WinSDK
#endif

#if os(Windows)
public typealias PlatformSocketFD = SOCKET
public let invalidPlatformSocketFD = INVALID_SOCKET
#else
public typealias PlatformSocketFD = Int32
public let invalidPlatformSocketFD = Int32(-1)
#endif

public enum SocketError: Error {
case socketCreationFailed(String)
case socketSettingReUseAddrFailed(String)
Expand All @@ -23,11 +35,10 @@ public enum SocketError: Error {

// swiftlint: disable identifier_name
open class Socket: Hashable, Equatable {

let socketFileDescriptor: Int32
let socketFileDescriptor: PlatformSocketFD
private var shutdown = false

public init(socketFileDescriptor: Int32) {
public init(socketFileDescriptor: PlatformSocketFD) {
self.socketFileDescriptor = socketFileDescriptor
}

Expand Down Expand Up @@ -55,7 +66,7 @@ open class Socket: Hashable, Equatable {
throw SocketError.getSockNameFailed(Errno.description())
}
let sin_port = pointer.pointee.sin_port
#if os(Linux)
#if os(Linux) || os(Windows)
return ntohs(sin_port)
#else
return Int(OSHostByteOrder()) != OSLittleEndian ? sin_port.littleEndian : sin_port.bigEndian
Expand Down Expand Up @@ -112,6 +123,8 @@ open class Socket: Hashable, Equatable {
while sent < length {
#if os(Linux)
let result = send(self.socketFileDescriptor, pointer + sent, Int(length - sent), Int32(MSG_NOSIGNAL))
#elseif os(Windows)
let result = Int(send(self.socketFileDescriptor, pointer + sent, Int32(length - sent), 0))
#else
let result = write(self.socketFileDescriptor, pointer + sent, Int(length - sent))
#endif
Expand All @@ -133,6 +146,8 @@ open class Socket: Hashable, Equatable {

#if os(Linux)
let count = Glibc.read(self.socketFileDescriptor as Int32, &byte, 1)
#elseif os(Windows)
let count = recv(self.socketFileDescriptor, &byte, 1, 0)
#else
let count = Darwin.read(self.socketFileDescriptor as Int32, &byte, 1)
#endif
Expand Down Expand Up @@ -172,6 +187,8 @@ open class Socket: Hashable, Equatable {

#if os(Linux)
let bytesRead = Glibc.read(self.socketFileDescriptor as Int32, baseAddress + offset, readLength)
#elseif os(Windows)
let bytesRead = Int(recv(self.socketFileDescriptor, baseAddress + offset, Int32(readLength), 0))
#else
let bytesRead = Darwin.read(self.socketFileDescriptor as Int32, baseAddress + offset, readLength)
#endif
Expand Down Expand Up @@ -205,14 +222,19 @@ open class Socket: Hashable, Equatable {
throw SocketError.getPeerNameFailed(Errno.description())
}
var hostBuffer = [CChar](repeating: 0, count: Int(NI_MAXHOST))
if getnameinfo(&addr, len, &hostBuffer, socklen_t(hostBuffer.count), nil, 0, NI_NUMERICHOST) != 0 {
#if os(Windows)
let hostBufferSize = DWORD(hostBuffer.count)
#else
let hostBufferSize = socklen_t(hostBuffer.count)
#endif
if getnameinfo(&addr, len, &hostBuffer, hostBufferSize, nil, 0, NI_NUMERICHOST) != 0 {
throw SocketError.getNameInfoFailed(Errno.description())
}
return String(cString: hostBuffer)
}

public class func setNoSigPipe(_ socket: Int32) {
#if os(Linux)
public class func setNoSigPipe(_ socket: PlatformSocketFD) {
#if os(Linux) || os(Windows)
// There is no SO_NOSIGPIPE in Linux (nor some other systems). You can instead use the MSG_NOSIGNAL flag when calling send(),
// or use signal(SIGPIPE, SIG_IGN) to make your entire application ignore SIGPIPE.
#else
Expand All @@ -222,9 +244,11 @@ open class Socket: Hashable, Equatable {
#endif
}

public class func close(_ socket: Int32) {
public class func close(_ socket: PlatformSocketFD) {
#if os(Linux)
_ = Glibc.close(socket)
#elseif os(Windows)
_ = closesocket(socket)
#else
_ = Darwin.close(socket)
#endif
Expand Down
36 changes: 34 additions & 2 deletions Xcode/Sources/String+File.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@

import Foundation

#if os(Windows)
import WinSDK
#endif

extension String {

public enum FileError: Error {
Expand All @@ -25,7 +29,7 @@ extension String {
fclose(pointer)
}

public func seek(_ offset: Int) -> Bool {
public func seek(_ offset: Int32) -> Bool {
return (fseek(pointer, offset, SEEK_SET) == 0)
}

Expand Down Expand Up @@ -98,18 +102,45 @@ extension String {
public func directory() throws -> Bool {
return try self.withStat {
if let stat = $0 {
#if os(Windows)
// Need to disambiguate here.
return Int32(stat.st_mode) & ucrt.S_IFMT == ucrt.S_IFDIR
#else
return stat.st_mode & S_IFMT == S_IFDIR
#endif
}
return false
}
}

public func files() throws -> [String] {
var results = [String]()
#if os(Windows)
var data = WIN32_FIND_DATAW()
let handle = self.withCString(encodedAs: UTF16.self) {
return FindFirstFileW($0, &data)
}
guard handle != INVALID_HANDLE_VALUE else {
throw FileError.error(Int32(GetLastError()))
}
defer { FindClose(handle) }
let appendToResults = {
let fileName = withUnsafePointer(to: &data.cFileName) { (ptr) -> String in
ptr.withMemoryRebound(to: unichar.self, capacity: Int(MAX_PATH * 2)) {
String(utf16CodeUnits: $0, count: wcslen($0))
}
}
results.append(fileName)
}
appendToResults()
while FindNextFileW(handle, &data) {
appendToResults()
}
#else
guard let dir = self.withCString({ opendir($0) }) else {
throw FileError.error(errno)
}
defer { closedir(dir) }
var results = [String]()
while let ent = readdir(dir) {
var name = ent.pointee.d_name
let fileName = withUnsafePointer(to: &name) { (ptr) -> String? in
Expand All @@ -129,6 +160,7 @@ extension String {
results.append(fileName)
}
}
#endif
return results
}

Expand Down
Loading