<html>
<head>
    <base href="https://wiki.asterisk.org/wiki">
            <link rel="stylesheet" href="/wiki/s/en/2176/25/9/_/styles/combined.css?spaceKey=AST&amp;forWysiwyg=true" type="text/css">
    </head>
<body style="background: white;" bgcolor="white" class="email-body">
<div id="pageContent">
<div id="notificationFormat">
<div class="wiki-content">
<div class="email">
    <h2><a href="https://wiki.asterisk.org/wiki/display/AST/res_sip+design">res_sip design</a></h2>
    <h4>Page <b>edited</b> by             <a href="https://wiki.asterisk.org/wiki/display/~mmichelson">Mark Michelson</a>
    </h4>
        <div id="versionComment">
        <b>Comment:</b>
        Fill in ast_sip_digest_challenge_data a bit more.<br />
    </div>
        <br/>
                         <h4>Changes (20)</h4>
                                 
    
<div id="page-diffs">
                    <table class="diff" cellpadding="0" cellspacing="0">
    
            <tr><td class="diff-snipped" >...<br></td></tr>
            <tr><td class="diff-unchanged" > <br>/*! <br></td></tr>
            <tr><td class="diff-changed-lines" >* \brief Data used for creating authentication <span class="diff-changed-words">challenges<span class="diff-added-chars"style="background-color: #dfd;">.</span></span> <br></td></tr>
            <tr><td class="diff-added-lines" style="background-color: #dfd;"> *  <br> * This data gets populated by an authenticator&#39;s get_authentication_credentials() callback. <br></td></tr>
            <tr><td class="diff-unchanged" > */ <br>struct ast_sip_digest_challenge_data { <br></td></tr>
            <tr><td class="diff-deleted-lines" style="color:#999;background-color:#fdd;text-decoration:line-through;">    /*! The realm to which the user is authenticating */ <br></td></tr>
            <tr><td class="diff-added-lines" style="background-color: #dfd;">    /*! <br>     * The realm to which the user is authenticating. An authenticator MUST fill this in. <br>     */ <br></td></tr>
            <tr><td class="diff-unchanged" >    const char *realm; <br>    /*! <br></td></tr>
            <tr><td class="diff-deleted-lines" style="color:#999;background-color:#fdd;text-decoration:line-through;">     * The username and secret to challenge. Can be <br>     * expressed either as plaintext or as an MD5 sum <br></td></tr>
            <tr><td class="diff-added-lines" style="background-color: #dfd;">     * Indicates whether the username and password are in plaintext or encoded as MD5. <br>     * If this is non-zero, then the data is an MD5 sum. Otherwise, the username and password are plaintext. <br>     * Authenticators MUST set this. <br></td></tr>
            <tr><td class="diff-unchanged" >     */ <br></td></tr>
            <tr><td class="diff-added-lines" style="background-color: #dfd;">    int is_md5; <br>    /*! <br>     * This is the actual username and secret. The is_md5 field is used to determine which member <br>     * of the union is to be used when creating the authentication challenge. In other words, if <br>     * is_md5 is non-zero, then we will use the md5 field of the auth union. Otherwise, we will <br>     * use the plain struct in the auth union. <br>     * Authenticators MUST fill in the appropriate field of the union. <br>     */ <br></td></tr>
            <tr><td class="diff-unchanged" >    union { <br></td></tr>
            <tr><td class="diff-added-lines" style="background-color: #dfd;">        /*! <br>         * Structure containing the username and password to encode in a digest authentication challenge. <br>         */ <br></td></tr>
            <tr><td class="diff-changed-lines" >struct <span class="diff-deleted-words"style="color:#999;background-color:#fdd;text-decoration:line-through;">plain</span> { <br></td></tr>
            <tr><td class="diff-unchanged" >            const char *username; <br>            const char *password; <br></td></tr>
            <tr><td class="diff-added-lines" style="background-color: #dfd;">        } plain; <br></td></tr>
            <tr><td class="diff-changed-lines" ><span class="diff-deleted-words"style="color:#999;background-color:#fdd;text-decoration:line-through;">};</span> <span class="diff-added-words"style="background-color: #dfd;">/*!</span> <br></td></tr>
            <tr><td class="diff-added-lines" style="background-color: #dfd;">         * An MD5-encoded string that incorporates the username and password. <br>         */ <br></td></tr>
            <tr><td class="diff-unchanged" >        const char *md5; <br></td></tr>
            <tr><td class="diff-deleted-lines" style="color:#999;background-color:#fdd;text-decoration:line-through;">    }; <br></td></tr>
            <tr><td class="diff-added-lines" style="background-color: #dfd;">    } auth; <br></td></tr>
            <tr><td class="diff-unchanged" >    /*! <br></td></tr>
            <tr><td class="diff-deleted-lines" style="color:#999;background-color:#fdd;text-decoration:line-through;">     * If non-zero the username and password are expressed as an <br>     * MD5 sum. Otherwise, the username and password are plaintext. <br></td></tr>
            <tr><td class="diff-added-lines" style="background-color: #dfd;">     * Domain for which the authentication challenge is being sent. This corresponds to the &quot;domain=&quot; portion of <br>     * a digest authentication. <br>     * <br>     * Authenticators do not have to fill in this field since it is an optional part of a digest. <br></td></tr>
            <tr><td class="diff-unchanged" >     */ <br></td></tr>
            <tr><td class="diff-deleted-lines" style="color:#999;background-color:#fdd;text-decoration:line-through;">    int is_md5; <br>    /*! Optional domain to use in the challenge */ <br></td></tr>
            <tr><td class="diff-unchanged" >    const char *domain; <br></td></tr>
            <tr><td class="diff-deleted-lines" style="color:#999;background-color:#fdd;text-decoration:line-through;">    /*! Optional opaque to use in the challenge */ <br></td></tr>
            <tr><td class="diff-added-lines" style="background-color: #dfd;">    /*! <br>     * Opaque string for digest challenge. This corresponds to the &quot;opaque=&quot; portion of a digest authentication. <br>     * Authenticators do not have to fill in this field. If an authenticator does not fill it in, Asterisk will provide one. <br>     */ <br></td></tr>
            <tr><td class="diff-unchanged" >    const char *opaque; <br></td></tr>
            <tr><td class="diff-added-lines" style="background-color: #dfd;">    /*! <br>     * Nonce string for digest challenge. This corresponds to the &quot;nonce=&quot; portion of a digest authentication. <br>     * Authenticators do not have to fill in this field. If an authenticator does not fill it in, Asterisk will provide one. <br>     */ <br>    const char *nonce; <br></td></tr>
            <tr><td class="diff-unchanged" >}; <br> <br></td></tr>
            <tr><td class="diff-snipped" >...<br></td></tr>
    
            </table>
    </div>                            <h4>Full Content</h4>
                    <div class="notificationGreySide">
        <div class='panelMacro'><table class='warningMacro'><colgroup><col width='24'><col></colgroup><tr><td valign='top'><img src="/wiki/images/icons/emoticons/forbidden.gif" width="16" height="16" align="absmiddle" alt="" border="0"></td><td>This page is a work in progress. Please refrain from making comments until this warning has been removed</td></tr></table></div>

