Use Overview
From reSIProcate
ReSIProcate is an object oriented SIP interface and stack implemented in C++. The reSIProcate approach emphasizes consistency, type safety, and ease of use.
A central component of any SIP service is handling of SIP messages and their parts. A SIP message consists of headers, request/status line, and body.
Contents |
[edit] Headers
Headers are accessed from messages with the header method. The header method is overloaded so that its return value is appopriate for each type of header. The actual header method is determined by the header type token passed to the overloaded header method.
[edit] Header Access Tokens
Each header type defined in RFC3261 has a corresponding header access token. For example, the header access tokens for To and From headers are h_To and h_From. The rule for determing the header access token from a header as named in RFC3261 is to remove all dashes from the header name and prefix the result with "h_". For example, "Content-Disposition" becomes h_ContentDisposition.
Given an existing message, fetching the To header is simply:
const NameAddr& to = message->header(h_To);
[edit] Well-formedness check
Each header-field-value type has a function that may be used to determine whether or not it is well-formed.
if(message->header(h_To).isWellFormed())
{
// Do stuff with the header
}
Right now, isWellFormed() is minimally picky; it will only return false if the header-field-value is unparsable. It does not report the presence of forbidden characters, unless their presence makes it impossible to parse the header. No method exists to carry out a full, pedantic syntax check on a header-field-value. This functionality may be added in the future.
[edit] Accessor/Setters
The header methods are both accessors and setters. Accessing a header that isn't in the message creates the header in a default state if the message is non-const.
To set an empty message's To header:
SipMessage message;
// displayName and uri are accessor/setter methods on NameAddr, the storage class
// for To headers.
message.header(h_To).displayName() = "Speedy Shannon";
message.header(h_To).uri() = Uri("speedy@home.com");
Please note: If a header is malformed, and it has not yet been parsed, these accessors/setters will throw a ParseBuffer::Exception!
[edit] Existence Check
The header methods are used also to access existing headers. If you want to make sure that you are accessing an existing header and are not creating a default header, use the exists method. The exists method is overloaded with the same access tokens.
SipMessage* message;
if (!message->exists(h_To))
{
// complain bitterly
...
}
else
{
NameAddr& to = message->header(h_To);
...
}
[edit] Const Access
However, if the message variable is declared const, the header methods will not create a default instance of a missing header, but will throw SipMessage::Exception. This is a typical mode when working with incoming messages.
try
{
const SipMessage* message;
To::Type& to = message->header(h_To);
...
}
catch (SipMessage::Exception e)
{
// complain bitterly
...
}
[edit] Remove
The remove method is also overloaded for the access tokens. Removing a header that does not exist is a no-op.
SipMessage* message = ...; message->remove(h_RecordRoutes);
[edit] Single Instance
Each header type is either a single instance or multiple instance. For example, the header type To is single instance while the header type Record-Route is multiple instance. The return types differ accordingly.
[edit] Multiple Instance
Multiple instance headers are accessed through a collection of the appropriate header type. As a programming hint, access tokens for multiple headers are pluralized.
Similarly, the collection of each header type is named the pluralized header type. Below is an example accessing a collection of NameAddr instances.
NameAddrs& rr = message.header(h_RecordRoutes);
The collection of header values can be iterated in the usual stl like fashion.
for (NameAddrs::iterator i = rr.begin(); i != rr.end(); ++i)
{
NameAddr& r = *i;
...
}
All collections of header values support begin, end, empty, size, front, back, push_back, push_front, reverse, and clear. Each collection is specific to the header type so no casting is necessary.
NameAddr na;
na.displayName() = "Alice";
na.uri() = Uri("sip:alice@company.com");
rr.push_back(na);
[edit] Request/Status Line
The request/status lines are special cases of headers. They are accessed by the header method with the header type tokens h_RequestLine and h_StatusLine. A message may have one or the other of these headers but never both. To determine if a message has a Request Line, use:
if (message->isRequest())
{
...
}
Similarly for Status Line:
if (message->isResponse())
{
...
}
Note that a newly created message has neither a request or status line. The application must add one or the other for the message to be well formed.
[edit] Body
A message body is accessed with the getContents method. The retured value is of type Contents*, an abstract type. The return value must be cast (dynamic_cast is recommended for runtime type safety) to be used. The content type of a message can be determined by examining the Content-Type header of the message.
New message contents are created by instantiating an instance of a type derived from Contents. For example, SdpContents. A variety of content types are currently supported, including mulitpart, signed, and Pkcs7. New content types can be created either inside or outside of the reSIP library (see Creating a New Contents Type).
Setting the contents of a message takes care of setting the Content-Type and Content-Length of the message.
Pkcs7* pres = new Pkcs7(); ... message->setContents(pres);
Alternatively, pass the newly created contents as an auto_ptr and avoid the copy:
std::auto_ptr<Contents> pres(new Pkcs7()); ... message->setContents(pres);
Recursive multipart contents are supported.
[edit] Header Types
Every RFC 3261 header has a corresponding access token. However, many of the headers have identical form. For example. The To and From header values both consist of a display name and a URI. The To and From headers are managed programmatically as NameAddr instances. The class that manages each header type is responsible for parsing header text, providing storage and access during the life of the message, and serializing the header value to text for transmission.
The table below shows the reSIP types for each of the built in RFC headers currently supported by reSIP. The reSIP type is the return type of a SipMessage header call with the access token as its argument. Plural values mean that the return value is a collection of the type indicated by the singular. The plural type exists in reSIP and is an STL like container.
| RFC Name | reSIP Access Token | reSIP Type |
|---|---|---|
| Accept | h_Accepts | Mimes |
| Accept-Encoding | h_AcceptEncodings | Tokens |
| Accept-Language | h_AcceptLanguages | Tokens |
| Alert-Info | h_AlertInfos | GenericUris |
| Allow | h_Allows | Tokens |
| Authentication-Info | h_AuthenticationInfos | Auths |
| Authorization | h_Authorizations | Auths |
| Call-ID | h_CallID, h_CallId | CallID, CallId |
| Call-Info | h_CallInfos | GenericUris |
| Contact | h_Contacts | NameAddrs |
| Content-Disposition | h_ContentDisposition | Tokens |
| Content-Encoding | h_ContentEncoding | Tokens |
| Content-Language | h_ContentLanguages | Tokens |
| Content-Length | h_ContentLength | UInt32Category |
| Content-Type | h_ContentType | Mime |
| Content-Transfer-Encoding | h_ContentTransferEncoding | StringCategory |
| CSeq | h_CSeq | CSeqCategory |
| Date | h_Date | DateCategory |
| Error-Info | h_ErrorInfos | GenericUris |
| Expires | h_Expires | UInt32Category |
| From | h_From | NameAddr |
| In-ReplyTo | h_InReplyTo | CallID, CallId |
| Max-Forwards | h_MaxForwards | UInt32Category |
| MIME-Version | h_MIMEVersion | Tokens |
| Min-Expires | h_MinExpires | UInt32Category |
| Organization | h_Organization | StringCategory |
| Priority | h_Priority | Tokens |
| Proxy-Authenticate | h_ProxyAuthenticates | Auths |
| Proxy-Authorization | h_ProxyAuthorizations | Auths |
| Proxy-Require | h_ProxyRequires | Tokens |
| Record-Route | h_RecordRoutes | NameAddrs |
| Reply-To | h_ReplyTo | NameAddr |
| Require | h_Requires | Tokens |
| Retry-After | h_RetryAfter | UInt32Category |
| Route | h_Routes | NameAddrs |
| Server | h_Server | StringCategory |
| Subject | h_Subject | StringCategory |
| Supported | h_Supporteds | Tokens |
| Timestamp | h_Timestamp | StringCategory |
| To | h_To | NameAddr |
| Unsupported | h_Unsupporteds | Tokens |
| User-Agent | h_UserAgent | StringCategory |
| Via | h_Vias | Vias |
| Warning | h_Warnings | WarningCategories |
| WWW-Authenticate | h_WWWAuthenticates | Auths |
The following table lists each of the reSIP types for managing headers. A complete list of accessors is included for each type. Recall that many headers are multi-valued; the return type in the multi-valued cases must be iterated to get to the types shown. Multi-values headers are identified with multi-valued.
[edit] RequestLine
RFC name:
Request-Line
Description:
The first line of a request message. Does not correspond to a header proper
but is accessed with the header interface in reSIP.
Example:
INVITE sip:bob@biloxi.com SIP/2.0
Parts:
RFC Name accessor reSIP type settable
--------------------------------------------------------------
Request-URI uri() Uri yes
Method getMethod() MethodTypes yes
Method unknownMethodName() Data yes
SIP-Version getSipVersion() Data no
RFC Headers: <none>
[edit] StatusLine
RFC name:
Status-Line
Description:
The first line of a response message. Does not correspond to a header proper
but is accessed with the header interface in reSIP.
Example:
SIP/2.0 200 OK
Parts:
RFC Name accessor reSIP type settable
--------------------------------------------------------------
Status-Code statusCode() int yes
SIP-Version getSipVersion() Data no
Reason-Phrase reason() Data yes
RFC Headers: <none>
[edit] Auth
RFC name:
challenge
Description:
Identifies the authentication scheme in a challenge response.
Example:
Digest-Authenticate: username="Alice", realm="atlanta.com",
nonce="84a4cc6f3082121f32b42a2187831a9e",
response="7587245234b3434cc3412213e5f113a5432"
Parts:
RFC Name accessor reSIP type settable
----------------------------------------------------------
auth-scheme scheme() Data yes
RFC Headers:
- Authentication-Info
- Authorization multi-valued
- Proxy-Authenticate multi-valued
- Proxy-Authorization multi-valued
- WWW-Authenticate multi-valued
Note that the parameters to the Auth type are comma separated. reSIP correctly interprets the commas as separating parameters and not header values.
[edit] CSeqCategory
RFC name:
CSeq
Description:
Places the message in sequence in the call.
Example:
CSeq: 314159 INVITE
Parts:
RFC Name accessor reSIP type settable
--------------------------------------------------------------
sequence() int yes
Method method() MethodTypes yes
unknownMethodName() Data no
RFC Headers:
- CSeq
[edit] CallId
RFC name:
Call-ID
Description:
Uniquely identifies the call.
Example:
Call-ID: a84b4c76e66710@pc33.atlanta.com
Parts:
RFC Name accessor reSIP type settable
----------------------------------------------------------
value() Data yes
RFC Headers:
- Call-ID
Note: C++ type synonym for CallID
[edit] DateCategory
RFC name:
SIP-date
Description:
Human readable date string.
Example:
Date: Sat, 13 Nov 2010 23:29:00 GMT
Parts:
RFC Name accessor reSIP type settable
----------------------------------------------------------
wkday dayOfWeek() DayOfWeek yes
date1
dayOfMonth int yes
month() int yes
year() int yes
time
hour() int yes
minute() int yes
second() int yes
RFC Headers:
- Date
[edit] GenericUri
RFC name:
absoluteURI
Description:
Non-structured human readable URI.
Example:
Alert-Info: <http://www.example.com/sounds/moo.wav>
Parts:
RFC Name accessor reSIP type settable
----------------------------------------------------------
uri() Data yes
RFC Headers:
- Alert-Info
- Call-Info
- Error-Info
[edit] ExpiresCategory
RFC name: expires
Description:
Seconds to expiration.
Example:
Expires: 5
Parts:
RFC Name accessor reSIP type settable
----------------------------------------------------------
value() int yes
RFC Headers:
- Expires
[edit] Mime
RFC name: media-type Description: Mime type and sub-type. Example: Content-Type: application/sdp Parts: RFC Name accessor reSIP type settable ---------------------------------------------------------- m-type type() Data yes m-subtype subType() Data yes
RFC Headers:
- Accept multi-valued
- Content-Type
[edit] NameAddr
RFC name: name-addr Description: URI and display name. Example: To: Bob <sip:bob@biloxi.com> Parts: RFC Name accessor reSIP type settable ---------------------------------------------------------- display-name displayName() Data yes addr-spec uri() Uri yes
RFC Headers:
- Contact multi-valued
- From
- Record-Route multi-valued
- Refer-To
- Referred-By
- Reply-To
- Route multi-valued
- To
[edit] StringCategory
RFC name:
TEXT-UTF8-TRIM
Description:
Unstructured human readable text.
Example:
Organization: Boxes by Bob
Parts:
RFC Name accessor reSIP type settable
----------------------------------------------------------
value() Data yes
RFC Headers:
- Content-Transfer-Encoding
- Organization
- Server
- Subject
- User-Agent
- Timestamp
- Extension Header multi-valued
[edit] Token
RFC name:
token
Description:
A word.
Example:
Accept-Encoding: gzip
Parts:
RFC Name accessor reSIP type settable
----------------------------------------------------------
value() Data yes
RFC Headers:
- Accept-Encoding multi-valued
- Accept-Language multi-valued
- Allow multi-valued
- Allow-Events multi-valued
- Content-Disposition
- Content-Encoding
- Content-Language multi-valued
- Event
- Mime-Version
- Priority
- Proxy-Require multi-valued
- Require multi-valued
- Security-Client multi-valued
- Security-Server multi-valued
- Security-Verify multi-valued
- Subscription-State multi-valued
- Supported multi-valued
- Unsupported multi-valued
[edit] UInt32Category
RFC name:
1*DIGIT
Description:
An integer.
Example:
Max-Forwards: 70
Parts:
RFC Name accessor reSIP type settable
----------------------------------------------------------
value() int yes
comment comment() Data yes
RFC Headers:
- Content-Length does not permit (comment) but reSIP does
- Max-Forwards does not permit (comment) but reSIP does
- Min-Expires does not permit (comment) but reSIP does
- Retry-After
[edit] Via
RFC name: via-parm Description: Via entry. Example: Via: SIP/2.0/UDP pc33.atlanta.com;branch=z9hG4bK776asdhds Parts: RFC Name accessor reSIP type settable ------------------------------------------------------------ protocol-name protocolName() Data yes protocol-version protocolVersion() Data yes transport transport() Data yes host sentHost() Data yes port sentPort() int yes
RFC RFC Headers:
- Via (multi-valued)
[edit] WarningCategory
RFC name: warning-value Description: Example: Parts: RFC Name accessor reSIP type settable -------------------------------------------------------- warn-code code() int yes warn-agent hostname() Data yes warn-text text() Data yes
RFC Headers:
- Warning multi-valued
[edit] Parameters
Parameters are accessed from headers. The syntax is similar to header access.
Like headers, there is an overloaded accessor method. For parameters, this
method is param. The argument to param is a parameter
type token indicating the parameter to be accessed. The parameter type
token always begins with "p_" and the rest is camelCase starting with a
lowercase.
For example:
const Data& tag = msg->header(h_To).param(p_tag);
Like headers, there is also an overloaded exists method and
an overloaded remove method. For both methods, the argument is
again the parameter type token.
According to the grammar, each header has a set of acceptable parameters. Some headers accept no parameters. reSIP makes a simplifying assumption; all headers can have all parameters. While it is the goal of reSIP that every legal SIP message be parseable, reSIP does not strictly enforce production of legal SIP. In practice, correct usage will result in legal SIP, but it is not very difficult to use reSIP to produce a problematic message. Take home lesson -- the reSIP programmer must take responsibilty when adding parameters to a header.
A corollary to this simplifying assumption is that the form of a parameter is independent of the header it appears in. A ttl parameter must always be followed by an integer even when used in a header that does not specify the syntax for a ttl parameter. (!dlb! potential compatibility issue)
Parameters, like headers, corresponds to a small set of classes that manage parsing, accesing, and serializing to text.
| RFC name | reSIP access token | reSIP type |
|---|---|---|
| access-type | p_accessType | DataParameter |
| algorithm | p_algorithm | DataParameter |
| boundary | p_boundary | DataParameter |
| branch | p_branch | BranchParameter |
| charset | p_charset | DataParameter |
| cnonce | p_cnonce | QuotedDataParameter |
| comp | p_comp | DataParameter |
| d-alg | p_dAlg | DataParameter |
| d-qop | p_dQop | DataParameter |
| d-ver | p_dVer | QuotedDataParameter |
| directory | p_directory | DataParameter |
| domain | p_domain | QuotedDataParameter |
| duration | p_duration | IntegerParameter |
| expiration | p_expiration | IntegerParameter |
| expires | p_expires | IntegerParameter |
| filename | p_filename | DataParameter |
| from-tag | p_fromTag | DataParameter |
| handling | p_handling | DataParameter |
| id | p_id | DataParameter |
| lr | p_lr | ExistsParameter |
| maddr | p_maddr | DataParameter |
| method | p_method | DataParameter |
| micalg | p_micalg | DataParameter |
| mobility | p_mobility | DataParameter |
| mode | p_mode | DataParameter |
| name | p_name | DataParameter |
| nc | p_nc | DataParameter |
| nonce | p_nonce | QuotedDataParameter |
| opaque | p_opaque | QuotedDataParameter |
| permission | p_permission | DataParameter |
| protocol | p_protocol | DataParameter // should be QuotedDataParameter? |
| purpose | p_purpose | DataParameter |
| q | p_q | FloatParameter |
| realm | p_realm | QuotedDataParameter |
| reason | p_reason | DataParameter |
| received | p_received | DataParameter |
| response | p_response | QuotedDataParameter |
| retry-after | p_retryAfter | IntegerParameter |
| rport | p_rport | RportParameter |
| server | p_server | DataParameter |
| site | p_site | DataParameter |
| size | p_size | DataParameter |
| smime-type | p_smimeType | DataParameter |
| stale | p_stale | DataParameter |
| tag | p_tag | DataParameter |
| to-tag | p_toTag | DataParameter |
| transport | p_transport | DataParameter |
| ttl | p_ttl | IntegerParameter |
| uri | p_uri | QuotedDataParameter |
| user | p_user | DataParameter |
| username | p_username | DataParameter // should be QuotedDataParameter? |