mmtik
June 7, 2016, 1:01pm
1
We have variable “status” in environment.
Run the command by API:
>>> /system/script/environment/set
>>> =numbers=status
>>> =value=1465304159
Check read_len, got '5'
recv 5
<<< !done
Check read_len, got '0'
>>> /ip/firewall/address-list/add
>>> =address=10.20.20.253
>>> =list=accept
Check read_len, got '5'
recv 5
<<< !done
Check read_len, got '8'
recv 8
<<< =ret=*3C
Check read_len, got '0'
We dont have variable “status” in environment.
Run the command:
>>> /system/script/environment/set
>>> =numbers=status
>>> =value=1465304300
Check read_len, got '5'
recv 5
<<< !trap
Check read_len, got '21'
recv 21
<<< =message=no such item
Check read_len, got '0'
>>> /ip/firewall/address-list/add
>>> =address=10.20.20.253
>>> =list=accept
Check read_len, got '5'
recv 5
<<< !done
Check read_len, got '0'
Command “/ip/firewall/address-list/add” is not apply…
P.S.
version: 6.35.1 (stable)
cpu: MIPS 24Kc V7.4
What about
/set
=name=status
=value=1465304159
(assuming the variable already exists)
or
/global
=name=status
=value=1465304159
(if it doesn’t)
mmtik
June 8, 2016, 5:29am
3
Not variable problem. It is taken as an example.
The problem is that the subsequent instruction is not satisfied …
More accurately - it will be done after the following command:
>>> /system/script/environment/set
>>> =numbers=status
>>> =value=1465363657
Check read_len, got '5'
recv 5
<<< !trap
Check read_len, got '21'
recv 21
<<< =message=no such item
Check read_len, got '0'
>>> /ip/firewall/address-list/add
>>> =address=10.20.20.253
>>> =list=accept
Check read_len, got '5'
recv 5
<<< !done
Check read_len, got '0'
>>> /system/script/environment/print
Check read_len, got '5'
recv 5
<<< !done
Check read_len, got '8'
recv 8
<<< =ret=*3E
Check read_len, got '0'
Right. The “/system/environment/print” is the one that fails… But what I’m saying is that it fails because the command
/system/script/environment/set
=numbers=status
=value=1465363657
Fails.
The failure is detectable - that’s what the !trap is, i.e. the part
!trap
=message=no such item
is telling you that the “set” failed, supposedly because the variable doesn’t exist prior to the call.
And if you want to create the variable, you need to use “/global” instead of “/system/script/environment/set”.
mmtik
June 13, 2016, 11:30am
5
The problem is not the creation of a variable. The problem is the following command after creating the variable.
If the command has caused the error, execution of subsequent commands via the API becomes problematic.
janisk
June 14, 2016, 7:48am
6
You cannot get the value if you have not set it in the first place. No variable - no value to get.
Aaah. I see it now. You’re intentionally causing a !trap to demonstrate its handling…
But I’m not sure the bug is in RouterOS. It looks more like a bug of either your API client of choice (which one is it anyway?) or the code you’re using around it.
When there are errors, RouterOS returns a !trap reply AND a !done reply, not just a !trap reply. At the same time, a command is only REALLY executed when you receive its !done reply. What your code does is that it sends two commands, but only keeps reading until it gets one !done reply, and it should instead keep reading until it gets two !done replies.
How exactly should you solve this depends on whether the bug is in the API client or your code. Show us the code you’re using.
mmtik
June 27, 2016, 11:22am
8
Using PERL API based on https://github.com/akschu/MikroTikPerl , with my rework.
sub read_byte{
my $line;
if ($error_msg) {return 0}
eval {
local $SIG{__DIE__} = 'IGNORE';
local $SIG{ALRM} = sub {die};
alarm 5;
eval {
$sock->read($line,1);
};
alarm 0;
};
alarm 0;
if ($!){
$error_msg=$!;
if ($debug > 4)
{
print "\nERROR: $!\n";
}
return 0;
}
return ord($line);
}
sub read_len {
my $len;
if ($debug > 4) {print "Check read_len"}
$len = read_byte();
if ($debug > 4) {print ", got '$len'\n"}
if ($len==0) {
$error_len++;
if ($error_len>3){$error_msg='connection lost'}
} else {$error_len=0}
if (($len & 0x80) == 0x00)
{
return $len
}
elsif (($len & 0xC0) == 0x80)
{
$len &= ~0x80;
$len <<= 8;
$len += read_byte();
}
elsif (($len & 0xE0) == 0xC0)
{
$len &= ~0xC0;
$len <<= 8;
$len += read_byte();
$len <<= 8;
$len += read_byte();
}
elsif (($len & 0xF0) == 0xE0)
{
$len &= ~0xE0;
$len <<= 8;
$len += read_byte();
$len <<= 8;
$len += read_byte();
$len <<= 8;
$len += read_byte();
}
elsif (($len & 0xF8) == 0xF0)
{
$len = read_byte();
$len <<= 8;
$len += read_byte();
$len <<= 8;
$len += read_byte();
$len <<= 8;
$len += read_byte();
}
return $len;
}
focus on problem:
after recive from router: “=message=no such item”
check the router is still something send to me, but not send: “Check read_len, got ‘0’”
janisk
June 27, 2016, 1:05pm
9
when you send a command to the router, router will respond with the response and then indicate that it ended sending stuff. In your case it sends !trap as your command caused some error and then sends !done, indicating that the command is done.
see here for examples:
http://wiki.mikrotik.com/wiki/Manual:API#Command_examples
->> /command
<<- !re item
<<- !re item
<<- !done
when you have traps, see /cancel command example where you can cancel individual tagged commands or what happens when you cancel everything.
mmtik:
Using PERL API based on https://github.com/akschu/MikroTikPerl , with my rework.
focus on problem:
after recive from router: “=message=no such item”
check the router is still something send to me, but not send: “Check read_len, got ‘0’”
OK, that’s your API client… And the Perl code from which you call it (feel free to replace your router credentials)?
Trying a similar test with my router (and API client), I get, as expected:
MODE | LENGTH | LENGTH | CONTENTS
| (decoded) | (encoded) |
-----|-------------|--------------|--------------------------------------------
SEND | <prompt> | <prompt> | /system/script/environment/set
SEND | <prompt> | <prompt> | =numbers=status
SEND | <prompt> | <prompt> | =value=1465363657
SEND | <prompt> | <prompt> |
SENT | 30 | 0x1E | /system/script/environment/set
SENT | 15 | 0x0F | =numbers=status
SENT | 17 | 0x11 | =value=1465363657
SENT | 0 | 0x00 |
RECV | 5 | 0x05 | !trap
RECV | 21 | 0x15 | =message=no such item
RECV | 0 | 0x00 |
SEND | <prompt> | <prompt> | /put
SEND | <prompt> | <prompt> | =message=test
SEND | <prompt> | <prompt> |
SENT | 4 | 0x04 | /put
SENT | 13 | 0x0D | =message=test
SENT | 0 | 0x00 |
RECV | 5 | 0x05 | !done
RECV | 0 | 0x00 |
SEND | <prompt> | <prompt> |
SENT | 0 | 0x00 |
RECV | 5 | 0x05 | !done
RECV | 9 | 0x09 | =ret=test
RECV | 0 | 0x00 |
SEND | <prompt> | <prompt> |
SENT | 0 | 0x00 |
NOTE | Receiving timed out |
SEND | <prompt> | <prompt> | /quit
SEND | <prompt> | <prompt> |
SENT | 5 | 0x05 | /quit
SENT | 0 | 0x00 |
RECV | 6 | 0x06 | !fatal
RECV | 29 | 0x1D | session terminated on request
RECV | 0 | 0x00 |
NOTE | Connection terminated |
Notice how I do the second command before I get the first one’s !done… Maybe if you were to keep reading until the !done sentence, and only send the second command there, it would work as you’d expect, e.g.
MODE | LENGTH | LENGTH | CONTENTS
| (decoded) | (encoded) |
-----|-------------|--------------|--------------------------------------------
SEND | <prompt> | <prompt> | /system/script/environment/set
SEND | <prompt> | <prompt> | =numbers=status
SEND | <prompt> | <prompt> | =value=1465363657
SEND | <prompt> | <prompt> |
SENT | 30 | 0x1E | /system/script/environment/set
SENT | 15 | 0x0F | =numbers=status
SENT | 17 | 0x11 | =value=1465363657
SENT | 0 | 0x00 |
RECV | 5 | 0x05 | !trap
RECV | 21 | 0x15 | =message=no such item
RECV | 0 | 0x00 |
RECV | 5 | 0x05 | !done
RECV | 0 | 0x00 |
NOTE | Receiving timed out |
SEND | <prompt> | <prompt> | /put
SEND | <prompt> | <prompt> | =message=test
SEND | <prompt> | <prompt> |
SENT | 4 | 0x04 | /put
SENT | 13 | 0x0D | =message=test
SENT | 0 | 0x00 |
RECV | 5 | 0x05 | !done
RECV | 9 | 0x09 | =ret=test
RECV | 0 | 0x00 |
NOTE | Receiving timed out |
SEND | <prompt> | <prompt> | /quit
SEND | <prompt> | <prompt> |
SENT | 5 | 0x05 | /quit
SENT | 0 | 0x00 |
RECV | 6 | 0x06 | !fatal
RECV | 29 | 0x1D | session terminated on request
RECV | 0 | 0x00 |
NOTE | Connection terminated |