Sign in to follow this  
Followers 0
jvanegmond

Source Dedicator Server Monitor for Windows

8 posts in this topic

#1 ·  Posted (edited)

Source Dedicator Server Monitor for Windows

Introduction

After trying a few SRCDS (Source Dedicated Server) server restarters, I wasn't satisfied with all the features. Most of them do not even properly detect crashes because they use conventional methods of detecting a crash. I've decided to write my own that does the job better for everyone.

This uses a new system of simulating a player trying to connect to the server. If the server for some reason is not answering to the query, it is restarted. Whether this be a crash or a freeze.

Features

  • Easy to set up.

    A standard windows form with a few controls provides easy access to all the available settings.

  • Easy to manage.

    Your preferences are automatically remembered. So next time you start the server, you won't have to set it up again.

  • Flexibility.

    Your server will keep running, no matter what error you get that causes it to crash.

  • Reliability.

    The monitor is built with long-term reliability in mind. Once you have this program, you will never have to restart your server manually again.

Download

Currently only source is available. Ask me for a compiled package with or without installer should you need one.

Source Dedicated Server Monitor for Windows:

File: ServerMonitor.au3

Opt("GUIOnEventMode", 1)
Opt("WinTitleMatchMode", 2)

#include <GUIConstantsEx.au3>
#include <WindowsConstants.au3>

Dim $DEBUG = False

Dim $mRunning = False
Dim $mPath = "C:\scrds\server\orangebox\srcds.exe"
Dim $mParameter = "-console -game GAMENAME_HERE -maxplayers 12 -autoupdate"
Dim $mTimeStart
Dim $mProcessID = 0
Dim $mConsoleText = ""
Dim $mIPAdress = @IPAddress1
Dim $mPort = 27015
Dim $mServerRunning = False
Dim $mDBPath = @UserProfileDir & "\" & "serverdata.ini"

$mIPAdress = IniRead($mDBPath, "Data", "IP", $mIPAdress)
$mPort = IniRead($mDBPath, "Data", "Port", $mPort)
$mPath = IniRead($mDBPath, "Data", "Path", $mPath)
$mParameter = IniRead($mDBPath, "Data", "Parameter", $mParameter)

#Region ### START Koda GUI section ### Form=
$Form1 = GUICreate("Source Dedicated Server Monitor by Manadar.com", 378, 444)
GUISetOnEvent($GUI_EVENT_CLOSE,"_Event_Close")
GUISetFont(8,400,0,"Tahoma")
$Group1 = GUICtrlCreateGroup("Status", 8, 8, 361, 217)
$Label1 = GUICtrlCreateEdit("", 16, 24, 345, 193)
$Menu1 = GUICtrlCreateContextMenu($Label1)
$MenuItem = GUICtrlCreateMenuItem("Copy all", $Menu1)
GUICtrlSetOnEvent($MenuItem, "_Console_Copy")
GUICtrlCreateGroup("", -99, -99, 1, 1)
$Group4 = GUICtrlCreateGroup("Server address", 8, 232, 361, 57)
$Input4 = GUICtrlCreateInput($mIPAdress, 16, 248, 225, 21)
$Label2 = GUICtrlCreateLabel(":", 247, 250, 7, 17)
$Input5 = GUICtrlCreateInput($mPort, 256, 248, 105, 21)
GUICtrlCreateGroup("", -99, -99, 1, 1)
$Group2 = GUICtrlCreateGroup("Path to server", 8, 288, 361, 49)
$Input2 = GUICtrlCreateInput($mPath, 16, 304, 249, 21)
$Button1 = GUICtrlCreateButton("Browse", 272, 304, 91, 25)
GUICtrlSetOnEvent($Button1, "_Event_Browse")
GUICtrlCreateGroup("", -99, -99, 1, 1)
$Group3 = GUICtrlCreateGroup("Parameters for restart", 8, 344, 361, 49)
$Input3 = GUICtrlCreateInput($mParameter, 16, 360, 345, 21)
GUICtrlCreateGroup("", -99, -99, 1, 1)
$Button2 = GUICtrlCreateButton("Monitor my server", 8, 400, 179, 33)
GUICtrlSetOnEvent($Button2, "_Event_Monitor")
$Button3 = GUICtrlCreateButton("About", 200, 400, 171, 33)
GUICtrlSetOnEvent($Button3, "_Event_About")

