ChessMate Posted January 14, 2022 Share Posted January 14, 2022 (edited) Hello, I am working on a script to automate the nginx certificate renewal. I need to work on a kind of command prompt to do this so I work with STDOut and and STDIn. The two first answers are working just fine. The third seems to send a blank value so the script failed to proceed to the next answer. The two first need only to send one character but the third need to send a word so it could be the issue. Do you have any idea what could cause this issue ? StdInWrite is supposed to be able to send a word (with only standard ASCII character) without any problem so I don't understand. expandcollapse popup#include <Constants.au3> #include <AutoItConstants.au3> #include <MsgBoxConstants.au3> #include <InetConstants.au3> #include <WinAPIFiles.au3> #include <StringConstants.au3> ;Pour renouveler le certificat nginx Global $intPID = 0, _ $strSTDOutRead = "" $intPID = Run("C:\nginx\win-acme.v2" & "\wacs.exe", "", @SW_SHOW, $STDIN_CHILD + $STDOUT_CHILD) If $intPID = 0 Then ConsoleWrite("Error while running the application '" & "wacs.exe" & "'. Error: " & @error & @CRLF) Else While 1 $strSTDOutRead &= StdoutRead($intPID) If @error Then ExitLoop If StringInStr($strSTDOutRead, "Please choose from the menu:") Then StdinWrite($intPID, "M") ; Full options StdinWrite($intPID) ExitLoop EndIf WEnd While 1 $strSTDOutRead &= StdoutRead($intPID) If @error Then ExitLoop If StringInStr($strSTDOutRead, "How shall we determine the domain(s) to include in the certificate?:") Then StdinWrite($intPID, "2") ; Manual input StdinWrite($intPID) ExitLoop EndIf WEnd While 1 $strSTDOutRead &= StdoutRead($intPID) If @error Then ExitLoop If StringInStr($strSTDOutRead, "Host:") Then StdinWrite($intPID, "*.repl-aced.com") ; Domain name StdinWrite($intPID) ExitLoop EndIf WEnd While 1 $strSTDOutRead &= StdoutRead($intPID) If @error Then ExitLoop If StringInStr($strSTDOutRead, "to accept or type an alternative:") Then StdinWrite($intPID, "{ENTER}") ; Accept StdinWrite($intPID) ConsoleWrite("Test6") ExitLoop EndIf MsgBox($MB_ICONINFORMATION, "", $strSTDOutRead) Return WEnd EndIf Edited January 17, 2022 by ChessMate Link to comment Share on other sites More sharing options...
markyrocks Posted January 14, 2022 Share Posted January 14, 2022 (edited) you can try using some sleeps in there. Just bc your code starts reading the stdOut buffer (or tries to ) that doesn't mean that it has been released by the sending process. The right way to do it is to use a mutex and lock the std handle object and wait for it to actually locks (it won't if the other process has control of it). There should be a mutexwait function if not I know theres a waitforobject function in the win api udf. The mutex wont lock until the handle returns the free signal. That stdoutread just looks at the stdout buffer if its empty it leaves. You looking may actually be preventing the write on the other end. It really just depends on what stdout() is doing exactly. A mutex is pretty much the standard for dealing with shared objects. Well not around here but everywhere else. Edited January 14, 2022 by markyrocks Spoiler "I Believe array math to be potentially fatal, I may be dying from array math poisoning" Link to comment Share on other sites More sharing options...
ChessMate Posted January 14, 2022 Author Share Posted January 14, 2022 (edited) I have had a hard time understanding what is a muttex and how it works and using Sleep even for 10 seconds doesn't work to fix this. The StdInWrite($intPID) without paratmeter is supposed to forcefully close the current STDinWrite stream so the sending process is supposed to be stopped. I have tried this and _WinAPI_WaitForSingleObject but both these WinAPI functions return : While 1 $strSTDOutRead &= StdoutRead($intPID) If @error Then ExitLoop If StringInStr($strSTDOutRead, "Host:") Then _WinAPI_CreateMutex($intPID) StdinWrite($intPID, "*.repl-aced.com") ; Domain name StdinWrite($intPID) ExitLoop EndIf WEnd As WinAPIFiles.au3 is included, I don't understand the issue. Edited January 14, 2022 by ChessMate Link to comment Share on other sites More sharing options...
ChessMate Posted January 14, 2022 Author Share Posted January 14, 2022 You were right, the StdOutRead monopolize the connexion. I manage to use _Singleton to check it. However, how am I supposed to kill the StdOutRead process to let the StdInWrite answer ? Something must replace this Sleep(1000) but ProcessClose($strSTDOutRead) for example doesn't work. While 1 $strSTDOutRead &= StdoutRead($intPID) If @error Then ExitLoop If StringInStr($strSTDOutRead, "Host:") Then While(_Singleton ( $intPID , 1 )=0) Sleep(1000) WEnd StdinWrite($intPID) StdinWrite($intPID, "*.repl-aced.com") ; Domain name StdinWrite($intPID) ConsoleWrite("Test3") ExitLoop EndIf WEnd Link to comment Share on other sites More sharing options...
Solution KaFu Posted January 14, 2022 Solution Share Posted January 14, 2022 (edited) "StdoutRead() does not block, it will return immediately." Try adding " & @LF" to the end of your StdinWrite() calls, as this does normally trigger execution. StdinWrite(PID) > maybe remove these calls? If the stream is closed, it's gone. "If the function is called with no second argument, StdinWrite() closes the stream and invalidates it for further writing." Edited January 14, 2022 by KaFu ChessMate 1 OS: Win10-22H2 - 64bit - German, AutoIt Version: 3.3.16.1, AutoIt Editor: SciTE, Website: https://funk.eu AMT - Auto-Movie-Thumbnailer (2024-Oct-13) BIC - Batch-Image-Cropper (2023-Apr-01) COP - Color Picker (2009-May-21) DCS - Dynamic Cursor Selector (2024-Oct-13) HMW - Hide my Windows (2024-Oct-19) HRC - HotKey Resolution Changer (2012-May-16) ICU - Icon Configuration Utility (2018-Sep-16) SMF - Search my Files (2024-Oct-20) - THE file info and duplicates search tool SSD - Set Sound Device (2017-Sep-16) Link to comment Share on other sites More sharing options...
ChessMate Posted January 14, 2022 Author Share Posted January 14, 2022 It worked, thank you KaFu: Just to better understand the issue, why was StdinWrite($intPID, "2") working and StdinWrite($intPID, "*.repl-aced.com") not working when they were both after a StdInWrite without arguments ? Here is the functional code : expandcollapse popup #include <Constants.au3> #include <AutoItConstants.au3> #include <MsgBoxConstants.au3> #include <InetConstants.au3> #include <WinAPIFiles.au3> #include <StringConstants.au3> #include <Misc.au3> ;Pour renouveler le certificat nginx Global $intPID = 0, _ $strSTDOutRead = "" $intPID = Run("C:\nginx\win-acme.v2" & "\wacs.exe", "", @SW_SHOW, $STDIN_CHILD + $STDOUT_CHILD) If $intPID = 0 Then ConsoleWrite("Error while running the application '" & "wacs.exe" & "'. Error: " & @error & @CRLF) Else $SintPID=_Singleton($intPID ,1) If $SintPID = 0 Then MsgBox($MB_SYSTEMMODAL, "Warning", "An occurence of test is already running") Exit EndIf MsgBox($MB_SYSTEMMODAL, "OK", "the first occurence of test is running") While 1 $strSTDOutRead &= StdoutRead($intPID) If @error Then ExitLoop If StringInStr($strSTDOutRead, "Please choose from the menu:") Then StdinWrite($intPID, "M"& @LF) ; Full options ConsoleWrite("Test1 ") ExitLoop EndIf WEnd While 1 $strSTDOutRead &= StdoutRead($intPID) If @error Then ExitLoop If StringInStr($strSTDOutRead, "How shall we determine the domain(s) to include in the certificate?:") Then ;_WinAPI_CreateMutex($intPID) StdinWrite($intPID, "2"& @LF) ; Manual input ConsoleWrite("Test2 ") ExitLoop EndIf WEnd While 1 $strSTDOutRead &= StdoutRead($intPID) If @error Then ExitLoop If StringInStr($strSTDOutRead, "Host:") Then StdinWrite($intPID, "*.repl-aced.com"& @LF) ; Domain name ConsoleWrite("Test3") ExitLoop EndIf WEnd While 1 $strSTDOutRead &= StdoutRead($intPID) If @error Then ExitLoop If StringInStr($strSTDOutRead, "to accept or type an alternative:") Then StdinWrite($intPID, "{ENTER}"& @LF) ; Accept ConsoleWrite("Test4") ExitLoop EndIf MsgBox($MB_ICONINFORMATION, "", $strSTDOutRead) Return WEnd EndIf Link to comment Share on other sites More sharing options...
markyrocks Posted January 14, 2022 Share Posted January 14, 2022 https://www.autoitscript.com/autoit3/docs/libfunctions/_WinAPI_GetStdHandle.htm gets the handle to the specific stream. https://www.autoitscript.com/autoit3/docs/libfunctions/_WinAPI_WaitForSingleObject.htm wait for the handle to signal released. https://www.autoitscript.com/autoit3/docs/libfunctions/_WinAPI_CreateMutex.htm you can optionally create a mutex around the attempts to read the stream bc you may be interupted by the sender. when you'r done call mutex release close the mutex handle. This is pretty basic stuff in the world of multithreaded programming. I've used it in autoit b4 so i know it works. They don't exactly make it easy, its more straight forward in other languages. Spoiler "I Believe array math to be potentially fatal, I may be dying from array math poisoning" Link to comment Share on other sites More sharing options...
KaFu Posted January 14, 2022 Share Posted January 14, 2022 (edited) 1 hour ago, ChessMate said: Just to better understand the issue, why was StdinWrite($intPID, "2") working and StdinWrite($intPID, "*.repl-aced.com") not working when they were both after a StdInWrite without arguments ? You're sure it really worked? Normally without a @LF (which is like hitting enter on the console) no command is executed. Maybe the @errors were triggered (no data) and that's why those loops were exited. You have to give the server process time to execute and answer, so normally I would first loop idly in StdoutRead() to receive an answer at all (maybe with a time-out), and then only exist the loop once data was received and no more is coming. Otherwise you might issue commands too fast for the server to respond properly. Edited January 14, 2022 by KaFu OS: Win10-22H2 - 64bit - German, AutoIt Version: 3.3.16.1, AutoIt Editor: SciTE, Website: https://funk.eu AMT - Auto-Movie-Thumbnailer (2024-Oct-13) BIC - Batch-Image-Cropper (2023-Apr-01) COP - Color Picker (2009-May-21) DCS - Dynamic Cursor Selector (2024-Oct-13) HMW - Hide my Windows (2024-Oct-19) HRC - HotKey Resolution Changer (2012-May-16) ICU - Icon Configuration Utility (2018-Sep-16) SMF - Search my Files (2024-Oct-20) - THE file info and duplicates search tool SSD - Set Sound Device (2017-Sep-16) Link to comment Share on other sites More sharing options...
ChessMate Posted January 17, 2022 Author Share Posted January 17, 2022 On 1/14/2022 at 3:05 PM, KaFu said: You're sure it really worked? Normally without a @LF (which is like hitting enter on the console) no command is executed. Maybe the @errors were triggered (no data) and that's why those loops were exited. You have to give the server process time to execute and answer, so normally I would first loop idly in StdoutRead() to receive an answer at all (maybe with a time-out), and then only exist the loop once data was received and no more is coming. Otherwise you might issue commands too fast for the server to respond properly. The two first questions were directly following each other in the prompt, not the third so I guess based on your answer that the interval between the two first is short enough to be shorter than the interval between the inputs. StdinWrite($intPID) probably managed to send a kind of enter signal too, even if it was not the proper way to realize it. Link to comment Share on other sites More sharing options...
Recommended Posts
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 accountSign in
Already have an account? Sign in here.
Sign In Now