17 function escape($data)
19 return addcslashes($data,
"\x00..\x1F\x7F..\xFF");
22 function signal_handler($signo)
24 $logging = \Plop\Plop::getInstance();
26 "Received signal #%d. Shutting down...",
32 function main($confFile =
'pssht.xml')
34 $hasSignalDispatch = function_exists(
'pcntl_signal_dispatch');
35 if (extension_loaded(
'pcntl')) {
36 pcntl_signal(SIGTERM,
'signal_handler');
37 pcntl_signal(SIGINT,
'signal_handler');
40 $home = getenv(
'HOME');
41 $user = getenv(
'USER');
42 if (extension_loaded(
'posix')) {
43 $entry = posix_getpwuid(posix_geteuid());
44 $home = $entry[
'dir'];
45 $user = $entry[
'name'];
49 $container =
new ContainerBuilder();
50 $container->setParameter(
'CWD', getcwd());
51 $container->setParameter(
'HOME', $home);
52 $container->setParameter(
'USER', $user);
53 $container->setParameter(
'pssht.base_dir', dirname(__DIR__));
55 $loader =
new XmlFileLoader($container,
new FileLocator(getcwd()));
57 $loader->load($confFile);
58 }
catch (\InvalidArgumentException $e) {
59 $logging = \Plop\Plop::getInstance();
60 $logging->error($e->getMessage());
63 $container->get(
'logging', ContainerInterface::NULL_ON_INVALID_REFERENCE);
64 $logging = \Plop\Plop::getInstance();
66 "pssht %s is starting (PID %d)",
67 array(PSSHT_VERSION, getmypid())
71 \fpoirotte\Pssht\ECC\Curve::initialize();
77 $sockets = array(
'servers' => array(),
'clients' => array());
80 $listen = (array) $container->getParameter(
'listen');
81 foreach ($listen as $spec) {
82 $socket = stream_socket_server(
"tcp://$spec");
83 $sockets[
'servers'][] = $socket;
84 $address = stream_socket_get_name($socket,
false);
85 $logging->info(
"Listening for new connections on %s", array($address));
89 $read = array_merge($sockets[
'servers'], $sockets[
'clients']);
93 foreach ($clients as $id => $client) {
94 if (count($client->getEncoder()->getBuffer())) {
95 $write[] = $sockets[
'clients'][$id];
99 if (@stream_select($read, $write, $except, 2) ===
false) {
101 'Error while waiting for activity on sockets: %s',
102 array(socket_strerror(socket_last_error()))
107 if ($hasSignalDispatch) {
108 function_exists(
'pcntl_signal_dispatch');
111 foreach ($read as $socket) {
112 if (in_array($socket, $sockets[
'servers'],
true)) {
113 $new = stream_socket_accept($socket);
114 if ($new ===
false) {
116 'Could not accept new client: %s',
117 array(socket_strerror(socket_last_error()))
122 for ($id = 0; isset($sockets[
'clients'][$id]); $id++) {
125 $sockets[
'clients'][$id] = $new;
126 $peer = stream_socket_get_name($new,
true);
128 '#%(id)d New client connected from %(peer)s',
129 array(
'id' => $id,
'peer' => $peer)
131 $client = $container->get(
'client');
132 $clients[$id] = $client;
133 $client->setAddress(substr($peer, 0, strrpos($peer,
':')));
137 $data = fread($socket, 8192);
138 $peer = stream_socket_get_name($socket,
true);
141 $id = array_search($socket, $sockets[
'clients'],
true);
143 '#%(id)d Client disconnected from %(peer)s (socket closed)',
144 array(
'id' => $id,
'peer' => $peer)
147 } elseif ($data !==
false) {
148 $length = strlen($data);
149 $id = array_search($socket, $sockets[
'clients'],
true);
150 $clients[$id]->getDecoder()->getBuffer()->push($data);
154 '#%(id)d Received %(length)d bytes from %(peer)s',
155 array(
'id' => $id,
'peer' => $peer,
'length' => $length)
157 $logging->log(5,
'%s', array(escape($data)));
162 while ($clients[$id]->readMessage()) {
168 }
catch (\
fpoirotte\Pssht\Messages\DISCONNECT $e) {
170 '#%(id)d Client disconnected from %(peer)s ' .
171 '(DISCONNECT message received)',
172 array(
'id' => $id,
'peer' => $peer)
174 }
catch (\Exception $e) {
176 '#%(id)d Client disconnected from %(peer)s ' .
179 array(
'id' => $id,
'peer' => $peer)
186 unset($sockets[
'clients'][$id]);
187 unset($clients[$id]);
191 foreach ($write as $socket) {
192 $id = array_search($socket, $sockets[
'clients'],
true);
197 $peer = stream_socket_get_name($socket,
true);
198 $buffer = $clients[$id]->getEncoder()->getBuffer();
199 $size = count($buffer);
200 $data = $buffer->get($size);
202 $written = fwrite($socket, $data);
203 if ($written ===
false) {
209 "#%(id)d Sent %(written)d bytes to %(peer)s",
210 array(
'id' => $id,
'peer' => $peer,
'written' => $written)
212 $logging->log(5,
'%s', array(escape(substr($data, 0, $written))));
213 $data = substr($data, $written);
214 $clients[$id]->updateWriteStats($written);
218 if (!$clients[$id]->isConnected()) {
220 unset($sockets[
'clients'][$id]);
221 unset($clients[$id]);