Why does /quit sometimes reply with "!done" and sometimes with "!fatal"?

Hi!

I'm sending sms with Java using my LtAP mini LTE kit (v7.16.2) and the API (copied code from the library and created my own, much simpler classes):
/login =name=admin =password=mypw
/tool/sms/send =port=lte1 =type=class-1 status-report-request=no =phone-number="0123456789" =message="Something"
/quit

Replies:

/login -> !done
/tools/sms/send -> !re (no data though and no !done)
/quit -> !done

If I try to log out again directly after receiving /login's "!done", then the reply is:

!fatal
session terminated on request

When I try to send two sms in a row (the second one is never sent but that's a different problem), then I get the same "!fatal" reply on /quit.

Why is it not "!done" too and especially, why is it "!fatal"? I requested the logout, there shouldn't be an error like this imo.

Timing issue? Can you add a delay to give the command some time to finish?

Do you think that the “!done” is a leftover of the sms sending process?

The exact code is:

private void receiveReply(InputStream in, StringBuilder result) throws IOException {
    int len = readLen(in);
    if(len > 0) {
        byte buf[] = new byte[len];
        for (int i = 0; i < len; ++i) {
            int c = in.read();
            if (c < 0) {
                System.err.println("Truncated data. Expected to read more bytes");
            }
            buf[i] = (byte) (c & 0xFF);
        }
        String res = new String(buf, Charset.forName("UTF-8"));
        if (result.length() > 0) {
            result.append("\n");
        }
        result.append(res);
        receiveReply(in, result);
    } else {
        //here
    }
}

This is running in a thread. I already tried to have it sleep for 2s “here”, then try again one more time to fetch something (only for /quit, with /login calling “readLen” again makes it lock up). It’s still always replying with “!fatal”.

Edit: The first “!done” reply for /quit was indeed a leftover of /tool/sms/send, I now always wait 5 seconds when the reply is only “!re” (without “!done”), then try to fetch more. I also tried that with /quit but it still only returned “!fatal” plus the same message, so looks like that’s all there is. Why does a command I started replies like it failed though? Is that really the expected behavior? Is there a “better” way than /quit to quit the current session?

The !fatal is a little odd, since I'd expect /quit to actually return nothing since that does mean close terminal in CLI.

But why bother with the /quit in the first place? You can just terminate the connection client-side if you want to logout. I'm not sure there is much to cleanup in API side, and the /quit may actually be more expensive since it may have to restart a process. This may be why it be a "fatal" error since the process dies (as result of /quit), since API network session is still present, it interprets the loss of it's own internal connection to worker process as a fatal error.

Imo it’s important to return something, so you know that it actually finished/worked, just not something that makes it look like it failed.

I always do /login before I send sms, then call /quit and close the socket connection at the end. If I don’t /quit, won’t I stay logged in for some time? Is there any kind of check to see if I’m already logged in?

IDK the internals, but they don't document a "logout" nor document using /quit as a substitute, so one should presume it's not needed. /quit is just a mapped CLI call, not an API method, so it kills the process/thread.

But if you disconnect from TCP connection, I have to imagine your login is removed since the thread handling connection terminates. And reconnecting will require a new /login, so I'm not sure how creds can be "reused" if you drop the connection.

The docs do say:

  • If the API connection is closed, RouterOS sends !fatal with a reason as a reply and then closes the connection;

So in that sense quit is working as documented.

Also, if your needs are limited to just sending an SMS... I'd imagine the REST API might be easier and more standard. But REST API also does not have a "login" or "logout", since creds are always provided in HTTP. The "native" API is more useful if have long-duration connections and/or need to pipeline requests.

I only found /quit by searching for a logout command on google, which lead to this very old thread. I’ve now tested it without /quit a couple of times and no problems so far.

That’s good, then I won’t have to worry about handling login in two different ways. Thanks!

Sending sms through the commands is as easy as opening a socket to the device, sending the 2-3 commands (almost as-is), checking the reply and closing the connection again - no need to deal with json. Thinking about how long it took me to get AT commands to run with my old USB modem, this was a walk in the park. Is there any downside to using this over the REST API? It does seem to be a lot easier to handle (which I’m not mad about).

Actually, using API is very likely more efficient - as you note, it's a socket with packed data. The REST API, AFAIK, "proxy's" to the native API internally.

More suggesting there are plenty of libraries for HTTP, so it's pretty trivial for a single operation like SMS.

Since you've already done the work with API, I'd stick with that.