Much needed refactor of orbislib into orbislib2.
This commit is contained in:
@@ -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}
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user