Eksplorimi i motorit VoIP Mediastreamer2. Pjesa 7

Materiali i artikullit është marrë nga ime kanal zen.

Eksplorimi i motorit VoIP Mediastreamer2. Pjesa 7

Përdorimi i TShark për të analizuar paketat RTP

Eksplorimi i motorit VoIP Mediastreamer2. Pjesa 7

Në të fundit artikull Ne mblodhëm një qark me telekomandë nga një gjenerator toni dhe një detektor toni, komunikimi midis të cilit u krye duke përdorur një rrymë RTP.

Në këtë artikull, ne vazhdojmë të studiojmë transmetimin e sinjalit audio duke përdorur protokollin RTP. Së pari, le të ndajmë aplikacionin tonë të testimit në një transmetues dhe një marrës dhe të mësojmë se si të ekzaminojmë rrjedhën RTP duke përdorur një analizues të trafikut në rrjet.

Pra, në mënyrë që të mund të shohim më qartë se cilët elementë të programit janë përgjegjës për transmetimin RTP dhe cilët janë përgjegjës për marrjen, ne e ndajmë skedarin tonë mstest6.c në dy programe të pavarura për transmetuesin dhe marrësin; do të vendosim funksionet e përbashkëta që përdorin të dy në skedarin e tretë, të cilin do ta quajmë mstest_common.c, do të lidhet nga transmetuesi dhe marrësi duke përdorur direktivën e përfshirjes:

/* Файл mstest_common.c Общие функции для передатчика и приемника. */
#include <mediastreamer2/msfilter.h>
#include <mediastreamer2/msticker.h>
#include <mediastreamer2/msrtp.h>
#include <ortp/rtpsession.h>
#include <ortp/payloadtype.h>

define PCMU 0

/*---------------------------------------------------------*/
/* Функция регистрации типов полезных нагрузок. */
void register_payloads(void)
{  
 /* Регистрируем типы нагрузок в таблице профилей. Позднее, по индексу    взятому 
     из заголовка RTP-пакета из этой таблицы будут извлекаться    параметры 
     нагрузки, необходимые для декодирования данных пакета. */
  rtp_profile_set_payload (&av_profile, PCMU, &payload_type_pcm8000);
}

/*---------------------------------------------------------*/
/* Эта функция создана из функции create_duplex_rtpsession() в audiostream.c   медиастримера2. */
 static RtpSession *create_rtpsession (int loc_rtp_port, int loc_rtcp_port,  bool_t ipv6, RtpSessionMode mode)
{  
  RtpSession *rtpr;  rtpr = rtp_session_new ((int) mode);  
  rtp_session_set_scheduling_mode (rtpr, 0);  
  rtp_session_set_blocking_mode (rtpr, 0);
  rtp_session_enable_adaptive_jitter_compensation (rtpr, TRUE);
  rtp_session_set_symmetric_rtp (rtpr, TRUE); 
  rtp_session_set_local_addr (rtpr, ipv6 ? "::" : "0.0.0.0", loc_rtp_port,  loc_rtcp_port); 
  rtp_session_signal_connect (rtpr, "timestamp_jump",  (RtpCallback) rtp_session_resync, 0);
  rtp_session_signal_connect (rtpr, "ssrc_changed",  (RtpCallback) rtp_session_resync, 0);
  rtp_session_set_ssrc_changed_threshold (rtpr, 0);
  rtp_session_set_send_payload_type(rtpr, PCMU);

  /* По умолчанию выключаем RTCP-сессию, так как наш пульт не будет использовать 
  её. */  
 rtp_session_enable_rtcp (rtpr, FALSE);
 return rtpr;
}

Tani skedari i veçantë i transmetuesit:

/* Файл mstest6.c Имитатор пульта управления (передатчика). */
#include <mediastreamer2/dtmfgen.h>
#include <mediastreamer2/msrtp.h>
#include "mstest_common.c"

