sip phone 日誌7

SIP消息解析設計<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />

    sip的協議複雜,需逐個擊破,這次我們開始對其協議進行語法分析

1)    sip包括兩種消息:產生和處理

a)      產生請求包括 請求行 消息頭 空行 消息體

b)      處理請求包括 狀態行 消息頭 空行 消息體

2)    請求行包括 Method  Request-URI  SIP-VERSION

a)      Method包括:

l        INVITE

l        ACK   

l        CANCEL

l        REGISTE

l        BYE   

l        OPTIONS

3)    狀態行包括 SIP-VERSION  STATUS-CODE  Reason-Phrase

4)    消息頭包括多個消息行

5)    消息頭類型

a)      vias

b)      froms

c)      tos

d)      call_ids

e)      cseqs

f)      max_forwards

g)      contacts

h)      content_types

i)      content_lengths

j)      supported

k)      require

我們剛開始以簡單的消息來分析:
INVATE sip:[email protected] SIP/2.0
Via: SIP/2.0/UDP workstation1000.university.com:5060
From: Laura Brown <sip:[email protected]>
To: Bob Johnson <sip:[email protected]>
Call-ID: [email protected]
CSeq: 1 INVATE
Contact: Laura Brown <sip:[email protected]>
Content-Type:  application/sdp
Content-Length:154


以上SIP消息中可能出現的數據類型:
整形,浮數型,字符串,Email,域名,隨機串,空行,空格等

下面我們先把相應正則表達式寫好:

1.      ws         [ /t]+            //空格

2.      nl            /n            

3.      whitespace    ^[ /t]*/n          //空行

4.      url       ([^ /t/</>]*)@([^ /t/</>]*)  

