Skip to content

Commit

Permalink
Update Mac signal reader and parser to use system profiler
Browse files Browse the repository at this point in the history
  • Loading branch information
SteveDesmond-ca committed Dec 10, 2024
1 parent e8c545b commit 39adda3
Show file tree
Hide file tree
Showing 6 changed files with 202 additions and 62 deletions.
2 changes: 1 addition & 1 deletion Mac.Tests/Mac.Tests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,6 @@
<PackageReference Include="coverlet.collector" Version="6.0.0" />
<ProjectReference Include="..\Core\Core.csproj" />
<ProjectReference Include="..\Mac\Mac.csproj" />
<None Include="airport-output.txt" CopyToOutputDirectory="PreserveNewest" />
<None Include="system_profiler-output.txt" CopyToOutputDirectory="PreserveNewest" />
</ItemGroup>
</Project>
53 changes: 14 additions & 39 deletions Mac.Tests/MacSignalParserTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,59 +16,34 @@ public async Task ResultsAreParsedIntoSignals()
//arrange
var logger = Substitute.For<ILogger>();
var signalParser = new MacSignalParser(logger);
var contents = await File.ReadAllTextAsync("airport-output.txt");
var contents = await File.ReadAllTextAsync("system_profiler-output.txt");

//act
var signals = signalParser.Parse(contents).ToList();

//assert
Assert.Equal("net1", signals[0].SSID);
Assert.Equal("xx:bf:xx:f7:13:xx", signals[0].MAC);
Assert.Empty(signals[0].MAC);
Assert.Equal(Frequency._2_4_GHz, signals[0].Frequency);
Assert.Equal(11, signals[0].Channel);
Assert.Equal(-83, signals[0].Strength);
Assert.Equal(9, signals[0].Channel);
Assert.Equal(-39, signals[0].Strength);

Assert.Equal("ssid🏎2", signals[1].SSID);
Assert.Equal("xx:3d:xx:96:97:xx", signals[1].MAC);
Assert.Empty(signals[1].MAC);
Assert.Equal(Frequency._5_GHz, signals[1].Frequency);
Assert.Equal(149, signals[1].Channel);
Assert.Equal(-82, signals[1].Strength);
Assert.Equal(44, signals[1].Channel);
Assert.Equal(-50, signals[1].Strength);

Assert.Equal("access_point_3", signals[2].SSID);
Assert.Equal("xx:3d:xx:96:98:xx", signals[2].MAC);
Assert.Equal(Frequency._2_4_GHz, signals[2].Frequency);
Assert.Equal(11, signals[2].Channel);
Assert.Equal(-76, signals[2].Strength);
Assert.Empty(signals[2].MAC);
Assert.Equal(Frequency._5_GHz, signals[2].Frequency);
Assert.Equal(149, signals[2].Channel);
Assert.Equal(-42, signals[2].Strength);

Assert.Equal("wap-4", signals[3].SSID);
Assert.Equal("xx:cb:xx:ad:a8:xx", signals[3].MAC);
Assert.Empty(signals[3].MAC);
Assert.Equal(Frequency._2_4_GHz, signals[3].Frequency);
Assert.Equal(6, signals[3].Channel);
Assert.Equal(-37, signals[3].Strength);

Assert.Equal("router5", signals[4].SSID);
Assert.Equal("xx:cb:xx:ad:a8:xx", signals[4].MAC);
Assert.Equal(Frequency._5_GHz, signals[4].Frequency);
Assert.Equal(149, signals[4].Channel);
Assert.Equal(-42, signals[4].Strength);
}

[Fact]
public async Task IgnoresInvalidResults()
{
//arrange
var logger = Substitute.For<ILogger>();
var signalParser = new MacSignalParser(logger);
var contents = await File.ReadAllTextAsync("airport-output.txt");
contents = contents
.Replace("13:xx", "")
.Replace("97:xx", "")
.Replace("a8:xx", "");

//act
var signals = signalParser.Parse(contents);

//assert
Assert.Equal("access_point_3", signals.Single().SSID);
Assert.Equal(11, signals[3].Channel);
Assert.Equal(-90, signals[3].Strength);
}
}
6 changes: 0 additions & 6 deletions Mac.Tests/airport-output.txt

This file was deleted.