/*----------------------------------------------------------*/
int main()
{ 
  ms_init();

/* Создаем экземпляры фильтров. */
  MSFilter *voidsource = ms_filter_new(MS_VOID_SOURCE_ID); 
  MSFilter *dtmfgen = ms_filter_new(MS_DTMF_GEN_ID);

/* Создаем фильтр кодера. */
  MSFilter *encoder = ms_filter_create_encoder("PCMU");

/* Регистрируем типы нагрузки. */
  register_payloads();

/* Создаем RTP-сессию передатчика. */
  RtpSession *tx_rtp_session = create_rtpsession (8010, 8011, FALSE, RTP_SESSION_SENDONLY);  
 rtp_session_set_remote_addr_and_port(tx_rtp_session,"127.0.0.1", 7010, 7011); 
 rtp_session_set_send_payload_type(tx_rtp_session, PCMU);  
 MSFilter *rtpsend = ms_filter_new(MS_RTP_SEND_ID); 
 ms_filter_call_method(rtpsend, MS_RTP_SEND_SET_SESSION, tx_rtp_session);

/* Создаем источник тактов - тикер. */ 
 MSTicker *ticker_tx = ms_ticker_new();

/* Соединяем фильтры передатчика. */ 
 ms_filter_link(voidsource, 0, dtmfgen, 0);  
 ms_filter_link(dtmfgen, 0, encoder, 0);
 ms_filter_link(encoder, 0, rtpsend, 0);

/* Подключаем источник тактов. */
  ms_ticker_attach(ticker_tx, voidsource);

/* Настраиваем структуру, управляющую выходным сигналом генератора. */ 
 MSDtmfGenCustomTone dtmf_cfg; 
 dtmf_cfg.tone_name[0] = 0; 
 dtmf_cfg.duration = 1000; 
 dtmf_cfg.frequencies[0] = 440;

/* Будем генерировать один тон, частоту второго тона установим в 0. */  
 dtmf_cfg.frequencies[1] = 0; 
 dtmf_cfg.amplitude = 1.0; 
 dtmf_cfg.interval = 0.;  
 dtmf_cfg.repeat_count = 0.;

/* Организуем цикл сканирования нажатых клавиш. Ввод нуля завершает
* цикл и работу программы. */  
 char key='9'; 
 printf("Нажмите клавишу команды, затем ввод.n"  
"Для завершения программы введите 0.n");  
while(key != '0')  
{
 key = getchar();   
 if ((key >= 49) && (key <= 54)) 
   {
      printf("Отправлена команда: %cn", key);
      /* Устанавливаем частоту генератора в соответствии с
       * кодом нажатой клавиши. */
      dtmf_cfg.frequencies[0] = 440 + 100*(key-49);

      /* Включаем звуковой генератор c обновленной частотой. */
      ms_filter_call_method(dtmfgen, MS_DTMF_GEN_PLAY_CUSTOM,      (void*)&dtmf_cfg); 
   }
   /* Укладываем тред в спячку на 20мс, чтобы другие треды 
   * приложения получили время на работу. */ 
  ms_usleep(20000);
  }
}

Dhe së fundi, skedari i marrësit:

/* Файл mstest7.c Имитатор приемника. */
include <mediastreamer2/mssndcard.h>
include <mediastreamer2/mstonedetector.h>
include <mediastreamer2/msrtp.h>

/* Подключаем заголовочный файл с функциями управления событиями  медиастримера.*/
include <mediastreamer2/mseventqueue.h>
/* Подключаем файл общих функций. */
include "mstest_common.c"

/* Функция обратного вызова, она будет вызвана фильтром, как только он   обнаружит совпадение характеристик входного сигнала с заданными. */
static void tone_detected_cb(void *data, MSFilter *f, unsigned int event_id,MSToneDetectorEvent *ev)
{ 
 printf("Принята команда: %sn", ev->tone_name);
}

