How to remotely tell a Mac to sleep without using SSH?

0

I am needing assistance in getting a Mac to go to sleep without the usage of SSH. Almost any other method is acceptable.

Backstory: Product Salesman and Project Manger sold a thing without asking programmers. Programmers now how have to turn on and off a Mac using a product that can only send UDP and TCP strings/hex. It does allow Conduct the painful manual Telnet process, and SSH is completely out of the picture. We are 100% not MAC people.

Things we have tried:

  • homebrew's telnetd - refuses to open and console states running for 0 seconds, re-spawning in 10 seconds. Searching for how to debug this has lead to a hundred dead ends of "It should just work!" Which is useless when it doesn't.
  • Mac's NC command. While we were able to open an udp session back and forth between our control server and the Mac on ports 3000 and 3001, after googling and finangling this, come to find out not much more can be done with it as far as launching a command.
  • We attempted to put the NC command inside of a bash script.. this is going terrible, it appears in trying to capture the live output of NC it locks the script on that line and thus parsing never occurs. We did a super simple test script of the below.

     output=$(nc -u -l -k 3000; kill$!)
     echo "$output"
    

Again, Mac newbs, Bash newbs. Google and Stack Searchboxes have failed us! We did find the command of "pmset sleepnow" which does what we wan, so there's that.

Just looking for a simple way to take a UDP message of "sleep" and it puts the Mac to sleep.

Antony T.

Posted 2020-01-28T19:32:47.837

Reputation: 143

2Why exactly is SSH not an option? – Ecstasy – 2020-01-28T19:51:18.007

You could use Remote Apple Events for this. https://www.makeuseof.com/tag/remotely-control-mac-simple-applescripts/

– Spiff – 2020-01-28T20:01:23.170

@Spiff That looked promising at the beginning, but does this only work from one Mac to another? The automation control computer can basically send strings of Hex or ASCII via UDP or TCP. – Antony T. – 2020-01-28T20:12:51.027

@Ecstasy Conducting manual line by line SSH handshakes from a custom programming language (Product sold) or it's included javascript-ish engine which is half baked and doesn't allow libraries is more headache than there are hours in a month. – Antony T. – 2020-01-28T20:13:26.213

Answers

1

About nc and the script.

If nc you used is similar to the one in my Kubuntu (and it seems to be the OpenBSD implementation) then -k means "stay listening" and it will make the tool never exit by itself. But even without -k, nc using UDP will not be able to tell if the communication is over, because UDP is connectionless. When the first message is received, nc will fix on the address and port of the remote end; it will remain in this state unless you used -w.

If you allow nc to exit and only then you parse what it received, then there will be no listening process to handle a possible second connection attempt. Such primitive approach may be enough if any communication on the given port should put the computer to sleep:

nc -w 0 -u -l 3000 >/dev/null && echo "Sleep now!"
# replace echo with pmset or whatever

Using -w 0 and -k allows me to receive short messages sent from different addresses/ports. The tool will not exit but it's possible to pipe the received data to be analyzed:

nc -w 0 -k -u -l 3000 | while IFS= read -r line; do
   [ "$line" = sleep ] && echo "Sleep now!"
done
# replace echo with pmset or whatever

It may be OK for short UDP messages. In general there are few issues:

  • I guess messages incoming as two or more packets may trigger -w 0 prematurely. It's possible that longer transmissions from two sources will get interleaved. To prevent this you can:

    • use longer timeout (e.g. -w 1) and hope it's enough;
    • use TCP, so nc knows when the current connection ends (but note if the other device disappears without formally terminating the connection, nc will wait; so -w still seems useful; without -w the TCP keepalive mechanism will eventually terminate the connection and unblock nc, it may happen after two hours or so);
  • At least in my Kubuntu nc -k is good enough to handle multiple connections at once, i.e. it seems there is no gap in listening when it handles the very first connection. Still data from different connections appear in the stdout of nc in sequence, so as long as the first connection is alive, the while read … loop won't see anything from other connections. A single (rogue?) connection may prevent other (legitimate?) connections from triggering the desired action.

For these reasons an approach that analyzes data from each connection separately is advised. You can do this with socat. Compare this another answer of mine. In your case a basic stub may be:

socat -T 1 UDP-LISTEN:3000,fork SYSTEM:'
   IFS= read -r line && [ "$line" = sleep ] && echo "Sleep now!" >/dev/tty
'
# again, replace echo with pmset or whatever

There is no loop in the shell code. From each incoming connection we read and test exactly one line.

Notes:

  • I used socat available in my Kubuntu. I don't really know Mac, but see this.
  • There is absolutely no authentication.
  • IFS= read -r line expects a properly terminated line, so the connecting device should send like sleep\n where \n denotes the newline character (LF, 0x0A).

Kamil Maciorowski

Posted 2020-01-28T19:32:47.837

Reputation: 38 429

0

The long nc answer is probably the best one, especially if you're not familiar with Macs (but are with Linux). Another option, which I have used in the past, is to write a simple CGI script (if you're OK with running Apache on the Mac). Whenever the CGI is run, it can create a file in a certain directory (anywhere, it doesn't really matter, as long as Apache/CGI can write there).

Then, separately, write a launchd agent (like a service/daemon in other Linuxes) that is "listening" for files in this directory. When the agent (really, the script behind the agent) detects the file, put the Mac to sleep!

It's more convoluted, but I have used it before! For some reason (security, I assume) you can just call an sleep-inducing executable or an AppleScript directly from the CGI, so using this file as a semaphore is a decent workaround.

jimtut

Posted 2020-01-28T19:32:47.837

Reputation: 832