5.      qstring   /"[^/"/n]*[/"/n]  //匹配”dfdfd”

6.      commpro   UDP|TCP|TLS|SCTP  //通訊協議

7.      float     [0-9]*.[0-9]*

8.      integer   [0-9]+

9.      threenum  [0-9]{3}  //三位整數

10.  string        [a-zA-Z][a-zA-Z0-9]+

11.  field     [a-zA-Z0-9.]+

12.  name      [a-zA-Z]+[ ]*[a-zA-Z]*

13.  localid   [a-zA-Z0-9-]+@[a-zA-Z0-9.]+
這幾個表達式都比較簡單,讀者可參考正則表達式對照。


這裏先介始一下lexyacc,Window下開發的朋友可能有點陌生,但在Xnix下很通行.lex是詞法識別工具,yacc是語法識別工具.相結起來就可完成一種計算機語言的編譯程序.具體這就不展開介紹,可參考:

l        www-900.ibm.com/developerWorks/ cn/linux/sdk/lex/index.shtml

l        http://dinosaur.compilertools.net/

l        lexyacc(第二版)》

通過使用這兩個工具可以快速解析SIP消息.並且因lexyacc可生成C代碼,我們可以很快移植到我們程序代碼中。

首先我們來寫lex:
**********************************************************
%{
#include <string.h>

extern int lineno;

%}
ws   [ /t]+

nl         /n

whitespace  ^[ /t]*/n

url   ([^ /t/</>]*)@([^ /t/</>]*)

qstring    /"[^/"/n]*[/"/n]

commpro  UDP|TCP|TLS|SCTP

float   [0-9]*.[0-9]*

integer  [0-9]+

threenum [0-9]{3}

str     [a-zA-Z][a-zA-Z0-9]+

field   [a-zA-Z0-9.]+

name   [a-zA-Z]+[ ]*[a-zA-Z]*

localid  [a-zA-Z0-9-]+@[a-zA-Z0-9.]+

 

 

%%
{ws} ;

{whitespace}    { return WHITESPACE; }


{url}   { yylval.string = strdup(yytext); return URL; }

{qstring}  { yylval.string = strdup(yytext+1); /* skip open quote */
             if(yylval.string[yyleng-2] != '"')
          warning("Unterminated character string",(char *)0);
     else
          yylval.string[yyleng-2] = '/0'; /* remove close quote */
             return QSTRING;
           }

{commpro}   { yylval.string = strdup(yytext); return COMMPRO; }

{float}   { yylval.floatval = atof(yytext); return FLOAT; }

{integer}  { yylval.intval = atoi(yytext); return INTEGER; }

{threenum} { yylval.intval = atoi(yytext); return THREENUM; }

{str}   { yylval.string = strdup(yytext); return STR; }

{field}  { yylval.string = strdup(yytext); return FIELD; }

{name}   { yylval.string = strdup(yytext); return NAME; }

{localid}  { yylval.string = strdup(yytext); return LOCALID; }
         
         
/*command*/         
INVITE     { return INVITE; }
ACK        { return ACK; }
CANCEL     { return CANCEL; }
REGISTER   { return REGISTER; }
BYE        { return BYE; }
OPTIONS    { return OPTIONS; }

/*msg head*/
Via:        { return VIA; }
From:       { return FROM; }
To:         { return TO; }
Call-ID:    { return CALLID; }
CSeq:       { return CSEQ; }
Max-Forwards:  { return MAXFORWARDS; }
Contact:    { return CONTACT; }
Content_type: { return CONTACTTYPE; }
Content_length: { return CONTACTLENGTH; }
Supported: { return SUPPORTED; }
Require: { return REQUIRE; }

 

{nl}       { lineno++; }
.          { return yytext[0]; }
%%

***********************************************************************


寫好lex,我們就來把前面的語法分析變成yacc代碼:
*************************************************************
%{
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
%}

%union {
   
    char    *string;     /* string buffer */
    int     intval;
    double  floatval;
    int     cmd;          /* command value */
    int     headfield;
}

 


%token <string>  QSTRING LOCALID COMMPRO URL FIELD NAME STR
%token <cmd>   INVITE ACK CANCEL REGISTER BYE OPTIONS
%token <headfield>  VIA FROM TO CALLID CSEQ MAXFORWARD CONTACT CONTACTTYP CONTACTLEN SUPPORTED REQUIRE
%token <floatval> FLOAT
%token <intval>  INTEGER THREENUM

%type <intval>  lineno
%%

 


start: sip_msg
 ;
 
/*sip
包括兩種消息:產生和處理*/
sip_msg: generating_request
 | sending_request
 ;
 
/***************************************************************/
/*
請求包括 請求行 消息頭 空行 消息體 */
generating_Request: req_line msg_head SPACELINE msg_body
 | start_line msg_heads
 ;


/*
處理包括 狀態行 消息頭 空行 消息體 */
sending_request: status_line msg_head SPACELINE msg_body
/***************************************************************/


/***************************************************************/
/*
請求行包括 Method  Request-URI  SIP-VERSION  */
req_line: command require_url sip_ver
 ;

/*狀態行包括 SIP-VERSION  STATUS-CODE  Reason-Phrase */
status_line: sip_ver status_code reason_phrase
 ;
/***************************************************************/


/***************************************************************/
/*
消息體包括多個消息行*/
msg_heads: msg_head
 |msg_heads msg_head
 ; /*
可多個 如:msg_heads: via from to msg_head: via from to cseq call_id*/

//msg_head: vias froms tos call_ids cseqs max_forwards contacts content_types content_lengths
 ;

/*頭域類型*/
msg_head: vias /*
任何一個*/
 | froms
 | tos
 | call_ids
 | cseqs
 | max_forwards
 | contacts
 | content_types
 | content_lengths
 | supported
 | require
 ;
/***************************************************************/


/********************************************************************/

vias:via /*一個或多個*/
 | vias via
 ;
via: VIA sip_ver_pro field
 ;
 
froms: from /*
一個*/
 ;
from: FROM NAME require_url
 ;
 
tos: to /*
一個*/
 ;
to: TO NAME require_url
 ;
 
call_ids: call_id /*
一個*/
 ;
call_id: CALL_ID URL
 ;
 
cseqs:    cseq /*
一個*/
 ;
cseq: CSEQ INTEGER command
 ;
 
max_forwards: max_forward /*
一個*/
 ;
max_forward: MAXFORWARDS INTEGER
 ;

 

contacts:  /*空或一個*/
 | contact
 ;
contact:  CONTACT NAME require_url
 ;
 
content_types: /*
空或一個*/
 | content_type
 ;
content_type:
 | media_type
 ;


content_lengths: /*
空或一個*/
 | content_length
content_length: CONTACTLENGTH INTEGER
 ;
 
/********************************************************************/

 

 

/********************************************************************/
command:  INVITE
 | ACK
 | CANCEL
 | REGISTER
 | BYE
 | OPTIONS
 ;

status_code: THREENUM
 ;

reason_phrase: STR
 ;

require_url: sip ":" URL { printf(" %s ",$2); }
 | "<" sip URL ">"
 ;
sip_ver: "SIP/" INTEGER { printf(" %d ",$2); }
 ;

sip: sip
 |sips
 ;

sip_ver_pro: sip_ver "/" commpro
 ;
 
 
field:  FIELD ":" INTEGER
 ;
 
media-type: STR "/" STR
 ;
/********************************************************************/

 

makefile:
*******************************
CC = gcc
LIBS = -ly -ll -lm
LEX = flex
YACC = yacc
CFLAGS = -DYYDEBUG=1

SipAnalyse:y.tab.o lex.yy.o
 $(CC) $(CFLAGS) -o SipAnalyse y.tab.o lex.yy.o $(LIBS)
 
lex.yy.o: lex.yy.c y.tab.h


y.tab.c y.tab.h: sip.y
 $(YACC) -d sip.y
 
lex.yy.c: sip.l
 $(LEX) sip.l
****************************************
以上代碼還沒有檢查,如有問題請回復,有興趣者在此基礎上進行修改。
                                                                                                   大大狗
                                                                                                [email protected]

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章