/*----------------------------------------------------------*/
int main()
{ 
 ms_init();

/* Создаем экземпляры фильтров. */  
 MSSndCard *card_playback =  ms_snd_card_manager_get_default_card(ms_snd_card_manager_get()); 
 MSFilter *snd_card_write = ms_snd_card_create_writer(card_playback); 
 MSFilter *detector = ms_filter_new(MS_TONE_DETECTOR_ID);

/* Очищаем массив находящийся внутри детектора тонов, он описывает
* особые приметы разыскиваемых сигналов.*/
  ms_filter_call_method(detector, MS_TONE_DETECTOR_CLEAR_SCANS, 0);

/* Подключаем к фильтру функцию обратного вызова. */  
ms_filter_set_notify_callback(detector,  (MSFilterNotifyFunc)tone_detected_cb, NULL);

/* Создаем массив, каждый элемент которого описывает характеристику
* одного из тонов, который требуется обнаруживать:
Текстовое имя
* данного элемента, частота в герцах, длительность в миллисекундах,
* минимальный уровень относительно 0,775В. */
  MSToneDetectorDef scan[6]= 
 {   
    {"V+",440, 100, 0.1}, /* Команда "Увеличить громкость". */
    {"V-",540, 100, 0.1}, /* Команда "Уменьшить громкость". */
    {"C+",640, 100, 0.1}, /* Команда "Увеличить номер канала". */
    {"C-",740, 100, 0.1}, /* Команда "Уменьшить номер канала". */
    {"ON",840, 100, 0.1}, /* Команда "Включить телевизор". */
    {"OFF", 940, 100, 0.1}/* Команда "Выключить телевизор". */
  };

/* Передаем "приметы" сигналов детектор тонов. */
  int i; 
 for (i = 0; i < 6; i++) 
 { 
   ms_filter_call_method(detector, MS_TONE_DETECTOR_ADD_SCAN,    &scan[i]); 
 }

/* Создаем фильтр декодера */
  MSFilter *decoder=ms_filter_create_decoder("PCMU");

/* Регистрируем типы нагрузки. */
  register_payloads();

/* Создаем RTP-сессию приемника. */
  MSFilter *rtprecv = ms_filter_new(MS_RTP_RECV_ID);
  RtpSession *rx_rtp_session = create_rtpsession (7010, 7011, FALSE, RTP_SESSION_RECVONLY);
  ms_filter_call_method(rtprecv, MS_RTP_RECV_SET_SESSION, rx_rtp_session);

/* Создаем источник тактов - тикер. */ 
 MSTicker *ticker_rx = ms_ticker_new();

/* Соединяем фильтры приёмника. */
  ms_filter_link(rtprecv, 0, decoder, 0);
  ms_filter_link(decoder, 0, detector, 0);
  ms_filter_link(detector, 0, snd_card_write, 0);

/* Подключаем источник тактов. */
  ms_ticker_attach(ticker_rx, rtprecv);
  char key='9';
  printf( "Для завершения программы введите 0.n");
  while(key != '0') 
 {
    key = getchar();
   /* Укладываем тред в спячку на 20мс, чтобы другие треды    * приложения получили время на работу. */
   ms_usleep(20000); 
 }
}

Ne përpilojmë transmetuesin dhe marrësin, më pas nisim secilin në tastierën e vet. Pastaj duhet të funksionojë si më parë - vetëm ne duhet të fusim numrat nga 1 në 6 në tastierën e transmetuesit, dhe përgjigja ndaj tyre duhet të shfaqet në tastierën e marrësit. Tonet duhet të jenë të dëgjueshme në altoparlant. Nëse gjithçka është kështu, atëherë ne kemi krijuar një lidhje midis marrësit dhe transmetuesit - ekziston një transmetim i vazhdueshëm i paketave RTP nga transmetuesi te marrësi.