GUICtrlSetState($Button2,$GUI_FOCUS)

GUISetState(@SW_SHOW)
#EndRegion ### END Koda GUI section ###

UDPStartup()

_Console_AddLine("Source Dedicated Server Monitor. © Manadar.com 2008")

_Check_Handler()
$mTimeStart = TimerInit()
While 1
    If TimerDiff($mTimeStart) > 3000 Then
        $mTimeStart = TimerInit()
        _Check_Handler()
    EndIf
    Sleep(100)
WEnd

Func _DEBUG($pText)
    If Not $DEBUG Then Return
    
    $pText = StringReplace(StringStripCR($pText),@LF,"")
    $lLog = _Console_PrintTime() & $pText & @CRLF
    ConsoleWrite($lLog)
    
    FileWrite("debug.log", $lLog)
EndFunc

Func _Check_Handler()
    _DEBUG("Function: _Check_Handler()")
    _DEBUG("$mRunning = " & $mRunning)
    If Not $mRunning Then Return
    
    _DEBUG("$mProcessID = " & $mProcessID)
    If Not $mProcessID Then
        
        _Console_AddLine(_Console_PrintTime() & "Trying to attach to srcds.exe")
        $mProcessID = ProcessExists("srcds.exe")
        _DEBUG("$mProcessID = " & $mProcessID)
        If $mProcessID <> 0 Then
            _Console_AddLine(_Console_PrintTime() & "srcds.exe found. Attached to process.")
        Else
            _Server_Start()
        EndIf
        
    EndIf
    
    If $mProcessID Then
        _Check_Server()
    EndIf
EndFunc

Func _Check_Server()
    _DEBUG("Function: _Check_Server()")
    _DEBUG("$mProcessID = " & $mProcessID)
    If Not $mProcessID Then Return
    
    If Not ProcessExists($mProcessID) Then
        _Event_RestartNow()
        Return
    EndIf
    
    $lUDPOpen = UDPOpen($mIPAdress, $mPort)
    $lUDPSend = UDPSend($lUDPOpen, _Query_String() )
    
    $lStartWait = TimerInit()
    While ProcessExists($mProcessID)
        $lReturnData = UDPRecv($lUDPOpen,200)
        If $lReturnData Then
            If $mServerRunning = False Then
                $mServerRunning = True
                _Console_AddLine(_Console_PrintTime() & "Server is up and running.")
                $mRunning = True
                $mProcessID = 0
                _Check_Handler()
            EndIf
            ExitLoop
        EndIf
        If TimerDiff($lStartWait) > 30000 Then
            _Event_RestartNow()
            UDPCloseSocket($lUDPOpen)
            UDPCloseSocket($lUDPOpen)
            UDPCloseSocket($lUDPOpen)
            Return
        EndIf
        Sleep(10)
    WEnd
    
    UDPCloseSocket($lUDPOpen)
    UDPCloseSocket($lUDPOpen)
    UDPCloseSocket($lUDPOpen)
EndFunc

Func _Console_PrintTime()
    Return "[" & @HOUR & ":" & @MIN & ":" & @SEC & "." & _Time_Milliseconds() & "] "
EndFunc

Func _Console_AddLine($pText)
    _Console_Add($pText & @CRLF)
EndFunc

Func _Console_Copy()
    ClipPut($mConsoleText)
EndFunc

Func _Console_Add($pText)
    _DEBUG("Console: " & $pText)
    
    $mConsoleText &= $pText
    
    FileWrite("console.log", $pText)
    
    GUICtrlSetData($Label1, $mConsoleText)
    ControlSend($Form1, "", $Label1, "^{END}")
EndFunc

Func _Console_Clear()
    $mConsoleText = ""
    GUICtrlSetData($Label1,"")
EndFunc

Func _Event_Browse()
    $lFileOpenDialog = FileOpenDialog("Source Dedicated Server Monitor", GUICtrlRead($Input2), "srcds.exe (srcds.exe)|Executables (*.exe)|All (*.*)",3,"srcds.exe",$Form1)
    If @error Then Return
    
    If Not FileExists($lFileOpenDialog) Then Return
    
    GUICtrlSetData($Input2, $lFileOpenDialog)
EndFunc

Func _Event_RestartNow()
    _DEBUG("Function: _Event_RestartNow()")
    
    $mRunning = False
    $mProcessID = 0
    _Console_AddLine(_Console_PrintTime() & "Restart server sequence started.")
    
    _Server_Force_Close()
    _Console_AddLine(_Console_PrintTime() & "Server process killed.")
    
    _Server_Start()
