Shell script AT Commands : not able to send sms through serial port - shell

I have the below shell script (expect) where I am trying to send SMS. I have referred many stack overflow references and found out that ctrl-z maps to \x1a. However, even after appending it to the message and sending to the port or sending ctrl z separately to the port didn't help me. It timeouts later.
The script is written to send sms in pdu format. Irrespective of that, I believe, this is a generic issue to send ctrl-z to port. If you feel the script has some other errors, please share the solution for the same.
Also the length (34) mentioned below is the length of the (PDU_LENGTH -2)/2 as per the specification. This length doesn't include ctrl-z character.
at_command = "AT+CMGS=34\r"
message_content = "0011000C810056890......"
Script:
set PROMPT "0"
set timeout "$COMMAND_TIMEOUT"
send "$at_command"
expect {
"OK" { puts "Command Accepted\n"; }
"ERROR" { puts "Command Failed\n"; }
timeout { puts "Unable to connect to $HOSTIP at $HOSTPORT"; exit 1 }
"*>*" { set PROMPT "1"; }
}
if { "$PROMPT" == "1" } {
send "$message_content"
send "\x1a"
expect {
"OK" { puts "\nCommand accepted"; }
"ERROR" { puts "\nCommand failed"; }
"*>*" { puts "CTRL-Z dint reach UT. Error..."; }
"*" { puts "Unexpected return value received"; }
}
}
Am very sure the script sends $message_content" to port but exits immediately after sending "$message_content".
OUTPUT:
AT+CMGS=34
>

I did something like this in c# with an SMS-Gateway-Modul.
I had to switch to PDU-Mode first!
After that i had to transmit the expected PDU-Length and finally the PDU itself.
Every command has to be committed with can carriage return ASC[13] and the PDU had to be committed with an ASC[26] finally.
Here you can see a schematic(!) flow, how i did it in c#:
1) Create PDU and get length
int len;
var pdu = PDUGenerator.GetPdu(destination, message, "", out len);
2) Switch to PDUMode
SendToCom("AT+CMGF=0" + System.Convert.ToChar(13));
3) Announce message length
SendToCom("AT+CMGS=" + len + System.Convert.ToChar(13));
4) Send PDU and commit
SendToCom(pdu + System.Convert.ToChar(26));

Related

How to suppress "ERROR message: short read (SSL routines, SSL routines), value: 335544539"

Reference:
websocket_client_sync_ssl.cpp
// Read a message into our buffer
ws.read(buffer);
// Close the WebSocket connection
ws.close(websocket::close_code::normal);
Based on my test, the ws.close will spit out a warning below:
ERROR message: short read (SSL routines, SSL routines), value:
335544539
Based on this post short read, this error can be safely ignored in the end of the session. I have tried the following method to suppress the warning:
try
{
boost::system::error_code close_ec;
ws.close(websocket::close_code::normal, close_ec);
if (close_ec)
{
std::cerr << "ERROR message: " << close_ec.message() << ", value: " << close_ec.value() << std::endl;
}
}
catch(...)
{
}
However, the ws.close still prints out the warning message.
Question> Is there a way that I can suppress this message?
However, the ws.close still prints out the warning message.
Are you sure? It looks like that's simply coming from the line:
std::cerr << "ERROR message: " << close_ec.message() << ", value: " << close_ec.value() << std::endl;
So, you would check the value of close_ec and conditionally handle it: Short read error-Boost asio synchoronous https call
Also, note that some kinds of "short reads" can constitute security errors. Some of the samples have very insightful comments about this:
// `net::ssl::error::stream_truncated`, also known as an SSL "short read",
// indicates the peer closed the connection without performing the
// required closing handshake (for example, Google does this to
// improve performance). Generally this can be a security issue,
// but if your communication protocol is self-terminated (as
// it is with both HTTP and WebSocket) then you may simply
// ignore the lack of close_notify:
//
// https://github.com/boostorg/beast/issues/38
//
// https://security.stackexchange.com/questions/91435/how-to-handle-a-malicious-ssl-tls-shutdown
//
// When a short read would cut off the end of an HTTP message,
// Beast returns the error beast::http::error::partial_message.
// Therefore, if we see a short read here, it has occurred
// after the message has been completed, so it is safe to ignore it.
if(ec == net::ssl::error::stream_truncated)
ec = {};
else if(ec)
return;