Tani është koha për të instaluar një analizues trafiku; për këtë ne do të instalojmë versionin e konsolës së programit të shkëlqyer Wireshark - ai quhet TShark. Zgjodha TShark për diskutim të mëtejshëm në mënyrë që të lehtësoj përshkrimin e menaxhimit të programit. Me Wireshark, do të më duheshin një det pamjesh të ekranit, të cilat mund të vjetërohen shpejt kur të lëshohet një version i ri i Wireshark.

Nëse dini të përdorni Wireshark, mund ta përdorni për të studiuar shembujt tanë. Por edhe në këtë rast, unë rekomandoj që të zotëroni TShark, pasi do t'ju ndihmojë të automatizoni testimin e aplikacioneve tuaja VoIP, si dhe të kryeni kapjen në distancë.

Instaloni TShark me komandën:

$ sudo apt-get install tshark

Tradicionalisht, ne kontrollojmë rezultatin e instalimit duke kërkuar versionin e programit:

$ tshark --version

Nëse merret një përgjigje adekuate, vazhdojmë më tej.

Meqenëse paketat tona futen vetëm brenda kompjuterit për momentin, ne mund t'i themi tshark të tregojë vetëm paketa të tilla. Për ta bërë këtë, duhet të zgjidhni kapjen e paketave nga ndërfaqja loopback (loopback) duke kaluar opsionin TShark - unë ja:

$ sudo tshark -i lo

Mesazhet në lidhje me paketat e dërguara nga transmetuesi ynë do të fillojnë menjëherë të derdhen në tastierë (vazhdimisht, pavarësisht nëse kemi shtypur butonin në telekomandë apo jo). Ndoshta ka programe në kompjuterin tuaj që dërgojnë gjithashtu pako përmes një qarku lokal, në këtë rast ne do të marrim një përzierje të paketave tona dhe të njerëzve të tjerë. Për t'u siguruar që në listë të shohim vetëm paketa të dërguara nga telekomanda, ne do të shtojmë një filtër sipas numrit të portit. Duke shtypur Ctrl-C ne ndalojmë analizuesin dhe futim një filtër për numrin e portës që telekomanda përdor si portin e destinacionit për transmetimin e tij (8010): -f "udp port 8010". Tani linja jonë e komandës do të duket si kjo:

$ sudo tshark -i lo -f "udp port 8010"

Dalja e mëposhtme do të shfaqet në tastierë (10 rreshtat e parë):

 1 0.000000000    127.0.0.1 → 127.0.0.1    UDP 214 8010 → 7010 Len=172 
 2 0.020059705    127.0.0.1 → 127.0.0.1    UDP 214 8010 → 7010 Len=172
 3 0.040044409    127.0.0.1 → 127.0.0.1    UDP 214 8010 → 7010 Len=172 
 4 0.060057104    127.0.0.1 → 127.0.0.1    UDP 214 8010 → 7010 Len=172
 5 0.080082311    127.0.0.1 → 127.0.0.1    UDP 214 8010 → 7010 Len=172  
 6 0.100597153    127.0.0.1 → 127.0.0.1    UDP 214 8010 → 7010 Len=172 
 7 0.120122668    127.0.0.1 → 127.0.0.1    UDP 214 8010 → 7010 Len=172
 8 0.140204789    127.0.0.1 → 127.0.0.1    UDP 214 8010 → 7010 Len=172
 9 0.160719008    127.0.0.1 → 127.0.0.1    UDP 214 8010 → 7010 Len=172
10 0.180673685    127.0.0.1 → 127.0.0.1    UDP 214 8010 → 7010 Len=172

Për momentin, këto nuk janë pako, por një listë e numëruar ngjarjesh, ku çdo rresht është një mesazh për paketën tjetër që u vu re në ndërfaqe. Meqenëse tashmë jemi kujdesur për filtrimin e paketave, në listë shohim vetëm mesazhe rreth paketave nga transmetuesi ynë. Më pas, le ta deshifrojmë këtë tabelë sipas numrave të kolonave:

