/[resiprocate]/main/sip/resiprocate/README
ViewVC logotype

Annotation of /main/sip/resiprocate/README

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1284 - (hide annotations) (download)
Sat Mar 22 19:33:59 2003 UTC (16 years, 10 months ago) by jason
File size: 7944 byte(s)
*** empty log message ***

1 jason 173 September 23, 2002
2     head/vocal/sip2/sipstack/README
3    
4     SipMessage design goals:
5     - efficient parsing
6     - reasonable interface for the application writer
7     - reasonably easy path to adding new headers, methods, parameter names
8    
9     SipMessage design.
10    
11     There are two APIs to SipMessage; one from the transport layer 'up' and one from
12     the application layer 'down'. The transport layers pulls the raw message text
13     off the wire, parses the text just enough to segment it onto headers and sets
14     the text of the headers into the SipMessage generically. This minimal header
15     parse phase is called "pre-parsing".
16    
17     The pre-parse phase needs to identify the header for generic storage into the
18     SipMessage. In addition, the pre-parse phase needs to know if unescaped commas
19     are delimiters in the header text to be parsed. However, the pre-parse phase
20     does not require static typing of the header or whether the header can appear
21     multiple times in the message.
22    
23     The pre-parse phase allows unknown headers.
24    
25     The application requests a specific header by static type. If the header does
26     not exists, an empty header of the appropriate type is created. If the header
27     has not already been parsed, a parser is created and associated with the
28     header. The parser is not invoked until the application requests a sub-part of
29     the header. This permits headers to be moved from one message to another without
30     parsing within the header.
31    
32     The parser is statically typed to provide a specific interface to the
33     application. The specifics of how to parse a message of a given type is
34     implemented by the parser type. The static header types are available to the
35     application through global variables named after the headers; e.g. CallId, CSeq,
36     From, Via.
37    
38     The interface from each parser is a set of accessors. Each accessor may return a
39     reference, allowing the application to set the corresponding value directly, or
40     it may return a const reference, indicating a read only value. Most parsers also
41     present an interface to a generic parameter accessor. This generic parameter
42     accessors allows the application to get or set proprietary parameters.
43    
44     The application retrieves unknown headers by the string name of the unknown
45     header.
46    
47     Interface Examples:
48    
49     SipMessage *msg;
50     msg->get(From).getAddressOfRecord();
51     Data& aor = msg->get(From)->host();
52     msg->get(From).host() = "vovida.org";
53     msg->exists(Warning);
54     msg->exists("Proprietary-Header"); // true if present
55     msg->get("Proprietary-Header"); // returns ParserContainer<String>&
56    
57     for (Vias::iterator i = msg->get(Vias).begin();
58     i != msg->get(Vias).end(); i++)
59     {
60     Data& host = i->host();
61     int& port = i->port();
62     }
63    
64     Implementation:
65    
66     There is a fixed set of headers. Each header is assigned an enum value. There is
67     a type associated with each enum value and a distinctly named global variable of
68     header type. The enum value is used to store and retrieve the headers at
69     runtime. The header type is used to retrieve the parsed and statically typed
70     headers at compile time.
71    
72     A SipMessage contains an array of pointers to HeaderFieldValueList. This array
73     is indexed by the header enums.
74    
75     The pre-parse phase consists of:
76     0. determine the boundaries of the header string
77     1. determine the boundaries of the header name string
78     2. look up the enum value for the header name
79     3. look up the comma tokenizing property of the header enum
80     4. determine the boundaries of each header in the header string
81     5. for each header in the header string, add the header string boundaries by
82     enum to the message -- the message stores the header string boundaries in the
83     as indexed by the header enum
84    
85     While processing headers the pre-parse will allocate chunks of memory to hold the
86     header strings. Each of these buffers is passed opaquely to the message for
87     deletion when the message is deleted.
88    
89     After pre-parsing the message header array contains one HeaderFieldValueList for
90     each header encountered in the pre-parse. Each HeaderFieldValueList contains
91     a list of HeaderFieldValue.
92    
93     The application requests the contents of a header through a type safe interface;
94     the returned object is either a particular parser type or a particular parser
95     container. A parser container is returned if and only if the header is specified
96     to permit multiple values.
97    
98     If the header specifies multiple values, the returned value is iterable. Each
99     iteration provides access to a header value. In addition, there is an interface
100     on the returned value to determine the number of header values.
101    
102     The returned value in the single header value case, and within the iteration
103     over the multi header value case provides access to the components of the header
104     value specfic to the type of header. For example, CSeq provides getMethod() and
105     sequence. For sequence, the sequence value is an integer returned by reference
106     and may be directly modified.
107    
108     Adding a new header:
109    
110     Assume the new header name New-Header
111    
112     Symbols.hxx
113     1. Add New_Header to the static symbol declarations.
114     Symbols.chxx
115     1. Add New_Header = "New-Header" to the static symbol definitions.
116    
117     HeaderTypes.hxx
118     1. Add New_Header to the Headers::Type enum. Add this entry anywhere before UNKNOWN.
119     Headers are output in the same order they appear in the Headers::Type enum.
120     2. Determine if the header allows multiple values. Use the MultiHeader template
121     if the new header allows multiple values, use the Header template if the new
122     header does not allow multiple values.
123     3. Determine the parser type for the header. This may be StringComponent for
124     unstructured headers, may be another existing parser type (see
125     ParserCategories.hxx), or may require a new parser type.
126     4. Add the declaration of the header type and the header type global variable to
127     HeaderTypes.hxx
128     e.g.:
129     class Header<Headers::New_Header>
130     {
131     public:
132     typedef StringComponent Type;
133     Header()
134     {
135     Headers::CommaTokenizing[Headers::New_Header] = Type::isCommaTokenizing;
136     HeaderStrings[Headers::New_Header] = Symbols::New_Header;
137     }
138     };
139     extern Header<Headers::Content_Disposition> Content_Disposition;
140     5. Add the mapping from the four character hash to the header enum. This is
141     error prone. The hash value is platform dependent.
142    
143     HeaderTypesSetup.cxx
144     1. Add a line to the hash id generator.
145    
146     HeaderTypes.cxx
147     1. Add the definition of the new header type global variable. Be sure to use the
148     same template type as in the declaration.
149     e.g.
150     Header<Headers::New_Header> Vocal2:: New_Header>;
151    
152     ParserCategories.hxx
153     (if the new header requires a new parser)
154    
155     1. Declare the new parser category as publicly inheriting from
156     ParserCategory.
157     2. Determine if commas can be used to include multiple header values in a single
158     line.
159     3. Declare virtual ParserCategory* clone(HeaderFieldValue*) const;
160     4. Declare virtual void parse();
161     5. Declare private members as required to store the parsed header value.
162     6. Declare public methods as required to access the parsed header value.
163     7. Typedef the container for the parser. Not required if the header value is
164     never used in a header that allows multiple values.
165    
166     e.g.
167     typedef ParserContainer<NewComponent> NewComponents;
168    
169     ParserCategories.cxx
170     (if the new header requires a new parser)
171     1. Define clone(), parse()
172     2. Define accessors. Each accessor must call checkParsed() before processing any
173     data.
174    
175    
176     (*
177     It would be nice if getHeaderType(const char *headerName, int len)
178     was defined my configure/make. The supported.hxx would be replaced
179     with a configuration file headers.hdr that specified the SIP header name, the
180     C++ parser category, and whether the header allows multiple values.
181    
182     This file could be compiled into the various declarations and definitions.
183     It is even possible to allow the user to specify additional headers in the
184     code; have the automatically generated types go into the enum
185     HeaderTypesBase, and have HeaderTypes inherit; HeaderTypes::Types could
186     continue where the inherited enum leaves off.
187     *)
188    
189 jason 1284
190    

webmaster AT resiprocate DOT org
ViewVC Help
Powered by ViewVC 1.1.27