<h1><a name="res_sipdesign-Overview"></a>Overview</h1>

<p>res_sip is the decadent dark chocolate core of the new SIP work in Asterisk 12. It is the cockpit of the SIP jet. As such, its contents are those upon which all other SIP modules (and potentially non-SIP modules) will rely. The following describes its design and its public APIs.</p>

<h1><a name="res_sipdesign-Makeup"></a>Makeup</h1>

<p>res_sip can be divided into four overall sections:</p>

<ul>
        <li>service registrar</li>
        <li>SIP threadpool operator</li>
        <li>provider of common SIP methods</li>
        <li>servicer of PJSIP endpoint (i.e. reads incoming SIP messages)</li>
</ul>


<h1><a name="res_sipdesign-Startupprocess"></a>Startup process</h1>

<p>On startup, res_sip will create a threadpool for SIP to use. The threadpool's specifics will be discussed on a separate page. The threadpool will be used for as much of SIP's operation as possible. After starting the threadpool, res_sip will create a PJSIP endpoint and then begin handling incoming requests from the endpoint.</p>

<h1><a name="res_sipdesign-Publicmethods"></a>Public methods</h1>

<h2><a name="res_sipdesign-Structures"></a>Structures</h2>
<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="theme: Confluence; brush: c; gutter: false">/*!
 * \brief Opaque structure representing related SIP tasks
 */