Numri i ngjarjes.
Koha e shfaqjes së saj.
Adresa IP e burimit të paketës dhe adresa IP e destinacionit të paketës.
Protokolli i paketës shfaqet si UDP sepse paketat RTP dërgohen si ngarkesë brenda paketave UDP.
Madhësia e paketës në bajt.
Numri i portit burimor të paketës dhe numri i portit të destinacionit të paketës.
Madhësia e ngarkesës së paketës, nga këtu mund të konkludojmë se transmetuesi ynë gjeneron pako RTP me madhësi 172 bajt, të cilat, si një rosë në gjoks, ndodhet brenda një pakete UDP me madhësi 214 bajt.
Tani është koha për të parë brenda paketave UDP, për këtë ne do të lëshojmë TShark me një grup të zgjeruar çelësash:

sudo tshark -i lo -f "udp port 8010"  -P -V -O rtp -o rtp.heuristic_rtp:TRUE -x

Si rezultat, prodhimi i programit do të pasurohet - një deshifrim i përmbajtjes së brendshme të paketës që e ka shkaktuar atë do të shtohet në secilën ngjarje. Për të parë më mirë daljen, mund ta ndaloni TShark duke shtypur Ctrl-C, ose mund ta dublikoni daljen e tij në një skedar duke shtuar një tubacion në programin tee në komandën e ekzekutimit, duke specifikuar emrin e skedarit, tee :

$ sudo tshark -i lo -f "udp port 8010"  -P -V -O rtp -o rtp.heuristic_rtp:TRUE -x | tee  log.txt

Tani le të shohim se çfarë kemi marrë në skedar, këtu është paketa e parë prej tij:

1 0.000000000    127.0.0.1 → 127.0.0.1    RTP 214 PT=ITU-T G.711 PCMU, SSRC=0x6B8B4567, Seq=58366, Time=355368720
Frame 1: 214 bytes on wire (1712 bits), 214 bytes captured (1712 bits) on interface 0
Ethernet II, Src: 00:00:00_00:00:00 (00:00:00:00:00:00), Dst: 00:00:00_00:00:00 (00:00:00:00:00:00)
Internet Protocol Version 4, Src: 127.0.0.1, Dst: 127.0.0.1User Datagram Protocol, Src Port: 8010, Dst Port: 7010
Real-Time Transport Protocol    [Stream setup by HEUR RT (frame 1)]
        [Setup frame: 1] 
       [Setup Method: HEUR RT]
    10.. .... = Version: RFC 1889 Version (2)
    ..0. .... = Padding: False
    ...0 .... = Extension: False
    .... 0000 = Contributing source identifiers count: 0   
   0... .... = Marker: False
    Payload type: ITU-T G.711 PCMU (0)
    Sequence number: 58366    [Extended sequence number: 58366]
    Timestamp: 355368720
    Synchronization Source identifier: 0x6b8b4567 (1804289383)
    Payload: ffffffffffffffffffffffffffffffffffffffffffffffff...

0000  00 00 00 00 00 00 00 00 00 00 00 00 08 00 45 00   ..............E.
0010  00 c8 3c 69 40 00 40 11 ff b9 7f 00 00 01 7f 00   ..<i@.@.........
0020  00 01 1f 4a 1b 62 00 b4 fe c7 80 00 e3 fe 15 2e   ...J.b..........
0030  7f 10 6b 8b 45 67 ff ff ff ff ff ff ff ff ff ff   ..k.Eg..........
0040  ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff   ................
0050  ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff   ................
0060  ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff   ................
0070  ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff   ................
0080  ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff   ................
0090  ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff   ................
00a0  ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff   ................
00b0  ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff   ................
00c0  ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff   ................
00d0  ff ff ff ff ff ff                                  ......

Ne do t'i kushtojmë artikullin vijues analizës së informacionit të përmbajtur në këtë listë dhe në mënyrë të pashmangshme do të flasim për strukturën e brendshme të paketës RTP.

Burimi: www.habr.com

Shto një koment