1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
|
<?php
namespace gipfl\SystemD;
use RuntimeException;
use function file_exists;
use function is_writable;
class NotificationSocket
{
/** @var resource */
protected $socket;
/** @var string */
protected $path;
/**
* @param string $path
*/
public function __construct($path)
{
if (@file_exists($path) && is_writable($path)) {
$this->path = $path;
} else {
throw new RuntimeException("Unix Socket '$path' is not writable");
}
$this->connect();
}
/**
* Send custom parameters to systemd
*
* This is for internal use only, but might be used to test new functionality
*
* @param array $params
* @internal
*/
public function send(array $params)
{
$message = $this->buildMessage($params);
$length = \strlen($message);
$result = @socket_send($this->socket, $message, $length, 0);
if ($result === false) {
$error = \socket_last_error($this->socket);
throw new RuntimeException(
"Failed to send to SystemD: " . \socket_strerror($error),
$error
);
}
if ($result !== $length) {
throw new RuntimeException(
"Wanted to send $length Bytes to SystemD, only $result have been sent"
);
}
}
/**
* Get the path to the the systemd notification socket
*
* Usually /run/systemd/notify or similar
*
* @return string
*/
public function getPath()
{
return $this->path;
}
/**
* Transforms a key/value array into a string like "key1=val1\nkey2=val2"
*
* @param array $params
* @return string
*/
protected function buildMessage(array $params)
{
$message = '';
foreach ($params as $key => $value) {
$message .= "$key=$value\n";
}
return $message;
}
/**
* Connect to the discovered socket
*
* Will be /run/systemd/notify or similar. No async logic, as this
* shouldn't block. If systemd blocks we're dead anyway, so who cares
*/
protected function connect()
{
$path = $this->path;
$socket = @\socket_create(AF_UNIX, SOCK_DGRAM, 0);
if ($socket === false) {
throw new RuntimeException('Unable to create socket');
}
if (! @\socket_connect($socket, $path)) {
$error = \socket_last_error($socket);
throw new RuntimeException(
"Unable to connect to unix domain socket $path: " . \socket_strerror($error),
$error
);
}
$this->socket = $socket;
}
/**
* Disconnect the socket if connected
*/
public function disconnect()
{
if (\is_resource($this->socket)) {
@\socket_close($this->socket);
$this->socket = null;
}
}
public function __destruct()
{
$this->disconnect();
}
}
|