📜 ⬆️ ⬇️

Sending and receiving SMS messages using VoIP gateways GoIP and Yeastar



Since we are selling VoIP equipment, we are often addressed with various technical issues. Sometimes it comes to the point that customers ask for code examples in specific programming languages. Working with SMS and integrating them into business processes is just one of these regular questions, so I want to stop there and look at it in more detail.


Why GoIP and Yeastar


In fact, I would like to tell you more about OpenVox, but there is already an article on Habré about their gateways, and they were not available at the time of this writing. Dinstar also makes such similar gateways, but there are so few catastrophic calls on these gateways, so I decided not to consider them either.


Goip




GoIP GSM gateways are manufactured in China under the brands of several companies and belong to the lowest price category, which is partly why they are the most popular. Everything I described in relation to DBL's GoIP 4 , in theory, it should work on Hybertone gateways, but I will not vouch for this, since there may be differences in the firmware.


▪ Web interface


The easiest way to send an SMS is to go to the gateway page, select the Send SMS section, specify the line from which you want to send the message, the recipient's number and the text of the message itself. The option is simple, but it is good except for the test, nothing more. However, it is possible to send SMS using GET and POST requests.


→ GET


For the GET type, use the query of the form:
http://192.168.1.190/default/en_US/send.html?u=admin&p=admin&l=1&n=89991234567&m=test


 u=admin –   p=admin –  l=1 – ,      n=89991234567 –   (    «8»,   «+7»  «7»  ) m=test –   

If something went wrong, then in response we will receive a message of the form: «ERROR, » , otherwise: «Sending, L1 Send SMS to 89991234567; ID:55c489da» «Sending, L1 Send SMS to 89991234567; ID:55c489da» . «Sending, L1 Send SMS to 89991234567; ID:55c489da» I think everything is clear here: the status, the line number, the recipient's number, and the assigned indicator so that you can later track the status of the shipment.


→ POST


Sending a request with a POST is the same as sending through a form in the web interface, it is different in that we ourselves must specify an SMS identifier, in certain cases it may be more convenient. Also through POST, we can send a USSD request, which can also be useful.


A simple perl example using the Mojolicious framework:


 #!/usr/bin/perl -w use utf8; use Mojo::UserAgent; my $ua = Mojo::UserAgent->new; $ua->post('http://admin:admin@192.168.1.190/default/en_US/sms_info.html?type=sms' => {Accept => '*/*'} => form => { line => '1', smskey => '57867a25', action => 'SMS', telnum => '89991234567', smscontent => '!', send => 'Send' }); 

To send a USSD, you will have to slightly change the request:


 $ua->post('http://admin:admin@192.168.1.190/default/en_US/sms_info.html?type=ussd' => {Accept => '*/*'} => form => { line1 => '1', smskey => '57876006', action => 'USSD', telnum => '*100#', send => 'Send' }); 

To get the result, you will have to make a separate GET request for the status of messages.


→ Message Status


It is necessary to track statuses at least because we can try to send a message while the line is busy sending another message and, as a result, it will not work. Plus, the GoIP developers did not bother with the creation of a separate means of obtaining the results of USSD queries, but simply write them in the form of decoding errors.


Shipping statuses can be tracked to:
http://192.168.1.190/default/en_US/send_status.xml?u=admin&p=admin


In response, we will receive XML, which displays the status of one last post to the channel, I had GoIP 4 on hand, and it had a single firmware with the eighth, therefore, in the statuses of 8 channels, although physically there were 4 of them:


 <?xml version="1.0" encoding="utf-8"?> <send-sms-status> <id1>57867a25</id1> <status1>DONE</status1> <error1></error1> <id2>57867277</id2> <status2>ERRORDONE</status2> <error2>send, but provider not reply.</error2> <id3>57876006</id3> <status3>DONE</status3> <error3> : 57.2 .</error3> <id4></id4> <status4>DONE</status4> <error4></error4> <id5></id5> <status5></status5> <error5></error5> <id6></id6> <status6></status6> <error6></error6> <id7></id7> <status7></status7> <error7></error7> <id8></id8> <status8></status8> <error8></error8> </send-sms-status> 

▪ SMPP protocol


SMPP (Short message peer-to-peer protocol) is a special protocol used to transfer SMS and USSD messages between a client and a server. This is probably the only "normal" way to receive messages. Yes, the web interface displays the last five messages for each channel, but the option to periodically climb on it and check if something new has appeared, I cannot be considered adequate.


SMPP



Although with SMPP, everything is not so smooth. First, messages come in UTF-16BE encoding. At first, I did not get information about this anywhere and had to jump pretty with a tambourine in order to understand what kind of encoding SMS messages are received in. The truth after that was found the parameter ( data_coding ), which just indicates how the message is encoded.


Secondly, as destination_addr there will always be system_id , with which we connect to GoIP, that is, there is no way to understand which particular SIM card the message came from. This can be bypassed - it is necessary to connect with system_id + 0 + , then we will receive messages only for a given channel, naturally, a minus of such a solution is that you need to keep several connections.


