Проверка Доступности Sip-Провайдера

В этой статье я хочу поделиться одним интересным, на мой взгляд, способом проверки доступности sip провайдера или другого устройства, он особенно актуален, когда по каким-то причинам невозможно проверить icmp-сторону icmp-запросами, и основан на по OPTIONS запросам протокола SIP. Кому интересна данная тема, просьба обращаться под кат. И так, протокол SIP, который описан в RFC 3261, имеет замечательный тип запроса OPTIONS, этот тип запроса используется для проверки совместимости сторон, он позволяет клиенту получить информацию о том, какие методы поддерживает удаленная сторона, И самое главное, нет необходимости звонить удаленному абоненту (не нужно отправлять INVITE-запрос).

Пример запроса OPTIONS из RFC:

 
 OPTIONS sip:[email protected] SIP/2.0
       Via: SIP/2.0/UDP pc33.atlanta.com;branch=z9hG4bKhjhs8ass877
       Max-Forwards: 70
       To: <sip:[email protected]>
       From: Alice <sip:[email protected]>;tag=1928301774
       Call-ID: a84b4c76e66710
       CSeq: 63104 OPTIONS
       Contact: <sip:[email protected]>
       Accept: application/sdp
       Content-Length: 0
 
Ответ на такой запрос должен быть таким же, как если бы мы отправили запрос INVITE, например, это может быть ответ 200 (ОК), означающий, что удаленная сторона готова принять вызов.

Перейдем к практической части, она сводится к тому, что нам необходимо подготовить IP-пакет с соответствующими данными и отправить его удаленной стороне и получить на него ответ. Для этого мы можем написать простой скрипт, например на Perl:

 
 #!/usr/bin/perl
 use IO::Socket;
 use POSIX 'strftime';
 
 sub SipPing {
         my ($msg,$remotehost,$callid,$socket,$date,$branch,$localip,$dest);
         $remotehost = shift;
         $localip = shift;
         $socket = IO::Socket::INET->new (
                 PeerAddr => $remotehost,
                 PeerPort => 5060,
                 LocalPort => 5060,
                 LocalAddr => $localip,
                 Reuse => 1, 
                 Proto => 'udp',
         );
         $callid .

= ('0'.

'9', "a".

"f")[int(rand(16))] for 1 .

32; $date = strftime('%a, %e %B %Y %I:%M:%S %Z',localtime()); $branch="z9hG4bk" .

time(); my $packet = qq( OPTIONS sip:$remotehost SIP/2.0 Via: SIP/2.0/UDP $localip:5060;branch=z9hG4bK39aaa111;rport Max-Forwards: 70 From: "UA" <sip:ua\@$localip>;tag=as54192a85 To: <sip:$remotehost> Contact: <sip:asterisk\@$localip:5060> Call-ID: 7706430b46622c057aeaa5ec057a0b59\@$localip:5060 CSeq: 102 OPTIONS User-Agent: UA Date: Wed, 21 Dec 2013 00:00:01 GMT Allow: INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, SUBSCRIBE, NOTIFY, INFO, PUBLISH Supported: replaces, timer Content-Length: 0 ); print $socket $packet; eval { local $SIG{ALRM} = sub { die }; alarm 1; my $sock_addr = recv($socket,$msg,190,0); alarm 0; 1; } or die "Failed"; if ($msg) { print "Response: $msg\n"; } else { print "Failed"; } close($socket); } $remoteHost = '192.168.0.3'; $localIp = '192.168.0.2'; &SipPing($remoteHost, $localIp);

С помощью такого простого скрипта вы сможете проверить доступность SIP-агента, без необходимости регистрации или звонка.

Стоит отметить, что некоторые провайдеры разрешают принимать запросы OPTIONS только с порта 5060 на порт 5060, для этого мы указываем локальный порт, а если порт занят, например Asterisk, то пригодится параметр Reuse => 1. Вот и все.

Теги: #perl #sip #voip #voip #perl #Разработка систем связи

Вместе с данным постом часто просматривают: