Skip to content

Commit 77cf445

Browse files
committed
Initial locking support (on Communicator, Request, Response, Query and login).
1 parent 81e22ca commit 77cf445

File tree

5 files changed

+139
-22
lines changed

5 files changed

+139
-22
lines changed

src/PEAR2/Net/RouterOS/Client.php

Lines changed: 35 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,11 @@
2020
*/
2121
namespace PEAR2\Net\RouterOS;
2222

23+
/**
24+
* Refers to transmitter direction constants.
25+
*/
26+
use PEAR2\Net\Transmitter as T;
27+
2328
/**
2429
* A RouterOS client.
2530
*
@@ -160,23 +165,19 @@ public static function login(Communicator $com, $username, $password = '')
160165
$password
161166
);
162167
}
163-
168+
$old = null;
164169
try {
165-
$request = new Request('/login');
166-
$request->send($com);
167-
$response = new Response($com);
168-
$request->setArgument('name', $username);
169-
$request->setArgument(
170-
'response', '00' . md5(
171-
chr(0) . $password
172-
. pack('H*', $response->getArgument('ret'))
173-
)
174-
);
175-
$request->send($com);
176-
$response = new Response($com);
177-
return $response->getType() === Response::TYPE_FINAL
178-
&& null === $response->getArgument('ret');
170+
if ($com->getTransmitter()->isPersistent()) {
171+
$old = $com->getTransmitter()->lock(T\Stream::DIRECTION_ALL);
172+
$result = self::_performLogin($com, $username, $password);
173+
$com->getTransmitter()->lock($old, true);
174+
return $result;
175+
}
176+
return self::_performLogin($com, $username, $password);
179177
} catch (\Exception $e) {
178+
if ($com->getTransmitter()->isPersistent() && null !== $old) {
179+
$com->getTransmitter()->lock($old, true);
180+
}
180181
throw ($e instanceof NotSupportedException
181182
|| $e instanceof UnexpectedValueException
182183
|| !$com->getTransmitter()->isDataAwaiting()) ? new SocketException(
@@ -185,6 +186,25 @@ public static function login(Communicator $com, $username, $password = '')
185186
}
186187
}
187188

189+
private static function _performLogin(
190+
Communicator $com, $username, $password
191+
) {
192+
$request = new Request('/login');
193+
$request->send($com);
194+
$response = new Response($com);
195+
$request->setArgument('name', $username);
196+
$request->setArgument(
197+
'response', '00' . md5(
198+
chr(0) . $password
199+
. pack('H*', $response->getArgument('ret'))
200+
)
201+
);
202+
$request->send($com);
203+
$response = new Response($com);
204+
return $response->getType() === Response::TYPE_FINAL
205+
&& null === $response->getArgument('ret');
206+
}
207+
188208
/**
189209
* Sets the charset(s) for this connection.
190210
*

src/PEAR2/Net/RouterOS/Communicator.php

Lines changed: 59 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ class Communicator
8282
protected $charsets = array();
8383

8484
/**
85-
* @var TcpClient The transmitter for the connection.
85+
* @var T\TcpClient The transmitter for the connection.
8686
*/
8787
protected $trans;
8888

@@ -317,6 +317,12 @@ public function sendWord($word)
317317
}
318318
$length = strlen($word);
319319
static::verifyLengthSupport($length);
320+
if ($this->trans->isPersistent()) {
321+
$old = $this->trans->lock(T\Stream::DIRECTION_SEND);
322+
$bytes = $this->trans->send(self::encodeLength($length) . $word);
323+
$this->trans->lock($old, true);
324+
return $bytes;
325+
}
320326
return $this->trans->send(self::encodeLength($length) . $word);
321327
}
322328

@@ -440,7 +446,18 @@ public static function encodeLength($length)
440446
*/
441447
public function getNextWord()
442448
{
443-
$word = $this->trans->receive(self::decodeLength($this->trans), 'word');
449+
if ($this->trans->isPersistent()) {
450+
$old = $this->trans->lock(T\Stream::DIRECTION_RECEIVE);
451+
$word = $this->trans->receive(
452+
self::decodeLength($this->trans), 'word'
453+
);
454+
$this->trans->lock($old, true);
455+
} else {
456+
$word = $this->trans->receive(
457+
self::decodeLength($this->trans), 'word'
458+
);
459+
}
460+
444461
if (null !== ($remoteCharset = $this->getCharset(self::CHARSET_REMOTE))
445462
&& null !== ($localCharset = $this->getCharset(self::CHARSET_LOCAL))
446463
) {
@@ -450,6 +467,7 @@ public function getNextWord()
450467
$word
451468
);
452469
}
470+
453471
return $word;
454472
}
455473

@@ -473,9 +491,19 @@ public function getNextWordAsStream()
473491
$remoteCharset . '.' . $localCharset . '//IGNORE//TRANSLIT'
474492
);
475493
}
476-
$stream = $this->trans->receiveStream(
477-
self::decodeLength($this->trans), $filters, 'stream word'
478-
);
494+
495+
if ($this->trans->isPersistent()) {
496+
$old = $this->trans->lock(T\Stream::DIRECTION_RECEIVE);
497+
$stream = $this->trans->receiveStream(
498+
self::decodeLength($this->trans), $filters, 'stream word'
499+
);
500+
$this->trans->lock($old, true);
501+
} else {
502+
$stream = $this->trans->receiveStream(
503+
self::decodeLength($this->trans), $filters, 'stream word'
504+
);
505+
}
506+
479507
return $stream;
480508
}
481509

@@ -491,6 +519,31 @@ public function getNextWordAsStream()
491519
* @return int The decoded length
492520
*/
493521
public static function decodeLength(T\Stream $trans)
522+
{
523+
if ($trans->isPersistent()) {
524+
$old = $trans->lock($trans::DIRECTION_RECEIVE);
525+
$length = self::_decodeLength($trans);
526+
$trans->lock($old, true);
527+
return $length;
528+
}
529+
return self::_decodeLength($trans);
530+
}
531+
532+
/**
533+
* Decodes the lenght of the incoming message.
534+
*
535+
* Decodes the lenght of the incoming message, as specified by the RouterOS
536+
* API.
537+
*
538+
* Difference with the non private function is that this one doesn't perform
539+
* locking if the connection is a persistent one.
540+
*
541+
* @param T\Stream $trans The transmitter from which to decode the length of
542+
* the incoming message.
543+
*
544+
* @return int The decoded length
545+
*/
546+
private static function _decodeLength(T\Stream $trans)
494547
{
495548
$byte = ord($trans->receive(1, 'initial length byte'));
496549
if ($byte & 0x80) {
@@ -508,7 +561,7 @@ public static function decodeLength(T\Stream $trans)
508561
+ (double) sprintf('%u', $rem['~']);
509562
}
510563
throw new NotSupportedException(
511-
'Unknown control byte encountered.', 1600, null, $byte
564+
'Unknown control byte encountered.', 1601, null, $byte
512565
);
513566
} else {
514567
return $byte;

src/PEAR2/Net/RouterOS/Query.php

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,11 @@
2020
*/
2121
namespace PEAR2\Net\RouterOS;
2222

23+
/**
24+
* Refers to transmitter direction constants.
25+
*/
26+
use PEAR2\Net\Transmitter as T;
27+
2328
/**
2429
* Represents a query for RouterOS requests.
2530
*
@@ -168,6 +173,17 @@ public function andWhere($name, $value = null, $action = self::ACTION_EXIST)
168173
* @return int The number of bytes sent.
169174
*/
170175
public function send(Communicator $com)
176+
{
177+
if ($com->getTransmitter()->isPersistent()) {
178+
$old = $com->getTransmitter()->lock(T\Stream::DIRECTION_SEND);
179+
$bytes = $this->_send($com);
180+
$com->getTransmitter()->lock($old, true);
181+
return $bytes;
182+
}
183+
return $this->_send($com);
184+
}
185+
186+
private function _send(Communicator $com)
171187
{
172188
if (!$com->getTransmitter()->isAcceptingData()) {
173189
throw new SocketException(

src/PEAR2/Net/RouterOS/Request.php

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,11 @@
2020
*/
2121
namespace PEAR2\Net\RouterOS;
2222

23+
/**
24+
* Refers to transmitter direction constants.
25+
*/
26+
use PEAR2\Net\Transmitter as T;
27+
2328
/**
2429
* Represents a RouterOS request.
2530
*
@@ -238,6 +243,29 @@ public function removeAllArguments()
238243
* @see Client::sendAsync()
239244
*/
240245
public function send(Communicator $com)
246+
{
247+
if ($com->getTransmitter()->isPersistent()) {
248+
$old = $com->getTransmitter()->lock(T\Stream::DIRECTION_SEND);
249+
$bytes = $this->_send($com);
250+
$com->getTransmitter()->lock($old, true);
251+
return $bytes;
252+
}
253+
return $this->_send($com);
254+
}
255+
256+
/**
257+
* Sends a request over a communicator.
258+
*
259+
* The only difference with the non private equivalent is that this one does
260+
* not do locking.
261+
*
262+
* @param Communicator $com The communicator to send the request over.
263+
*
264+
* @return int The number of bytes sent.
265+
* @see Client::sendSync()
266+
* @see Client::sendAsync()
267+
*/
268+
private function _send(Communicator $com)
241269
{
242270
if (!$com->getTransmitter()->isAcceptingData()) {
243271
throw new SocketException(

tests/RequestHandlingTest.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -592,7 +592,7 @@ public function testControlByteException()
592592
Communicator::decodeLength($trans);
593593
} catch (NotSupportedException $e) {
594594
$this->assertEquals(
595-
1600, $e->getCode(), 'Improper exception code.'
595+
1601, $e->getCode(), 'Improper exception code.'
596596
);
597597
$this->assertEquals(
598598
$controlByte, $e->getValue(), 'Improper exception value.'

0 commit comments

Comments
 (0)