struct ast_sip_work;

/*!
 * \brief Data used for creating authentication challenges.
 * 
 * This data gets populated by an authenticator's get_authentication_credentials() callback.
 */
struct ast_sip_digest_challenge_data {
    /*!
     * The realm to which the user is authenticating. An authenticator MUST fill this in.
     */
    const char *realm;
    /*!
     * Indicates whether the username and password are in plaintext or encoded as MD5.
     * If this is non-zero, then the data is an MD5 sum. Otherwise, the username and password are plaintext.
     * Authenticators MUST set this.
     */
    int is_md5;
    /*!
     * This is the actual username and secret. The is_md5 field is used to determine which member
     * of the union is to be used when creating the authentication challenge. In other words, if
     * is_md5 is non-zero, then we will use the md5 field of the auth union. Otherwise, we will
     * use the plain struct in the auth union.
     * Authenticators MUST fill in the appropriate field of the union.
     */
    union {
        /*!
         * Structure containing the username and password to encode in a digest authentication challenge.
         */
        struct {
            const char *username;
            const char *password;
        } plain;
        /*!
         * An MD5-encoded string that incorporates the username and password.
         */
        const char *md5;
    } auth;
    /*!
     * Domain for which the authentication challenge is being sent. This corresponds to the "domain=" portion of
     * a digest authentication.
     *
     * Authenticators do not have to fill in this field since it is an optional part of a digest.
     */
    const char *domain;
    /*!
     * Opaque string for digest challenge. This corresponds to the "opaque=" portion of a digest authentication.
     * Authenticators do not have to fill in this field. If an authenticator does not fill it in, Asterisk will provide one.
     */
    const char *opaque;
    /*!
     * Nonce string for digest challenge. This corresponds to the "nonce=" portion of a digest authentication.
     * Authenticators do not have to fill in this field. If an authenticator does not fill it in, Asterisk will provide one.
     */
    const char *nonce;
};

/*!
 * \brief An interchangeable way of handling digest authentication for SIP
 */
struct ast_sip_authenticator {
    /*! 
     * \brief Check if a request requires authentication
     * See ast_sip_requires_authentication for more details
     */
    int (*requires_authentication)(struct ast_sip_endpoint *endpoint, struct pjsip_rx_data *rdata);
    /*!
     * \brief Attempt to authenticate the incoming request
     * See ast_sip_authenticate_request for more details
     */
    int (*authenticate_request)(struct ast_sip_endpoint *endpoint, struct pjsip_rx_data *rdata);
    /*!
     * \brief Get digest authentication details
     * See ast_sip_get_authentication_credentials for more details
     */
    int (*get_authentication_credentials)(struct sip_digest_challenge_data *challenge);
};

/*!
 * \brief An entity responsible for identifying the source of a SIP message
 */
struct ast_sip_endpoint_identifier {
    /*!
     * \brief Callback used to identify the source of a message.
     * See ast_sip_identify_endpoint for more details
     */
    struct ast_sip_endpoint *(*identify_endpoint)(struct pjsip_rx_data *data);
};</pre>
</div></div>
<h2><a name="res_sipdesign-Serviceregistration"></a>Service registration</h2>
<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="theme: Confluence; brush: c; gutter: false">/*!
 * \brief Register a SIP service in Asterisk.
 *
 * This is more-or-less a wrapper around pjsip_endpt_register_module().
 * Registering a service makes it so that PJSIP will call into the
 * service at appropriate times. For more information about PJSIP module
 * callbacks, see the PJSIP documentation. Asterisk modules that call
 * this function will likely do so at module load time.
 *
 * \param module The module that is to be registered with PJSIP
 * \retval 0 Success
 * \retval -1 Failure
 */
int ast_sip_register_service(pjsip_module *module);