162 changes: 162 additions & 0 deletions Mac.Tests/system_profiler-output.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
{
"SPAirPortDataType" : [
{
"spairport_airport_interfaces" : [
{
"_name" : "en0",
"spairport_airport_other_local_wireless_networks" : [
{
"_name" : "net1",
"spairport_network_channel" : "9 (2GHz, 40MHz)",
"spairport_network_phymode" : "802.11",
"spairport_network_type" : "spairport_network_type_station",
"spairport_security_mode" : "pairport_security_mode_wpa3_transition",
"spairport_signal_noise" : "-39 dBm / -90 dBm"
},
{
"_name" : "ssid🏎2",
"spairport_network_channel" : "44 (5GHz, 80MHz)",
"spairport_network_phymode" : "802.11",
"spairport_network_type" : "spairport_network_type_station",
"spairport_security_mode" : "pairport_security_mode_wpa3_transition",
"spairport_signal_noise" : "-50 dBm / -90 dBm"
},
{
"_name" : "access_point_3",
"spairport_network_channel" : "149 (5GHz, 80MHz)",
"spairport_network_phymode" : "802.11",
"spairport_network_type" : "spairport_network_type_station",
"spairport_security_mode" : "pairport_security_mode_wpa3_transition",
"spairport_signal_noise" : "-42 dBm / -90 dBm"
},
{
"_name" : "wap-4",
"spairport_network_channel" : "11 (2GHz, 40MHz)",
"spairport_network_phymode" : "802.11",
"spairport_network_type" : "spairport_network_type_station",
"spairport_security_mode" : "spairport_security_mode_wpa2_personal",
"spairport_signal_noise" : "-90 dBm / -90 dBm"
}
],
"spairport_caps_airdrop" : "spairport_caps_supported",
"spairport_caps_autounlock" : "spairport_caps_supported",
"spairport_caps_wow" : "spairport_caps_supported",
"spairport_current_network_information" : {
"_name" : "net1",
"spairport_network_channel" : "149 (5GHz, 80MHz)",
"spairport_network_country_code" : "US",
"spairport_network_mcs" : 7,
"spairport_network_phymode" : "802.11ac",
"spairport_network_rate" : 975,
"spairport_network_type" : "spairport_network_type_station",
"spairport_security_mode" : "pairport_security_mode_wpa3_transition",
"spairport_signal_noise" : "-48 dBm / -90 dBm"
},
"spairport_status_information" : "spairport_status_connected",
"spairport_supported_channels" : [
"1 (2GHz)",
"2 (2GHz)",
"3 (2GHz)",
"4 (2GHz)",
"5 (2GHz)",
"6 (2GHz)",
"7 (2GHz)",
"8 (2GHz)",
"9 (2GHz)",
"10 (2GHz)",
"11 (2GHz)",
"12 (2GHz)",
"13 (2GHz)",
"36 (5GHz)",
"40 (5GHz)",
"44 (5GHz)",
"48 (5GHz)",
"52 (5GHz)",
"56 (5GHz)",
"60 (5GHz)",
"64 (5GHz)",
"100 (5GHz)",
"104 (5GHz)",
"108 (5GHz)",
"112 (5GHz)",
"116 (5GHz)",
"120 (5GHz)",
"124 (5GHz)",
"128 (5GHz)",
"132 (5GHz)",
"136 (5GHz)",
"140 (5GHz)",
"144 (5GHz)",
"149 (5GHz)",
"153 (5GHz)",
"157 (5GHz)",
"161 (5GHz)",
"165 (5GHz)"
],
"spairport_supported_phymodes" : "802.11 a/b/g/n/ac",
"spairport_wireless_card_type" : "spairport_wireless_card_type_wifi (0x14E4, 0x7BF)",
"spairport_wireless_country_code" : "US",
"spairport_wireless_firmware_version" : "wl0: Jul 10 2023 12:30:19 version 9.30.503.0.32.5.92 FWID 01-88a8883",
"spairport_wireless_locale" : "ETSI",
"spairport_wireless_mac_address" : "f0:18:98:2b:b7:78"
},
{
"_name" : "awdl0",
"spairport_current_network_information" : {
"spairport_network_type" : "spairport_network_type_station"
},
"spairport_supported_channels" : [
"1 (2GHz)",
"2 (2GHz)",
"3 (2GHz)",
"4 (2GHz)",
"5 (2GHz)",
"6 (2GHz)",
"7 (2GHz)",
"8 (2GHz)",
"9 (2GHz)",
"10 (2GHz)",
"11 (2GHz)",
"12 (2GHz)",
"13 (2GHz)",
"36 (5GHz)",
"40 (5GHz)",
"44 (5GHz)",
"48 (5GHz)",
"52 (5GHz)",
"56 (5GHz)",
"60 (5GHz)",
"64 (5GHz)",
"100 (5GHz)",
"104 (5GHz)",
"108 (5GHz)",
"112 (5GHz)",
"116 (5GHz)",
"120 (5GHz)",
"124 (5GHz)",
"128 (5GHz)",
"132 (5GHz)",
"136 (5GHz)",
"140 (5GHz)",
"144 (5GHz)",
"149 (5GHz)",
"153 (5GHz)",
"157 (5GHz)",
"161 (5GHz)",
"165 (5GHz)"
],
"spairport_wireless_mac_address" : "5e:01:d5:ed:24:a0"
}
],
"spairport_software_information" : {
"spairport_corewlan_version" : "16.0 (1657)",
"spairport_corewlankit_version" : "16.0 (1657)",
"spairport_diagnostics_version" : "11.0 (1163)",
"spairport_extra_version" : "17.0 (1728)",
"spairport_family_version" : "12.0 (1200.13.0)",
"spairport_profiler_version" : "15.0 (1502)",
"spairport_utility_version" : "6.3.9 (639.23)"
}
}
]
}
39 changes: 24 additions & 15 deletions Mac/MacSignalParser.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System.Text;
using System.Text.Json;
using WiFiSurveyor.Core;