The simplest example of receiving messages using the library Net::SMPP :


 #!/usr/bin/perl -w use utf8; use strict; use Net::SMPP; use Encode; use feature 'say'; my $smpp = Net::SMPP->new_transceiver('192.168.1.190', system_id => 'arttel', #        – arttel01,  – arttel02  .. password => 'arttel', port => '7777', smpp_version=> 0x34 ) or die "Can't connect to SMSC: $!"; while (1) { my $pdu = $smpp->read_pdu(); #     my $short_message = Encode::decode("UTF-16BE", $pdu->{short_message}); say $short_message; } 

With sending the same story, if you need to send an SMS from a specific SIM card, then connect with the id of the desired channel:


 #!/usr/bin/perl -w use utf8; use strict; use Net::SMPP; my $smpp = Net::SMPP->new_transceiver('192.168.4.107', system_id => 'arttel01', password => 'arttel', port => '7777', smpp_version=> 0x34 ) or die "Can't connect to SMSC: $!"; &send_message('89991234567', '!!!'); sub send_message { my ($sm_dest_addr, $sm_message) = @_; my $result = eval { my $pru = $smpp->submit_sm( source_addr_ton => 0x05, #    source_addr_npi => 0x01, #     source_addr => '', dest_addr_ton => 0x01, #    dest_addr_npi => 0x01, #     destination_addr => $sm_dest_addr, data_coding => 0x01, #        short_message => $sm_message ) or return 1; return 0; }; if ($result == 1){ print "Can't send message: $!"; } } #   SMSC $smpp->unbind(); 

Description of send options
ParameterDescriptionMeanings
source_addr_tonSender number type0x00 - Unknown (Unknown)
0x01 - International (International)
0x02 - State
0x03 - Network Special
0x04 - Subscriber Number (Subscriber Number)
0x05 - Alphanumeric
0x06 - Abbreviated
source_addr_npiSender Numbering Plan ID0x00 - Unknown 0x01 - ISDN (E163 / E164)
0x02 - Data (X.121)
0x03 - Telex (F.69)
0x04 - Land Mobile (E.212)
0x05 - National
0x06 - Private
0x07 - ERMES
0x08 - Internet (IP)
0x09 - WAP Client Id (must be defined by the WAP Forum)
dest_addr_tonRecipient Number Type0x01 - International (International)
dest_addr_npiRecipient Numbering Plan Identifier0x01 - ISDN (E163 / E164) (for numbers)
0x02 - National (for the rest)
data_codingDefines the encoding scheme for user data of a short message.0x01 - IA5 (CCITT T.50) / ASCII (ANSI X3.4) Latin alphabet 7 bits per 1 character maximum length of one message 160 characters
0x07 - Latin / Hebrew (ISO-8859-8) Latin alphabet 8 bits per 1 character maximum message length 140 characters
0x08 - UCS2 (ISO / IEC-10646) for national alphabets (for example, Russian) maximum message length 70 characters

Yeastar




Yeastar’s homeland is the same as GoIP’s China, although it seems to me that Yeastar try to make devices with a greater claim for quality and usability than their competitors. This applies to both physical and software execution. But they also have flaws. For example, the documentation does not always keep up with changes in new firmware, and in some cases it may not have important points.


▪ Web interface


You can send and receive messages through the web interface, in general, this is the standard way for such hardware. In Yeastar gateways, this interface is something remotely reminiscent of unpretentious web muzzles - Inbox and OutboxOutbox with simple filters and search. In any case, it is a head taller than what is in the GoIP, and most importantly not the last five incoming messages for each channel are stored, but much more. Only, unfortunately, it is not clear how much, again in the datasheet about this there is not a word.


→ GET


Just as in most of these glands, you can send a message using a GET request, which is generally not surprising, it is one of the easiest ways to integrate. Naturally, Yeastar has its own implementation with its own features.


First you need to enable the ability to send SMS messages and USSD requests. To do this, you need to activate "API Settings", if you prefer the interface in Russian, then this section will be called "AMI Settings" (is it really very logical?). Secondly, it is necessary to change the default password until you do this, authorization does not pass, about this, again, not a word in the documentation.


API Settings Settings


After these manipulations, we can use requests for SMS and USSD, respectively:


http://192.168.5.150/cgi/WebCGI?1500101=account=arttel&password=arttel&port=1&destination=89991234567&content=test


 Response: Success Message: Commit successfully! 

http://192.168.5.150/cgi/WebCGI?1500102=account=arttel&password=arttel&port=1&content=%2A100%23


 Request: 1,*100# Response: Success Message:  : 36.3 . 

Briefly about the parameters:


 account=arttel –        API Settings password=arttel –   API Settings port=1 – ,      destination=89991234567 –  ,     SMS content=test –    USSD  

