205 lines
7.3 KiB
C#
205 lines
7.3 KiB
C#
/*
|
|
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
* All rights reserved.
|
|
*
|
|
* Licensed under the Oculus SDK License Agreement (the "License");
|
|
* you may not use the Oculus SDK except in compliance with the License,
|
|
* which is provided at the time of installation or download, or which
|
|
* otherwise accompanies this software in either electronic or hard copy form.
|
|
*
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* https://developer.oculus.com/licenses/oculussdk/
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, the Oculus SDK
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Diagnostics;
|
|
using System.IO;
|
|
using System.Text.RegularExpressions;
|
|
|
|
namespace Meta.XR.Simulator.Editor
|
|
{
|
|
internal class ProcessPort
|
|
{
|
|
public override string ToString()
|
|
{
|
|
return $"{ProcessName}({ProcessId}) ({Protocol} port {PortNumber})";
|
|
}
|
|
public string ProcessName { get; set; }
|
|
public int ProcessId { get; set; }
|
|
public string PortNumber { get; set; }
|
|
public string Protocol { get; set; }
|
|
}
|
|
internal class ProcessUtils
|
|
{
|
|
public virtual string GetProcessByPid(int pid)
|
|
{
|
|
string procName;
|
|
try
|
|
{
|
|
procName = Process.GetProcessById(pid).ProcessName;
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
UnityEngine.Debug.LogError(ex);
|
|
procName = "-";
|
|
}
|
|
|
|
return procName;
|
|
}
|
|
|
|
public virtual List<ProcessPort> GetProcessesByPort(string targetPort)
|
|
{
|
|
var ports = new List<ProcessPort>();
|
|
#if UNITY_EDITOR_OSX
|
|
var path = "lsof";
|
|
var args = $"-t -n -P -iTCP:{targetPort} -sTCP:LISTEN";
|
|
#elif UNITY_EDITOR_WIN
|
|
var path = "netstat.exe";
|
|
var args = "-a -n -o";
|
|
#else
|
|
return ports;
|
|
#endif
|
|
var (retCode, content) = ExecuteProcess(path, args);
|
|
#if UNITY_EDITOR_OSX
|
|
if(retCode == 1){
|
|
// According lsof man page, lsof will return 1 if there is no processes on specified port.
|
|
return ports;
|
|
}
|
|
#endif
|
|
if (retCode != 0)
|
|
{
|
|
UnityEngine.Debug.LogError(
|
|
$"{path} {args} call failed, exitCode={retCode}, content={content}");
|
|
return ports;
|
|
}
|
|
|
|
string[] rows = content.Split(Environment.NewLine);
|
|
foreach (string row in rows)
|
|
{
|
|
int processId = 0;
|
|
string protocol = "", portNumber = "";
|
|
#if UNITY_EDITOR_OSX
|
|
if(String.IsNullOrEmpty(row))
|
|
{
|
|
continue;
|
|
}
|
|
processId = Convert.ToInt32(row);
|
|
protocol = "TCPv6";
|
|
portNumber = targetPort;
|
|
#elif UNITY_EDITOR_WIN
|
|
Regex tokenRE = new Regex("\\s+");
|
|
Regex localAddressRE = new Regex(@"\[(.*?)\]");
|
|
string[] tokens = tokenRE.Split(row);
|
|
if (tokens.Length > 4 && (tokens[1].Equals("UDP") || tokens[1].Equals("TCP")))
|
|
{
|
|
string localAddress = localAddressRE.Replace(tokens[2], "1.1.1.1");
|
|
portNumber = localAddress.Split(':')[1];
|
|
if (targetPort != portNumber)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
processId = 0;
|
|
try
|
|
{
|
|
processId = tokens[1].Equals("UDP")
|
|
? Convert.ToInt32(tokens[4])
|
|
: Convert.ToInt32(tokens[5]);
|
|
|
|
protocol = localAddress.Contains("1.1.1.1")
|
|
? String.Format("{0}v6", tokens[1])
|
|
: String.Format("{0}v4", tokens[1]);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
UnityEngine.Debug.LogError(tokens[1] + " " + tokens[4] + " " + tokens[5]);
|
|
throw ex;
|
|
}
|
|
}
|
|
#endif
|
|
if (processId != 0)
|
|
{
|
|
string processName = GetProcessByPid(processId);
|
|
UnityEngine.Debug.Log($"Found {protocol} port {portNumber} used by {processName}({processId})");
|
|
ports.Add(new ProcessPort
|
|
{
|
|
Protocol = protocol,
|
|
PortNumber = portNumber,
|
|
ProcessName = processName,
|
|
ProcessId = processId
|
|
});
|
|
}
|
|
}
|
|
|
|
return ports;
|
|
}
|
|
|
|
public virtual void StopProcess(string processPort, string logContext)
|
|
{
|
|
var existingProcesses = Utils.ProcessUtils.GetProcessesByPort(processPort);
|
|
foreach (var existingProcess in existingProcesses)
|
|
{
|
|
Utils.LogUtils.ReportInfo(logContext, $"Stopping {existingProcess.ProcessName} with PID {existingProcess.ProcessId}");
|
|
var p = Process.GetProcessById(existingProcess.ProcessId);
|
|
p.Kill();
|
|
p.WaitForExit();
|
|
}
|
|
}
|
|
|
|
public virtual void LaunchProcess(string binaryPath, string arguments, string logContext, bool createWindow = true)
|
|
{
|
|
Utils.LogUtils.ReportInfo(logContext, "Launching " + binaryPath + ", createWindow=" + createWindow + ", arguments=" + arguments);
|
|
var newProcess = new Process();
|
|
newProcess.StartInfo.FileName = binaryPath;
|
|
newProcess.StartInfo.Arguments = arguments;
|
|
|
|
if (!createWindow)
|
|
{
|
|
newProcess.StartInfo.CreateNoWindow = true;
|
|
newProcess.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
|
|
newProcess.StartInfo.UseShellExecute = false;
|
|
newProcess.StartInfo.RedirectStandardOutput = true;
|
|
newProcess.StartInfo.RedirectStandardError = true;
|
|
}
|
|
if (!newProcess.Start())
|
|
{
|
|
Utils.LogUtils.DisplayDialogOrError(logContext, "failed to launch " + binaryPath);
|
|
}
|
|
}
|
|
|
|
public virtual (int retCode, string contents) ExecuteProcess(string path, string args)
|
|
{
|
|
using var p = new Process();
|
|
var ps = new ProcessStartInfo
|
|
{
|
|
Arguments = args,
|
|
FileName = path,
|
|
UseShellExecute = false,
|
|
WindowStyle = ProcessWindowStyle.Hidden,
|
|
RedirectStandardInput = true,
|
|
RedirectStandardOutput = true,
|
|
RedirectStandardError = true
|
|
};
|
|
|
|
p.StartInfo = ps;
|
|
p.Start();
|
|
|
|
StreamReader stdOutput = p.StandardOutput;
|
|
StreamReader stdError = p.StandardError;
|
|
|
|
string content = stdOutput.ReadToEnd() + stdError.ReadToEnd();
|
|
p.WaitForExit();
|
|
int retCode = p.ExitCode;
|
|
return (retCode, content);
|
|
}
|
|
}
|
|
}
|