namespace WiFiSurveyor.Mac;
Expand All @@ -11,39 +12,47 @@ public MacSignalParser(ILogger logger)
=> _logger = logger;

public IReadOnlyList<Signal> Parse(string results)
=> results.Split("\n", StringSplitOptions.RemoveEmptyEntries)
.Skip(1)
.Select(line => GetSignal(Encoding.UTF8.GetBytes(line)))
=> JsonSerializer.Deserialize<JsonElement>(results)
.GetProperty("SPAirPortDataType").EnumerateArray().First()
.GetProperty("spairport_airport_interfaces").EnumerateArray().First()
.GetProperty("spairport_airport_other_local_wireless_networks").EnumerateArray()
.Select(j => GetSignal(j))
.Where(s => s is not null)
.Cast<Signal>()
.ToArray();

private Signal? GetSignal(ReadOnlySpan<byte> line)
private Signal? GetSignal(JsonElement json)
{
try
{
return new()
return new Signal
{
SSID = Encoding.UTF8.GetString(line[..32]).Trim(),
MAC = Encoding.UTF8.GetString(line[32..50]).Trim(),
Strength = short.Parse(Encoding.UTF8.GetString(line[50..55]).Trim()),
Channel = GetChannel(Encoding.UTF8.GetString(line[55..64]).Trim()),
Frequency = GetFrequency(Encoding.UTF8.GetString(line[55..64]).Trim())
SSID = GetString(json, "_name"),
MAC = string.Empty,
Strength = GetStrength(GetString(json, "spairport_signal_noise")),
Channel = GetChannel(GetString(json, "spairport_network_channel")),
Frequency = GetFrequency(GetString(json, "spairport_network_channel"))
};
}
catch (Exception e)
{
_logger.LogIf(LogLevel.Warning, "{now}: Could not parse signal data -- {data}", DateTime.Now, Encoding.UTF8.GetString(line));
_logger.LogIf(LogLevel.Warning, "{now}: Could not parse signal data -- {data}", DateTime.Now, json.ToString());
_logger.LogIf(LogLevel.Debug, "{exception}", e.ToString());
return null;
}
}

private static Frequency GetFrequency(string column)
=> GetChannel(column) < 32
private static string GetString(JsonElement json, string property)
=> json.GetProperty(property).GetString() ?? string.Empty;

private static short GetStrength(string value)
=> short.Parse(value.Split(' ')[0]);

private static Frequency GetFrequency(string value)
=> GetChannel(value) < 32
? Frequency._2_4_GHz
: Frequency._5_GHz;

private static byte GetChannel(string column)
=> byte.Parse(column.Split(',')[0]);
private static byte GetChannel(string value)
=> byte.Parse(value.Split(' ')[0]);
}
2 changes: 1 addition & 1 deletion Mac/MacSignalReader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,5 @@ public MacSignalReader(ICommandService commandService) : base(commandService)
{
}

protected override ProcessStartInfo Info => new("/System/Library/PrivateFrameworks/Apple80211.framework/Versions/Current/Resources/airport", " -s");
protected override ProcessStartInfo Info => new("system_profiler", "SPAirPortDataType -detailLevel full -json");

Check warning on line 12 in Mac/MacSignalReader.cs

View workflow job for this annotation

GitHub Actions / Code-Quality

Make sure the "PATH" used to find this command includes only what you intend. (https://rules.sonarsource.com/csharp/RSPEC-4036)

Check warning on line 12 in Mac/MacSignalReader.cs

View workflow job for this annotation

GitHub Actions / Code-Quality

Make sure the "PATH" used to find this command includes only what you intend. (https://rules.sonarsource.com/csharp/RSPEC-4036)
}

0 comments on commit 39adda3

Please sign in to comment.