149 lines
5.6 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using System;
using System.Net.Sockets;
using System.Net;
namespace AmtScanner.Api.Services
{
/// <summary>
/// AMT platform data. e.g. provisioning state.
/// </summary>
public struct PlatformData
{
/// <summary>
/// The provisioning state of the AMT machine.
/// </summary>
public ProvisioningState ProvisioningState { get; internal set; }
/// <summary>
/// The major version of the AMT machine.
/// </summary>
public uint MajorVersion { get; internal set; }
/// <summary>
/// The minor version of the AMT machine.
/// </summary>
public uint MinorVersion { get; internal set; }
}
/// <summary>
/// The provisioning state of the AMT machine.
/// </summary>
public enum ProvisioningState
{
Pre = 0,
In = 1,
Post = 2,
Unknown
}
public class RMCPPingApi
{
private const int RMCP_PORT = 623;
private const int RMCP_HEADER_SIZE = 4;
private const int ASF_RMCP_DATA_MINIMUM_SIZE = 8;
private const int RMCP_RESENCE_PONG_DATA_SIZE = 16;
/// <summary>
/// 获取AMT平台数据支持自定义超时
/// </summary>
public static PlatformData GetPlatformData(string address, int timeoutMs = 5000)
{
return GetPlatformDataByRMCPPing(address, timeoutMs);
}
private static PlatformData GetPlatformDataByRMCPPing(string address, int timeoutMs)
{
const int DASH_SUPPORT_BYTE_OFFSET_DSP_0232_100B = 9;
const int DASH_SUPPORT_INDICATING_BIT = 32;
const int VERS_BYTE = 0;
const int RSVD_BYTE = 1;
const int SEQ_BYTE = 2;
const int CLASS_BYTE = 3;
const int VERS = 0x06;
const int RSVD = 0x0;
const int SEQ = 0x0;
const int CLASS = 0x86;
using (Socket clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp))
{
try
{
// 按照SDK的方式先用IPEndPoint连接再用地址和端口连接
IPEndPoint ipEndPoint = new IPEndPoint(IPAddress.Parse(address), RMCP_PORT);
clientSocket.Connect(ipEndPoint as EndPoint);
clientSocket.Connect(address, RMCP_PORT);
byte[] rmcpPingPacketData = GetRMCPPingPacketData();
clientSocket.Send(rmcpPingPacketData, 0, rmcpPingPacketData.Length, SocketFlags.None);
clientSocket.ReceiveTimeout = timeoutMs;
byte[] byteData = new byte[4];
clientSocket.Receive(byteData, 0, byteData.Length, SocketFlags.None);
if ((byteData[VERS_BYTE] == VERS) && (byteData[RSVD_BYTE] == RSVD) &&
(byteData[SEQ_BYTE] == SEQ) && (byteData[CLASS_BYTE] == CLASS))
{
byte[] pongBuffer = new byte[RMCP_HEADER_SIZE + ASF_RMCP_DATA_MINIMUM_SIZE + RMCP_RESENCE_PONG_DATA_SIZE];
clientSocket.Receive(pongBuffer, 0, pongBuffer.Length, SocketFlags.None);
if ((pongBuffer[12] == 0) && (pongBuffer[13] == 0) &&
(pongBuffer[14] == 0x01) && (pongBuffer[15] == 0x57))
{
ushort dashSupportByteVersionB = pongBuffer[RMCP_HEADER_SIZE + ASF_RMCP_DATA_MINIMUM_SIZE + DASH_SUPPORT_BYTE_OFFSET_DSP_0232_100B];
if (0 != (dashSupportByteVersionB & DASH_SUPPORT_INDICATING_BIT))
{
return ParsePlatformDataFromRMCPPing(pongBuffer);
}
}
}
throw new Exception("Not an AMT device");
}
catch (Exception ex)
{
throw new Exception($"Failed to get platform data: {ex.Message}", ex);
}
finally
{
clientSocket.Close();
}
}
}
private static PlatformData ParsePlatformDataFromRMCPPing(byte[] pongBuffer)
{
const int CONFIGURATION_STATE_BYTE = 7;
const int VERSION_BYTE = 6;
const int UPDATED_VERSION_BYTE = 10;
PlatformData platformData = new PlatformData();
if (pongBuffer[RMCP_HEADER_SIZE + ASF_RMCP_DATA_MINIMUM_SIZE + VERSION_BYTE] == 0)
{
platformData.MinorVersion = pongBuffer[RMCP_HEADER_SIZE + ASF_RMCP_DATA_MINIMUM_SIZE + UPDATED_VERSION_BYTE + 1];
platformData.MajorVersion = pongBuffer[RMCP_HEADER_SIZE + ASF_RMCP_DATA_MINIMUM_SIZE + UPDATED_VERSION_BYTE];
}
else
{
platformData.MinorVersion = (uint)(pongBuffer[RMCP_HEADER_SIZE + ASF_RMCP_DATA_MINIMUM_SIZE + VERSION_BYTE] & 0xf);
platformData.MajorVersion = (uint)((pongBuffer[RMCP_HEADER_SIZE + ASF_RMCP_DATA_MINIMUM_SIZE + VERSION_BYTE] & 0xf0) >> 4);
}
platformData.ProvisioningState = (ProvisioningState)(pongBuffer[RMCP_HEADER_SIZE + ASF_RMCP_DATA_MINIMUM_SIZE + CONFIGURATION_STATE_BYTE] & 0x3);
return platformData;
}
private static byte[] GetRMCPPingPacketData()
{
return new byte[]
{
0x06, 0x00, 0x00, 0x06, // RMCP Header
0x00, 0x00, 0x11, 0xBE, // ASF IANA
0x80, 0x00, 0x00, 0x00 // Presence Ping
};
}
}
}