EndFunc

Func _Server_Force_Close()
    For $i = 0 to 10
        ProcessClose($mProcessID)
        ProcessClose("srcds.exe")
        If WinExists("srcds") Then
            $hWnd = WinGetHandle("srcds")
            WinClose($hWnd)
        EndIf
        Sleep(10)
    Next
EndFunc

Func _Server_Start()
    _DEBUG("Function: _Server_Start()")
    
    Dim $lConsecutiveFail = 0
    
    _Console_AddLine(_Console_PrintTime() & "Starting server: """ & $mPath & " " & $mParameter & '"')
    Run($mPath & " " & $mParameter)
    
    $lStartWait = TimerInit()
    While ProcessExists("srcds.exe")
        $lUDPOpen = UDPOpen($mIPAdress, $mPort)
        $lUDPSend = UDPSend($lUDPOpen, _Query_String() )
        
        For $x = 0 to 10
            $lReturnData = UDPRecv($lUDPOpen,200)
            If $lReturnData Then
                
                $mRunning = True
                $mServerRunning = True
                _Console_AddLine(_Console_PrintTime() & "Server up and running.")
                
                Return
            EndIf
            Sleep(50)
        Next
        
        UDPCloseSocket($lUDPOpen)
        UDPCloseSocket($lUDPOpen)
        UDPCloseSocket($lUDPOpen)
        
        If TimerDiff($lStartWait) > 5000 Then
            $lConsecutiveFail += 1
            If $lConsecutiveFail > 40 Then ; 2 minutes start up time max
                _Console_AddLine(_Console_PrintTime() & "Unable to start new server (Incorrect parameters?).")
                _Event_Monitor_Stop()
                ExitLoop
            EndIf
        EndIf
        Sleep(100)
    WEnd
    
    _Console_AddLine(_Console_PrintTime() & "Unable to start new server (Incorrect parameters?).")
    _Event_Monitor_Stop()
EndFunc

Func _Event_Close()
    $mPath = GUICtrlRead($Input2)
    $mParameter = GUICtrlRead($Input3)
    $mIPAdress = GUICtrlRead($Input4)
    $mPort = GUICtrlRead($Input5)
    
    IniWrite($mDBPath, "Data", "IP", $mIPAdress)
    IniWrite($mDBPath, "Data", "Port", $mPort)
    IniWrite($mDBPath, "Data", "Path", $mPath)
    IniWrite($mDBPath, "Data", "Parameter", $mParameter)
    
    Exit
EndFunc

Func _Event_About()
    $lMessageBoxResult = MsgBox(0x44, "Source Dedicated Server Monitor by Manadar.com", "Source Dedicated Server Monitor is copyrighted by Jos van Egmond" & @CRLF & _ 
    "Would you like to visit www.manadar.com?")
    If $lMessageBoxResult = 6 Then
        ShellExecute("http://www.manadar.com")
    EndIf
EndFunc

Func _Event_Monitor()
    GUICtrlSetState($Button1, $GUI_DISABLE)
    GUICtrlSetState($Input2, $GUI_DISABLE)
    GUICtrlSetState($Input3, $GUI_DISABLE)
    GUICtrlSetState($Button2, $GUI_DISABLE)
    GUICtrlSetState($Input4, $GUI_DISABLE)
    GUICtrlSetState($Input5, $GUI_DISABLE)
    
    $mPath = GUICtrlRead($Input2)
    $mParameter = GUICtrlRead($Input3)
    $mIPAdress = GUICtrlRead($Input4)
    $mPort = GUICtrlRead($Input5)
    
    $mRunning = True
    _Check_Handler()
EndFunc

Func _Event_Monitor_Stop()
    GUICtrlSetState($Button1, $GUI_ENABLE)
    GUICtrlSetState($Input2, $GUI_ENABLE)
    GUICtrlSetState($Input3, $GUI_ENABLE)
    GUICtrlSetState($Button2, $GUI_ENABLE)
    GUICtrlSetState($Input4, $GUI_ENABLE)
    GUICtrlSetState($Input5, $GUI_ENABLE)
    
    $mRunning = False
EndFunc

