📜 ⬆️ ⬇️

Sleep and use InternetSharing on Macbook

The article describes how to automatically disable / enable InternetSharing, which prevents the Macbook from entering sleep mode or re-awakens the laptop if you manually put it to sleep.

Prehistory

I work on a Macbook, there is no 3G in the room. When connecting a laptop to the network via RJ-45, it is convenient to use InternetSharing (hereinafter IS), since some work is connected with mobile devices. Once having set up IS, I forgot about the problem with the Internet on the phone, however I began to notice when I came to work, the laptop was turned on. The first time did not attach importance. The second time I decided to look in the logs, when he turns it on. It turned out that it turns on after a couple of minutes, as I put it into sleep mode.

As it turned out the IS service blocks sleep while it is active.
Team
pmset -g assertions 
will point out that IS is guilty:
pid 70000: [0x000 ... 000] PreventSystemSleep named: "com.apple.InternetSharing".

I began to look for how people solve a similar problem, but only ran into "turn off the service."
I had to solve the problem myself.
')
What to do?

As it turned out, the configured IS service starts and stops using the file:
/System/Library/LaunchDaemons/com.apple.InternetSharing.plist

The solution turned out to be this: turn on the service when waking up and off when going into sleep mode, that is, use the following commands:


But for these operations, it is required to enter the password of the user with administrator rights.

It remains to learn "How to run the program upon waking up and when going to sleep" and at the same time would not require entering a password.

Decision

The first is to make our service, which will run as administrator, that is, do not require a password to be entered for launchctl.
The second - will send our service team on waking up and going to sleep, respectively, start and stop.

So, the service will listen on the port, for example, 10001 and wait for the start and stop commands.
Let's write the service in PHP (full code below), respectively, to start IS and stop it, the following actions will be performed:
for start:
 shell_exec('launchctl load -F /System/Library/LaunchDaemons/com.apple.InternetSharing.plist'); 

to stop:
 shell_exec('launchctl unload /System/Library/LaunchDaemons/com.apple.InternetSharing.plist'); 


To start our service, you need to place the com.username.InternetSharing.plist file in the /Library/LaunchDaemons/ folder.
Run with the command:
 sudo launchctl load -F /Library/LaunchDaemons/com.username.InternetSharing.plist 


In order to catch the events of awakening and go to sleep, we use the Scenario program. Let's write for it on AppleScripts two creaks that will call the client program (full code below) with the parameter start or stop.

Startup script
do shell script "/usr/bin/php /Users/username/CheckMac/client.php start"
Stop script
do shell script "/usr/bin/php /Users/username/CheckMac/client.php stop"

Place them in the special directories of the Scenario program:
"~/Library/Scenario/Wake Scripts" and "~/Library/Scenario/Sleep Scripts" .

Result

When enabled, the Scenario program runs the script from the " Wake Scripts " folder, which launches the Client program with the start parameter. The client program is associated with our service, which can start the IS service, as it has sufficient rights.
When switching to sleep mode, a similar operation is performed, only with the " Sleep Scripts " folder and with the stop parameter.

Code

Service

/Users/username/CheckMac/listen.php
 <?php // PHP 5.3.10 //   error_reporting(E_ALL ^ E_WARNING); set_time_limit(0); ob_implicit_flush(); $port = 10001; $sock = socket_create(AF_INET, SOCK_STREAM, SOL_TCP); socket_bind($sock, "127.0.0.1", $port) or die('Port listened'."\n"); socket_set_option($sock, SOL_SOCKET, SO_KEEPALIVE, 1); socket_set_nonblock($sock); socket_listen($sock, 1000); $clients = array($sock); $tarr = array(); $iparr = array(); $current = 0; while (true) { $read = $clients; if (count($tarr) > 0) foreach ($tarr as $ind => $tim) { //      10  -  if ((time() - $tim) > 10) { socket_close($read[$ind + 1]); unset($clients[$ind+1]); unset($iparr[$ind]); unset($tarr[$ind]); echo "Disconnect client.\n"; continue; } } //    -  if (socket_select($read, $write = NULL, $except = NULL, 1) < 1) continue; //   if (in_array($sock, $read)) { $current ++; $clients[$current] = $newsock = socket_accept($sock); socket_write($newsock, "<OK>\n"); socket_getpeername($newsock, $ip); echo "New connection from ip: {$ip}\n"; $key = array_search($sock, $read); $iparr[$current-1] = $ip; $tarr[$current-1] = time(); unset($read[$key]); $read[$current] = $newsock; continue; } //   foreach ($read as $index => $read_sock) { $data = socket_read($read_sock, 1024); if ($data === false) { $key = array_search($read_sock, $clients); unset($clients[$key]); unset($iparr[$key - 1]); echo "Disconnect client.\n"; unset($tarr[$key - 1]); continue; } $data = trim($data); //    if (!empty($data)) { echo $iparr[$index - 1] . "[$index] - $data\n"; $tarr[$index - 1] = time(); switch ($data) { case "quit": socket_close($read_sock); $key = array_search($read_sock, $clients); unset($clients[$key]); unset($iparr[$key - 1]); echo "Disconnect client.\n"; unset($tarr[$key - 1]); break; case "ping": socket_write($read_sock, "<PONG> " . time() . "\n"); break; //     IS case 'start': $s = shell_exec('launchctl list'); if(strpos($s, 'com.apple.InternetSharing') === false){ shell_exec('launchctl load -F /System/Library/LaunchDaemons/com.apple.InternetSharing.plist'); } break; //     IS case 'stop': $s = shell_exec('launchctl list'); if(strpos($s, 'com.apple.InternetSharing') !== false){ shell_exec('launchctl unload /System/Library/LaunchDaemons/com.apple.InternetSharing.plist'); } break; } if ($data === "close") { socket_close($sock); break(2); } } } } socket_close($sock); 

com.username.InternetSharing.plist

/Library/LaunchDaemons/com.username.InternetSharing.plist
 <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> <key>Label</key> <string>com.username.InternetSharing</string> <key>ProgramArguments</key> <array> <string>/usr/bin/php</string> <string>/Users/username/CheckMac/listen.php</string> </array> <key>RunAtLoad</key> <true/> </dict> </plist> 

Client program

/Users/username/CheckMac/client.php
 <?php $fp = fsockopen("127.0.0.1", 10001, $errno, $errstr, 30); if (!$fp) { echo "$errstr ($errno)<br />\n"; } else { $out = @$argv[1]."\r\n"; fwrite($fp, $out); fgets($fp, 128); sleep(1); //       $out = "quit\r\n"; fwrite($fp, $out); fgets($fp, 128); fclose($fp); } 

IS launch script (Not a text file - created by AppleScripts)

~ / Library / Scenario / Wake Scripts / wake.scpt
do shell script "/usr/bin/php /Users/username/CheckMac/client.php start"

Script oastnova IS

~ / Library / Scenario / Sleep Scripts / sleep.scpt
do shell script "/usr/bin/php /Users/username/CheckMac/client.php stop"

Source: https://habr.com/ru/post/150617/


All Articles