mirror of
https://github.com/onyx-and-iris/q3rcon-ps.git
synced 2026-04-18 19:03:30 +00:00
initial commit
This commit is contained in:
79
lib/Q3Rcon.psm1
Normal file
79
lib/Q3Rcon.psm1
Normal file
@@ -0,0 +1,79 @@
|
||||
. $PSScriptRoot\packet.ps1
|
||||
. $PSScriptRoot\base.ps1
|
||||
|
||||
|
||||
class Rcon {
|
||||
[Object]$base
|
||||
|
||||
Rcon ([string]$hostname, [int]$port, [string]$passwd) {
|
||||
$this.base = New-Base -hostname $hostname -port $port -passwd $passwd
|
||||
}
|
||||
|
||||
[Rcon] Login() {
|
||||
$resp = $this.base._send("login")
|
||||
if ($resp -in @("Bad rcon", "Bad rconpassword.", "Invalid password.")) {
|
||||
throw "invalid rcon password"
|
||||
}
|
||||
$this.base.ToString() | Write-Debug
|
||||
return $this
|
||||
}
|
||||
|
||||
[string] Send($msg) {
|
||||
return $this.base._send($msg)
|
||||
}
|
||||
|
||||
[void] Say($msg) {
|
||||
$this.base._send($msg)
|
||||
}
|
||||
|
||||
[void] FastRestart() {
|
||||
$this.base._send("fast_restart", 2000)
|
||||
}
|
||||
|
||||
[void] MapRotate() {
|
||||
$this.base._send("map_rotate", 2000)
|
||||
}
|
||||
|
||||
[void] MapRestart() {
|
||||
$this.base._send("map_restart", 2000)
|
||||
}
|
||||
|
||||
[string] Map() {
|
||||
return $this.base._send("mapname")
|
||||
}
|
||||
|
||||
[void] SetMap($mapname) {
|
||||
$this.base._send("map mp_$mapname")
|
||||
}
|
||||
|
||||
[string] Gametype() {
|
||||
return $this.base._send("g_gametype")
|
||||
}
|
||||
|
||||
[void] SetGametype($gametype) {
|
||||
$this.base._send("g_gametype $gametype")
|
||||
}
|
||||
|
||||
[string] HostName() {
|
||||
return $this.base._send("sv_hostname")
|
||||
}
|
||||
|
||||
[void] SetHostName($hostname) {
|
||||
$this.base._send("sv_hostname $hostname")
|
||||
}
|
||||
}
|
||||
|
||||
Function Connect-Rcon {
|
||||
param([string]$hostname, [int]$port, [string]$passwd)
|
||||
|
||||
[Rcon]::new($hostname, $port, $passwd).Login()
|
||||
}
|
||||
|
||||
Function Disconnect-Rcon {
|
||||
param([Rcon]$rcon)
|
||||
|
||||
$rcon.base._close()
|
||||
"Disconnected from {0}:{1}" -f $rcon.base.hostname, $rcon.base.port | Write-Debug
|
||||
}
|
||||
|
||||
Export-ModuleMember -Function Connect-Rcon, Disconnect-Rcon
|
||||
88
lib/base.ps1
Normal file
88
lib/base.ps1
Normal file
@@ -0,0 +1,88 @@
|
||||
class Base {
|
||||
[string]$hostname
|
||||
[int]$port
|
||||
[string]$passwd
|
||||
[Object]$request
|
||||
[Object]$response
|
||||
hidden [System.Net.Sockets.Socket] $_socket
|
||||
|
||||
Base ([string]$hostname, [int]$port, [string]$passwd) {
|
||||
$this.hostname = $hostname
|
||||
$this.port = $port
|
||||
$this.passwd = $passwd
|
||||
|
||||
$this.request = New-RequestPacket($this.passwd)
|
||||
$this.response = New-ResponsePacket
|
||||
|
||||
$ip = [system.net.IPAddress]::Parse([System.Net.Dns]::GetHostAddresses($this.hostname)[0].IPAddressToString)
|
||||
|
||||
$endpoint = New-Object System.Net.IPEndPoint $ip, $this.port
|
||||
try {
|
||||
$this._socket = [System.Net.Sockets.Socket]::New(
|
||||
[System.Net.Sockets.AddressFamily]::InterNetwork,
|
||||
[System.Net.Sockets.SocketType]::Dgram,
|
||||
[System.Net.Sockets.ProtocolType]::UDP
|
||||
)
|
||||
$this._socket.Connect($endpoint)
|
||||
$this._socket.ReceiveTimeout = 100
|
||||
}
|
||||
catch [System.Net.Sockets.SocketException] {
|
||||
throw "Failed to create UDP connection to server."
|
||||
}
|
||||
}
|
||||
|
||||
[string] ToString () {
|
||||
return "Rcon connection {0}:{1} with pass {2}" -f $this.hostname, $this.port, $this.passwd
|
||||
}
|
||||
|
||||
[string] _send([string]$msg) {
|
||||
$this._socket.Send($this.request.Payload($msg))
|
||||
|
||||
[string[]]$data = @()
|
||||
$sw = [Diagnostics.Stopwatch]::StartNew()
|
||||
While ($sw.ElapsedMilliseconds -lt 50) {
|
||||
try {
|
||||
$buf = New-Object System.Byte[] 4096
|
||||
$this._socket.Receive($buf)
|
||||
$data += [System.Text.Encoding]::ASCII.GetString($($buf | Select-Object -Skip $($this.response.Header().Length - 1)))
|
||||
}
|
||||
catch [System.Net.Sockets.SocketException] {
|
||||
if ( $_.Exception.SocketErrorCode -eq 'TimedOut' ) {
|
||||
"finished waiting for fragment" | Write-Debug
|
||||
}
|
||||
}
|
||||
}
|
||||
$sw.Stop()
|
||||
return [string]::Join("", $data)
|
||||
}
|
||||
|
||||
[string] _send([string]$msg, [int]$timeout) {
|
||||
$this._socket.Send($this.request.Payload($msg))
|
||||
|
||||
[string[]]$data = @()
|
||||
$sw = [Diagnostics.Stopwatch]::StartNew()
|
||||
While ($sw.ElapsedMilliseconds -lt $timeout) {
|
||||
try {
|
||||
$buf = New-Object System.Byte[] 4096
|
||||
$this._socket.Receive($buf)
|
||||
$data += [System.Text.Encoding]::ASCII.GetString($($buf | Select-Object -Skip $($this.response.Header().Length - 1)))
|
||||
}
|
||||
catch [System.Net.Sockets.SocketException] {
|
||||
if ( $_.Exception.SocketErrorCode -eq 'TimedOut' ) {
|
||||
"finished waiting for fragment" | Write-Debug
|
||||
}
|
||||
}
|
||||
}
|
||||
return [string]::Join("", $data)
|
||||
}
|
||||
|
||||
[void] _close() {
|
||||
$this._socket.Close()
|
||||
}
|
||||
}
|
||||
|
||||
Function New-Base {
|
||||
param([string]$hostname, [int]$port, [string]$passwd)
|
||||
|
||||
[Base]::new($hostname, $port, $passwd)
|
||||
}
|
||||
37
lib/packet.ps1
Normal file
37
lib/packet.ps1
Normal file
@@ -0,0 +1,37 @@
|
||||
class Packet {
|
||||
[System.Byte[]]$MAGIC = @(, 0xFF * 4)
|
||||
|
||||
[string] Header() {
|
||||
throw "method not implemented"
|
||||
}
|
||||
}
|
||||
|
||||
class RequestPacket : Packet {
|
||||
[string]$passwd
|
||||
|
||||
RequestPacket([string]$passwd) {
|
||||
$this.passwd = $passwd
|
||||
}
|
||||
|
||||
[System.Byte[]] Header() {
|
||||
return $this.MAGIC + [System.Text.Encoding]::ASCII.GetBytes("rcon")
|
||||
}
|
||||
|
||||
[System.Byte[]] Payload([string]$msg) {
|
||||
return $this.Header() + [System.Text.Encoding]::ASCII.GetBytes($(" {0} {1}" -f $this.passwd, $msg))
|
||||
}
|
||||
}
|
||||
|
||||
class ResponsePacket : Packet {
|
||||
[System.Byte[]] Header() {
|
||||
return $this.MAGIC + [System.Text.Encoding]::ASCII.GetBytes("print\n")
|
||||
}
|
||||
}
|
||||
|
||||
Function New-RequestPacket([string]$passwd) {
|
||||
[RequestPacket]::new($passwd)
|
||||
}
|
||||
|
||||
Function New-ResponsePacket {
|
||||
[ResponsePacket]::new()
|
||||
}
|
||||
Reference in New Issue
Block a user