Func _Time_Milliseconds()
    Local $stSystemTime = DllStructCreate('ushort;ushort;ushort;ushort;ushort;ushort;ushort;ushort')
    
    DllCall('kernel32.dll', 'none', 'GetSystemTime', 'ptr', DllStructGetPtr($stSystemTime))
    
    $sMilliSeconds = StringFormat('%03d', DllStructGetData($stSystemTime, 8))
    $stSystemTime = 0
    
    Return $sMilliSeconds
EndFunc

Func _Query_String()
    $lHexQuery = "FF FF FF FF 54 53 6F 75 72 63 65 20 45 6E 67 69 6E 65 20 51 75 65 72 79 00 "
    
    $lSplit = StringSplit($lHexQuery," ")
    $lHexQuery = ""
    
    For $x = 1 to $lSplit[0]
        If $lSplit[$x] Then
            $lHexQuery &= Chr((Dec($lSplit[$x])))
        EndIf
    Next
    
    Return $lHexQuery
EndFunc

Bonus Crash Utility.

File: CrashTest.au3

#include <GUIConstants.au3>

#Region ### START Koda GUI section ### Form=
$Form1 = GUICreate("serverCrash Test Utility", 194, 82, 193, 115)
$Button1 = GUICtrlCreateButton("Crash", 8, 8, 179, 25, 0)
$Button2 = GUICtrlCreateButton("Uncrash", 8, 40, 179, 25, 0)
GUISetState(@SW_SHOW)
#EndRegion ### END Koda GUI section ###

While 1
    $nMsg = GUIGetMsg()
    Switch $nMsg
        Case $GUI_EVENT_CLOSE
            Exit
        Case $Button1
            _ProcessSuspend("srcds.exe")
        Case $Button2
            _ProcessResume("srcds.exe")
    EndSwitch
WEnd


Func _ProcessSuspend($process)
    $processid = ProcessExists($process)
    If $processid Then
        $ai_Handle = DllCall("kernel32.dll", 'int', 'OpenProcess', 'int', 0x1f0fff, 'int', False, 'int', $processid)
        $i_sucess = DllCall("ntdll.dll", "int", "NtSuspendProcess", "int", $ai_Handle[0])
        DllCall('kernel32.dll', 'ptr', 'CloseHandle', 'ptr', $ai_Handle)
        If IsArray($i_sucess) Then
            Return 1
        Else
            SetError(1)
            Return 0
        EndIf
    Else
        SetError(2)
        Return 0
    EndIf
EndFunc   ;==>_ProcessSuspend

Func _ProcessResume($process)
    $processid = ProcessExists($process)
    If $processid Then
        $ai_Handle = DllCall("kernel32.dll", 'int', 'OpenProcess', 'int', 0x1f0fff, 'int', False, 'int', $processid)
        $i_sucess = DllCall("ntdll.dll", "int", "NtResumeProcess", "int", $ai_Handle[0])
        DllCall('kernel32.dll', 'ptr', 'CloseHandle', 'ptr', $ai_Handle)
        If IsArray($i_sucess) Then
            Return 1
        Else
            SetError(1)
            Return 0
        EndIf
    Else
        SetError(2)
        Return 0
    EndIf
EndFunc   ;==>_ProcessResume
Edited by Manadar

Share this post


Link to post
Share on other sites



#2 ·  Posted (edited)

Updated to version 1.1

Changes:

- Perfect crash detection.

- Keeps a log of everything that happens.

- Added the ability to keep a debugging log.

Bugs fixed:

- Can no longer spaz out and start the server a lot.

I'm working on a 2.0 version with an improved GUI, web interface and generally more features. No, I am not.

Edited by Manadar

Share this post


Link to post
Share on other sites

How is progress with v2 ?

(I'm not using it, but many of my friends are interested)

Also, good job :D

Share this post


Link to post
Share on other sites

Thanks. Is the new version opensource ?

Share this post


Link to post
Share on other sites

Hey Manadar, could you please upload both those utilities again? The downloads are down.


[left][sub]We're trapped in the belly of this horrible machine.[/sub][sup]And the machine is bleeding to death...[/sup][sup][/sup][/left]

Share this post


Link to post
Share on other sites

#8 ·  Posted (edited)

I provided a link to them in post #4. I've edited the original post and fixed the links. Thanks for your interest.

Edit: Removed download links, added them as source to the post.

Edited by Manadar

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!


Register a new account

Sign in

Already have an account? Sign in here.


Sign In Now
Sign in to follow this  
Followers 0