/*!
 * This is the opposite of ast_sip_register_service().  Unregistering a
 * service means that PJSIP will no longer call into the module any more.
 * This will likely occur when an Asterisk module is unloaded.
 *
 * \param module The PJSIP module to unregister
 */
void ast_sip_unregister_service(pjsip_module *module);

/*!
 * \brief Register a SIP authenticator
 *
 * An authenticator has three main purposes:
 * 1) Determining if authentication should be performed on an incoming request
 * 2) Gathering credentials necessary for issuing an authentication challenge
 * 3) Authenticating a request that has credentials
 *
 * Asterisk provides a default authenticator, but it may be replaced by a
 * custom one if desired.
 *
 * \param auth The authenticator to register
 * \retval 0 Success
 * \retval -1 Failure
 */
int ast_sip_register_authenticator(struct ast_sip_authenticator *auth);

/*!
 * \brief Unregister a SIP authenticator
 *
 * When there is no authenticator registered, requests cannot be challenged
 * or authenticated.
 *
 * \param auth The authenticator to unregister
 */
void ast_sip_unregister_authenticator(struct ast_sip_authenticator *auth);

/*!
 * \brief Register a SIP endpoint identifier
 *
 * An endpoint identifier's purpose is to determine which endpoint a given SIP
 * message has come from.
 *
 * Multiple endpoint identifiers may be registered so that if an endpoint
 * cannot be identified by one identifier, it may be identified by another.
 *
 * Asterisk provides two endpoint identifiers. One identifies endpoints based
 * on the user part of the From header URI. The other identifies endpoints based
 * on the source IP address.
 *
 * \param identifier The SIP endpoint identifier to register
 * \retval 0 Success
 * \retval -1 Failure
 */
int ast_sip_register_endpoint_identifier(struct ast_sip_endpoint_identifier *identifier);

/*!
 * \brief Unregister a SIP endpoint identifier
 *
 * This stops an endpoint identifier from being used.
 *
 * \param identifier The SIP endoint identifier to unregister
 */
void ast_sip_unregister_endpoint_identifier(struct ast_sip_endpoint_identifier *identifier);</pre>
</div></div>
<h2><a name="res_sipdesign-Threadpoolusage"></a>Threadpool usage</h2>
<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="theme: Confluence; brush: c; gutter: false">/*!
 * \brief Create a new SIP work structure
 *
 * A SIP work is a means of grouping together SIP tasks. For instance, one
 * might create a SIP work so that all tasks for a given SIP dialog will
 * be grouped together. Grouping the work together ensures that the
 * threadpool will distribute the tasks in such a way so that grouped work
 * will execute sequentially. Executing grouped tasks sequentially means
 * less contention for shared resources.
 *
 * \retval NULL Failure
 * \retval non-NULL Newly-created SIP work
 */
struct ast_sip_work *ast_sip_create_work(void);

/*!
 * \brief Destroy a SIP work structure
 *
 * \param work The SIP work to destroy
 */
void ast_sip_destroy_work(struct ast_sip_work *work);

/*!
 * \brief Pushes a task into the SIP threadpool
 *
 * This uses the SIP work provided to determine how to push the task.
 *
 * \param work The SIP work to which the task belongs
 * \param sip_task The task to execute
 * \param task_data The parameter to pass to the task when it executes
 * \retval 0 Success
 * \retval -1 Failure
 */
int ast_sip_push_task(struct ast_sip_work *work, int (*sip_task)(void *), void *task_data);</pre>
</div></div>
<h2><a name="res_sipdesign-CommonSIPmethods"></a>Common SIP methods</h2>
<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="theme: Confluence; brush: c; gutter: false">/*!
 * \brief General purpose method for sending a SIP request
 *
 * Its typical use would be to send one-off messages such as an out of dialog
 * SIP MESSAGE.
 *
 * \param method The method of the SIP request to send
 * \param body The message body for the SIP request
 * \dlg Optional. If specified, the dialog on which to send the message. Otherwise, the message
 *      will be sent out of dialog.
 * \retval 0 Success
 * \retval -1 Failure
 */
int ast_sip_send_request(const char *method, const char *body, struct pjsip_dialog *dlg);