ssh "packet_write_wait: Connection to x.x.x.x port 22: Broken pipe" -- where is the source code?

We got a client ssh to a remote server showing this error. It has always been running fine, no firewall rules change either. When an ssh session is idled over the weekend, it is still connected. Just some times when we 'less' and shift-F on a file for couple of hours, it shows this error.
I'm not trying to solve this problem in this post. We want to look at the ssh source code to figure out what is going on. On Centos 7, I downloaded openssh-7.4p1-21.el7.src.rpm, and extracted openssh-7.4p1.tar.gz. 'grep' through source code and found 'packet_write_wait' function. But curiously, "Broken pipe" (or -i on each word separately) is not found in all the .h and .c files. Where is that error text coming from?
You can find a copy of the OpenSSH source code in github. The packet_write_wait function is in opacket.c:
void
packet_write_wait(void)
{
int r;
if ((r = ssh_packet_write_wait(active_state)) != 0)
sshpkt_fatal(active_state, __func__, r);
}
It calls another function to write the packet. If that fails, it calls sshpkt_fatal. sshpkt_fatal is in packet.c, and its job is to print an error message and then exit.
/*
* Pretty-print connection-terminating errors and exit.
*/
void
sshpkt_fatal(struct ssh *ssh, const char *tag, int r)
{
switch (r) {
case SSH_ERR_CONN_CLOSED:
logdie("Connection closed by %.200s port %d",
ssh_remote_ipaddr(ssh), ssh_remote_port(ssh));
[...code removed...]
/* FALLTHROUGH */
default:
logdie("%s%sConnection %s %.200s port %d: %s",
tag != NULL ? tag : "", tag != NULL ? ": " : "",
ssh->state->server_side ? "from" : "to",
ssh_remote_ipaddr(ssh), ssh_remote_port(ssh), ssh_err(r));
}
}
The message that you're asking about is handled by the default case. The last argument, which provides the text after the colon, is provided by calling ssh_err:
const char *
ssh_err(int n)
{
switch (n) {
case SSH_ERR_SUCCESS:
return "success";
case SSH_ERR_INTERNAL_ERROR:
return "unexpected internal error";
[...etc...]
The ssh_err case that you're interested in is this one:
case SSH_ERR_SYSTEM_ERROR:
return strerror(errno);
In short, the "Broken pipe" message comes from the standard library function strerror, which converts error numbers to standard error messages.
The list of standard error codes indicates that "Broken pipe" is associated with the EPIPE error.

How to receive messages via wifi while running main program in ESP32?

Ive incorporated multiple features i want in a microcontroller program (ESP32 Wroom32) and needed some advice on the best way to keep the program running and receive messages while it is running.
Current code:
//includes and declarations
setup()
{
//setup up wifi, server
}
main(){
WiFiClient client = server.available();
byte new_command[40];
if (client) // If client object is created, a connection is setup
{
Serial.println("New wifi Client.");
String currentLine = ""; //Used to print messages
while (client.connected())
{
recv_byte = client.read();
new_command = read_incoming(&recv_byte, client); //Returns received command and check for format. If invalid, returns a 0 array
if (new_command[0] != 0) //Checks if message is not zero, None of valid messages start with zero
{
execute_command(new_command);
//new_command is set to zero
}
}//end of while loop
}//end of if loop
}
The downside of this is that the ESP32 waits till the command is finished executing before it is ready to receive a new message. It is desired that the ESP32 receive commands and store them, and execute it at its own pace. I am planning to change the current code to receive a messages while the code is running as follows:
main()
{
WiFiClient client = server.available();
byte new_command[40];
int command_count = 0;
byte command_array[50][40];
if (command_count != 0)
{
execute_command(command_array[0]);
//Decrement command_count
//Shift all commands in command_array by 1 row above
//Set last executed command to zero
}
}//end of main loop
def message_interrupt(int recv_byte, WiFiClient& running_client)
{
If (running_client.connected())
{
recv_byte = running_client.read();
new_command = read_incoming(&recv_byte, running_client); //Returns received command and check for format. If invalid, returns a 0 array
//add new command to command_array after last command
//increment command_count
}
}
Which interrupt do I use to receive the message and update the command_array ? https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-guides/wifi.html Doesnt mention any receive/transmit events. I couldnt find any receive/transmit interrupt either or maybe I searched for the wrong term.

FTP Arduino issue with ESP8266

Trying to do FTP with my router from an ESP8266 WiFi-board and using the Arduino-IDE, I keep getting the following error message:
331 Password required for anonymous.
My code looks like this:
if (client.connect(server, 21)) { // 21 = FTP server
Serial.println(F("Command connected FIRST TIME"));
} else {
Serial.println(F("Command connection failed FIRST TIME"));
}
eRcv();
Serial.println("OUTPUT BUFFER 1");
Serial.println(outBuf);
client.println(F("USER anonymous"));
eRcv();
Serial.println("OUTPUT BUFFER 2");
Serial.println(outBuf);
client.println(F("PASS anonymous"));
eRcv();
Serial.println("OUTPUT BUFFER 3");
Serial.println(outBuf);
client.println(F("SYST"));
eRcv();
Serial.println("OUTPUT BUFFER 4");
Serial.println(outBuf);
client.println(F("Type I"));
eRcv();
My log looks like that:
WiFi connected; IP address: 192.168.178.33
Command connected FIRST TIME
OUTPUT BUFFER 1
220 FRITZ!Box7490 FTP server ready.
OUTPUT BUFFER 2
331 Password required for anonymous.
As you can see, the error message I receive (i.e. err 331) happens already at cmd nr 2 (i.e. "PASS anonymous2).
The router is set to accept an anonymous FTP (that should not be the problem). The router, of course, is set to allow FTP.
I read something about a "passive mode" (client.println(F("PASV"));) but it seems to me that the "PASS anonymous" should go through independent of PASV-mode ore not. Is this correct ?
Are there any other suggestions of what to do here ?
Much appreciated!
P.S. For completion, the FTP-receive (delivering the "outBuf" from the example-code above) looks like this:
//-------------- FTP receive
byte eRcv() {
byte respCode;
byte thisByte;
long StartTimeoutTime = millis();
while (!client.available() && (millis() - StartTimeoutTime < 1000))
{ // wait for answer with 1 second timeout
delay(1);
}
if (millis() - StartTimeoutTime >= 1000)
{
efail();
return 0;
}
respCode = client.peek();
outCount = 0;
while (client.available()) {
thisByte = client.read();
//Serial.write(thisByte);
if (outCount < 127) {
outBuf[outCount] = thisByte;
outCount++;
outBuf[outCount] = 0;
}
}
if (respCode >= '4') {
efail();
return 0;
}
return 1;
} // eRcv()
Anonymous authentication with FTP still requires that you send a username and a password. Traditionally the username is anonymous and an email address is used as a password. Something like user#test.com works fine. Here is a link to RFC 959, File Transfer Protocol.
From here it looks like you might not be waiting long enough for the server to send the 220 message before you send the USER. After you connect, wait for the server to finish sending its welcome message. Then send your USER, wait for the 331, then send your PASS. The server might also be sending multiple strings for the first message. Try logging into the FTP server with the commandline client for your o/s and see exactly what it's sending you, and adjust your code for that.

expect - how to discard the buffer if expected string is not found

I need to spawn a script that produces lots of output which makes the regex matching of the output slow. Also the buffer fills quickly even when I use quite a large match_max value.
I would like to check the output for a particular string. If the string does not exist, I would like to discard the output read so far.
I have tried using default matches, globs and negative regexes to catch the unwanted strings, but could not get this working.
How can this be done with expect?
This 'seems' to work (more testing is required):
set success_string "\[INFO\] Started Jetty\r\n"
spawn "/usr/bin/mvn" "-pl" ":cloud-client-ui" "jetty:run"
expect {
-re "(\[^\r]*\)\r\n"
{
set current_line $expect_out(buffer)
if { [string equal "$current_line" "$success_string"] } {
puts "exiting with matched string $current_line"
exit 0
} else {
puts "discarding $current_line"
exp_continue
}
}
eof { puts "eof"; exit 1; }
timeout { puts "timeout"; exit 1; }
}

Resources