mirror of
https://github.com/munki/munki.git
synced 2026-05-24 07:08:39 -05:00
Implementation of app_usage_monitor
This commit is contained in:
@@ -0,0 +1,202 @@
|
||||
//
|
||||
// main.swift
|
||||
// app_usage_monitor
|
||||
//
|
||||
// Created by Greg Neagle on 8/1/24.
|
||||
//
|
||||
// Copyright 2024 Greg Neagle.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// https://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
import AppKit
|
||||
import Foundation
|
||||
|
||||
enum AppUsageClientError: Error {
|
||||
case socketError(code: UNIXDomainSocketClientErrorCode, description: String)
|
||||
case taskError(description: String)
|
||||
}
|
||||
|
||||
class AppUsageClient {
|
||||
// handles communication with appusaged daemon
|
||||
|
||||
let APPUSAGED_SOCKET = "/var/run/appusaged"
|
||||
let socket = UNIXDomainSocketClient()
|
||||
|
||||
func connect() throws {
|
||||
// Connect to appusaged
|
||||
socket.connect(to: APPUSAGED_SOCKET)
|
||||
if socket.errCode != .noError {
|
||||
throw AppUsageClientError.socketError(
|
||||
code: socket.errCode,
|
||||
description: "Failed to connect to \(APPUSAGED_SOCKET)"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
func sendRequest(_ request: PlistDict) throws -> String {
|
||||
// Send a request to appusaged
|
||||
let requestStr = try plistToString(request)
|
||||
socket.write(requestStr)
|
||||
if socket.errCode != .noError {
|
||||
throw AppUsageClientError.socketError(
|
||||
code: socket.errCode,
|
||||
description: "Failed to write to \(APPUSAGED_SOCKET)"
|
||||
)
|
||||
}
|
||||
let reply = socket.read(timeout: 1)
|
||||
if reply.isEmpty {
|
||||
return "ERROR:No reply"
|
||||
}
|
||||
return reply.trimmingCharacters(in: .whitespacesAndNewlines)
|
||||
}
|
||||
|
||||
func disconnect() {
|
||||
// Disconnect from appusaged
|
||||
socket.close()
|
||||
}
|
||||
|
||||
func process(_ request: PlistDict) throws -> String {
|
||||
// Send a request and return the result
|
||||
try connect()
|
||||
let result = try sendRequest(request)
|
||||
disconnect()
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
||||
class NotificationHandler: NSObject {
|
||||
// A subclass of NSObject to handle workspace notifications
|
||||
|
||||
let usage = AppUsageClient()
|
||||
let wsNotificationCenter = NSWorkspace.shared.notificationCenter
|
||||
let distributedNotificationCenter = DistributedNotificationCenter.default()
|
||||
|
||||
override init() {
|
||||
super.init()
|
||||
wsNotificationCenter.addObserver(
|
||||
self,
|
||||
selector: #selector(didLaunchApplicationNotification(_:)),
|
||||
name: NSWorkspace.didLaunchApplicationNotification,
|
||||
object: nil
|
||||
)
|
||||
wsNotificationCenter.addObserver(
|
||||
self,
|
||||
selector: #selector(didActivateApplicationNotification(_:)),
|
||||
name: NSWorkspace.didActivateApplicationNotification,
|
||||
object: nil
|
||||
)
|
||||
wsNotificationCenter.addObserver(
|
||||
self,
|
||||
selector: #selector(didTerminateApplicationNotification(_:)),
|
||||
name: NSWorkspace.didTerminateApplicationNotification,
|
||||
object: nil
|
||||
)
|
||||
wsNotificationCenter.addObserver(
|
||||
self,
|
||||
selector: #selector(requestedItemForInstall(_:)),
|
||||
name: NSNotification.Name("com.googlecode.munki.managedsoftwareupdate.installrequest"),
|
||||
object: nil
|
||||
)
|
||||
}
|
||||
|
||||
deinit {
|
||||
// Unregister for all the notifications we registered for
|
||||
wsNotificationCenter.removeObserver(self)
|
||||
distributedNotificationCenter.removeObserver(self)
|
||||
}
|
||||
|
||||
func getInfoDictForApp(_ appObject: NSRunningApplication) -> [String: String] {
|
||||
// Returns a dict with info about an application.
|
||||
// Args:
|
||||
// appObject: NSRunningApplication object
|
||||
// Returns:
|
||||
// appDict: ["bundle_id": str,
|
||||
// "path": str,
|
||||
// "version": str]
|
||||
var bundleID = ""
|
||||
var appPath = ""
|
||||
var appVersion = "0"
|
||||
|
||||
if let url = appObject.bundleURL {
|
||||
appPath = url.path()
|
||||
}
|
||||
if let _bundleID = appObject.bundleIdentifier {
|
||||
bundleID = _bundleID
|
||||
} else if !appPath.isEmpty {
|
||||
// use the base filename
|
||||
bundleID = (appPath as NSString).lastPathComponent
|
||||
}
|
||||
if !appPath.isEmpty {
|
||||
// try to get the version from the bundle's plist
|
||||
if let appInfoPlist = NSDictionary(
|
||||
contentsOfFile: (appPath as NSString).appendingPathComponent("Contents/Info.plist")) as? PlistDict
|
||||
{
|
||||
appVersion = appInfoPlist["CFBundleShortVersionString"] as? String ?? appInfoPlist["CFBundleVersion"] as? String ?? "0"
|
||||
}
|
||||
}
|
||||
return ["bundle_id": bundleID,
|
||||
"path": appPath,
|
||||
"version": appVersion]
|
||||
}
|
||||
|
||||
func process(event: String, notification: NSNotification) {
|
||||
if let appObject = notification.userInfo?["NSWorkspaceApplicationKey"] as? NSRunningApplication {
|
||||
let appDict = getInfoDictForApp(appObject)
|
||||
let _ = try? usage.process(
|
||||
["event": event,
|
||||
"app_dict": appDict]
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@objc func didLaunchApplicationNotification(_ notification: NSNotification) {
|
||||
// Handle NSWorkspaceDidLaunchApplicationNotification
|
||||
process(event: "launch", notification: notification)
|
||||
}
|
||||
|
||||
@objc func didActivateApplicationNotification(_ notification: NSNotification) {
|
||||
// Handle NSWorkspaceDidActivateApplicationNotification
|
||||
process(event: "activate", notification: notification)
|
||||
}
|
||||
|
||||
@objc func didTerminateApplicationNotification(_ notification: NSNotification) {
|
||||
// Handle NSWorkspaceDidTerminateApplicationNotification
|
||||
process(event: "quit", notification: notification)
|
||||
}
|
||||
|
||||
@objc func requestedItemForInstall(_ notification: NSNotification) {
|
||||
// Handle com.googlecode.munki.managedsoftwareupdate.installrequest
|
||||
if let installInfo = notification.userInfo as? [String: String] {
|
||||
let _ = try? usage.process(
|
||||
["event": installInfo["event"] ?? "unknown",
|
||||
"name": installInfo["name"] ?? "unknown",
|
||||
"version": installInfo["version"] ?? "unknown"]
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
// Initialize our handler object and let NSWorkspace's notification center
|
||||
// know we are interested in notifications
|
||||
let notificationHandler = NotificationHandler()
|
||||
|
||||
while true {
|
||||
// listen for notifications forever
|
||||
// give time to the runloop so we can actually get notifications
|
||||
RunLoop.current.run(until: Date(timeIntervalSinceNow: 0.1))
|
||||
}
|
||||
}
|
||||
|
||||
// run it!
|
||||
main()
|
||||
@@ -18,7 +18,6 @@
|
||||
C013644B2C2F8EFE008DB215 /* GitFileRepo.swift in Sources */ = {isa = PBXBuildFile; fileRef = C01364482C2F8EFE008DB215 /* GitFileRepo.swift */; };
|
||||
C013644E2C30F5D8008DB215 /* RepoFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = C013644C2C30F5D8008DB215 /* RepoFactory.swift */; };
|
||||
C013644F2C30F5D8008DB215 /* RepoFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = C013644C2C30F5D8008DB215 /* RepoFactory.swift */; };
|
||||
C01364522C311DFA008DB215 /* ArgumentParser in Frameworks */ = {isa = PBXBuildFile; productRef = C01364512C311DFA008DB215 /* ArgumentParser */; };
|
||||
C01364542C321FE7008DB215 /* dmgutils.swift in Sources */ = {isa = PBXBuildFile; fileRef = C01364532C321FE7008DB215 /* dmgutils.swift */; };
|
||||
C01364552C321FE7008DB215 /* dmgutils.swift in Sources */ = {isa = PBXBuildFile; fileRef = C01364532C321FE7008DB215 /* dmgutils.swift */; };
|
||||
C01364582C3265D6008DB215 /* display.swift in Sources */ = {isa = PBXBuildFile; fileRef = C01364572C3265D6008DB215 /* display.swift */; };
|
||||
@@ -26,7 +25,6 @@
|
||||
C030A98F2C39C135007F0B34 /* munkihash.swift in Sources */ = {isa = PBXBuildFile; fileRef = C030A98E2C39C135007F0B34 /* munkihash.swift */; };
|
||||
C030A9902C39C135007F0B34 /* munkihash.swift in Sources */ = {isa = PBXBuildFile; fileRef = C030A98E2C39C135007F0B34 /* munkihash.swift */; };
|
||||
C030A9982C3A2E18007F0B34 /* makepkginfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = C030A9972C3A2E18007F0B34 /* makepkginfo.swift */; };
|
||||
C030A99D2C3B12A6007F0B34 /* ArgumentParser in Frameworks */ = {isa = PBXBuildFile; productRef = C030A99C2C3B12A6007F0B34 /* ArgumentParser */; };
|
||||
C030A9A12C3B4F5B007F0B34 /* pkginfoOptions.swift in Sources */ = {isa = PBXBuildFile; fileRef = C030A99E2C3B4F04007F0B34 /* pkginfoOptions.swift */; };
|
||||
C030A9A22C3B4F63007F0B34 /* pkginfolib.swift in Sources */ = {isa = PBXBuildFile; fileRef = C07074E12C3489FA00B86310 /* pkginfolib.swift */; };
|
||||
C030A9A32C3B4FBC007F0B34 /* utils.swift in Sources */ = {isa = PBXBuildFile; fileRef = C07A6FD12C2B654300090743 /* utils.swift */; };
|
||||
@@ -53,13 +51,11 @@
|
||||
C030A9C12C419565007F0B34 /* osinstaller.swift in Sources */ = {isa = PBXBuildFile; fileRef = C030A9B12C3DB88E007F0B34 /* osinstaller.swift */; };
|
||||
C030A9C22C41B556007F0B34 /* pkginfolib.swift in Sources */ = {isa = PBXBuildFile; fileRef = C07074E12C3489FA00B86310 /* pkginfolib.swift */; };
|
||||
C030A9C32C41B581007F0B34 /* pkginfoOptions.swift in Sources */ = {isa = PBXBuildFile; fileRef = C030A99E2C3B4F04007F0B34 /* pkginfoOptions.swift */; };
|
||||
C030A9C52C41B59F007F0B34 /* ArgumentParser in Frameworks */ = {isa = PBXBuildFile; productRef = C030A9C42C41B59F007F0B34 /* ArgumentParser */; };
|
||||
C030A9C82C41F32E007F0B34 /* munkiimportOptions.swift in Sources */ = {isa = PBXBuildFile; fileRef = C030A9C62C41F32E007F0B34 /* munkiimportOptions.swift */; };
|
||||
C030A9D02C41F798007F0B34 /* munkiimport.swift in Sources */ = {isa = PBXBuildFile; fileRef = C030A9CF2C41F798007F0B34 /* munkiimport.swift */; };
|
||||
C030A9D42C41F849007F0B34 /* munkiimportOptions.swift in Sources */ = {isa = PBXBuildFile; fileRef = C030A9C62C41F32E007F0B34 /* munkiimportOptions.swift */; };
|
||||
C030A9D52C41F897007F0B34 /* pkginfoOptions.swift in Sources */ = {isa = PBXBuildFile; fileRef = C030A99E2C3B4F04007F0B34 /* pkginfoOptions.swift */; };
|
||||
C030A9D62C41F8CB007F0B34 /* utils.swift in Sources */ = {isa = PBXBuildFile; fileRef = C07A6FD12C2B654300090743 /* utils.swift */; };
|
||||
C030A9D82C41F8FC007F0B34 /* ArgumentParser in Frameworks */ = {isa = PBXBuildFile; productRef = C030A9D72C41F8FC007F0B34 /* ArgumentParser */; };
|
||||
C030A9D92C424057007F0B34 /* prefs.swift in Sources */ = {isa = PBXBuildFile; fileRef = C07A6FAF2C2B22A400090743 /* prefs.swift */; };
|
||||
C030A9DA2C42405D007F0B34 /* constants.swift in Sources */ = {isa = PBXBuildFile; fileRef = C07A6FB12C2B22D300090743 /* constants.swift */; };
|
||||
C030A9DB2C424065007F0B34 /* cliutils.swift in Sources */ = {isa = PBXBuildFile; fileRef = C07A6FD92C2CF19600090743 /* cliutils.swift */; };
|
||||
@@ -107,7 +103,6 @@
|
||||
C07A6FC72C2B5C0700090743 /* makecatalogs.swift in Sources */ = {isa = PBXBuildFile; fileRef = C07A6FC62C2B5C0700090743 /* makecatalogs.swift */; };
|
||||
C07A6FCB2C2B5C3A00090743 /* prefs.swift in Sources */ = {isa = PBXBuildFile; fileRef = C07A6FAF2C2B22A400090743 /* prefs.swift */; };
|
||||
C07A6FCC2C2B5C3D00090743 /* constants.swift in Sources */ = {isa = PBXBuildFile; fileRef = C07A6FB12C2B22D300090743 /* constants.swift */; };
|
||||
C07A6FCF2C2B62A600090743 /* ArgumentParser in Frameworks */ = {isa = PBXBuildFile; productRef = C07A6FCE2C2B62A600090743 /* ArgumentParser */; };
|
||||
C07A6FD22C2B654300090743 /* utils.swift in Sources */ = {isa = PBXBuildFile; fileRef = C07A6FD12C2B654300090743 /* utils.swift */; };
|
||||
C07A6FD32C2B659300090743 /* utils.swift in Sources */ = {isa = PBXBuildFile; fileRef = C07A6FD12C2B654300090743 /* utils.swift */; };
|
||||
C07A6FD42C2B659400090743 /* utils.swift in Sources */ = {isa = PBXBuildFile; fileRef = C07A6FD12C2B654300090743 /* utils.swift */; };
|
||||
@@ -136,12 +131,17 @@
|
||||
C0D00FB82C45BCB90021DA9C /* errors.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0D00FB52C45BCB90021DA9C /* errors.swift */; };
|
||||
C0D00FB92C45BCB90021DA9C /* errors.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0D00FB52C45BCB90021DA9C /* errors.swift */; };
|
||||
C0D00FBA2C45BCB90021DA9C /* errors.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0D00FB52C45BCB90021DA9C /* errors.swift */; };
|
||||
C0D9C2462C5C5B370019A067 /* socketclient.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0D9C2452C5C5B370019A067 /* socketclient.swift */; };
|
||||
C0D9C24E2C5C5C920019A067 /* main.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0D9C24D2C5C5C920019A067 /* main.swift */; };
|
||||
C0D9C2522C5C5D1F0019A067 /* errors.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0D00FB52C45BCB90021DA9C /* errors.swift */; };
|
||||
C0D9C2532C5C5D4F0019A067 /* socketclient.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0D9C2452C5C5B370019A067 /* socketclient.swift */; };
|
||||
C0D9C2542C5C5EBC0019A067 /* constants.swift in Sources */ = {isa = PBXBuildFile; fileRef = C07A6FB12C2B22D300090743 /* constants.swift */; };
|
||||
C0D9C2552C5C5EC00019A067 /* plistutils.swift in Sources */ = {isa = PBXBuildFile; fileRef = C01364422C2DD1BA008DB215 /* plistutils.swift */; };
|
||||
C0E993F82C5BEDAB006FDF44 /* removepackages.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0E993F72C5BEDAB006FDF44 /* removepackages.swift */; };
|
||||
C0E993FC2C5BEDE7006FDF44 /* rmpkgs.swift in Sources */ = {isa = PBXBuildFile; fileRef = C043ED222C483EEE0047C025 /* rmpkgs.swift */; };
|
||||
C0E993FD2C5BEDFA006FDF44 /* display.swift in Sources */ = {isa = PBXBuildFile; fileRef = C01364572C3265D6008DB215 /* display.swift */; };
|
||||
C0E993FE2C5BEE0D006FDF44 /* cliutils.swift in Sources */ = {isa = PBXBuildFile; fileRef = C07A6FD92C2CF19600090743 /* cliutils.swift */; };
|
||||
C0E993FF2C5BEE1B006FDF44 /* fileutils.swift in Sources */ = {isa = PBXBuildFile; fileRef = C030A9B52C3DF6D0007F0B34 /* fileutils.swift */; };
|
||||
C0E994012C5BEE35006FDF44 /* ArgumentParser in Frameworks */ = {isa = PBXBuildFile; productRef = C0E994002C5BEE35006FDF44 /* ArgumentParser */; };
|
||||
C0E994022C5BF4BD006FDF44 /* sqlite3.swift in Sources */ = {isa = PBXBuildFile; fileRef = C043ED1E2C4822C70047C025 /* sqlite3.swift */; };
|
||||
C0E994032C5BF4CF006FDF44 /* munkilog.swift in Sources */ = {isa = PBXBuildFile; fileRef = C07074DB2C33AE5F00B86310 /* munkilog.swift */; };
|
||||
C0E994042C5BF4DC006FDF44 /* prefs.swift in Sources */ = {isa = PBXBuildFile; fileRef = C07A6FAF2C2B22A400090743 /* prefs.swift */; };
|
||||
@@ -151,6 +151,12 @@
|
||||
C0E994082C5BF53D006FDF44 /* errors.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0D00FB52C45BCB90021DA9C /* errors.swift */; };
|
||||
C0E994092C5BF54E006FDF44 /* utils.swift in Sources */ = {isa = PBXBuildFile; fileRef = C07A6FD12C2B654300090743 /* utils.swift */; };
|
||||
C0E9940A2C5BF56C006FDF44 /* version.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0D00FAF2C458EAA0021DA9C /* version.swift */; };
|
||||
C0E9941A2C5C10E1006FDF44 /* ArgumentParser in Frameworks */ = {isa = PBXBuildFile; productRef = C0E994192C5C10E1006FDF44 /* ArgumentParser */; };
|
||||
C0E9941C2C5C10F8006FDF44 /* ArgumentParser in Frameworks */ = {isa = PBXBuildFile; productRef = C0E9941B2C5C10F8006FDF44 /* ArgumentParser */; };
|
||||
C0E9941E2C5C10FE006FDF44 /* ArgumentParser in Frameworks */ = {isa = PBXBuildFile; productRef = C0E9941D2C5C10FE006FDF44 /* ArgumentParser */; };
|
||||
C0E994202C5C1103006FDF44 /* ArgumentParser in Frameworks */ = {isa = PBXBuildFile; productRef = C0E9941F2C5C1103006FDF44 /* ArgumentParser */; };
|
||||
C0E994222C5C1109006FDF44 /* ArgumentParser in Frameworks */ = {isa = PBXBuildFile; productRef = C0E994212C5C1109006FDF44 /* ArgumentParser */; };
|
||||
C0E994242C5C110E006FDF44 /* ArgumentParser in Frameworks */ = {isa = PBXBuildFile; productRef = C0E994232C5C110E006FDF44 /* ArgumentParser */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXCopyFilesBuildPhase section */
|
||||
@@ -199,6 +205,15 @@
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 1;
|
||||
};
|
||||
C0D9C2492C5C5C920019A067 /* CopyFiles */ = {
|
||||
isa = PBXCopyFilesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
dstPath = /usr/share/man/man1/;
|
||||
dstSubfolderSpec = 0;
|
||||
files = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 1;
|
||||
};
|
||||
C0E993F32C5BEDAB006FDF44 /* CopyFiles */ = {
|
||||
isa = PBXCopyFilesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
@@ -255,6 +270,9 @@
|
||||
C0D00FA72C45814F0021DA9C /* repoutils.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = repoutils.swift; sourceTree = "<group>"; };
|
||||
C0D00FAF2C458EAA0021DA9C /* version.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = version.swift; sourceTree = "<group>"; };
|
||||
C0D00FB52C45BCB90021DA9C /* errors.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = errors.swift; sourceTree = "<group>"; };
|
||||
C0D9C2452C5C5B370019A067 /* socketclient.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = socketclient.swift; sourceTree = "<group>"; };
|
||||
C0D9C24B2C5C5C920019A067 /* app_usage_monitor */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = app_usage_monitor; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
C0D9C24D2C5C5C920019A067 /* main.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = main.swift; sourceTree = "<group>"; };
|
||||
C0E993F52C5BEDAB006FDF44 /* removepackages */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = removepackages; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
C0E993F72C5BEDAB006FDF44 /* removepackages.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = removepackages.swift; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
@@ -264,7 +282,7 @@
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
C030A99D2C3B12A6007F0B34 /* ArgumentParser in Frameworks */,
|
||||
C0E994202C5C1103006FDF44 /* ArgumentParser in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@@ -272,8 +290,8 @@
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
C0E994222C5C1109006FDF44 /* ArgumentParser in Frameworks */,
|
||||
C030A9F42C435113007F0B34 /* libedit.tbd in Frameworks */,
|
||||
C030A9D82C41F8FC007F0B34 /* ArgumentParser in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@@ -281,7 +299,7 @@
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
C01364522C311DFA008DB215 /* ArgumentParser in Frameworks */,
|
||||
C0E9941C2C5C10F8006FDF44 /* ArgumentParser in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@@ -289,7 +307,7 @@
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
C030A9C52C41B59F007F0B34 /* ArgumentParser in Frameworks */,
|
||||
C0E9941A2C5C10E1006FDF44 /* ArgumentParser in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@@ -297,7 +315,14 @@
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
C07A6FCF2C2B62A600090743 /* ArgumentParser in Frameworks */,
|
||||
C0E9941E2C5C10FE006FDF44 /* ArgumentParser in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
C0D9C2482C5C5C920019A067 /* Frameworks */ = {
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@@ -305,7 +330,7 @@
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
C0E994012C5BEE35006FDF44 /* ArgumentParser in Frameworks */,
|
||||
C0E994242C5C110E006FDF44 /* ArgumentParser in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@@ -379,6 +404,7 @@
|
||||
C030A9962C3A2E18007F0B34 /* makepkginfo */,
|
||||
C030A9CE2C41F798007F0B34 /* munkiimport */,
|
||||
C0E993F62C5BEDAB006FDF44 /* removepackages */,
|
||||
C0D9C24C2C5C5C920019A067 /* app_usage_monitor */,
|
||||
C07A6FA62C2A82B400090743 /* Products */,
|
||||
C01364502C311DFA008DB215 /* Frameworks */,
|
||||
);
|
||||
@@ -393,6 +419,7 @@
|
||||
C030A9952C3A2E18007F0B34 /* makepkginfo */,
|
||||
C030A9CD2C41F798007F0B34 /* munkiimport */,
|
||||
C0E993F52C5BEDAB006FDF44 /* removepackages */,
|
||||
C0D9C24B2C5C5C920019A067 /* app_usage_monitor */,
|
||||
);
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
@@ -448,10 +475,19 @@
|
||||
C0D00FAF2C458EAA0021DA9C /* version.swift */,
|
||||
C0D00FB52C45BCB90021DA9C /* errors.swift */,
|
||||
C043ED1E2C4822C70047C025 /* sqlite3.swift */,
|
||||
C0D9C2452C5C5B370019A067 /* socketclient.swift */,
|
||||
);
|
||||
path = shared;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
C0D9C24C2C5C5C920019A067 /* app_usage_monitor */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
C0D9C24D2C5C5C920019A067 /* main.swift */,
|
||||
);
|
||||
path = app_usage_monitor;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
C0E993F62C5BEDAB006FDF44 /* removepackages */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
@@ -477,7 +513,7 @@
|
||||
);
|
||||
name = makepkginfo;
|
||||
packageProductDependencies = (
|
||||
C030A99C2C3B12A6007F0B34 /* ArgumentParser */,
|
||||
C0E9941F2C5C1103006FDF44 /* ArgumentParser */,
|
||||
);
|
||||
productName = makepkginfo;
|
||||
productReference = C030A9952C3A2E18007F0B34 /* makepkginfo */;
|
||||
@@ -497,7 +533,7 @@
|
||||
);
|
||||
name = munkiimport;
|
||||
packageProductDependencies = (
|
||||
C030A9D72C41F8FC007F0B34 /* ArgumentParser */,
|
||||
C0E994212C5C1109006FDF44 /* ArgumentParser */,
|
||||
);
|
||||
productName = munkiimport;
|
||||
productReference = C030A9CD2C41F798007F0B34 /* munkiimport */;
|
||||
@@ -517,7 +553,7 @@
|
||||
);
|
||||
name = managedsoftwareupdate;
|
||||
packageProductDependencies = (
|
||||
C01364512C311DFA008DB215 /* ArgumentParser */,
|
||||
C0E9941B2C5C10F8006FDF44 /* ArgumentParser */,
|
||||
);
|
||||
productName = munki;
|
||||
productReference = C07A6FA52C2A82B400090743 /* managedsoftwareupdate */;
|
||||
@@ -537,7 +573,7 @@
|
||||
);
|
||||
name = munkitester;
|
||||
packageProductDependencies = (
|
||||
C030A9C42C41B59F007F0B34 /* ArgumentParser */,
|
||||
C0E994192C5C10E1006FDF44 /* ArgumentParser */,
|
||||
);
|
||||
productName = munkitester;
|
||||
productReference = C07A6FB72C2B5ADE00090743 /* munkitester */;
|
||||
@@ -557,12 +593,29 @@
|
||||
);
|
||||
name = makecatalogs;
|
||||
packageProductDependencies = (
|
||||
C07A6FCE2C2B62A600090743 /* ArgumentParser */,
|
||||
C0E9941D2C5C10FE006FDF44 /* ArgumentParser */,
|
||||
);
|
||||
productName = makecatalogs;
|
||||
productReference = C07A6FC42C2B5C0700090743 /* makecatalogs */;
|
||||
productType = "com.apple.product-type.tool";
|
||||
};
|
||||
C0D9C24A2C5C5C920019A067 /* app_usage_monitor */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = C0D9C24F2C5C5C920019A067 /* Build configuration list for PBXNativeTarget "app_usage_monitor" */;
|
||||
buildPhases = (
|
||||
C0D9C2472C5C5C920019A067 /* Sources */,
|
||||
C0D9C2482C5C5C920019A067 /* Frameworks */,
|
||||
C0D9C2492C5C5C920019A067 /* CopyFiles */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
dependencies = (
|
||||
);
|
||||
name = app_usage_monitor;
|
||||
productName = app_usage_monitor;
|
||||
productReference = C0D9C24B2C5C5C920019A067 /* app_usage_monitor */;
|
||||
productType = "com.apple.product-type.tool";
|
||||
};
|
||||
C0E993F42C5BEDAB006FDF44 /* removepackages */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = C0E993FB2C5BEDAB006FDF44 /* Build configuration list for PBXNativeTarget "removepackages" */;
|
||||
@@ -577,7 +630,7 @@
|
||||
);
|
||||
name = removepackages;
|
||||
packageProductDependencies = (
|
||||
C0E994002C5BEE35006FDF44 /* ArgumentParser */,
|
||||
C0E994232C5C110E006FDF44 /* ArgumentParser */,
|
||||
);
|
||||
productName = removepackages;
|
||||
productReference = C0E993F52C5BEDAB006FDF44 /* removepackages */;
|
||||
@@ -610,6 +663,9 @@
|
||||
C07A6FC32C2B5C0700090743 = {
|
||||
CreatedOnToolsVersion = 15.4;
|
||||
};
|
||||
C0D9C24A2C5C5C920019A067 = {
|
||||
CreatedOnToolsVersion = 15.4;
|
||||
};
|
||||
C0E993F42C5BEDAB006FDF44 = {
|
||||
CreatedOnToolsVersion = 15.4;
|
||||
};
|
||||
@@ -625,7 +681,7 @@
|
||||
);
|
||||
mainGroup = C07A6F9C2C2A82B400090743;
|
||||
packageReferences = (
|
||||
C07A6FCD2C2B62A600090743 /* XCRemoteSwiftPackageReference "swift-argument-parser" */,
|
||||
C0E994182C5C10E1006FDF44 /* XCRemoteSwiftPackageReference "swift-argument-parser" */,
|
||||
);
|
||||
productRefGroup = C07A6FA62C2A82B400090743 /* Products */;
|
||||
projectDirPath = "";
|
||||
@@ -637,6 +693,7 @@
|
||||
C030A9942C3A2E18007F0B34 /* makepkginfo */,
|
||||
C030A9CC2C41F798007F0B34 /* munkiimport */,
|
||||
C0E993F42C5BEDAB006FDF44 /* removepackages */,
|
||||
C0D9C24A2C5C5C920019A067 /* app_usage_monitor */,
|
||||
);
|
||||
};
|
||||
/* End PBXProject section */
|
||||
@@ -744,6 +801,7 @@
|
||||
C0D00FB72C45BCB90021DA9C /* errors.swift in Sources */,
|
||||
C030A9C82C41F32E007F0B34 /* munkiimportOptions.swift in Sources */,
|
||||
C030A9C02C409738007F0B34 /* iconutils.swift in Sources */,
|
||||
C0D9C2462C5C5B370019A067 /* socketclient.swift in Sources */,
|
||||
C030A9F62C435183007F0B34 /* readline.swift in Sources */,
|
||||
C0D00FB12C458EAA0021DA9C /* version.swift in Sources */,
|
||||
C030A9C32C41B581007F0B34 /* pkginfoOptions.swift in Sources */,
|
||||
@@ -800,6 +858,18 @@
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
C0D9C2472C5C5C920019A067 /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
C0D9C2522C5C5D1F0019A067 /* errors.swift in Sources */,
|
||||
C0D9C24E2C5C5C920019A067 /* main.swift in Sources */,
|
||||
C0D9C2532C5C5D4F0019A067 /* socketclient.swift in Sources */,
|
||||
C0D9C2542C5C5EBC0019A067 /* constants.swift in Sources */,
|
||||
C0D9C2552C5C5EC00019A067 /* plistutils.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
C0E993F12C5BEDAB006FDF44 /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
@@ -1086,6 +1156,28 @@
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
C0D9C2502C5C5C920019A067 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
DEVELOPMENT_TEAM = 52ZFZKM6BK;
|
||||
ENABLE_HARDENED_RUNTIME = YES;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_VERSION = 5.0;
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
C0D9C2512C5C5C920019A067 /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
DEVELOPMENT_TEAM = 52ZFZKM6BK;
|
||||
ENABLE_HARDENED_RUNTIME = YES;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_VERSION = 5.0;
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
C0E993F92C5BEDAB006FDF44 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
@@ -1165,6 +1257,15 @@
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
C0D9C24F2C5C5C920019A067 /* Build configuration list for PBXNativeTarget "app_usage_monitor" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
C0D9C2502C5C5C920019A067 /* Debug */,
|
||||
C0D9C2512C5C5C920019A067 /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
C0E993FB2C5BEDAB006FDF44 /* Build configuration list for PBXNativeTarget "removepackages" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
@@ -1177,45 +1278,45 @@
|
||||
/* End XCConfigurationList section */
|
||||
|
||||
/* Begin XCRemoteSwiftPackageReference section */
|
||||
C07A6FCD2C2B62A600090743 /* XCRemoteSwiftPackageReference "swift-argument-parser" */ = {
|
||||
C0E994182C5C10E1006FDF44 /* XCRemoteSwiftPackageReference "swift-argument-parser" */ = {
|
||||
isa = XCRemoteSwiftPackageReference;
|
||||
repositoryURL = "https://github.com/apple/swift-argument-parser.git";
|
||||
requirement = {
|
||||
kind = upToNextMajorVersion;
|
||||
minimumVersion = 1.4.0;
|
||||
minimumVersion = 1.5.0;
|
||||
};
|
||||
};
|
||||
/* End XCRemoteSwiftPackageReference section */
|
||||
|
||||
/* Begin XCSwiftPackageProductDependency section */
|
||||
C01364512C311DFA008DB215 /* ArgumentParser */ = {
|
||||
C0E994192C5C10E1006FDF44 /* ArgumentParser */ = {
|
||||
isa = XCSwiftPackageProductDependency;
|
||||
package = C07A6FCD2C2B62A600090743 /* XCRemoteSwiftPackageReference "swift-argument-parser" */;
|
||||
package = C0E994182C5C10E1006FDF44 /* XCRemoteSwiftPackageReference "swift-argument-parser" */;
|
||||
productName = ArgumentParser;
|
||||
};
|
||||
C030A99C2C3B12A6007F0B34 /* ArgumentParser */ = {
|
||||
C0E9941B2C5C10F8006FDF44 /* ArgumentParser */ = {
|
||||
isa = XCSwiftPackageProductDependency;
|
||||
package = C07A6FCD2C2B62A600090743 /* XCRemoteSwiftPackageReference "swift-argument-parser" */;
|
||||
package = C0E994182C5C10E1006FDF44 /* XCRemoteSwiftPackageReference "swift-argument-parser" */;
|
||||
productName = ArgumentParser;
|
||||
};
|
||||
C030A9C42C41B59F007F0B34 /* ArgumentParser */ = {
|
||||
C0E9941D2C5C10FE006FDF44 /* ArgumentParser */ = {
|
||||
isa = XCSwiftPackageProductDependency;
|
||||
package = C07A6FCD2C2B62A600090743 /* XCRemoteSwiftPackageReference "swift-argument-parser" */;
|
||||
package = C0E994182C5C10E1006FDF44 /* XCRemoteSwiftPackageReference "swift-argument-parser" */;
|
||||
productName = ArgumentParser;
|
||||
};
|
||||
C030A9D72C41F8FC007F0B34 /* ArgumentParser */ = {
|
||||
C0E9941F2C5C1103006FDF44 /* ArgumentParser */ = {
|
||||
isa = XCSwiftPackageProductDependency;
|
||||
package = C07A6FCD2C2B62A600090743 /* XCRemoteSwiftPackageReference "swift-argument-parser" */;
|
||||
package = C0E994182C5C10E1006FDF44 /* XCRemoteSwiftPackageReference "swift-argument-parser" */;
|
||||
productName = ArgumentParser;
|
||||
};
|
||||
C07A6FCE2C2B62A600090743 /* ArgumentParser */ = {
|
||||
C0E994212C5C1109006FDF44 /* ArgumentParser */ = {
|
||||
isa = XCSwiftPackageProductDependency;
|
||||
package = C07A6FCD2C2B62A600090743 /* XCRemoteSwiftPackageReference "swift-argument-parser" */;
|
||||
package = C0E994182C5C10E1006FDF44 /* XCRemoteSwiftPackageReference "swift-argument-parser" */;
|
||||
productName = ArgumentParser;
|
||||
};
|
||||
C0E994002C5BEE35006FDF44 /* ArgumentParser */ = {
|
||||
C0E994232C5C110E006FDF44 /* ArgumentParser */ = {
|
||||
isa = XCSwiftPackageProductDependency;
|
||||
package = C07A6FCD2C2B62A600090743 /* XCRemoteSwiftPackageReference "swift-argument-parser" */;
|
||||
package = C0E994182C5C10E1006FDF44 /* XCRemoteSwiftPackageReference "swift-argument-parser" */;
|
||||
productName = ArgumentParser;
|
||||
};
|
||||
/* End XCSwiftPackageProductDependency section */
|
||||
|
||||
+2
-2
@@ -6,8 +6,8 @@
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/apple/swift-argument-parser.git",
|
||||
"state" : {
|
||||
"revision" : "0fbc8848e389af3bb55c182bc19ca9d5dc2f255b",
|
||||
"version" : "1.4.0"
|
||||
"revision" : "41982a3656a71c768319979febd796c6fd111d5c",
|
||||
"version" : "1.5.0"
|
||||
}
|
||||
}
|
||||
],
|
||||
|
||||
@@ -0,0 +1,206 @@
|
||||
//
|
||||
// socketclient.swift
|
||||
//
|
||||
// Created by Greg Neagle on 7/23/18.
|
||||
// Copyright © 2018-2024 The Munki Project. All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// https://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
import CoreFoundation
|
||||
import Darwin
|
||||
import Foundation
|
||||
|
||||
enum UNIXDomainSocketClientErrorCode: Int {
|
||||
case noError = 0, addressError, createError, socketError, connectError, readError, writeError, timeoutError
|
||||
}
|
||||
|
||||
class UNIXDomainSocketClient {
|
||||
// A basic implementation of Unix domain sockets for MSC
|
||||
// We use CFSocket calls when we can, and fallback to Darwin (BSD/C) API
|
||||
// when we must.
|
||||
|
||||
var socketRef: CFSocket?
|
||||
var errCode: UNIXDomainSocketClientErrorCode = .noError
|
||||
|
||||
func close() {
|
||||
// close the socket if it exists
|
||||
if let socket = socketRef {
|
||||
CFSocketInvalidate(socket)
|
||||
socketRef = nil
|
||||
}
|
||||
}
|
||||
|
||||
private func addrRefCreate(_ path: String) -> CFData? {
|
||||
// make a sockaddr struct (this is ugly), wrap it in a CFData obj
|
||||
var socketAdr = sockaddr_un()
|
||||
socketAdr.sun_family = sa_family_t(AF_UNIX)
|
||||
socketAdr.sun_len = __uint8_t(MemoryLayout<sockaddr_un>.size)
|
||||
if var cstring_path = path.cString(using: .utf8) {
|
||||
if cstring_path.count > MemoryLayout.size(
|
||||
ofValue: socketAdr.sun_path)
|
||||
{
|
||||
// path is too long for this 1970s era struct
|
||||
return nil
|
||||
}
|
||||
memcpy(&socketAdr.sun_path, &cstring_path, cstring_path.count)
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
return NSData(bytes: &socketAdr,
|
||||
length: MemoryLayout.size(ofValue: socketAdr)) as CFData
|
||||
}
|
||||
|
||||
func connect(to path: String) {
|
||||
// Create a UNIX domain socket object and connect
|
||||
//
|
||||
// get a CFData reference to our socket path
|
||||
guard let adrDataRef = addrRefCreate(path) else {
|
||||
errCode = .addressError
|
||||
return
|
||||
}
|
||||
// create a CFSocket object
|
||||
guard let socket = CFSocketCreate(kCFAllocatorDefault,
|
||||
PF_UNIX,
|
||||
SOCK_STREAM,
|
||||
0,
|
||||
0,
|
||||
nil,
|
||||
nil)
|
||||
else {
|
||||
errCode = .createError
|
||||
return
|
||||
}
|
||||
// connect
|
||||
guard CFSocketConnectToAddress(socket,
|
||||
adrDataRef,
|
||||
1) == .success
|
||||
else {
|
||||
errCode = .connectError
|
||||
return
|
||||
}
|
||||
// save the socket obj for later use
|
||||
socketRef = socket
|
||||
}
|
||||
|
||||
func write(_ text: String) {
|
||||
// send text data to our socket
|
||||
//
|
||||
// ensure we have a non-nil socketRef
|
||||
guard let socket = socketRef else {
|
||||
errCode = .socketError
|
||||
return
|
||||
}
|
||||
if text.count == 0 || errCode != .noError {
|
||||
return
|
||||
}
|
||||
// make a CFData reference from our text data
|
||||
guard let data = text.data(using: .utf8) as CFData? else {
|
||||
errCode = .writeError
|
||||
return
|
||||
}
|
||||
errCode = .noError
|
||||
guard CFSocketSendData(socket, nil, data, 30) == .success else {
|
||||
errCode = .writeError
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
private func fdSet(_ fd: Int32, set: inout fd_set) {
|
||||
// Replacement for FD_SET macro
|
||||
let intOffset = Int(fd / 32)
|
||||
let bitOffset = fd % 32
|
||||
let mask = Int32(1 << bitOffset)
|
||||
switch intOffset {
|
||||
case 0: set.fds_bits.0 = set.fds_bits.0 | mask
|
||||
case 1: set.fds_bits.1 = set.fds_bits.1 | mask
|
||||
case 2: set.fds_bits.2 = set.fds_bits.2 | mask
|
||||
case 3: set.fds_bits.3 = set.fds_bits.3 | mask
|
||||
case 4: set.fds_bits.4 = set.fds_bits.4 | mask
|
||||
case 5: set.fds_bits.5 = set.fds_bits.5 | mask
|
||||
case 6: set.fds_bits.6 = set.fds_bits.6 | mask
|
||||
case 7: set.fds_bits.7 = set.fds_bits.7 | mask
|
||||
case 8: set.fds_bits.8 = set.fds_bits.8 | mask
|
||||
case 9: set.fds_bits.9 = set.fds_bits.9 | mask
|
||||
case 10: set.fds_bits.10 = set.fds_bits.10 | mask
|
||||
case 11: set.fds_bits.11 = set.fds_bits.11 | mask
|
||||
case 12: set.fds_bits.12 = set.fds_bits.12 | mask
|
||||
case 13: set.fds_bits.13 = set.fds_bits.13 | mask
|
||||
case 14: set.fds_bits.14 = set.fds_bits.14 | mask
|
||||
case 15: set.fds_bits.15 = set.fds_bits.15 | mask
|
||||
case 16: set.fds_bits.16 = set.fds_bits.16 | mask
|
||||
case 17: set.fds_bits.17 = set.fds_bits.17 | mask
|
||||
case 18: set.fds_bits.18 = set.fds_bits.18 | mask
|
||||
case 19: set.fds_bits.19 = set.fds_bits.19 | mask
|
||||
case 20: set.fds_bits.20 = set.fds_bits.20 | mask
|
||||
case 21: set.fds_bits.21 = set.fds_bits.21 | mask
|
||||
case 22: set.fds_bits.22 = set.fds_bits.22 | mask
|
||||
case 23: set.fds_bits.23 = set.fds_bits.23 | mask
|
||||
case 24: set.fds_bits.24 = set.fds_bits.24 | mask
|
||||
case 25: set.fds_bits.25 = set.fds_bits.25 | mask
|
||||
case 26: set.fds_bits.26 = set.fds_bits.26 | mask
|
||||
case 27: set.fds_bits.27 = set.fds_bits.27 | mask
|
||||
case 28: set.fds_bits.28 = set.fds_bits.28 | mask
|
||||
case 29: set.fds_bits.29 = set.fds_bits.29 | mask
|
||||
case 30: set.fds_bits.30 = set.fds_bits.30 | mask
|
||||
case 31: set.fds_bits.31 = set.fds_bits.31 | mask
|
||||
default: break
|
||||
}
|
||||
}
|
||||
|
||||
private func dataAvailable(timeout: Int = 10) -> Bool {
|
||||
// uses POSIX select() to wait for data to be available on the socket
|
||||
//
|
||||
// ensure we have a non-nil socketRef
|
||||
guard let socket = socketRef else {
|
||||
errCode = .socketError
|
||||
return false
|
||||
}
|
||||
var timer = timeval()
|
||||
timer.tv_sec = timeout
|
||||
timer.tv_usec = 0
|
||||
let socket_fd = CFSocketGetNative(socket)
|
||||
var readfds = fd_set(fds_bits: (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0))
|
||||
fdSet(socket_fd, set: &readfds)
|
||||
let result = select(socket_fd + 1, &readfds, nil, nil, &timer)
|
||||
return result > 0
|
||||
}
|
||||
|
||||
func read(maxsize: Int = 1024, timeout: Int = 10) -> String {
|
||||
// read a message from our socket
|
||||
// there's no CFSocketRead method, use BSD socket recv method instead
|
||||
//
|
||||
// ensure we have a non-nil socketRef
|
||||
guard let socket = socketRef else {
|
||||
errCode = .socketError
|
||||
return ""
|
||||
}
|
||||
// wait up until timeout seconds for data to become available
|
||||
if !dataAvailable(timeout: timeout) {
|
||||
errCode = .timeoutError
|
||||
return ""
|
||||
}
|
||||
// allocate some space for the return message.
|
||||
let buffer = UnsafeMutablePointer<UInt8>.allocate(capacity: maxsize)
|
||||
defer { buffer.deallocate() }
|
||||
// read from socket
|
||||
let msg_len = recv(CFSocketGetNative(socket), buffer, maxsize, 0)
|
||||
if let msg = NSString(bytes: buffer,
|
||||
length: msg_len,
|
||||
encoding: String.Encoding.utf8.rawValue) as String?
|
||||
{
|
||||
return msg
|
||||
}
|
||||
errCode = .readError
|
||||
return ""
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user