Much needed refactor of orbislib into orbislib2.

This commit is contained in:
Greg
2022-12-22 23:55:08 -07:00
parent b777f545bb
commit 92b753adf4
28 changed files with 3084 additions and 3 deletions
+19
View File
@@ -56,6 +56,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "OrbisLibAPI", "Playstation\
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "OrbisLibGeneralHelper", "Playstation\OrbisLibGeneralHelper\OrbisLibGeneralHelper.vcxproj", "{F0E3446E-D9D7-4F44-AC98-797C5124BE91}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OrbisLib2", "Windows\Libraries\OrbisLib2\OrbisLib2.csproj", "{75BA171D-708A-40AA-A27D-57150E5DFB7B}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -244,6 +246,22 @@ Global
{F0E3446E-D9D7-4F44-AC98-797C5124BE91}.Release|x64.Build.0 = Release|x64
{F0E3446E-D9D7-4F44-AC98-797C5124BE91}.Release|x86.ActiveCfg = Release|x64
{F0E3446E-D9D7-4F44-AC98-797C5124BE91}.Release|x86.Build.0 = Release|x64
{75BA171D-708A-40AA-A27D-57150E5DFB7B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{75BA171D-708A-40AA-A27D-57150E5DFB7B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{75BA171D-708A-40AA-A27D-57150E5DFB7B}.Debug|Win32.ActiveCfg = Debug|Any CPU
{75BA171D-708A-40AA-A27D-57150E5DFB7B}.Debug|Win32.Build.0 = Debug|Any CPU
{75BA171D-708A-40AA-A27D-57150E5DFB7B}.Debug|x64.ActiveCfg = Debug|Any CPU
{75BA171D-708A-40AA-A27D-57150E5DFB7B}.Debug|x64.Build.0 = Debug|Any CPU
{75BA171D-708A-40AA-A27D-57150E5DFB7B}.Debug|x86.ActiveCfg = Debug|Any CPU
{75BA171D-708A-40AA-A27D-57150E5DFB7B}.Debug|x86.Build.0 = Debug|Any CPU
{75BA171D-708A-40AA-A27D-57150E5DFB7B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{75BA171D-708A-40AA-A27D-57150E5DFB7B}.Release|Any CPU.Build.0 = Release|Any CPU
{75BA171D-708A-40AA-A27D-57150E5DFB7B}.Release|Win32.ActiveCfg = Release|Any CPU
{75BA171D-708A-40AA-A27D-57150E5DFB7B}.Release|Win32.Build.0 = Release|Any CPU
{75BA171D-708A-40AA-A27D-57150E5DFB7B}.Release|x64.ActiveCfg = Release|Any CPU
{75BA171D-708A-40AA-A27D-57150E5DFB7B}.Release|x64.Build.0 = Release|Any CPU
{75BA171D-708A-40AA-A27D-57150E5DFB7B}.Release|x86.ActiveCfg = Release|Any CPU
{75BA171D-708A-40AA-A27D-57150E5DFB7B}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -262,6 +280,7 @@ Global
{53869FE9-BAFF-4FED-B8E3-20660865426C} = {8F0E1457-FB1E-47A4-9DA8-74A6B757CAA4}
{22E600CA-B7A4-4FA1-A1DB-6BA4736E6121} = {8E8E4C8D-E3E1-4CB9-BD78-7ADAB2F2CF45}
{F0E3446E-D9D7-4F44-AC98-797C5124BE91} = {8E8E4C8D-E3E1-4CB9-BD78-7ADAB2F2CF45}
{75BA171D-708A-40AA-A27D-57150E5DFB7B} = {72E29C1E-8723-4885-A5ED-BD3A929D81B6}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {4B6EE1D0-5ADF-44A2-B6EE-E5C8E110EE47}
-1
View File
@@ -136,7 +136,6 @@ struct APIPacket
{
int PacketVersion;
int Command;
char ProcName[32];
};
#pragma endregion
@@ -0,0 +1,103 @@
using OrbisLib2.Common.Database;
using OrbisLib2.Common.Helpers;
using OrbisLib2.Targets;
using System.Net.Sockets;
namespace OrbisLib2.Common.API
{
public static class API
{
/// <summary>
/// Connects to the api.
/// </summary>
/// <param name="IPAddress">IP Address of the remote target.</param>
/// <param name="Port">The port of the remote target.</param>
/// <param name="TimeOut">The time we should wait before timing out.</param>
/// <param name="Sock">The socket created when connecting.</param>
/// <returns>Returns true if successful.</returns>
private static bool Connect(string IPAddress, int Port, int TimeOut, out Socket Sock)
{
Sock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
return Sock.EasyConnect(IPAddress, Port, TimeOut);
}
/// <summary>
/// Makes an API call to the remote target.
/// </summary>
/// <param name="DesiredTarget">The desired target to recieve the command.</param>
/// <param name="TimeOut">The time the socket should wait before timing out.</param>
/// <param name="Command">The command to be run.</param>
/// <param name="AdditionalCommunications">Optional lambda to send/recv additional data.</param>
/// <returns>Returns result of the communications with the API.</returns>
public static APIResults SendCommand(Target DesiredTarget, int TimeOut, APICommands Command, Action<Socket, APIResults>? AdditionalCommunications = null)
{
if(DesiredTarget.Info.IsAPIAvailable == false)
{
return APIResults.API_ERROR_COULDNT_CONNECT;
}
if (Connect(DesiredTarget.IPAddress, Settings.CreateInstance().APIPort, TimeOut, out Socket Sock))
{
// Send Inital Packet.
Sock.Send(Helper.StructToBytes(new APIPacket() { PacketVersion = Config.PacketVersion, Command = Command }));
// Get API Response.
var result = (APIResults)Sock.RecvInt32();
// Call lambda for additional calls.
if (result == APIResults.API_OK && AdditionalCommunications != null)
{
AdditionalCommunications.Invoke(Sock, result);
}
// Clean up.
Sock.Close();
return result;
}
else
return APIResults.API_ERROR_COULDNT_CONNECT;
}
/// <summary>
/// Sends additional data if required.
/// </summary>
/// <typeparam name="T">The packet type.</typeparam>
/// <param name="Sock">The socket instance were using.</param>
/// <param name="Packet">Any Packet structure.</param>
/// <returns>Returns the result of the action.</returns>
public static APIResults SendNextPacket<T>(Socket Sock, T Packet)
{
// Send Next Packet.
Sock.Send(Helper.StructToBytes(Packet));
// Get API Response.
return (APIResults)Sock.RecvInt32();
}
/// <summary>
///
/// </summary>
/// <param name="Sock"></param>
/// <param name="Value"></param>
/// <returns></returns>
public static APIResults SendInt32(Socket Sock, int Value)
{
try
{
// Send Next Packet.
Sock.Send(BitConverter.GetBytes(Value));
// Get API Response.
return (APIResults)Sock.RecvInt32();
}
catch
{
}
return APIResults.API_ERROR_GENERAL;
}
}
}
@@ -0,0 +1,352 @@
using System.Runtime.InteropServices;
namespace OrbisLib2.Common.API
{
public enum APICommands : int
{
/* ####### Proc functions ####### */
PROC_START = 1,
API_PROC_GET_LIST,
API_PROC_LOAD_ELF,
API_PROC_CALL, /* RPC Call. */
PROC_END,
/* ############################## */
/* ####### Apps functions ####### */
APP_START,
API_APPS_GET_LIST,
API_APPS_GET_INFO_STR,
API_APPS_STATUS,
API_APPS_START,
API_APPS_STOP,
API_APPS_SUSPEND,
API_APPS_RESUME,
API_APPS_DELETE,
APP_END,
/* ############################## */
/* ##### Debugger functions ##### */
DBG_START,
API_DBG_ATTACH, /* Debugger attach to target */
API_DBG_DETACH, /* Debugger detach from target */
API_DBG_GET_CURRENT,
API_DBG_READ,
API_DBG_WRITE,
API_DBG_KILL,
API_DBG_BREAK,
API_DBG_RESUME,
API_DBG_SIGNAL,
API_DBG_STEP,
API_DBG_STEP_OVER,
API_DBG_STEP_OUT,
API_DBG_GET_CALLSTACK,
API_DBG_GET_REG,
API_DBG_SET_REG,
API_DBG_GET_FREG,
API_DBG_SET_FREG,
API_DBG_GET_DBGREG,
API_DBG_SET_DBGREG,
/* Remote Library functions */
API_DBG_LOAD_SPRX,
API_DBG_UNLOAD_SPRX,
API_DBG_RELOAD_SPRX,
API_DBG_MODULE_LIST,
/* Thread Management */
API_DBG_THREAD_LIST,
API_DBG_THREAD_STOP,
API_DBG_THREAD_RESUME,
/* Breakpoint functions */
API_DBG_BREAKPOINT_GETFREE,
API_DBG_BREAKPOINT_SET,
API_DBG_BREAKPOINT_UPDATE,
API_DBG_BREAKPOINT_REMOVE,
API_DBG_BREAKPOINT_GETINFO,
API_DBG_BREAKPOINT_LIST,
/* Watchpoint functions */
API_DBG_WATCHPOINT_SET,
API_DBG_WATCHPOINT_UPDATE,
API_DBG_WATCHPOINT_REMOVE,
API_DBG_WATCHPOINT_GETINFO,
API_DBG_WATCHPOINT_LIST,
DBG_END,
/* ############################## */
/* ###### Kernel functions ###### */
KERN_START,
API_KERN_BASE,
API_KERN_READ,
API_KERN_WRITE,
KERN_END,
/* ############################## */
/* ###### Target functions ###### */
TARGET_START,
API_TARGET_INFO,
API_TARGET_RESTMODE,
API_TARGET_SHUTDOWN,
API_TARGET_REBOOT,
API_TARGET_NOTIFY,
API_TARGET_BUZZER,
API_TARGET_SET_LED,
API_TARGET_DUMP_PROC,
API_TARGET_SET_SETTINGS,
API_TARGET_GETFILE,
TARGET_END,
/* ############################## */
}
public enum APIResults : int
{
API_OK = 1,
API_ERROR_COULDNT_CONNECT,
API_ERROR_NOT_CONNECTED,
API_ERROR_NOT_ATTACHED,
API_ERROR_LOST_PROC,
API_ERROR_GENERAL,
API_ERROR_INVALID_ADDRESS,
//Debugger
API_ERROR_PROC_RUNNING,
API_ERROR_DEBUG_TO_ATTACHED,
}
[StructLayout(LayoutKind.Sequential, Pack = 4, CharSet = CharSet.Ansi, Size = 40), Serializable]
public struct APIPacket
{
public int PacketVersion;
public APICommands Command;
}
#region Process
[StructLayout(LayoutKind.Sequential, Pack = 8, CharSet = CharSet.Ansi)]
public struct ProcPacket
{
public int ProcessID;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
public string Name;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 10)]
public string TitleID;
}
#endregion
#region Apps
public enum AppState
{
STATE_ERROR = -1,
STATE_NOT_RUNNING,
STATE_RUNNING,
STATE_SUSPENDED,
};
[StructLayout(LayoutKind.Sequential, Pack = 8, CharSet = CharSet.Ansi), Serializable]
public struct AppInfoPacket
{
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 10)]
public string TitleId;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 100)]
public string ContentId;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 200)]
public byte[] TitleName;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 100)]
public string MetaDataPath;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 100)]
public string LastAccessTime;
public int Visible;
public int SortPriority;
public int DispLocation;
public char CanRemove;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 10)]
public string Category;
public int ContentSize;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 100)]
public string InstallDate;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 10)]
public string UICategory;
};
#endregion
#region Debug
[StructLayout(LayoutKind.Sequential, Pack = 4, CharSet = CharSet.Ansi)]
public struct LibraryPacket
{
public Int64 Handle;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
public string Path;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 64)]
public SegmentInfo[] Segments;
}
[StructLayout(LayoutKind.Sequential, Pack = 4, CharSet = CharSet.Ansi)]
public struct ProcRWPacket
{
public UInt64 Address;
public UInt64 Length;
}
[StructLayout(LayoutKind.Sequential, Pack = 4, CharSet = CharSet.Ansi)]
public struct ProcSPRXPacket
{
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
public string Name;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
public string Path;
public int ModuleHandle;
public int Flags;
}
[StructLayout(LayoutKind.Sequential, Pack = 4, CharSet = CharSet.Ansi)]
public struct ProcBreakpointPacket
{
public int Index;
public UInt64 Address;
public int Enable;
}
#endregion
#region Kernel
#endregion
#region Target
[StructLayout(LayoutKind.Sequential, Pack = 4, CharSet = CharSet.Ansi)]
public struct SegmentInfo
{
public UInt64 baseAddr;
public uint size;
public int prot;
}
public enum ConsoleTypes
{
UNK,
DIAG, //0x80
DEVKIT, //0x81
TESTKIT, //0x82
RETAIL, //0x83 -> 0x8F
KRATOS, //0xA0 IMPOSSIBLE??
};
public enum ConsoleLEDColours
{
white,
white_Blinking,
Blue_Blinking,
};
[StructLayout(LayoutKind.Sequential, Pack = 4, CharSet = CharSet.Ansi), Serializable]
public struct MemoryInfo
{
public int Used;
public int Free;
public int Total;
public float Percentage;
};
[StructLayout(LayoutKind.Sequential, Pack = 8, CharSet = CharSet.Ansi), Serializable]
public struct TargetInfoPacket
{
public int SDKVersion;
public int SoftwareVersion;
public int FactorySoftwareVersion;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 10)]
public string CurrentTitleID;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 100)]
public string ConsoleName;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 14)]
public string MotherboardSerial;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 10)]
public string Serial;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 14)]
public string Model;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 18)]
public string MACAddressLAN;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 18)]
public string MACAddressWIFI;
public int UART;
public int IDUMode;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)]
public byte[] IDPS;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)]
public byte[] PSID;
public int ConsoleType;
public int Attached;
public int AttachedPid;
public int ForegroundAccountId;
public ulong FreeSpace;
public ulong TotalSpace;
public int CPUTemp;
public int SOCTemp;
public int ThreadCount;
public float AverageCPUUsage;
public int BusyCore;
public MemoryInfo Ram;
public MemoryInfo VRam;
}
[StructLayout(LayoutKind.Sequential, Pack = 4, CharSet = CharSet.Ansi)]
public struct TargetNotifyPacket
{
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 1024)]
public string IconURI;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 1024)]
public string Message;
}
public enum BuzzerType
{
RingOnce = 1,
RingThree,
LongRing,
ThreeLongRing,
ThreeLongDoubleBeeps,
}
[StructLayout(LayoutKind.Sequential, Pack = 4, CharSet = CharSet.Ansi)]
public struct TargetSettingsPacket
{
public int AutoLoadSettings;
public int ShowDebugTitleIdLabel;
public int ShowDevkitPanel;
public int ShowDebugSettings;
public int ShowAppHome;
public int ShowBuildOverlay;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
public string GameOverlayLocation;
public int ShowCPUUsage;
public int ShowThreadCount;
public int Showram;
public int Showvram;
public int ShowCPUTemp;
public int ShowSOCTemp;
};
#endregion
}
@@ -0,0 +1,66 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace OrbisLib2.Common
{
public class Config
{
/// <summary>
/// The prort that is used to interact with the Target Console.
/// </summary>
public static readonly int APIPort = 6900;
/// <summary>
/// Port used to communicate events to the host machine from the Target Console.
/// </summary>
public static readonly int EventPort = 6901;
/// <summary>
/// The Port used to recieve debug logs from the Target Console.
/// </summary>
public static readonly int DebugPort = 6902;
/// <summary>
/// The default port for FTP.
/// </summary>
public static readonly int FTPPort = 2121;
/// <summary>
///
/// </summary>
public static readonly int DispatcherPort = 6919;
/// <summary>
///
/// </summary>
public static readonly int DispatcherClientPort = 6920;
/// <summary>
/// Name of the data base used to store the user data / Target List.
/// </summary>
public static readonly string DataBaseName = "OrbisSuiteUserData.db";
/// <summary>
/// The Path to the Orbis Suite data.
/// </summary>
public static readonly string OrbisPath = $@"{Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData)}\Orbis Suite";
/// <summary>
/// Path of the data base used to store the user data / Target List.
/// </summary>
public static readonly string DataBasePath = $@"{OrbisPath}\{DataBaseName}";
/// <summary>
/// Maximum number of targets we can store.
/// </summary>
public static readonly int MaxTargets = 20;
/// <summary>
/// The version of the packets used to communicate with the Target Console.
/// </summary>
public static readonly int PacketVersion = 2;
}
}
@@ -0,0 +1,222 @@
using SQLite;
using System.Linq.Expressions;
namespace OrbisLib2.Common.Database
{
/// <summary>
/// Information about the targets saved.
/// </summary>
[Table("Targets")]
public class SavedTarget
{
[PrimaryKey, AutoIncrement, NotNull]
public int Id { get; set; }
/// <summary>
/// Weather or not this is our default target to be selected on start up.
/// </summary>
[NotNull]
[Column("DefaultTarget")]
public bool IsDefault { get; set; } = false;
/// <summary>
/// The name given to the target.
/// </summary>
[NotNull, Unique]
[Column("TargetName")]
public string Name { get; set; } = "-";
/// <summary>
/// The IP Address as a string.
/// </summary>
[NotNull, Unique]
public string IPAddress { get; set; } = "-";
/// <summary>
/// The port used to send payloads to the saved IP Address.
/// </summary>
[NotNull]
public int PayloadPort { get; set; } = 9020;
private TargetInfo _Info;
public TargetInfo Info
{
get
{
if (_Info == null)
{
var db = new SQLiteConnection(Config.DataBasePath);
// Create the table if it doesn't exist already.
db.CreateTable<TargetInfo>();
_Info = db.Find<TargetInfo>(x => x.TargetId == Id);
if (_Info == null)
{
_Info = new TargetInfo();
_Info.TargetId = Id;
db.Insert(_Info);
db.Close();
}
else
{
db.Close();
}
}
return _Info;
}
}
/// <summary>
/// Remove the default tag from the other row.
/// </summary>
private void CheckDefault()
{
var defaultTarget = FindDefaultTarget();
if (IsDefault && defaultTarget != null && defaultTarget.Id != Id)
{
defaultTarget.IsDefault = false;
defaultTarget.Save();
}
}
/// <summary>
/// Saves the current information about the target to the database.
/// </summary>
/// <returns>Returns true if any rows were effected.</returns>
public bool Save()
{
if (Name == string.Empty || Name == "-")
return false;
if (IPAddress == string.Empty || IPAddress == "-")
return false;
CheckDefault();
var db = new SQLiteConnection(Config.DataBasePath);
// Create the table if it doesn't exist already.
db.CreateTable<SavedTarget>();
var result = db.Update(this);
db.Close();
return (result > 0);
}
public SavedTarget Clone()
{
return (SavedTarget)this.MemberwiseClone();
}
/// <summary>
/// Adds a this Target to the data base.
/// </summary>
/// <returns>Returns true if a row was added to the database.</returns>
public bool Add()
{
try
{
if (Name == string.Empty || Name == "-")
return false;
if (IPAddress == string.Empty || IPAddress == "-")
return false;
CheckDefault();
var db = new SQLiteConnection(Config.DataBasePath);
// Create the table if it doesn't exist already.
db.CreateTable<SavedTarget>();
var result = db.Insert(this);
db.Close();
return (result > 0);
}
catch (Exception ex)
{
return false;
}
}
/// <summary>
/// Removes this current Target from the database.
/// </summary>
/// <returns>Returns true if a row was removed from the database.</returns>
public bool Remove()
{
var db = new SQLiteConnection(Config.DataBasePath);
var result = db.Delete(Info);
if (result <= 0)
{
Console.WriteLine("Failed to delete child db TargetDetails Details.");
return false;
}
result = db.Delete(this);
db.Close();
return (result > 0);
}
public static List<SavedTarget> GetTargetList()
{
var db = new SQLiteConnection(Config.DataBasePath);
// Create the table if it doesn't exist already.
db.CreateTable<SavedTarget>();
var result = db.Table<SavedTarget>().ToList();
db.Close();
return result;
}
public static SavedTarget FindDefaultTarget()
{
var db = new SQLiteConnection(Config.DataBasePath);
// Create the table if it doesn't exist already.
db.CreateTable<SavedTarget>();
var result = db.Find<SavedTarget>(x => x.IsDefault == true);
db.Close();
return result;
}
/// <summary>
/// Find a saved Target by a specific value using a predicate.
/// </summary>
/// <param name="predicate">The predicate of the columns we want to match on.</param>
/// <returns>Returns the first object that matches the predicate.</returns>
public static SavedTarget FindTarget(Expression<Func<SavedTarget, bool>> predicate)
{
var db = new SQLiteConnection(Config.DataBasePath);
// Create the table if it doesn't exist already.
db.CreateTable<SavedTarget>();
var result = db.Find(predicate);
db.Close();
return result;
}
/// <summary>
/// Find weahter or not a Target by specific value exists by using a predicate.
/// </summary>
/// <param name="predicate">The predicate of the columns we want to match on.</param>
/// <returns>Returns true if we found a match.</returns>
public static bool DoesTargetExist(Expression<Func<SavedTarget, bool>> predicate)
{
var db = new SQLiteConnection(Config.DataBasePath);
// Create the table if it doesn't exist already.
db.CreateTable<SavedTarget>();
var result = db.Find(predicate);
db.Close();
return (result != null);
}
}
}
@@ -0,0 +1,116 @@
using SQLite;
namespace OrbisLib2.Common.Database
{
/// <summary>
/// Used to get/set the settings of Orbis Suite.
/// </summary>
[Table("Settings")]
public class Settings
{
[PrimaryKey, AutoIncrement, NotNull]
public int Id { get; set; }
/// <summary>
/// The API port that OrbisLib communicates on.
/// </summary>
[NotNull]
public int APIPort { get; set; } = 6900;
/// <summary>
/// The port that will be used to access the targets file system using ftp
/// </summary>
[NotNull]
public int FTPPort { get; set; } = 2121;
/// <summary>
/// The port of a klog server that will be used to print console output similar to UART.
/// </summary>
[NotNull]
public int KlogPort { get; set; } = 3232;
/// <summary>
/// The serial COM port we will listen to for UART output.
/// </summary>
[NotNull]
public string? COMPort { get; set; } = "-";
/// <summary>
/// Starts the Orbis Suite taskbar app when windows boots.
/// </summary>
[NotNull]
public bool StartOnBoot { get; set; } = false;
/// <summary>
/// Choose which theme will be used across Orbis Suite.
/// </summary>
[NotNull]
public int Theme { get; set; } = 0;
/// <summary>
/// Enables the accent colours to cycle through all colours of the rainbow.
/// </summary>
[NotNull]
public bool RainbowColours { get; set; } = false;
/// <summary>
/// When viewd from the target details choose to censor the Target identifier.
/// </summary>
[NotNull]
public bool CensorIDPS { get; set; } = false;
/// <summary>
/// When viewd from the target details choose to censor the Target identifier.
/// </summary>
[NotNull]
public bool CensorPSID { get; set; } = false;
/// <summary>
/// SHow timestamps on the console output.
/// </summary>
[NotNull]
public bool ShowTimestamps { get; set; } = false;
/// <summary>
/// Word wrap the console output window.
/// </summary>
[NotNull]
public bool WordWrap { get; set; } = false;
public static Settings CreateInstance()
{
var db = new SQLiteConnection(Config.DataBasePath);
// Create the table if it doesn't exist already.
db.CreateTable<Settings>();
// Try to pull the entries of the settings
var list = db.Table<Settings>();
if (list.Count() > 0)
{
var instance = list.First();
db.Close();
return instance;
}
else
{
// Create settings entry since it doesn't exist.
var instance = new Settings();
var result = db.Insert(instance);
db.Close();
if (result > 0)
return instance;
else
throw new Exception("Failed to create settings row into database.");
}
}
public void Save()
{
var db = new SQLiteConnection(Config.DataBasePath, SQLiteOpenFlags.ReadWrite);
db.Update(this);
db.Close();
}
}
}
@@ -0,0 +1,279 @@
using OrbisLib2.Common.Database.Types;
using SQLite;
using System.Text.RegularExpressions;
namespace OrbisLib2.Common.Database
{
[Table("TargetInfo")]
public class TargetInfo
{
[PrimaryKey, AutoIncrement, NotNull]
public int Id { get; set; }
[NotNull]
public int TargetId { get; set; }
/// <summary>
/// Will be true if a tcp connection can be achieved on the saved IP Address.
/// </summary>
[NotNull]
[Column("Available")]
public bool IsAvailable { get; set; } = false;
/// <summary>
/// Will be true if the Orbis Suite API is running on the target.
/// </summary>
[NotNull]
[Column("APIAvailable")]
public bool IsAPIAvailable { get; set; } = false;
/// <summary>
/// The power/API status of the target.
/// </summary>
public TargetStatusType Status
{
get
{
if (IsAPIAvailable)
return TargetStatusType.APIAvailable;
else if (IsAvailable)
return TargetStatusType.Online;
else
return TargetStatusType.Offline;
}
}
/// <summary>
/// The SDK Version of the software installed on the target.
/// </summary>
[NotNull]
public string SDKVersion { get; set; } = "-";
/// <summary>
/// The full software version installed on the target.
/// </summary>
[NotNull]
public string SoftwareVersion { get; set; } = "-";
/// <summary>
/// The software version first installed on the target when sold.
/// </summary>
[NotNull]
public string FactorySoftwareVersion { get; set; } = "-";
/// <summary>
/// The current big game titleId running on the target.
/// </summary>
[NotNull]
public string CurrentTitleID { get; set; } = "-";
/// <summary>
/// The name of the target as set on the target.
/// </summary>
[NotNull]
public string ConsoleName { get; set; } = "-";
/// <summary>
/// The serial number of the targets motherboard.
/// </summary>
[NotNull]
public string MotherboardSerial { get; set; } = "-";
/// <summary>
/// The seraial number of the target.
/// </summary>
[NotNull]
public string Serial { get; set; } = "-";
/// <summary>
/// The model number of the target.
/// </summary>
[NotNull]
public string Model { get; set; } = "-";
public ConsoleModelType ModelType
{
get
{
// ConsoleModel
// CUH-1XXXX Fat
// CUH-2XXXX Slim
// CUH-7XXXX Pro
if (Model == null || !Regex.Match(Model, @"CUH-\d{1}\w{4}").Success)
return ConsoleModelType.Fat;
switch (char.IsDigit(Model[4]) ? int.Parse(Model[4].ToString()) : 0)
{
case 1:
return ConsoleModelType.Fat;
case 2:
return ConsoleModelType.Slim;
case 7:
return ConsoleModelType.Pro;
default:
return ConsoleModelType.Fat;
}
}
}
/// <summary>
/// The MAC address of the target LAN adapter.
/// </summary>
[NotNull]
public string MACAddressLAN { get; set; } = "-";
/// <summary>
/// The MAC address of the target WIFI adapter.
/// </summary>
[NotNull]
public string MACAddressWIFI { get; set; } = "-";
/// <summary>
/// Will be true if the UART flag is set in the targets flash.
/// </summary>
[NotNull]
public bool UART { get; set; } = false;
/// <summary>
/// Will return true if the IDUMode flag is set int he targets flash.
/// </summary>
[NotNull]
public bool IDUMode { get; set; } = false;
/// <summary>
/// A unique string used to identify the target.
/// </summary>
[NotNull]
public string IDPS { get; set; } = "-";
/// <summary>
/// A unique string used to identify the target.
/// </summary>
[NotNull]
public string PSID { get; set; } = "-";
/// <summary>
/// The console type like Retail/TestKit/Devkit.
/// </summary>
[NotNull]
public ConsoleType ConsoleType { get; set; } = 0;
/// <summary>
/// Will be true if the Orbis Suite Debugger is attached to a process.
/// </summary>
[NotNull]
[Column("Attached")]
public bool IsAttached { get; set; } = false;
/// <summary>
/// The current processId being debugged by the OrbisSuite Debugger.
/// </summary>
[NotNull]
public int CurrentProcessId { get; set; } = 0;
/// <summary>
/// The current foreground account identifier.
/// </summary>
[NotNull]
public int ForegroundAccountId { get; set; } = 0;
/// <summary>
/// The used space on the targets hard disk.
/// </summary>
[NotNull]
public long HDDUsedSpace { get; set; } = 0;
/// <summary>
/// The free space on the targets hard disk.
/// </summary>
[NotNull]
public long HDDFreeSpace { get; set; } = 0;
/// <summary>
/// The usable size of the targets hard disk.
/// </summary>
[NotNull]
public long HDDTotalSpace { get; set; } = 0;
/// <summary>
/// The current temperature of the CPU.
/// </summary>
public int CPUTemp { get; set; } = 0;
/// <summary>
/// The current tempurature of the SOC.
/// </summary>
public int SOCTemp { get; set; } = 0;
/// <summary>
/// The current thread count.
/// </summary>
public int ThreadCount { get; set; } = 0;
/// <summary>
/// The current average cpu usage.
/// </summary>
public float AverageCPUUsage { get; set; } = 0.0f;
/// <summary>
/// The current core that is the most busy.
/// </summary>
public int BusyCore { get; set; } = 0;
/// <summary>
/// The current system ram usage.
/// </summary>
public int RamUsage { get; set; } = 0;
/// <summary>
/// The current video ram usage.
/// </summary>
public int VRamUsage { get; set; } = 0;
/// <summary>
/// Shows the Title number of the games on the home screen of this target.
/// </summary>
[NotNull]
public bool ShowTitleId { get; set; } = false;
/// <summary>
/// Shows the devkit information display panel that will show some information about the target like the IP Address.
/// </summary>
[NotNull]
public bool ShowDevkitPanel { get; set; } = false;
/// <summary>
/// Shows a shortcut on the Home screen that can be used to quickly access the Orbis Toolbox menu.
/// </summary>
[NotNull]
public bool ShowToolboxShortcut { get; set; } = false;
/// <summary>
/// Shows the '★APP_HOME' on the home screen that can be used to quickly launch home brew to debug it with out a pkg.
/// </summary>
[NotNull]
public bool ShowAppHome { get; set; } = false;
/// <summary>
/// Saves the current information about the target to the database.
/// </summary>
/// <returns>Returns true if any rows were effected.</returns>
public bool Save()
{
var db = new SQLiteConnection(Config.DataBasePath);
// Create the table if it doesn't exist already.
db.CreateTable<TargetInfo>();
var result = db.Update(this);
db.Close();
return (result <= 0);
}
}
}
@@ -0,0 +1,13 @@
namespace OrbisLib2.Common.Database.Types
{
/// <summary>
/// The model revision type based on its model number.
/// </summary>
public enum ConsoleModelType
{
Unknown,
Fat,
Slim,
Pro
};
}
@@ -0,0 +1,12 @@
namespace OrbisLib2.Common.Database.Types
{
public enum ConsoleType
{
None,
Diag,
Devkit,
Testkit,
Retail,
Kratos,
};
}
@@ -0,0 +1,13 @@
namespace OrbisLib2.Common.Database.Types
{
/// <summary>
/// The current status of the Target & the Orbis Suite API.
/// </summary>
public enum TargetStatusType
{
None,
Offline,
Online,
APIAvailable
};
}
@@ -0,0 +1,224 @@
using OrbisLib2.Common.Helpers;
using OrbisLib2.General;
using OrbisLib2.Targets;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;
namespace OrbisLib2.Common.Dispatcher
{
public class DispatcherClient
{
private Listener? _EventListener;
private int _Port = -1;
private Task _HeartbeatTask;
private CancellationToken _HeartbeatCancellationToken;
public DispatcherClient()
{
_HeartbeatTask = Task.Run(() => DoHeartbeat());
}
private void _EventListener_SocketAccepted(Socket e)
{
try
{
var Packet = (ForwardPacket)e.RecvObject();
switch (Packet.Type)
{
default:
Console.WriteLine("Invalid Packet...");
break;
// Debugging
case ForwardPacket.PacketType.Print:
TargetManager.SelectedTarget.Events.RaiseProcPrintEvent(Packet.SenderIPAddress, Packet.Print.Sender, Packet.Print.Data);
break;
case ForwardPacket.PacketType.SerialCom:
// TODO:
break;
case ForwardPacket.PacketType.Intercept:
TargetManager.SelectedTarget.Events.RaiseProcInterceptEvent(Packet.SenderIPAddress);
break;
case ForwardPacket.PacketType.Continue:
TargetManager.SelectedTarget.Events.RaiseProcContinueEvent(Packet.SenderIPAddress);
break;
// Process States
case ForwardPacket.PacketType.ProcessDie:
TargetManager.SelectedTarget.Events.RaiseProcDieEvent(Packet.SenderIPAddress);
break;
case ForwardPacket.PacketType.ProcessAttach:
TargetManager.SelectedTarget.Events.RaiseProcAttachEvent(Packet.SenderIPAddress, Packet.ProcessName);
break;
case ForwardPacket.PacketType.ProcessDetach:
TargetManager.SelectedTarget.Events.RaiseProcDetachEvent(Packet.SenderIPAddress);
break;
// Target State
case ForwardPacket.PacketType.TargetSuspend:
TargetManager.SelectedTarget.Events.RaiseTargetSuspendEvent(Packet.SenderIPAddress);
break;
case ForwardPacket.PacketType.TargetResume:
TargetManager.SelectedTarget.Events.RaiseTargetResumeEvent(Packet.SenderIPAddress);
break;
case ForwardPacket.PacketType.TargetShutdown:
TargetManager.SelectedTarget.Events.RaiseTargetShutdownEvent(Packet.SenderIPAddress);
break;
case ForwardPacket.PacketType.TargetNewTitle:
TargetManager.SelectedTarget.Events.RaiseTargetNewTitleEvent(Packet.SenderIPAddress, Packet.TitleChange.TitleID);
break;
case ForwardPacket.PacketType.TargetAvailability:
Events.FireTargetAvailability(Packet.TargetAvailability.Available, Packet.TargetAvailability.Name);
break;
case ForwardPacket.PacketType.TargetAPIAvailability:
Events.FireTargetAPIAvailability(Packet.TargetAvailability.Available, Packet.TargetAvailability.Name);
break;
// Misc
case ForwardPacket.PacketType.DBTouched:
Events.FireDBTouched();
break;
}
}
catch (Exception ex)
{
Console.WriteLine($"[{System.Reflection.MethodBase.GetCurrentMethod()?.Name}] Error: {ex.Message}");
}
}
/// <summary>
/// Attempts to connect to the Dispatcher.
/// </summary>
/// <returns>Returns true if the connection was successful.</returns>
private bool Connect()
{
try
{
if (_Port != -1)
{
Console.WriteLine("[Connect] Already Connected!");
return true;
}
var Sock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
if (Sock.EasyConnect("127.0.0.1", Config.DispatcherPort, 1000))
{
Sock.SendObject(new DispatcherClientPacket(DispatcherClientPacket.PacketType.NewClient, System.Diagnostics.Process.GetCurrentProcess().ProcessName, -1));
_Port = Sock.RecvInt32();
Sock.Close();
if (_Port != -1)
{
Console.WriteLine($"Starting up _EventListener on port {_Port}");
_EventListener = new Listener(_Port);
_EventListener.Start();
_EventListener.SocketAccepted += _EventListener_SocketAccepted;
return true;
}
else
return false;
}
}
catch (Exception ex)
{
Console.WriteLine($"[{System.Reflection.MethodBase.GetCurrentMethod()?.Name}] Error: {ex.Message}");
}
return false;
}
/// <summary>
/// Sends a Heart beat Packet.
/// </summary>
/// <returns>Returns true if the packet was sent successfully.</returns>
private bool DoHeartBeat()
{
try
{
if (_Port == -1)
{
Console.WriteLine("[DoHeartBeat] Not Connected!");
return false;
}
var Sock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
if (Sock.EasyConnect("127.0.0.1", Config.DispatcherPort, 1000))
{
Sock.SendObject(new DispatcherClientPacket(DispatcherClientPacket.PacketType.HeartBeat, System.Diagnostics.Process.GetCurrentProcess().ProcessName, _Port));
var Result = Sock.RecvInt32();
Sock.Close();
return (Result == 1);
}
}
catch (Exception ex)
{
Console.WriteLine($"[{System.Reflection.MethodBase.GetCurrentMethod()?.Name}] Error: {ex.Message}");
}
return false;
}
/// <summary>
/// Task will Send heartbeat packets to the Service. This will also ensure that we are always connected to the service.
/// </summary>
/// <returns></returns>
private async Task DoHeartbeat()
{
while (!Connect())
{
await Task.Delay(500, _HeartbeatCancellationToken);
if (_HeartbeatCancellationToken.IsCancellationRequested)
break;
}
if (_Port != -1)
Console.WriteLine("[DispatcherClient] Connection Sucessful!");
while (true)
{
await Task.Delay(5000, _HeartbeatCancellationToken);
if (_HeartbeatCancellationToken.IsCancellationRequested)
break;
if (!DoHeartBeat())
{
_Port = -1;
while (!Connect())
{
await Task.Delay(500, _HeartbeatCancellationToken);
if (_HeartbeatCancellationToken.IsCancellationRequested)
break;
}
if (_Port != -1)
Console.WriteLine("[DispatcherClient] Reconnection Sucessful!");
}
}
}
}
}
@@ -0,0 +1,134 @@
namespace OrbisLib2.Common.Dispatcher
{
[Serializable]
internal sealed class DispatcherClientPacket
{
public enum PacketType
{
None,
NewClient,
RemoveClient,
HeartBeat
};
public PacketType Type { get; set; }
public string? ClientName { get; set; }
public int Port { get; set; }
public DispatcherClientPacket() { }
public DispatcherClientPacket(PacketType Type, string ClientName, int Port)
{
this.Type = Type;
this.ClientName = ClientName;
this.Port = Port;
}
}
[Serializable]
public class TitleChange
{
public string? TitleID { get; set; }
}
[Serializable]
public class Print
{
public string? Sender { get; set; }
public string? Data { get; set; }
}
[Serializable]
public class SerialCom
{
public byte[]? Data { get; set; }
}
[Serializable]
public class Break
{
public int Reason { get; set; }
//Regiseters
}
[Serializable]
public class TargetAvailability
{
public bool Available { get; set; }
public string? Name { get; set; }
}
[Serializable]
public class ForwardPacket
{
public enum PacketType
{
None,
// Debugging
Print,
SerialCom,
Intercept,
Continue,
// Process States
ProcessDie,
ProcessAttach,
ProcessDetach,
// Target State
TargetSuspend,
TargetResume,
TargetShutdown,
TargetNewTitle,
TargetAvailability,
TargetAPIAvailability,
// Misc
DBTouched,
};
/// <summary>
/// The event the packet is firing for.
/// </summary>
public PacketType Type { get; set; }
/// <summary>
/// The Target's IP Address which the Event belongs to.
/// </summary>
public string? SenderIPAddress { get; set; }
/// <summary>
/// Name of the process that the event was triggered for.
/// </summary>
public string? ProcessName { get; set; }
public TitleChange? TitleChange { get; set; }
public Print? Print { get; set; }
public SerialCom? SerialCom { get; set; }
public Break? Break { get; set; }
public TargetAvailability? TargetAvailability { get; set; }
public TargetAvailability? TargetAPIAvailability { get; set; }
public ForwardPacket(PacketType Type, string SenderIPAddress)
{
this.Type = Type;
this.SenderIPAddress = SenderIPAddress;
//TODO: Maybe add logic to the getter/setter so that it will create these...
TitleChange = new TitleChange();
Print = new Print();
SerialCom = new SerialCom();
Break = new Break();
TargetAvailability = new TargetAvailability();
TargetAPIAvailability = new TargetAvailability();
}
}
}
@@ -0,0 +1,210 @@
using System.Net.NetworkInformation;
using System.Net.Sockets;
using System.Runtime.InteropServices;
using System.Runtime.Serialization.Formatters.Binary;
using System.Text;
namespace OrbisLib2.Common.Helpers
{
public static class Helper
{
/// <summary>
/// Convert an object to a byte array
/// </summary>
/// <param name="obj">The Object to convert.</param>
/// <returns></returns>
public static byte[] ObjectToByteArray(Object obj)
{
BinaryFormatter bf = new BinaryFormatter();
using (var ms = new MemoryStream())
{
bf.Serialize(ms, obj);
return ms.ToArray();
}
}
/// <summary>
/// Convert a byte array to an Object
/// </summary>
/// <param name="arrBytes">The array to convert.</param>
/// <returns></returns>
public static Object ByteArrayToObject(byte[] arrBytes)
{
using (var memStream = new MemoryStream())
{
var binForm = new BinaryFormatter();
memStream.Write(arrBytes, 0, arrBytes.Length);
memStream.Seek(0, SeekOrigin.Begin);
return binForm.Deserialize(memStream);
}
}
/// <summary>
/// Sends an object and its size to the socket.
/// </summary>
/// <param name="s"></param>
/// <param name="obj">The object we would like to send. (Must be serializable.)</param>
public static void SendObject(this Socket s, object obj)
{
var Data = ObjectToByteArray(obj);
s.Send(BitConverter.GetBytes(Data.Length), sizeof(int), SocketFlags.None);
s.Send(Data);
}
/// <summary>
/// Recieve an object from a socket.
/// </summary>
/// <param name="s"></param>
/// <returns>Returns the object we would like to receive.</returns>
public static object RecvObject(this Socket s)
{
var ObjectSize = s.RecvInt32();
var ObjectData = new byte[ObjectSize];
s.Receive(ObjectData);
return ByteArrayToObject(ObjectData);
}
/// <summary>
/// Sends an int32 over socket.
/// </summary>
/// <param name="s"></param>
/// <param name="Data"></param>
public static void SendInt32(this Socket s, int Data)
{
s.Send(BitConverter.GetBytes(Data));
}
/// <summary>
/// Receives an int32 over sockets.
/// </summary>
/// <param name="s"></param>
/// <returns></returns>
public static int RecvInt32(this Socket s)
{
var Data = new byte[sizeof(int)];
s.Receive(Data);
return BitConverter.ToInt32(Data, 0);
}
/// <summary>
/// Easily connect to a socket and handle the time out.
/// </summary>
/// <param name="s"></param>
/// <param name="IPAddress">The address we would like to connect to.</param>
/// <param name="Port">The port of the socket we would like to connect to.</param>
/// <param name="TimeOut">The time we would like to wait for connection.</param>
/// <returns></returns>
public static bool EasyConnect(this Socket s, string IPAddress, int Port, int TimeOut)
{
s.ReceiveTimeout = s.SendTimeout = TimeOut;
var result = s.BeginConnect(IPAddress, Port, null, null);
result.AsyncWaitHandle.WaitOne(3000, true);
if (!s.Connected)
{
Console.WriteLine("Failed to connect to socket.");
s.Close();
return false;
}
// we have connected
s.EndConnect(result);
return true;
}
/// <summary>
/// Tests the availability of a tcp host.
/// </summary>
/// <param name="Host">Host Address.</param>
/// <param name="Port">Host Port.</param>
/// <returns></returns>
public static bool TestTcpConnection(string Host, int Port)
{
try
{
var client = new TcpClient();
var result = client.BeginConnect(Host, Port, null, null);
var success = result.AsyncWaitHandle.WaitOne(TimeSpan.FromSeconds(1));
if (!success)
{
return false;
}
client.EndConnect(result);
return true;
}
catch
{
}
return false;
}
/// <summary>
/// Attempts to ping a host.
/// </summary>
/// <param name="Host">Host Address</param>
/// <returns></returns>
public static bool PingHost(string Host)
{
try
{
var pingSender = new Ping();
var options = new PingOptions();
options.DontFragment = true;
var reply = pingSender.Send(Host, 120, Encoding.ASCII.GetBytes("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"), options);
return (reply.Status == IPStatus.Success);
}
catch
{
}
return false;
}
/// <summary>
///
/// </summary>
/// <param name="str"></param>
/// <returns></returns>
public static byte[] StructToBytes(object str)
{
int size = Marshal.SizeOf(str);
byte[] arr = new byte[size];
IntPtr ptr = Marshal.AllocHGlobal(size);
Marshal.StructureToPtr(str, ptr, true);
Marshal.Copy(ptr, arr, 0, size);
Marshal.FreeHGlobal(ptr);
return arr;
}
/// <summary>
///
/// </summary>
/// <param name="arr"></param>
/// <param name="str"></param>
public static void BytesToStruct<T>(byte[] arr, ref T str)
{
int size = Marshal.SizeOf(str);
IntPtr ptr = Marshal.AllocHGlobal(size);
Marshal.Copy(arr, 0, ptr, size);
str = (T)Marshal.PtrToStructure(ptr, str.GetType());
Marshal.FreeHGlobal(ptr);
}
}
}
@@ -0,0 +1,84 @@
using System.Net.Sockets;
using System.Net;
namespace OrbisLib2.Common.Helpers
{
public class Listener
{
private Socket s_Listener;
public bool Listening
{
get;
private set;
}
public int Port
{
get;
private set;
}
public Listener(int Port)
{
this.Port = Port;
}
public void Start()
{
//Make sure we have not started before.
if (Listening)
return;
//Create Socket to listen on.
s_Listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
//Bind Socket to Port and Listen with a backlog of 100.
s_Listener.Bind(new IPEndPoint(0, Port));
s_Listener.Listen(1000);
//Call BeginAccept with our call back so on every accept of a new socket connection the call back is called.
s_Listener.BeginAccept(CallBack, null);
Listening = true;
}
public void Stop()
{
if (!Listening)
return;
//Clean up for next connection.
s_Listener.Close();
s_Listener.Dispose();
Listening = false;
}
/*
Call back to handle all of our incoming connections and call our event.
*/
void CallBack(IAsyncResult ar)
{
try
{
//Complete the Accept of the incoming Connection and call the event if registered.
Socket s_Client = s_Listener.EndAccept(ar);
if (SocketAccepted != null)
{
SocketAccepted(s_Client);
}
//Begin Accepting other Connections again with our call back.
s_Listener.BeginAccept(CallBack, null);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
public delegate void SocketAcceptedHandler(Socket e);
public event SocketAcceptedHandler SocketAccepted;
}
}
@@ -0,0 +1,82 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace OrbisLib2.General
{
public class DBTouchedEvent : EventArgs
{
public DBTouchedEvent() { }
}
public class TargetStateChangedEvent : EventArgs
{
public enum TargetState
{
None,
Available,
UnAvailable,
APIAvailable,
APIUnAvailable,
};
public TargetState State { get; private set; }
public string Name { get; private set; }
public TargetStateChangedEvent(string Name, TargetState State)
{
this.Name = Name;
this.State = State;
}
}
public class Events
{
/// <summary>
/// The DBTouched Event gets invoked when the Database used to store target specific info is changed.
/// </summary>
public static event EventHandler<DBTouchedEvent>? DBTouched;
/// <summary>
/// Even is fired when ever the state of the target changes.
/// </summary>
public static event EventHandler<TargetStateChangedEvent>? TargetStateChanged;
/// <summary>
/// Will Fire the event for when the Database has been updated.
/// </summary>
internal static void FireDBTouched()
{
DBTouched?.Invoke(null, new DBTouchedEvent());
}
/// <summary>
/// Will Fire the event for Target Availability.
/// </summary>
/// <param name="Available"></param>
/// <param name="TargetName"></param>
internal static void FireTargetAvailability(bool Available, string TargetName)
{
if (Available)
TargetStateChanged?.Invoke(null, new TargetStateChangedEvent(TargetName, TargetStateChangedEvent.TargetState.Available));
else
TargetStateChanged?.Invoke(null, new TargetStateChangedEvent(TargetName, TargetStateChangedEvent.TargetState.UnAvailable));
}
/// <summary>
/// Will Fire the event for Target API Availability.
/// </summary>
/// <param name="Available"></param>
/// <param name="TargetName"></param>
internal static void FireTargetAPIAvailability(bool Available, string TargetName)
{
if (Available)
TargetStateChanged?.Invoke(null, new TargetStateChangedEvent(TargetName, TargetStateChangedEvent.TargetState.APIAvailable));
else
TargetStateChanged?.Invoke(null, new TargetStateChangedEvent(TargetName, TargetStateChangedEvent.TargetState.APIUnAvailable));
}
}
}
+167
View File
@@ -0,0 +1,167 @@
using System.Json;
using System.Net;
using System.Security.Cryptography;
using System.Text;
using System.Text.RegularExpressions;
namespace OrbisLib2.General
{
public class TMDB
{
private string Internal_TitleID = "";
public string TitleID
{
get
{
return Internal_TitleID;
}
set
{
Internal_TitleID = value.Contains("_00") ? value : value + "_00";
//Update the url for the new TitleID
tmdbUrl = GetUrl();
//Download the Json document and parse the data.
ParseJson();
}
}
public string tmdbUrl { get; private set; }
public JsonValue Data { get; private set; }
//Json Data
public int Revision { get; private set; }
public int PatchRevision { get; private set; }
public int FormatVersion { get; private set; }
public string NPTitleID { get; private set; }
public string Console { get; private set; }
public string[] Names { get; private set; } = new string[20];
public string[] Icons { get; private set; } = new string[20];
public int ParentalLevel { get; private set; }
public string Pronunciation { get; private set; }
public string ContentID { get; private set; }
public string BackgroundImage { get; private set; }
public string BGM { get; private set; }
public string Category { get; private set; }
public int PSVR { get; private set; }
public int NEOEnable { get; private set; }
private string GetUrl()
{
//TitleID format must follow CUSAXXXXX_00 format.
if (!Regex.IsMatch(TitleID, @"CUSA\d{5}_00"))
{
throw new Exception("TitleID format incorrect!! Format must follow CUSAXXXXX_00.");
}
//tmdb Key for PS3 and PS4 credits to https://github.com/Tustin
byte[] tmdb_key = { 0xF5, 0xDE, 0x66, 0xD2, 0x68, 0x0E, 0x25, 0x5B, 0x2D, 0xF7, 0x9E, 0x74, 0xF8, 0x90, 0xEB, 0xF3, 0x49, 0x26, 0x2F, 0x61, 0x8B, 0xCA, 0xE2, 0xA9,
0xAC, 0xCD, 0xEE, 0x51, 0x56, 0xCE, 0x8D, 0xF2, 0xCD, 0xF2, 0xD4, 0x8C, 0x71, 0x17, 0x3C, 0xDC, 0x25, 0x94, 0x46, 0x5B, 0x87, 0x40, 0x5D, 0x19,
0x7C, 0xF1, 0xAE, 0xD3, 0xB7, 0xE9, 0x67, 0x1E, 0xEB, 0x56, 0xCA, 0x67, 0x53, 0xC2, 0xE6, 0xB0,
};
//Make a new Hmac sha1 digest with the key tmdb_key
HMACSHA1 Digest = new HMACSHA1(tmdb_key);
//Compute new digest using the data of the TitleID
Digest.ComputeHash(Encoding.UTF8.GetBytes(TitleID));
//return the url for the json using the TitleID and generated Digest.
return $"https://tmdb.np.dl.playstation.net/tmdb2/{TitleID}_{BitConverter.ToString(Digest.Hash).Replace("-", "")}/{TitleID}.json";
}
private void ParseJson()
{
//Download the Json file.
var webClient = new WebClient();
Data = JsonValue.Parse(webClient.DownloadString(tmdbUrl));
//Parse the data.
if (Data.ContainsKey("revision"))
Revision = Data["revision"];
if (Data.ContainsKey("patchRevision"))
PatchRevision = Data["patchRevision"];
if (Data.ContainsKey("formatVersion"))
FormatVersion = Data["formatVersion"];
if (Data.ContainsKey("npTitleId"))
NPTitleID = Data["npTitleId"];
if (Data.ContainsKey("console"))
Console = Data["console"];
if (Data.ContainsKey("names"))
{
JsonValue jNames = Data["names"];
for (int i = 0; i < jNames.Count; i++)
{
JsonValue Temp = jNames[i];
if (Temp.ContainsKey("name"))
{
Regex rgx = new Regex(@"[^0-9a-zA-Z +.:']");
Names[i] = rgx.Replace(Temp["name"], "");
}
}
}
if (Data.ContainsKey("icons"))
{
JsonValue jIcons = Data["icons"];
for (int i = 0; i < jIcons.Count; i++)
{
JsonValue Temp = jIcons[i];
if (Temp.ContainsKey("icon") && Temp.ContainsKey("type"))
{
Icons[i] = Temp["icon"];
//Icons[i].Size = Temp["type"];
}
}
}
if (Data.ContainsKey("parentalLevel"))
ParentalLevel = Data["parentalLevel"];
if (Data.ContainsKey("pronunciation"))
Pronunciation = Data["pronunciation"];
if (Data.ContainsKey("contentId"))
ContentID = Data["contentId"];
if (Data.ContainsKey("backgroundImage"))
BackgroundImage = Data["backgroundImage"];
if (Data.ContainsKey("bgm"))
BGM = Data["bgm"];
if (Data.ContainsKey("category"))
Category = Data["category"];
if (Data.ContainsKey("psVr"))
PSVR = Data["psVr"];
if (Data.ContainsKey("neoEnable"))
NEOEnable = Data["neoEnable"];
}
public TMDB(string TitleID)
{
//Store TitleID Locally.
this.TitleID = TitleID;
}
}
public class Icons
{
public string Url { get; set; }
public string Size { get; set; }
}
}
@@ -0,0 +1,59 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace OrbisLib2.General
{
public static class Utilities
{
/// <summary>
/// Will censor a part of an input string with the desired sensor char.
/// </summary>
/// <param name="In">The string we would like to censor.</param>
/// <param name="CensorChar">The character we would like to use as the sensor.</param>
/// <param name="AllowedCount">The allowed number of characters starting from 0.</param>
/// <returns>Returns the censored string.</returns>
public static string CensorString(string In, char CensorChar, int AllowedCount)
{
try
{
string Out = In.Substring(0, AllowedCount);
Out += new string(CensorChar, In.Length - AllowedCount);
return Out;
}
catch
{
return string.Empty;
}
}
/// <summary>
/// Converts a number of bytes to a formated string.
/// </summary>
/// <param name="numberOfBytes">The number of bytes to be converted.</param>
/// <returns>Formatted string of the number of bytes represented in B, KB, MB or GB.</returns>
public static string BytesToString(long numberOfBytes)
{
string[] typeStrings = new string[]
{
"{0} B",
"{0:f1} KB",
"{0:f1} MB",
"{0:f1} GB"
};
double num = numberOfBytes;
for (int i = 0; i < 4; i++)
{
if (num <= 10240.0 || i >= 3)
{
return string.Format(typeStrings[i], num);
}
num /= 1024.0;
}
return "";
}
}
}
@@ -0,0 +1,17 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>annotations</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Ftp.dll" Version="2.0.22269.922" />
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="7.0.0" />
<PackageReference Include="sqlite-net-pcl" Version="1.8.116" />
<PackageReference Include="System.Data.SQLite" Version="1.0.117" />
<PackageReference Include="System.Json" Version="4.7.1" />
</ItemGroup>
</Project>
@@ -0,0 +1,198 @@
using OrbisLib2.Common.API;
using OrbisLib2.Common.Helpers;
using System.Net.Sockets;
using System.Runtime.InteropServices;
using System.Text;
using System.Text.RegularExpressions;
namespace OrbisLib2.Targets
{
public record AppInfo(string TitleId, string ContentId, string TitleName, string MetaDataPath, DateTime LastAccessTime,
int Visible, int SortPriority, int DisplayLocation, bool CanRemove, string Category, int ContentSize, DateTime InstallDate, string UICategory);
public class Application
{
private Target Target;
public Application(Target Target)
{
this.Target = Target;
}
public List<AppInfo> GetAppList()
{
var AppList = new List<AppInfo>();
var result = API.SendCommand(Target, 5000, APICommands.API_APPS_GET_LIST, (Socket Sock, APIResults Result) =>
{
// Get the number of apps installed.
int Count = Sock.RecvInt32();
// Itterate through the count to recieve all the apps details.
for (int i = 0; i < Count; i++)
{
// Recieve the bytes of the struct.
var Packet = new AppInfoPacket();
var RawPacket = new byte[Marshal.SizeOf(Packet)];
var bytes = Sock.Receive(RawPacket);
if (bytes <= 0)
break;
// Convert the recieved bytes to a struct.
Helper.BytesToStruct(RawPacket, ref Packet);
// Try to parse the date time strings.
if (!DateTime.TryParse(Packet.LastAccessTime, out DateTime LastAccessTime))
LastAccessTime = DateTime.MinValue;
if (!DateTime.TryParse(Packet.LastAccessTime, out DateTime InstallDate))
InstallDate = DateTime.MinValue;
// For some reason there is garbage after the string so this stops that :)
var firstNullIndex = Array.FindIndex(Packet.TitleName, b => b == 0);
string titleName = Encoding.UTF8.GetString(Packet.TitleName, 0, firstNullIndex);
// Add the entry to the list.
AppList.Add(new AppInfo(Packet.TitleId, Packet.ContentId, titleName, Packet.MetaDataPath, LastAccessTime, Packet.Visible,
Packet.SortPriority, Packet.DispLocation, Packet.CanRemove == 1, Packet.Category, Packet.ContentSize, InstallDate, Packet.UICategory));
}
});
return AppList;
}
public string GetAppInfoString(string TitleId, string Key)
{
if (!Regex.IsMatch(TitleId, @"[a-zA-Z]{4}\d{5}"))
{
Console.WriteLine($"Invaild titleId format {TitleId}");
return string.Empty;
}
var resultBuffer = new byte[200];
var result = API.SendCommand(Target, 5000, APICommands.API_APPS_GET_INFO_STR, (Socket Sock, APIResults Result) =>
{
// Send the titleId of the app.
Sock.Send(Encoding.ASCII.GetBytes(TitleId.PadRight(10, '\0')).Take(10).ToArray());
// Send the bytes of the key string.
Sock.Send(Encoding.ASCII.GetBytes(Key.PadRight(50, '\0')));
Sock.Receive(resultBuffer);
});
return Encoding.ASCII.GetString(resultBuffer);
}
public AppState GetAppState(string TitleId)
{
if (!Regex.IsMatch(TitleId, @"[a-zA-Z]{4}\d{5}"))
{
Console.WriteLine($"Invaild titleId format {TitleId}");
return AppState.STATE_ERROR;
}
AppState result = AppState.STATE_ERROR;
API.SendCommand(Target, 5000, APICommands.API_APPS_STATUS, (Socket Sock, APIResults Result) =>
{
// Send the titleId of the app.
var bytes = Encoding.ASCII.GetBytes(TitleId.PadRight(10, '\0')).Take(10).ToArray();
Sock.Send(bytes);
// Get the state from API.
result = (AppState)Sock.RecvInt32();
});
return result;
}
public bool Start(string TitleId)
{
if (!Regex.IsMatch(TitleId, @"[a-zA-Z]{4}\d{5}"))
{
Console.WriteLine($"Invaild titleId format {TitleId}");
return false;
}
int result = 0;
API.SendCommand(Target, 5000, APICommands.APP_START, (Socket Sock, APIResults Result) =>
{
// Send the titleId of the app.
var bytes = Encoding.ASCII.GetBytes(TitleId.PadRight(10, '\0')).Take(10).ToArray();
Sock.Send(bytes);
// Get the state from API.
result = Sock.RecvInt32();
});
return (result == 1);
}
public bool Stop(string TitleId)
{
if (!Regex.IsMatch(TitleId, @"[a-zA-Z]{4}\d{5}"))
{
Console.WriteLine($"Invaild titleId format {TitleId}");
return false;
}
int result = 0;
API.SendCommand(Target, 5000, APICommands.API_APPS_STOP, (Socket Sock, APIResults Result) =>
{
// Send the titleId of the app.
var bytes = Encoding.ASCII.GetBytes(TitleId.PadRight(10, '\0')).Take(10).ToArray();
Sock.Send(bytes);
// Get the state from API.
result = Sock.RecvInt32();
});
return (result == 1);
}
public bool Suspend(string TitleId)
{
if (!Regex.IsMatch(TitleId, @"[a-zA-Z]{4}\d{5}"))
{
Console.WriteLine($"Invaild titleId format {TitleId}");
return false;
}
int result = 0;
API.SendCommand(Target, 5000, APICommands.API_APPS_SUSPEND, (Socket Sock, APIResults Result) =>
{
// Send the titleId of the app.
var bytes = Encoding.ASCII.GetBytes(TitleId.PadRight(10, '\0')).Take(10).ToArray();
Sock.Send(bytes);
// Get the state from API.
result = Sock.RecvInt32();
});
return (result == 1);
}
public bool Resume(string TitleId)
{
if (!Regex.IsMatch(TitleId, @"[a-zA-Z]{4}\d{5}"))
{
Console.WriteLine($"Invaild titleId format {TitleId}");
return false;
}
int result = 0;
API.SendCommand(Target, 5000, APICommands.API_APPS_RESUME, (Socket Sock, APIResults Result) =>
{
// Send the titleId of the app.
var bytes = Encoding.ASCII.GetBytes(TitleId.PadRight(10, '\0')).Take(10).ToArray();
Sock.Send(bytes);
// Get the state from API.
result = Sock.RecvInt32();
});
return (result == 1);
}
}
}
@@ -0,0 +1,88 @@
using Limilabs.FTP.Client;
using OrbisLib2.Common;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace OrbisLib2.Targets
{
public class FTP
{
private Target Target;
public FTP(Target Target)
{
this.Target = Target;
}
public bool DownloadFile(string RemoteFilePath, string LocalFilePath)
{
using (Ftp ftp = new Ftp())
{
try
{
ftp.Connect(Target.IPAddress, Config.FTPPort);
ftp.Login("anonymous", "anonymous");
ftp.Download(RemoteFilePath, LocalFilePath);
ftp.Close();
}
catch (Exception ex)
{
if (ex.Message.Contains("The requested address is not valid in its context.") || ex.Message.Contains("File not found."))
{
File.Delete(LocalFilePath);
Console.WriteLine(ex.Message);
return false;
}
else if (ex.Message.Contains("No connection could be made because the target machine actively refused it.") ||
ex.Message.Contains("A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond."))
{
Console.WriteLine(ex.Message);
return false;
}
else
{
Console.WriteLine(ex.Message);
throw;
}
}
}
return true;
}
public void SendFile(string RemoteFilePath, string LocalFilePath)
{
using (Ftp ftp = new Ftp())
{
ftp.Connect(Target.IPAddress, Config.FTPPort);
ftp.Login("anonymous", "anonymous");
ftp.Upload(RemoteFilePath, LocalFilePath);
ftp.Close();
}
}
public List<FtpItem> GetDir(string Dir)
{
var ftpItems = new List<FtpItem>();
using (Ftp ftp = new Ftp())
{
ftp.Connect(Target.IPAddress, Config.FTPPort);
ftp.Login("anonymous", "anonymous");
ftp.ChangeFolder(Dir);
ftpItems = ftp.GetList();
ftp.Close();
}
return ftpItems;
}
}
}
@@ -0,0 +1,63 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;
namespace OrbisLib2.Targets
{
public class Payload
{
private Target Target;
public Payload(Target Target)
{
this.Target = Target;
}
/// <summary>
/// Sends Custom Payloads to Playstation 4 Console
/// </summary>
/// <param name="IP">PlayStation 4 IP address</param>
/// <param name="PayloadBuffer">Byte array of payload</param>
/// <param name="Port">Port used to recieve payload default value is 9020</param>
public bool InjectPayload(byte[] PayloadBuffer)
{
try
{
Socket socket;
socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
socket.ReceiveTimeout = 1000;
socket.SendTimeout = 1000;
IAsyncResult result = socket.BeginConnect(Target.IPAddress, Target.PayloadPort, null, null);
result.AsyncWaitHandle.WaitOne(3000, true);
if (!socket.Connected)
{
Console.WriteLine("Failed to connect to socket.");
socket.Close();
return false;
}
// we have connected
socket.EndConnect(result);
//Send Payload
socket.Send(PayloadBuffer);
socket.Close();
return true;
}
catch
{
Console.WriteLine("Failed to load Payload");
return false;
}
}
}
}
@@ -0,0 +1,179 @@
using OrbisLib2.Common.API;
using OrbisLib2.Common.Database;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;
namespace OrbisLib2.Targets
{
public class Target
{
private SavedTarget _SavedTarget;
/// <summary>
/// Weather or not this is our default target to be selected on start up.
/// </summary>
public bool IsDefault
{
get
{
return _SavedTarget.IsDefault;
}
set
{
_SavedTarget.IsDefault = value;
_SavedTarget.Save();
}
}
/// <summary>
/// The name given to the target.
/// </summary>
public string Name
{
get
{
return _SavedTarget.Name;
}
set
{
_SavedTarget.Name = value;
_SavedTarget.Save();
}
}
/// <summary>
/// The IP Address as a string.
/// </summary>
public string IPAddress
{
get
{
return _SavedTarget.IPAddress;
}
set
{
_SavedTarget.IPAddress = value;
_SavedTarget.Save();
}
}
/// <summary>
/// The port used to send payloads to the saved IP Address.
/// </summary>
public int PayloadPort
{
get
{
return _SavedTarget.PayloadPort;
}
set
{
_SavedTarget.PayloadPort = value;
_SavedTarget.Save();
}
}
public TargetInfo Info
{
get
{
return _SavedTarget.Info;
}
}
public TargetEvents Events;
// public Debug Debug;
public Payload Payload;
// public Process Process;
public FTP FTP;
public Application Application;
public Target(SavedTarget SavedTarget)
{
_SavedTarget = SavedTarget;
Events = new TargetEvents(this);
// Debug = new Debug(this);
Payload = new Payload(this);
// Process = new Process(PS4, this);
FTP = new FTP(this);
Application = new Application(this);
}
public bool Shutdown()
{
return API.SendCommand(this, 3000, APICommands.API_TARGET_SHUTDOWN) == APIResults.API_OK;
}
public bool Reboot()
{
return API.SendCommand(this, 3000, APICommands.API_TARGET_REBOOT) == APIResults.API_OK;
}
public bool Suspend()
{
return API.SendCommand(this, 3000, APICommands.API_TARGET_RESTMODE) == APIResults.API_OK;
}
public bool Notify(string Message)
{
var result = API.SendCommand(this, 3000, APICommands.API_TARGET_NOTIFY, (Socket Sock, APIResults Result) =>
{
Result = API.SendNextPacket(Sock, new TargetNotifyPacket() { Message = Message });
});
return result == APIResults.API_OK;
}
public bool Notify(string IconURI, string Message)
{
var result = API.SendCommand(this, 3000, APICommands.API_TARGET_NOTIFY, (Socket Sock, APIResults Result) =>
{
Result = API.SendNextPacket(Sock, new TargetNotifyPacket() { IconURI = IconURI, Message = Message });
});
return result == APIResults.API_OK;
}
public bool Buzzer(BuzzerType Type)
{
var result = API.SendCommand(this, 3000, APICommands.API_TARGET_BUZZER, (Socket Sock, APIResults Result) =>
{
Result = API.SendInt32(Sock, (int)Type);
});
return result == APIResults.API_OK;
}
public bool SetLED(ConsoleLEDColours Colour)
{
var result = API.SendCommand(this, 3000, APICommands.API_TARGET_SET_LED, (Socket Sock, APIResults Result) =>
{
Result = API.SendInt32(Sock, (int)Colour);
});
return result == APIResults.API_OK;
}
public bool SetSettings(bool ShowDebugTitleIdLabel, bool ShowDevkitPanel, bool ShowDebugSettings, bool ShowAppHome)
{
var result = API.SendCommand(this, 3000, APICommands.API_TARGET_SET_SETTINGS, (Socket Sock, APIResults Result) =>
{
Result = API.SendNextPacket(Sock, new TargetSettingsPacket()
{
ShowDebugTitleIdLabel = Convert.ToInt32(ShowDebugTitleIdLabel),
ShowDevkitPanel = Convert.ToInt32(ShowDevkitPanel),
ShowDebugSettings = Convert.ToInt32(ShowDebugSettings),
ShowAppHome = Convert.ToInt32(ShowAppHome)
});
});
return result == APIResults.API_OK;
}
}
}
@@ -0,0 +1,205 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace OrbisLib2.Targets
{
public class PrintEvent : EventArgs
{
public string Sender { get; private set; }
public string Data { get; private set; }
public PrintEvent(string Sender, string Data)
{
this.Sender = Sender;
this.Data = Data;
}
}
public class ProcInterceptEvent : EventArgs
{
public ProcInterceptEvent()
{
}
}
public class ProcContinueEvent : EventArgs
{
public ProcContinueEvent() { }
}
public class ProcDieEvent : EventArgs
{
public ProcDieEvent() { }
}
public class ProcAttachEvent : EventArgs
{
public string NewProcName { get; private set; }
public ProcAttachEvent(string NewProcName)
{
this.NewProcName = NewProcName;
}
}
public class ProcDetachEvent : EventArgs
{
public ProcDetachEvent() { }
}
public class TargetSuspendEvent : EventArgs
{
public TargetSuspendEvent() { }
}
public class TargetResumeEvent : EventArgs
{
public TargetResumeEvent() { }
}
public class TargetShutdownEvent : EventArgs
{
public TargetShutdownEvent() { }
}
public class TargetNewTitleEvent : EventArgs
{
public string TitleID { get; private set; }
public TargetNewTitleEvent(string TitleID)
{
this.TitleID = TitleID;
}
}
public class TargetEvents
{
private Target Target;
public event EventHandler<PrintEvent> Print;
public event EventHandler<ProcInterceptEvent> ProcIntercept;
public event EventHandler<ProcContinueEvent> ProcContinue;
public event EventHandler<ProcDieEvent> ProcDie;
public event EventHandler<ProcAttachEvent> ProcAttach;
public event EventHandler<ProcDetachEvent> ProcDetach;
public event EventHandler<TargetSuspendEvent> TargetSuspend;
public event EventHandler<TargetResumeEvent> TargetResume;
public event EventHandler<TargetShutdownEvent> TargetShutdown;
public event EventHandler<TargetNewTitleEvent> TargetNewTitle;
public TargetEvents(Target Target)
{
this.Target = Target;
}
/// <summary>
/// Event that should be fired when we recieve a print from the remote target.
/// </summary>
/// <param name="SenderIPAddress">The sending Target Address.</param>
/// <param name="Sender"></param>
/// <param name="Data"></param>
internal void RaiseProcPrintEvent(string SenderIPAddress, string Sender, string Data)
{
if (SenderIPAddress.Equals(Target.IPAddress))
Print?.Invoke(null, new PrintEvent(Sender, Data));
}
/// <summary>
/// Fires an event for when the Target's proccess were attached to has reached an intercepted state.
/// </summary>
/// <param name="IPAddr">The sending Target Address.</param>
internal void RaiseProcInterceptEvent(string IPAddr)
{
if (IPAddr.Equals(Target.IPAddress))
{
ProcIntercept?.Invoke(null, new ProcInterceptEvent());
}
}
/// <summary>
/// Fires an event when a procees on the Target has gotten the signal to continue execution.
/// </summary>
/// <param name="IPAddr">The sending Target Address.</param>
internal void RaiseProcContinueEvent(string IPAddr)
{
if (IPAddr.Equals(Target.IPAddress))
ProcContinue?.Invoke(null, new ProcContinueEvent());
}
/// <summary>
/// Fires an event for when a proccess is going to be shutting down on the Target.
/// </summary>
/// <param name="IPAddr">The sending Target Address.</param>
internal void RaiseProcDieEvent(string IPAddr)
{
if (IPAddr.Equals(Target.IPAddress))
ProcDie?.Invoke(null, new ProcDieEvent());
}
/// <summary>
/// Fires an event for when the OrbisLib API attaches to a process.
/// </summary>
/// <param name="IPAddr">The sending Target Address.</param>
/// <param name="NewProcName">The name of the process were attaching to.</param>
internal void RaiseProcAttachEvent(string IPAddr, string NewProcName)
{
if (IPAddr.Equals(Target.IPAddress))
ProcAttach?.Invoke(null, new ProcAttachEvent(NewProcName));
}
/// <summary>
/// Fires an event for when the OrbisLib API detaches to a process.
/// </summary>
/// <param name="IPAddr">The sending Target Address.</param>
internal void RaiseProcDetachEvent(string IPAddr)
{
if (IPAddr.Equals(Target.IPAddress))
ProcDetach?.Invoke(null, new ProcDetachEvent());
}
/// <summary>
/// Fires event for when Target is entering the suspended state.
/// </summary>
/// <param name="IPAddr">The sending Target Address.</param>
internal void RaiseTargetSuspendEvent(string IPAddr)
{
if (IPAddr.Equals(Target.IPAddress))
TargetSuspend?.Invoke(null, new TargetSuspendEvent());
}
/// <summary>
/// Fires event for when the Target is resuming from a suspended state.
/// </summary>
/// <param name="IPAddr">The sending Target Address.</param>
internal void RaiseTargetResumeEvent(string IPAddr)
{
if (IPAddr.Equals(Target.IPAddress))
TargetResume?.Invoke(null, new TargetResumeEvent());
}
/// <summary>
/// Fires an event for when the Target is shutting down.
/// </summary>
/// <param name="IPAddr">The sending Target Address.</param>
internal void RaiseTargetShutdownEvent(string IPAddr)
{
if (IPAddr.Equals(Target.IPAddress))
TargetShutdown?.Invoke(null, new TargetShutdownEvent());
}
/// <summary>
/// Fires an event for when we change the current game on the Target.
/// </summary>
/// <param name="IPAddr">The sending Target Address.</param>
/// <param name="TitleID">The next title index our Target will be running.</param>
internal void RaiseTargetNewTitleEvent(string IPAddr, string TitleID)
{
if (IPAddr.Equals(Target.IPAddress))
TargetNewTitle?.Invoke(null, new TargetNewTitleEvent(TitleID));
}
}
}
@@ -0,0 +1,175 @@
using Microsoft.Extensions.Logging;
using OrbisLib2.Common.API;
using OrbisLib2.Common.Database;
using OrbisLib2.Common.Database.Types;
using OrbisLib2.Common.Helpers;
using System.Net.Sockets;
using System.Runtime.InteropServices;
namespace OrbisLib2.Targets
{
public class TargetManager
{
/// <summary>
/// Returns a list of the Targets saved.
/// </summary>
public static List<Target> Targets
{
get
{
var temporaryList = new List<Target>();
var savedTargets = SavedTarget.GetTargetList();
if (savedTargets == null)
return temporaryList;
foreach (var target in savedTargets)
{
temporaryList.Add(new Target(target));
}
return temporaryList;
}
}
private static Target _SelectedTarget;
/// <summary>
/// Gets the currently selected target.
/// </summary>
public static Target SelectedTarget
{
get
{
// Set initially as the default target.
if (SelectedTarget == null)
{
var defaultTarget = SavedTarget.FindDefaultTarget();
if (defaultTarget != null)
{
_SelectedTarget = new Target(defaultTarget);
}
}
return _SelectedTarget;
}
set { _SelectedTarget = value; }
}
/// <summary>
/// Gets the specified target by name.
/// </summary>
/// <param name="TargetName">The specified target name.</param>
/// <param name="Out">Target output.</param>
/// <returns>Returns true if target is found.</returns>
public static Target? GetTarget(string TargetName)
{
var saveedTarget = SavedTarget.FindTarget(x => x.Name == TargetName);
if (saveedTarget == null)
{
return null;
}
return new Target(saveedTarget);
}
/// <summary>
/// Deletes the specified target.
/// </summary>
/// <param name="TargetName">The specified target name.</param>
/// <returns>Returns true if the operation was successful.</returns>
public static bool DeleteTarget(string TargetName)
{
var Target = SavedTarget.FindTarget(x => x.Name == TargetName);
return Target.Remove();
}
/// <summary>
/// Adds a new target.
/// </summary>
/// <param name="Default">If this target the new default.</param>
/// <param name="TargetName">The mame for this target.</param>
/// <param name="IPAddress">IP Address of this target.</param>
/// <param name="PayloadPort">The payload port to be used for this target.</param>
/// <returns>Returns true if successful.</returns>
public static bool NewTarget(bool Default, string TargetName, string IPAddress, int PayloadPort)
{
return new SavedTarget { IsDefault = Default, Name = TargetName, IPAddress = IPAddress, PayloadPort = PayloadPort }.Add();
}
/// <summary>
/// Updates extended information about the Target. *Requires the Target to be on and the API running.
/// </summary>
/// <param name="TargetName">The name of the target to update.</param>
/// <returns>Returns weather or not the action was successful or not.</returns>
public static bool UpdateTargetInfo(string TargetName)
{
Target? Target = GetTarget(TargetName);
if (Target == null)
{
Console.WriteLine($"Couldn't Find Target \"{TargetName}\".");
return false;
}
bool labdaReult = false;
var result = API.SendCommand(Target, 3000, APICommands.API_TARGET_INFO, (Sock, Result) =>
{
var Packet = new TargetInfoPacket();
var RawPacket = new byte[Marshal.SizeOf(Packet)];
var bytes = Sock.Receive(RawPacket);
if (bytes <= 0)
{
return;
}
Helper.BytesToStruct(RawPacket, ref Packet);
if (Packet.ConsoleName == null || Packet.ConsoleName == string.Empty)
return;
Target.Info.SDKVersion = $"{(Packet.SDKVersion >> 24 & 0xFF).ToString("X1")}.{(Packet.SDKVersion >> 12 & 0xFFF).ToString("X3")}.{(Packet.SDKVersion & 0xFFF).ToString("X3")}";
Target.Info.SoftwareVersion = $"{(Packet.SoftwareVersion >> 24 & 0xFF).ToString("X1")}.{(Packet.SoftwareVersion >> 16 & 0xFF).ToString("X2")}";
Target.Info.FactorySoftwareVersion = $"{(Packet.FactorySoftwareVersion >> 24 & 0xFF).ToString("X1")}.{(Packet.FactorySoftwareVersion >> 12 & 0xFFF).ToString("X3")}.{(Packet.FactorySoftwareVersion & 0xFFF).ToString("X3")}";
Target.Info.CurrentTitleID = Packet.CurrentTitleID;
Target.Info.ConsoleName = Packet.ConsoleName;
Target.Info.MotherboardSerial = Packet.MotherboardSerial;
Target.Info.Serial = Packet.Serial;
Target.Info.Model = Packet.Model;
Target.Info.MACAddressLAN = Packet.MACAddressLAN.ToUpper();
Target.Info.MACAddressWIFI = Packet.MACAddressWIFI.ToUpper();
Target.Info.UART = Packet.UART > 0;
Target.Info.IDUMode = Packet.IDUMode > 0;
Target.Info.IDPS = BitConverter.ToString(Packet.IDPS).Replace("-", string.Empty);
Target.Info.PSID = BitConverter.ToString(Packet.PSID).Replace("-", string.Empty);
Target.Info.ConsoleType = (ConsoleType)Packet.ConsoleType;
// Debugging.
Target.Info.IsAttached = Packet.Attached > 0;
// TODO: Implement this into the API.
Target.Info.CurrentProcessId = 0;// TODO: Update this to process Id Packet.CurrentProc;
// Storage.
Target.Info.HDDUsedSpace = (long)(Packet.TotalSpace - Packet.FreeSpace);
Target.Info.HDDFreeSpace = (long)Packet.FreeSpace;
Target.Info.HDDTotalSpace = (long)Packet.TotalSpace;
// Perf Stats.
Target.Info.CPUTemp = Packet.CPUTemp;
Target.Info.SOCTemp = Packet.SOCTemp;
Target.Info.ThreadCount = Packet.ThreadCount;
Target.Info.AverageCPUUsage = Packet.AverageCPUUsage;
Target.Info.BusyCore = Packet.BusyCore;
Target.Info.RamUsage = Packet.Ram.Used;
Target.Info.VRamUsage = Packet.VRam.Used;
labdaReult = true;
});
return result == APIResults.API_OK && labdaReult && Target.Info.Save();
}
}
}
@@ -167,6 +167,8 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="7.0.0" />
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="7.0.0" />
<PackageReference Include="WpfAnimatedGif" Version="2.0.2" />
</ItemGroup>
@@ -1 +1 @@
1990
1991
@@ -1 +1 @@
Version 3.0.1990 Debug Build Monday December 19 2022 8:42 PM
Version 3.0.1991 Debug Build Thursday December 22 2022 9:17 PM