The main difference from GoIP: when sending SMS from Yeastar, there is no need to monitor the busy channel or not, our message is put in a queue and as soon as the channel is released it will be sent. And with USSD requests, the work happens synchronously, that is, we receive the answer immediately and there is no need to search for it somewhere later. The only drawback is that the answers come in plain text, but I would like something more appropriate: JSON or XML.


▪ Asterisk Managment Interface


The entire line of Yeastar gateways is built around Asterisk (a software program for IP-telephony from the company Digium), therefore there is no support for such a specific protocol like SMPP. But there is the AMI protocol, native to Asterisk, which is quite simple to work with.


First, let's see how to receive messages:


 #!/usr/bin/perl -w use utf8; use strict; use warnings; use AnyEvent::Impl::Perl; use Asterisk::AMI; use Data::Dumper; use URI::Escape; use feature 'say'; #   AMI my $astman = Asterisk::AMI->new( PeerAddr => '192.168.5.150', #   Username => 'arttel', #    API Settings Secret => 'arttel', #   API Settings Events => 'on', Handlers => { ReceivedSMS => \&received_sms #     }, Keepalive => 60, on_error => sub { print "Error occured on socket\r\n"; exit; }, on_timeout => sub { print "Connection to asterisk timed out\r\n"; exit; } ); die "Unable to connect to asterisk" unless ($astman); sub received_sms { my ($asterisk, $event) = @_; say Dumper($event); #      say uri_unescape($event->{'Content'}) if ($event->{'Content'}); return 1; } AnyEvent::Impl::Perl::loop; =result $VAR1 = { 'Total' => '1', 'Recvtime' => '2016-07-15 17:49:55', 'ID' => '', 'Event' => 'ReceivedSMS', 'Privilege' => 'all,smscommand', 'Index' => '1', 'GsmSpan' => '4', 'Sender' => '+79991234567', 'Smsc' => '+79997456321', '--END SMS EVENT--' => undef, 'Content' => '%EF%BB%BF%D0%9A%D1%83-%D0%BA%D1%83' }; - =end 

The example is quite simple and it seems to me that everything should be clear. The only thing I want to pay attention to is «GsmSpan» . We are all used to the fact that array indexing starts from 0, here it’s not 0 and not 1, but 2, the serial number of the channel is displayed as + 1 , so the minimum GsmSpan is 2.


We can also send SMS and USSD requests via AMI:


 #!/usr/bin/perl -w use strict; use warnings; use Asterisk::AMI; use Data::Dumper; use URI::Escape; use Encode; use feature 'say'; # Connect to asterisk my $astman = Asterisk::AMI->new( PeerAddr => '192.168.5.150', Username => 'arttel', Secret => 'arttel', Timeout => 30, #    ,   USSD    Keepalive => 60, on_error => sub { print "Error occured on socket\r\n"; exit; }, on_timeout => sub { print "Connection to asterisk timed out\r\n"; exit; } ); die "Unable to connect to asterisk" unless ($astman); #  USSD  my %action = ( Action => 'smscommand', Command => 'gsm send ussd 2 "*100#"' ); my $actionid = $astman->send_action(\%action); my $response = $astman->get_response($actionid); my @cmd = @{$response->{CMD}}; my $i = 0; while ($i <= $#cmd) { if ($cmd[$i] =~ /USSD Message: (.+)/) { #   ,      my $decodedHex = pack('H*', $1); say decode("UCS-2BE", $decodedHex); } $i++; } #  SMS %action = ( Action => 'smscommand', Command => 'gsm send sms 2 89991234567 "" 11111' ); $actionid = $astman->send_action(\%action); $response = $astman->get_response($actionid); 

According to USSD, I think everything is clear, just do not forget that the channels are numbered from two. And there is a small clarification via SMS: if the fate of a message is indifferent to us and the status is not necessary to track, then nothing can be indicated after the message text. Otherwise, you must specify a unique identifier. Then, when the fate of sms will be known, the system will send us a message about its condition. Something like this:


 $VAR1 = { 'ID' => '11111', 'Event' => 'UpdateSMSSend', '--END SMS EVENT--' => undef, 'Status' => '1', 'Privilege' => 'all,smscommand', 'Smsc' => '+79991234567' }; 

Status = 1 tells us that the message was successfully delivered, and in case of an error the status will be 0. You can receive such messages by subscribing to the UpdateSMSSend event, this is done in the same way as when receiving an SMS.


As a conclusion


Personally, it would be more convenient for me to work with the Yeastar TG400 gateway via AMI. On the other hand, I do not see any big problems in the case of using GoIP. What I deliberately kept silent about: each manufacturer has a free software SMS server, in the case of GoIP you need PHP, Apache and MySQL to use it, and in the case of Yeastar, Windows. Such products are more suitable for sending identical messages to pre-prepared database of numbers, rather than integration with some applications. This is the reason why I missed them. If someone is interested, on the websites of manufacturers must be appropriate descriptions.


')

Source: https://habr.com/ru/post/395947/


All Articles