/*!
 * \brief Determine if an incoming request requires authentication
 *
 * This calls into the registered authenticator's requires_authentication callback
 * in order to determine if the request requires authentication.
 *
 * If there is no registered authenticator, then authentication will be assumed
 * not to be required.
 *
 * \param endpoint The endpoint from which the request originates
 * \param rdata The incoming SIP request
 * \retval non-zero The request requires authentication
 * \retval 0 The request does not require authentication
 */
int ast_sip_requires_authentication(struct ast_sip_endpoint *endpoint, struct pjsip_rx_data *rdata);

/*!
 * \brief Authenticate an inbound SIP request
 *
 * This calls into the registered authenticator's authenticate_request callback
 * in order to determine if the request contains proper credentials as to be
 * authenticated.
 *
 * If there is no registered authenticator, then the request will assumed to be
 * authenticated properly.
 *
 * \param endpoint The endpoint from which the request originates
 * \param rdata The incoming SIP request
 * \retval 0 Successfully authenticated
 * \retval nonzero Failure to authenticate
 */
int ast_sip_authenticate_request(struct ast_sip_endpoint *endpoint, struct pjsip_rx_data *rdata);

/*!
 * \brief Get authentication credentials in order to challenge a request
 *
 * This calls into the registered authenticator's get_authentication_credentials
 * callback in order to get credentials required for challenging a request.
 *
 * \param[out] challenge The necessary data in order to be able to challenge a request
 * \retval 0 Success
 * \retval -1 Failure
 */
int ast_sip_get_authentication_credentials(struct ast_sip_digest_challenge_data *challenge);

/*!
 * \brief Challenge an inbound SIP request with a 401
 *
 *
 * This method will send an authentication challenge based on the details
 * given in its parameter
 *
 * \param challenge Details to help in constructing a WWW-Authenticate header
 * \retval 0 Success
 * \retval -1 Failure
 */
int ast_sip_challenge_request(struct sip_digest_challenge_data *challenge);

/*!
 * \brief Determine the endpoint that has sent a SIP message
 *
 * This will call into each of the registered endpoint identifiers'
 * identify_endpoint() callbacks until one returns a non-NULL endpoint.
 *
 * \param rdata The inbound SIP message to use when identifying the endpoint.
 * \retval NULL No matching endpoint
 * \retval non-NULL The matching endpoint
 */
struct ast_sip_endpoint *ast_sip_identify_endpoint(struct pjsip_rx_data *rdata);

/*!
 * \brief Add a header to an outbound SIP message
 *
 * \param tdata The message to add the header to
 * \param name The header name
 * \param value The header value
 * \retval 0 Success
 * \retval -1 Failure
 */
int ast_sip_add_header(struct pjsip_tx_data *tdata, const char *name, const char *value);

/*
 * \brief Add a body to an outbound SIP message
 *
 * If this is called multiple times, the latest body will replace the current
 * body.
 *
 * \param tdata The message to add the body to
 * \param body The message body to add
 * \retval 0 Success
 * \retval -1 Failure
 */
int ast_sip_add_body(struct pjsip_tx_data *tdata, const char *body);</pre>
</div></div>
    </div>
        <div id="commentsSection" class="wiki-content pageSection">
        <div style="float: right;" class="grey">
                        <a href="https://wiki.asterisk.org/wiki/users/removespacenotification.action?spaceKey=AST">Stop watching space</a>
            <span style="padding: 0px 5px;">|</span>
                <a href="https://wiki.asterisk.org/wiki/users/editmyemailsettings.action">Change email notification preferences</a>
</div>
        <a href="https://wiki.asterisk.org/wiki/display/AST/res_sip+design">View Online</a>
        |
        <a href="https://wiki.asterisk.org/wiki/pages/diffpagesbyversion.action?pageId=22085835&revisedVersion=8&originalVersion=7">View Changes</a>
                |
        <a href="https://wiki.asterisk.org/wiki/display/AST/res_sip+design?showComments=true&amp;showCommentArea=true#addcomment">Add Comment</a>
            </div>
</div>
</div>
</div>
</div>
</body>
</html>