Changeset 1021


Ignore:
Timestamp:
Mar 1, 2007 12:08:27 AM (13 years ago)
Author:
bennylp
Message:

More work on STUN session framework

Location:
pjproject/trunk/pjlib-util
Files:
1 deleted
5 edited

Legend:

Unmodified
Added
Removed
  • pjproject/trunk/pjlib-util/include/pjlib-util/stun_msg.h

    r1003 r1021  
    11751175 * the FINGERPRINT CRC attribute for the message. 
    11761176 * 
    1177  * @param msg           The STUN message to be printed. 
     1177 * @param msg           The STUN message to be printed. Upon return, 
     1178 *                      some fields in the header (such as message 
     1179 *                      length) will be updated. 
    11781180 * @param pkt_buf       The buffer to be filled with the packet. 
    11791181 * @param buf_size      Size of the buffer. 
     
    11871189 * @return              PJ_SUCCESS on success or the appropriate error code. 
    11881190 */ 
    1189 PJ_DECL(pj_status_t) pj_stun_msg_encode(const pj_stun_msg *msg, 
     1191PJ_DECL(pj_status_t) pj_stun_msg_encode(pj_stun_msg *msg, 
    11901192                                        pj_uint8_t *pkt_buf, 
    11911193                                        unsigned buf_size, 
     
    14231425 * @param xor_ed        If non-zero, the port and address will be XOR-ed 
    14241426 *                      with magic, to make the XOR-MAPPED-ADDRESS attribute. 
     1427 * @param addr          A pj_sockaddr_in or pj_sockaddr_in6 structure. 
    14251428 * @param addr_len      Length of \a addr parameter. 
    1426  * @param addr          A pj_sockaddr_in or pj_sockaddr_in6 structure. 
    14271429 * @param p_attr        Pointer to receive the attribute. 
    14281430 * 
     
    14331435                                    int attr_type,  
    14341436                                    pj_bool_t xor_ed, 
     1437                                    const pj_sockaddr_t *addr, 
    14351438                                    unsigned addr_len, 
    1436                                     const pj_sockaddr_t *addr, 
    14371439                                    pj_stun_generic_ip_addr_attr **p_attr); 
    14381440 
     
    14481450 * @param xor_ed        If non-zero, the port and address will be XOR-ed 
    14491451 *                      with magic, to make the XOR-MAPPED-ADDRESS attribute. 
     1452 * @param addr          A pj_sockaddr_in or pj_sockaddr_in6 structure. 
    14501453 * @param addr_len      Length of \a addr parameter. 
    1451  * @param addr          A pj_sockaddr_in or pj_sockaddr_in6 structure. 
    14521454 * 
    14531455 * @return              PJ_SUCCESS on success or the appropriate error code. 
     
    14581460                                     int attr_type,  
    14591461                                     pj_bool_t xor_ed, 
    1460                                      unsigned addr_len, 
    1461                                      const pj_sockaddr_t *addr); 
     1462                                     const pj_sockaddr_t *addr, 
     1463                                     unsigned addr_len); 
    14621464 
    14631465/** 
  • pjproject/trunk/pjlib-util/include/pjlib-util/stun_session.h

    r1008 r1021  
    2525#include <pj/list.h> 
    2626 
     27PJ_BEGIN_DECL 
     28 
     29 
     30/* **************************************************************************/ 
     31/** 
     32 * @defgroup PJLIB_UTIL_STUN_SESSION STUN Client/Server Session 
     33 * @brief STUN client and server session 
     34 * @ingroup PJLIB_UTIL_STUN 
     35 * @{ 
     36 */ 
     37 
    2738 
    2839/** Forward declaration for pj_stun_tx_data */ 
     
    3142/** Forward declaration for pj_stun_session */ 
    3243typedef struct pj_stun_session pj_stun_session; 
     44 
    3345 
    3446/** 
     
    5264     *                      packet sending. 
    5365     */ 
    54     pj_status_t (*on_send_msg)(pj_stun_tx_data *tdata, 
     66    pj_status_t (*on_send_msg)(pj_stun_session *sess, 
    5567                               const void *pkt, 
    5668                               pj_size_t pkt_size, 
    57                                unsigned addr_len,  
    58                                const pj_sockaddr_t *dst_addr); 
    59  
    60     /** 
    61      * Callback to be called when Binding response is received or the  
    62      * transaction has timed out. 
     69                               const pj_sockaddr_t *dst_addr, 
     70                               unsigned addr_len); 
     71 
     72    /**  
     73     * Callback to be called on incoming STUN request message. In the  
     74     * callback processing, application MUST create a response by calling 
     75     * pj_stun_session_create_response() function and send the response 
     76     * with pj_stun_session_send_msg() function, before returning from 
     77     * the callback. 
     78     * 
     79     * @param sess          The STUN session. 
     80     * @param pkt           Pointer to the original STUN packet. 
     81     * @param pkt_len       Length of the STUN packet. 
     82     * @param msg           The parsed STUN request. 
     83     * @param src_addr      Source address of the packet. 
     84     * @param src_addr_len  Length of the source address. 
     85     * 
     86     * @return              The return value of this callback will be 
     87     *                      returned back to pj_stun_session_on_rx_pkt() 
     88     *                      function. 
     89     */ 
     90    pj_status_t (*on_rx_request)(pj_stun_session *sess, 
     91                                 const pj_uint8_t *pkt, 
     92                                 unsigned pkt_len, 
     93                                 const pj_stun_msg *msg, 
     94                                 const pj_sockaddr_t *src_addr, 
     95                                 unsigned src_addr_len); 
     96 
     97    /** 
     98     * Callback to be called when response is received or the transaction  
     99     * has timed out. 
    63100     * 
    64101     * @param sess          The STUN session. 
     
    70107     * @param response      The response message, on successful transaction. 
    71108     */ 
    72     void (*on_bind_response)(pj_stun_session *sess,  
    73                              pj_status_t status,  
    74                              pj_stun_tx_data *request, 
    75                              const pj_stun_msg *response); 
    76  
    77     /** 
    78      * Callback to be called when Allocate response is received or the  
    79      * transaction has timed out. 
    80      * 
    81      * @param sess          The STUN session. 
    82      * @param status        Status of the request. If the value if not 
    83      *                      PJ_SUCCESS, the transaction has timed-out 
    84      *                      or other error has occurred, and the response 
    85      *                      argument may be NULL. 
    86      * @param request       The original STUN request. 
    87      * @param response      The response message, on successful transaction. 
    88      */ 
    89     void (*on_allocate_response)(pj_stun_session *sess,  
    90                                  pj_status_t status,  
    91                                  pj_stun_tx_data *request, 
    92                                  const pj_stun_msg *response); 
    93  
    94     /** 
    95      * Callback to be called when Set Active Destination response is received 
    96      * or the transaction has timed out. 
    97      * 
    98      * @param sess          The STUN session. 
    99      * @param status        Status of the request. If the value if not 
    100      *                      PJ_SUCCESS, the transaction has timed-out 
    101      *                      or other error has occurred, and the response 
    102      *                      argument may be NULL. 
    103      * @param request       The original STUN request. 
    104      * @param response      The response message, on successful transaction. 
    105      */ 
    106     void (*on_set_active_destination_response)(pj_stun_session *sess,  
    107                                                pj_status_t status,  
    108                                                pj_stun_tx_data *request, 
    109                                                const pj_stun_msg *response); 
    110  
    111     /** 
    112      * Callback to be called when Connect response is received or the  
    113      * transaction has timed out. 
    114      * 
    115      * @param sess          The STUN session. 
    116      * @param status        Status of the request. If the value if not 
    117      *                      PJ_SUCCESS, the transaction has timed-out 
    118      *                      or other error has occurred, and the response 
    119      *                      argument may be NULL. 
    120      * @param request       The original STUN request. 
    121      * @param response      The response message, on successful transaction. 
    122      */ 
    123     void (*on_connect_response)( pj_stun_session *sess,  
    124                                  pj_status_t status,  
    125                                  pj_stun_tx_data *request, 
    126                                  const pj_stun_msg *response); 
     109    void (*on_request_complete)(pj_stun_session *sess, 
     110                                pj_status_t status, 
     111                                pj_stun_tx_data *tdata, 
     112                                const pj_stun_msg *response); 
     113 
     114 
     115    /** 
     116     * Type of callback to be called on incoming STUN indication. 
     117     */ 
     118    pj_status_t (*on_rx_indication)(pj_stun_session *sess, 
     119                                    const pj_uint8_t *pkt, 
     120                                    unsigned pkt_len, 
     121                                    const pj_stun_msg *msg, 
     122                                    const pj_sockaddr_t *src_addr, 
     123                                    unsigned src_addr_len); 
     124 
    127125} pj_stun_session_cb; 
    128126 
     
    360358PJ_DECL(pj_status_t) pj_stun_session_create_data_ind(pj_stun_session *sess, 
    361359                                                     pj_stun_tx_data **p_tdata); 
     360 
     361/** 
     362 * Create a STUN response message. After the message has been  
     363 * successfully created, application can send the message by calling  
     364 * pj_stun_session_send_msg(). 
     365 * 
     366 * @param sess      The STUN session instance. 
     367 * @param req       The STUN request where the response is to be created. 
     368 * @param err_code  Error code to be set in the response, if error response 
     369 *                  is to be created, according to pj_stun_status enumeration. 
     370 *                  This argument MUST be zero if successful response is 
     371 *                  to be created. 
     372 * @param err_msg   Optional pointer for the error message string, when 
     373 *                  creating error response. If the value is NULL and the 
     374 *                  \a err_code is non-zero, then default error message will 
     375 *                  be used. 
     376 * @param p_tdata   Pointer to receive the response message created. 
     377 * 
     378 * @return          PJ_SUCCESS on success, or the appropriate error code. 
     379 */ 
     380PJ_DECL(pj_status_t) pj_stun_session_create_response(pj_stun_session *sess, 
     381                                                     const pj_stun_msg *req, 
     382                                                     unsigned err_code, 
     383                                                     const pj_str_t *err_msg, 
     384                                                     pj_stun_tx_data **p_tdata); 
     385 
    362386 
    363387/** 
     
    373397 * @param sess      The STUN session instance. 
    374398 * @param options   Optional flags, from pj_stun_session_option. 
     399 * @param dst_addr  The destination socket address. 
    375400 * @param addr_len  Length of destination address. 
    376  * @param dst_addr  The destination socket address. 
    377401 * @param tdata     The STUN transmit data containing the STUN message to 
    378402 *                  be sent. 
     
    382406PJ_DECL(pj_status_t) pj_stun_session_send_msg(pj_stun_session *sess, 
    383407                                              unsigned options, 
     408                                              const pj_sockaddr_t *dst_addr, 
    384409                                              unsigned addr_len, 
    385                                               const pj_sockaddr_t *dst_addr, 
    386410                                              pj_stun_tx_data *tdata); 
    387411 
     
    403427 * @param packet     The packet containing STUN message. 
    404428 * @param pkt_size   Size of the packet. 
     429 * @param options    Options, from pj_stun_options. 
    405430 * @param parsed_len Optional pointer to receive the size of the parsed 
    406431 *                   STUN message (useful if packet is received via a 
     
    412437                                               const void *packet, 
    413438                                               pj_size_t pkt_size, 
    414                                                unsigned *parsed_len); 
    415  
    416  
     439                                               unsigned options, 
     440                                               unsigned *parsed_len, 
     441                                               const pj_sockaddr_t *src_addr, 
     442                                               unsigned src_addr_len); 
     443 
     444/** 
     445 * Destroy the transmit data. Call this function only when tdata has been 
     446 * created but application doesn't want to send the message (perhaps 
     447 * because of other error). 
     448 * 
     449 * @param sess      The STUN session. 
     450 * @param tdata     The transmit data. 
     451 * 
     452 * @return          PJ_SUCCESS on success, or the appropriate error code. 
     453 */ 
     454PJ_DECL(void) pj_stun_msg_destroy_tdata(pj_stun_session *sess, 
     455                                        pj_stun_tx_data *tdata); 
     456 
     457 
     458/** 
     459 * @} 
     460 */ 
     461 
     462 
     463PJ_END_DECL 
    417464 
    418465#endif  /* __PJLIB_UTIL_STUN_SESSION_H__ */ 
  • pjproject/trunk/pjlib-util/src/pjlib-util/stun_msg.c

    r1003 r1021  
    518518                                    int attr_type, 
    519519                                    pj_bool_t xor_ed, 
     520                                    const pj_sockaddr_t *addr, 
    520521                                    unsigned addr_len, 
    521                                     const pj_sockaddr_t *addr, 
    522522                                    pj_stun_generic_ip_addr_attr **p_attr) 
    523523{ 
     
    560560                                     int attr_type,  
    561561                                     pj_bool_t xor_ed, 
    562                                      unsigned addr_len, 
    563                                      const pj_sockaddr_t *addr) 
     562                                     const pj_sockaddr_t *addr, 
     563                                     unsigned addr_len) 
    564564{ 
    565565    pj_stun_generic_ip_addr_attr *attr; 
     
    567567 
    568568    status = pj_stun_generic_ip_addr_attr_create(pool, attr_type, xor_ed, 
    569                                                  addr_len, addr, &attr); 
     569                                                 addr, addr_len, &attr); 
    570570    if (status != PJ_SUCCESS) 
    571571        return status; 
     
    14351435PJ_INLINE(pj_uint16_t) GET_VAL16(const pj_uint8_t *pdu, unsigned pos) 
    14361436{ 
    1437     pj_uint16_t val = (pj_uint16_t) ((pdu[pos] << 8) + pdu[pos+1]); 
    1438     return pj_ntohs(val); 
     1437    return (pj_uint16_t) ((pdu[pos] << 8) + pdu[pos+1]); 
    14391438} 
    14401439 
    14411440PJ_INLINE(pj_uint32_t) GET_VAL32(const pj_uint8_t *pdu, unsigned pos) 
    14421441{ 
    1443     pj_uint32_t val = (pdu[pos+0] << 24) + 
    1444                       (pdu[pos+1] << 16) + 
    1445                       (pdu[pos+2] <<  8) + 
    1446                       (pdu[pos+3]); 
    1447     return pj_ntohl(val); 
     1442    return (pdu[pos+0] << 24) + 
     1443           (pdu[pos+1] << 16) + 
     1444           (pdu[pos+2] <<  8) + 
     1445           (pdu[pos+3]); 
    14481446} 
    14491447 
     
    14661464        return PJLIB_UTIL_ESTUNINMSGTYPE; 
    14671465 
     1466    /* Check the PDU length */ 
     1467    msg_len = GET_VAL16(pdu, 2); 
     1468    if ((msg_len + 20 > pdu_len) ||  
     1469        ((options & PJ_STUN_IS_DATAGRAM) && msg_len + 20 != pdu_len)) 
     1470    { 
     1471        return PJLIB_UTIL_ESTUNINMSGLEN; 
     1472    } 
     1473 
    14681474    /* If magic is set, then there is great possibility that this is 
    14691475     * a STUN message. 
    14701476     */ 
    1471     if (GET_VAL32(pdu, 4) != PJ_STUN_MAGIC) 
    1472         return PJLIB_UTIL_ESTUNNOTMAGIC; 
    1473  
    1474     /* Check the PDU length */ 
    1475     msg_len = GET_VAL16(pdu, 2); 
    1476     if ((msg_len > pdu_len) ||  
    1477         ((options & PJ_STUN_IS_DATAGRAM) && msg_len != pdu_len)) 
    1478     { 
    1479         return PJLIB_UTIL_ESTUNINMSGLEN; 
    1480     } 
    1481  
    1482     /* Check if FINGERPRINT attribute is present */ 
    1483     if (GET_VAL16(pdu, msg_len + 20) == PJ_STUN_ATTR_FINGERPRINT) { 
    1484         pj_uint16_t attr_len = GET_VAL16(pdu, msg_len + 22); 
    1485         pj_uint32_t fingerprint = GET_VAL32(pdu, msg_len + 24); 
    1486         pj_uint32_t crc; 
    1487  
    1488         if (attr_len != 4) 
    1489             return PJLIB_UTIL_ESTUNINATTRLEN; 
    1490  
    1491         crc = pj_crc32_calc(pdu, msg_len + 20); 
    1492         crc ^= STUN_XOR_FINGERPRINT; 
    1493  
    1494         if (crc != fingerprint) 
    1495             return PJLIB_UTIL_ESTUNFINGERPRINT; 
     1477    if (GET_VAL32(pdu, 4) == PJ_STUN_MAGIC) { 
     1478 
     1479        /* Check if FINGERPRINT attribute is present */ 
     1480        if (GET_VAL16(pdu, msg_len + 20) == PJ_STUN_ATTR_FINGERPRINT) { 
     1481            pj_uint16_t attr_len = GET_VAL16(pdu, msg_len + 22); 
     1482            pj_uint32_t fingerprint = GET_VAL32(pdu, msg_len + 24); 
     1483            pj_uint32_t crc; 
     1484 
     1485            if (attr_len != 4) 
     1486                return PJLIB_UTIL_ESTUNINATTRLEN; 
     1487 
     1488            crc = pj_crc32_calc(pdu, msg_len + 20); 
     1489            crc ^= STUN_XOR_FINGERPRINT; 
     1490 
     1491            if (crc != fingerprint) 
     1492                return PJLIB_UTIL_ESTUNFINGERPRINT; 
     1493        } 
    14961494    } 
    14971495 
     
    18201818 * Print the message structure to a buffer. 
    18211819 */ 
    1822 PJ_DEF(pj_status_t) pj_stun_msg_encode(const pj_stun_msg *msg, 
     1820PJ_DEF(pj_status_t) pj_stun_msg_encode(pj_stun_msg *msg, 
    18231821                                       pj_uint8_t *buf, unsigned buf_size, 
    18241822                                       unsigned options, 
     
    18341832    unsigned printed; 
    18351833    pj_status_t status; 
    1836     unsigned i, length; 
     1834    unsigned i; 
    18371835 
    18381836 
     
    18991897     */ 
    19001898    if (amsg_integrity && afingerprint) { 
    1901         length = (pj_uint16_t)((buf - start) - 20 + 24 + 8); 
     1899        msg->hdr.length = (pj_uint16_t)((buf - start) - 20 + 24 + 8); 
    19021900    } else if (amsg_integrity) { 
    1903         length = (pj_uint16_t)((buf - start) - 20 + 24); 
     1901        msg->hdr.length = (pj_uint16_t)((buf - start) - 20 + 24); 
    19041902    } else if (afingerprint) { 
    1905         length = (pj_uint16_t)((buf - start) - 20 + 8); 
     1903        msg->hdr.length = (pj_uint16_t)((buf - start) - 20 + 8); 
    19061904    } else { 
    1907         length = (pj_uint16_t)((buf - start) - 20); 
     1905        msg->hdr.length = (pj_uint16_t)((buf - start) - 20); 
    19081906    } 
    19091907 
    19101908    /* hdr->length = pj_htons(length); */ 
    1911     *(buf+2) = (pj_uint8_t)((length >> 8) & 0x00FF); 
    1912     *(buf+3) = (pj_uint8_t)(length & 0x00FF); 
     1909    start[2] = (pj_uint8_t)((msg->hdr.length >> 8) & 0x00FF); 
     1910    start[3] = (pj_uint8_t)(msg->hdr.length & 0x00FF); 
    19131911 
    19141912    /* Calculate message integrity, if present */ 
     
    20892087        *p_response = NULL; 
    20902088 
    2091     if (PJ_STUN_IS_REQUEST(msg->hdr.type)) 
     2089    if (!PJ_STUN_IS_REQUEST(msg->hdr.type)) 
    20922090        p_response = NULL; 
    20932091 
  • pjproject/trunk/pjlib-util/src/pjlib-util/stun_session.c

    r1008 r1021  
    2424    pj_stun_endpoint    *endpt; 
    2525    pj_pool_t           *pool; 
     26    pj_mutex_t          *mutex; 
    2627    pj_stun_session_cb   cb; 
    2728    void                *user_data; 
     
    4849 
    4950#if PJ_LOG_MAX_LEVEL >= 4 
    50 #   define LOG_ERR_(sess, title, rc) 
     51#   define LOG_ERR_(sess, title, rc) stun_perror(sess, title, rc) 
    5152static void stun_perror(pj_stun_session *sess, const char *title,  
    5253                        pj_status_t status) 
     
    6061 
    6162#else 
    62 #   define ERR_(sess, title, rc) 
     63#   define LOG_ERR_(sess, title, rc) 
    6364#endif 
    6465 
     
    116117 
    117118static pj_status_t create_tdata(pj_stun_session *sess, 
    118                                 unsigned msg_type, 
    119119                                void *user_data, 
    120120                                pj_stun_tx_data **p_tdata) 
    121121{ 
    122122    pj_pool_t *pool; 
    123     pj_status_t status; 
    124123    pj_stun_tx_data *tdata; 
    125124 
     
    134133    tdata->user_data = user_data; 
    135134 
     135    *p_tdata = tdata; 
     136 
     137    return PJ_SUCCESS; 
     138} 
     139 
     140static pj_status_t create_request_tdata(pj_stun_session *sess, 
     141                                        unsigned msg_type, 
     142                                        void *user_data, 
     143                                        pj_stun_tx_data **p_tdata) 
     144{ 
     145    pj_status_t status; 
     146    pj_stun_tx_data *tdata; 
     147 
     148    status = create_tdata(sess, user_data, &tdata); 
     149    if (status != PJ_SUCCESS) 
     150        return status; 
     151 
    136152    /* Create STUN message */ 
    137     status = pj_stun_msg_create(pool, msg_type,  PJ_STUN_MAGIC,  
     153    status = pj_stun_msg_create(tdata->pool, msg_type,  PJ_STUN_MAGIC,  
    138154                                NULL, &tdata->msg); 
    139155    if (status != PJ_SUCCESS) { 
    140         pj_pool_release(pool); 
    141         return status; 
    142     } 
    143  
    144     /* If this is a request, then copy the request's transaction ID 
    145      * as the transaction key. 
    146      */ 
    147     if (PJ_STUN_IS_REQUEST(msg_type)) { 
    148         pj_assert(sizeof(tdata->client_key)==sizeof(tdata->msg->hdr.tsx_id)); 
    149         pj_memcpy(tdata->client_key, tdata->msg->hdr.tsx_id, 
    150                   sizeof(tdata->msg->hdr.tsx_id)); 
    151     } 
     156        pj_pool_release(tdata->pool); 
     157        return status; 
     158    } 
     159 
     160    /* copy the request's transaction ID as the transaction key. */ 
     161    pj_assert(sizeof(tdata->client_key)==sizeof(tdata->msg->hdr.tsx_id)); 
     162    pj_memcpy(tdata->client_key, tdata->msg->hdr.tsx_id, 
     163              sizeof(tdata->msg->hdr.tsx_id)); 
    152164 
    153165    *p_tdata = tdata; 
     
    167179} 
    168180 
    169 static pj_status_t session_apply_req(pj_stun_session *sess, 
     181/* 
     182 * Destroy the transmit data. 
     183 */ 
     184PJ_DEF(void) pj_stun_msg_destroy_tdata( pj_stun_session *sess, 
     185                                        pj_stun_tx_data *tdata) 
     186{ 
     187    PJ_UNUSED_ARG(sess); 
     188    destroy_tdata(tdata); 
     189} 
     190 
     191static pj_status_t apply_msg_options(pj_stun_session *sess, 
    170192                                     pj_pool_t *pool, 
    171193                                     unsigned options, 
    172                                      pj_stun_msg *msg) 
     194                                     pj_stun_msg *msg, 
     195                                     pj_str_t **p_passwd) 
    173196{ 
    174197    pj_status_t status; 
     
    182205        pj_stun_generic_string_attr *arealm; 
    183206 
     207        *p_passwd = &sess->l_password; 
     208 
    184209        /* Create and add USERNAME attribute */ 
    185         status = pj_stun_generic_string_attr_create(sess->pool,  
     210        status = pj_stun_generic_string_attr_create(pool,  
    186211                                                    PJ_STUN_ATTR_USERNAME, 
    187212                                                    &sess->l_username, 
     
    193218 
    194219        /* Add REALM only when long term credential is used */ 
    195         status = pj_stun_generic_string_attr_create(sess->pool,  
     220        status = pj_stun_generic_string_attr_create(pool,  
    196221                                                    PJ_STUN_ATTR_REALM, 
    197222                                                    &sess->l_realm, 
     
    203228 
    204229        /* Add MESSAGE-INTEGRITY attribute */ 
    205         status = pj_stun_msg_integrity_attr_create(sess->pool, &amsgi); 
     230        status = pj_stun_msg_integrity_attr_create(pool, &amsgi); 
    206231        PJ_ASSERT_RETURN(status==PJ_SUCCESS, status); 
    207232 
    208233        status = pj_stun_msg_add_attr(msg, &amsgi->hdr); 
    209234        PJ_ASSERT_RETURN(status==PJ_SUCCESS, status); 
    210  
    211         PJ_TODO(COMPUTE_MESSAGE_INTEGRITY1); 
    212235 
    213236    } else if (options & PJ_STUN_USE_SHORT_TERM_CRED) { 
     
    215238        pj_stun_msg_integrity_attr *amsgi; 
    216239 
     240        *p_passwd = &sess->s_password; 
     241 
    217242        /* Create and add USERNAME attribute */ 
    218         status = pj_stun_generic_string_attr_create(sess->pool,  
     243        status = pj_stun_generic_string_attr_create(pool,  
    219244                                                    PJ_STUN_ATTR_USERNAME, 
    220245                                                    &sess->s_username, 
     
    226251 
    227252        /* Add MESSAGE-INTEGRITY attribute */ 
    228         status = pj_stun_msg_integrity_attr_create(sess->pool, &amsgi); 
     253        status = pj_stun_msg_integrity_attr_create(pool, &amsgi); 
    229254        PJ_ASSERT_RETURN(status==PJ_SUCCESS, status); 
    230255 
     
    232257        PJ_ASSERT_RETURN(status==PJ_SUCCESS, status); 
    233258 
    234         PJ_TODO(COMPUTE_MESSAGE_INTEGRITY2); 
     259    } else { 
     260        *p_passwd = NULL; 
    235261    } 
    236262 
     
    239265        pj_stun_fingerprint_attr *af; 
    240266 
    241         status = pj_stun_generic_uint_attr_create(sess->pool,  
     267        status = pj_stun_generic_uint_attr_create(pool,  
    242268                                                  PJ_STUN_ATTR_FINGERPRINT, 
    243269                                                  0, &af); 
     
    260286    tdata = (pj_stun_tx_data*) pj_stun_client_tsx_get_data(tsx); 
    261287 
    262     switch (PJ_STUN_GET_METHOD(tdata->msg->hdr.type)) { 
    263     case PJ_STUN_BINDING_METHOD: 
    264         tdata->sess->cb.on_bind_response(tdata->sess, status, tdata, response); 
    265         break; 
    266     case PJ_STUN_ALLOCATE_METHOD: 
    267         tdata->sess->cb.on_allocate_response(tdata->sess, status, 
    268                                              tdata, response); 
    269         break; 
    270     case PJ_STUN_SET_ACTIVE_DESTINATION_METHOD: 
    271         tdata->sess->cb.on_set_active_destination_response(tdata->sess, status, 
    272                                                            tdata, response); 
    273         break; 
    274     case PJ_STUN_CONNECT_METHOD: 
    275         tdata->sess->cb.on_connect_response(tdata->sess, status, tdata, 
    276                                             response); 
    277         break; 
    278     default: 
    279         pj_assert(!"Unknown method"); 
    280         break; 
     288    if (tdata->sess->cb.on_request_complete) { 
     289        (*tdata->sess->cb.on_request_complete)(tdata->sess, status, tdata,  
     290                                               response); 
    281291    } 
    282292} 
     
    290300    tdata = (pj_stun_tx_data*) pj_stun_client_tsx_get_data(tsx); 
    291301 
    292     return tdata->sess->cb.on_send_msg(tdata, stun_pkt, pkt_size, 
    293                                        tdata->addr_len, tdata->dst_addr); 
     302    return tdata->sess->cb.on_send_msg(tdata->sess, stun_pkt, pkt_size, 
     303                                       tdata->dst_addr, tdata->addr_len); 
    294304} 
    295305 
     
    303313    pj_pool_t   *pool; 
    304314    pj_stun_session *sess; 
     315    pj_status_t status; 
    305316 
    306317    PJ_ASSERT_RETURN(endpt && cb && p_sess, PJ_EINVAL); 
     318 
     319    if (name==NULL) 
     320        name = "sess%p"; 
    307321 
    308322    pool = pj_pool_create(endpt->pf, name, 4000, 4000, NULL); 
     
    316330    pj_list_init(&sess->pending_request_list); 
    317331 
     332    status = pj_mutex_create_recursive(pool, name, &sess->mutex); 
     333    if (status != PJ_SUCCESS) { 
     334        pj_pool_release(pool); 
     335        return status; 
     336    } 
     337 
    318338    *p_sess = sess; 
    319339 
    320     PJ_TODO(MUTEX_PROTECTION); 
    321  
    322340    return PJ_SUCCESS; 
    323341} 
     
    327345    PJ_ASSERT_RETURN(sess, PJ_EINVAL); 
    328346 
     347    pj_mutex_destroy(sess->mutex); 
    329348    pj_pool_release(sess->pool); 
    330349 
     
    337356{ 
    338357    PJ_ASSERT_RETURN(sess, PJ_EINVAL); 
     358    pj_mutex_lock(sess->mutex); 
    339359    sess->user_data = user_data; 
     360    pj_mutex_unlock(sess->mutex); 
    340361    return PJ_SUCCESS; 
    341362} 
     
    356377 
    357378    PJ_ASSERT_RETURN(sess, PJ_EINVAL); 
     379 
     380    pj_mutex_lock(sess->mutex); 
    358381    pj_strdup_with_null(sess->pool, &sess->l_realm, realm ? realm : &nil); 
    359382    pj_strdup_with_null(sess->pool, &sess->l_username, user ? user : &nil); 
    360383    pj_strdup_with_null(sess->pool, &sess->l_password, passwd ? passwd : &nil); 
     384    pj_mutex_unlock(sess->mutex); 
    361385 
    362386    return PJ_SUCCESS; 
     
    372396 
    373397    PJ_ASSERT_RETURN(sess, PJ_EINVAL); 
     398 
     399    pj_mutex_lock(sess->mutex); 
    374400    pj_strdup_with_null(sess->pool, &sess->s_username, user ? user : &nil); 
    375401    pj_strdup_with_null(sess->pool, &sess->s_password, passwd ? passwd : &nil); 
     402    pj_mutex_unlock(sess->mutex); 
    376403 
    377404    return PJ_SUCCESS; 
     
    387414    PJ_ASSERT_RETURN(sess && p_tdata, PJ_EINVAL); 
    388415 
    389     status = create_tdata(sess, PJ_STUN_BINDING_REQUEST, NULL, &tdata); 
     416    status = create_request_tdata(sess, PJ_STUN_BINDING_REQUEST, NULL,  
     417                                  &tdata); 
    390418    if (status != PJ_SUCCESS) 
    391419        return status; 
     
    398426                                                        pj_stun_tx_data **p_tdata) 
    399427{ 
     428    PJ_UNUSED_ARG(sess); 
     429    PJ_UNUSED_ARG(p_tdata); 
    400430    PJ_ASSERT_RETURN(PJ_FALSE, PJ_ENOTSUP); 
    401431} 
     
    406436                                                  pj_stun_tx_data **p_tdata) 
    407437{ 
     438    PJ_UNUSED_ARG(sess); 
     439    PJ_UNUSED_ARG(p_tdata); 
    408440    PJ_ASSERT_RETURN(PJ_FALSE, PJ_ENOTSUP); 
    409441} 
     
    412444                                                        pj_stun_tx_data **p_tdata) 
    413445{ 
     446    PJ_UNUSED_ARG(sess); 
     447    PJ_UNUSED_ARG(p_tdata); 
    414448    PJ_ASSERT_RETURN(PJ_FALSE, PJ_ENOTSUP); 
    415449} 
     
    419453                                             pj_stun_tx_data **p_tdata) 
    420454{ 
     455    PJ_UNUSED_ARG(sess); 
     456    PJ_UNUSED_ARG(p_tdata); 
    421457    PJ_ASSERT_RETURN(PJ_FALSE, PJ_ENOTSUP); 
    422458} 
     
    425461                                                     pj_stun_tx_data **p_tdata) 
    426462{ 
     463    PJ_UNUSED_ARG(sess); 
     464    PJ_UNUSED_ARG(p_tdata); 
    427465    PJ_ASSERT_RETURN(PJ_FALSE, PJ_ENOTSUP); 
    428466} 
     
    431469                                                     pj_stun_tx_data **p_tdata) 
    432470{ 
     471    PJ_UNUSED_ARG(sess); 
     472    PJ_UNUSED_ARG(p_tdata); 
    433473    PJ_ASSERT_RETURN(PJ_FALSE, PJ_ENOTSUP); 
    434474} 
     475 
     476 
     477/* 
     478 * Create a STUN response message. 
     479 */ 
     480PJ_DEF(pj_status_t) pj_stun_session_create_response( pj_stun_session *sess, 
     481                                                     const pj_stun_msg *req, 
     482                                                     unsigned err_code, 
     483                                                     const pj_str_t *err_msg, 
     484                                                     pj_stun_tx_data **p_tdata) 
     485{ 
     486    pj_status_t status; 
     487    pj_stun_tx_data *tdata; 
     488 
     489    status = create_tdata(sess, NULL, &tdata); 
     490    if (status != PJ_SUCCESS) 
     491        return status; 
     492 
     493    /* Create STUN response message */ 
     494    status = pj_stun_msg_create_response(tdata->pool, req, err_code, err_msg, 
     495                                         &tdata->msg); 
     496    if (status != PJ_SUCCESS) { 
     497        pj_pool_release(tdata->pool); 
     498        return status; 
     499    } 
     500 
     501    /* copy the request's transaction ID as the transaction key. */ 
     502    pj_assert(sizeof(tdata->client_key)==sizeof(req->hdr.tsx_id)); 
     503    pj_memcpy(tdata->client_key, req->hdr.tsx_id, sizeof(req->hdr.tsx_id)); 
     504 
     505    *p_tdata = tdata; 
     506 
     507    return PJ_SUCCESS; 
     508} 
     509 
     510 
     511/* Print outgoing message to log */ 
     512static void dump_tx_msg(pj_stun_session *sess, const pj_stun_msg *msg, 
     513                        unsigned pkt_size, const pj_sockaddr_t *addr) 
     514{ 
     515    const char *dst_name; 
     516    int dst_port; 
     517    const pj_sockaddr *dst = (const pj_sockaddr*)addr; 
     518    char buf[512]; 
     519     
     520    if (dst->sa_family == PJ_AF_INET) { 
     521        const pj_sockaddr_in *dst4 = (const pj_sockaddr_in*)dst; 
     522        dst_name = pj_inet_ntoa(dst4->sin_addr); 
     523        dst_port = pj_ntohs(dst4->sin_port); 
     524    } else if (dst->sa_family == PJ_AF_INET6) { 
     525        const pj_sockaddr_in6 *dst6 = (const pj_sockaddr_in6*)dst; 
     526        dst_name = "IPv6"; 
     527        dst_port = pj_ntohs(dst6->sin6_port); 
     528    } else { 
     529        LOG_ERR_(sess, "Invalid address family", PJ_EINVAL); 
     530        return; 
     531    } 
     532 
     533    PJ_LOG(5,(SNAME(sess),  
     534              "TX %d bytes STUN message to %s:%d:\n" 
     535              "--- begin STUN message ---\n" 
     536              "%s" 
     537              "--- end of STUN message ---\n", 
     538              pkt_size, dst_name, dst_port, 
     539              pj_stun_msg_dump(msg, buf, sizeof(buf), NULL))); 
     540 
     541} 
     542 
    435543 
    436544PJ_DEF(pj_status_t) pj_stun_session_send_msg( pj_stun_session *sess, 
    437545                                              unsigned options, 
     546                                              const pj_sockaddr_t *server, 
    438547                                              unsigned addr_len, 
    439                                               const pj_sockaddr_t *server, 
    440548                                              pj_stun_tx_data *tdata) 
    441549{ 
     550    pj_str_t *password; 
    442551    pj_status_t status; 
    443552 
     
    448557    tdata->pkt = pj_pool_alloc(tdata->pool, tdata->max_len); 
    449558 
    450     if (PJ_LOG_MAX_LEVEL >= 5) { 
    451         char *buf = (char*) tdata->pkt; 
    452         const char *dst_name; 
    453         int dst_port; 
    454         const pj_sockaddr *dst = (const pj_sockaddr*)server; 
    455          
    456         if (dst->sa_family == PJ_AF_INET) { 
    457             const pj_sockaddr_in *dst4 = (const pj_sockaddr_in*)dst; 
    458             dst_name = pj_inet_ntoa(dst4->sin_addr); 
    459             dst_port = pj_ntohs(dst4->sin_port); 
    460         } else if (dst->sa_family == PJ_AF_INET6) { 
    461             const pj_sockaddr_in6 *dst6 = (const pj_sockaddr_in6*)dst; 
    462             dst_name = "IPv6"; 
    463             dst_port = pj_ntohs(dst6->sin6_port); 
    464         } else { 
    465             LOG_ERR_(sess, "Invalid address family", PJ_EINVAL); 
    466             return PJ_EINVAL; 
    467         } 
    468  
    469         PJ_LOG(5,(SNAME(sess),  
    470                   "Sending STUN message to %s:%d:\n" 
    471                   "--- begin STUN message ---\n" 
    472                   "%s" 
    473                   "--- end of STUN message ---\n", 
    474                   dst_name, dst_port, 
    475                   pj_stun_msg_dump(tdata->msg, buf, tdata->max_len, NULL))); 
    476     } 
     559    /* Start locking the session now */ 
     560    pj_mutex_lock(sess->mutex); 
    477561 
    478562    /* Apply options */ 
    479     status = session_apply_req(sess, tdata->pool, options, tdata->msg); 
     563    status = apply_msg_options(sess, tdata->pool, options,  
     564                               tdata->msg, &password); 
    480565    if (status != PJ_SUCCESS) { 
     566        pj_stun_msg_destroy_tdata(sess, tdata); 
     567        pj_mutex_unlock(sess->mutex); 
    481568        LOG_ERR_(sess, "Error applying options", status); 
    482         destroy_tdata(tdata); 
    483569        return status; 
    484570    } 
     
    488574                                0, NULL, &tdata->pkt_size); 
    489575    if (status != PJ_SUCCESS) { 
     576        pj_stun_msg_destroy_tdata(sess, tdata); 
     577        pj_mutex_unlock(sess->mutex); 
    490578        LOG_ERR_(sess, "STUN encode() error", status); 
    491         destroy_tdata(tdata); 
    492         return status; 
    493     } 
     579        return status; 
     580    } 
     581 
     582    /* Dump packet */ 
     583    dump_tx_msg(sess, tdata->msg, tdata->pkt_size, server); 
    494584 
    495585    /* If this is a STUN request message, then send the request with 
     
    512602                                             tdata->pkt, tdata->pkt_size); 
    513603        if (status != PJ_SUCCESS && status != PJ_EPENDING) { 
     604            pj_stun_msg_destroy_tdata(sess, tdata); 
     605            pj_mutex_unlock(sess->mutex); 
    514606            LOG_ERR_(sess, "Error sending STUN request", status); 
    515             destroy_tdata(tdata); 
    516607            return status; 
    517608        } 
     
    522613    } else { 
    523614        /* Otherwise for non-request message, send directly to transport. */ 
    524         status = sess->cb.on_send_msg(tdata, tdata->pkt, tdata->pkt_size, 
    525                                       addr_len, server); 
     615        status = sess->cb.on_send_msg(sess, tdata->pkt, tdata->pkt_size, 
     616                                      server, addr_len); 
    526617 
    527618        if (status != PJ_SUCCESS && status != PJ_EPENDING) { 
    528619            LOG_ERR_(sess, "Error sending STUN request", status); 
    529             destroy_tdata(tdata); 
    530             return status; 
    531620        } 
    532     } 
    533  
    534  
     621 
     622        /* Destroy */ 
     623        pj_stun_msg_destroy_tdata(sess, tdata); 
     624    } 
     625 
     626 
     627    pj_mutex_unlock(sess->mutex); 
    535628    return status; 
     629} 
     630 
     631 
     632/* Handle incoming response */ 
     633static pj_status_t on_incoming_response(pj_stun_session *sess, 
     634                                        pj_stun_msg *msg) 
     635{ 
     636    pj_stun_tx_data *tdata; 
     637    pj_status_t status; 
     638 
     639    /* Lookup pending client transaction */ 
     640    tdata = tsx_lookup(sess, msg); 
     641    if (tdata == NULL) { 
     642        LOG_ERR_(sess, "STUN error finding transaction", PJ_ENOTFOUND); 
     643        return PJ_ENOTFOUND; 
     644    } 
     645 
     646    /* Pass the response to the transaction.  
     647     * If the message is accepted, transaction callback will be called, 
     648     * and this will call the session callback too. 
     649     */ 
     650    status = pj_stun_client_tsx_on_rx_msg(tdata->client_tsx, msg); 
     651    if (status != PJ_SUCCESS) { 
     652        return status; 
     653    } 
     654 
     655    /* If transaction has completed, destroy the transmit data. 
     656     * This will remove the transaction from the pending list too. 
     657     */ 
     658    if (pj_stun_client_tsx_is_complete(tdata->client_tsx)) { 
     659        pj_stun_msg_destroy_tdata(sess, tdata); 
     660        tdata = NULL; 
     661    } 
     662 
     663    return PJ_SUCCESS; 
     664} 
     665 
     666 
     667/* Send response */ 
     668static pj_status_t send_response(pj_stun_session *sess, unsigned options, 
     669                                 pj_pool_t *pool, pj_stun_msg *response, 
     670                                 const pj_sockaddr_t *addr, unsigned addr_len) 
     671{ 
     672    pj_uint8_t *out_pkt; 
     673    unsigned out_max_len, out_len; 
     674    pj_str_t *passwd; 
     675    pj_status_t status; 
     676 
     677    /* Alloc packet buffer */ 
     678    out_max_len = PJ_STUN_MAX_PKT_LEN; 
     679    out_pkt = pj_pool_alloc(pool, out_max_len); 
     680 
     681    /* Apply options */ 
     682    apply_msg_options(sess, pool, options, response, &passwd); 
     683 
     684    /* Encode */ 
     685    status = pj_stun_msg_encode(response, out_pkt, out_max_len, 0,  
     686                                passwd, &out_len); 
     687    if (status != PJ_SUCCESS) { 
     688        LOG_ERR_(sess, "Error encoding message", status); 
     689        return status; 
     690    } 
     691 
     692    /* Print log */ 
     693    dump_tx_msg(sess, response, out_len, addr); 
     694 
     695    /* Send packet */ 
     696    status = sess->cb.on_send_msg(sess, out_pkt, out_len, addr, addr_len); 
     697 
     698    return status; 
     699} 
     700 
     701/* Handle incoming request */ 
     702static pj_status_t on_incoming_request(pj_stun_session *sess, 
     703                                       pj_pool_t *tmp_pool, 
     704                                       const pj_uint8_t *in_pkt, 
     705                                       unsigned in_pkt_len, 
     706                                       const pj_stun_msg *msg, 
     707                                       const pj_sockaddr_t *src_addr, 
     708                                       unsigned src_addr_len) 
     709{ 
     710    pj_status_t status; 
     711 
     712    /* Distribute to handler, or respond with Bad Request */ 
     713    if (sess->cb.on_rx_request) { 
     714        status = (*sess->cb.on_rx_request)(sess, in_pkt, in_pkt_len, msg, 
     715                                           src_addr, src_addr_len); 
     716    } else { 
     717        pj_stun_msg *response = NULL; 
     718 
     719        status = pj_stun_msg_create_response(tmp_pool, msg,  
     720                                             PJ_STUN_STATUS_BAD_REQUEST, NULL, 
     721                                             &response); 
     722        if (status == PJ_SUCCESS && response) { 
     723            status = send_response(sess, 0, tmp_pool, response,  
     724                                   src_addr, src_addr_len); 
     725        } 
     726    } 
     727 
     728    return status;     
     729} 
     730 
     731 
     732/* Handle incoming indication */ 
     733static pj_status_t on_incoming_indication(pj_stun_session *sess, 
     734                                          pj_pool_t *tmp_pool, 
     735                                          const pj_uint8_t *in_pkt, 
     736                                          unsigned in_pkt_len, 
     737                                          const pj_stun_msg *msg, 
     738                                          const pj_sockaddr_t *src_addr, 
     739                                          unsigned src_addr_len) 
     740{ 
     741    PJ_UNUSED_ARG(tmp_pool); 
     742 
     743    /* Distribute to handler */ 
     744    if (sess->cb.on_rx_indication) { 
     745        return (*sess->cb.on_rx_indication)(sess, in_pkt, in_pkt_len, msg, 
     746                                            src_addr, src_addr_len); 
     747    } else { 
     748        return PJ_SUCCESS; 
     749    } 
    536750} 
    537751 
     
    540754                                              const void *packet, 
    541755                                              pj_size_t pkt_size, 
    542                                               unsigned *parsed_len) 
     756                                              unsigned options, 
     757                                              unsigned *parsed_len, 
     758                                              const pj_sockaddr_t *src_addr, 
     759                                              unsigned src_addr_len) 
    543760{ 
    544761    pj_stun_msg *msg, *response; 
     
    555772    /* Try to parse the message */ 
    556773    status = pj_stun_msg_decode(tmp_pool, (const pj_uint8_t*)packet, 
    557                                 pkt_size, 0, &msg, parsed_len, 
    558                                 &response); 
     774                                pkt_size, options,  
     775                                &msg, parsed_len, &response); 
    559776    if (status != PJ_SUCCESS) { 
    560777        LOG_ERR_(sess, "STUN msg_decode() error", status); 
    561778        if (response) { 
    562             PJ_TODO(SEND_RESPONSE); 
     779            send_response(sess, 0, tmp_pool, response,  
     780                          src_addr, src_addr_len); 
    563781        } 
    564782        pj_pool_release(tmp_pool); 
     
    568786    dump = pj_pool_alloc(tmp_pool, PJ_STUN_MAX_PKT_LEN); 
    569787 
    570     PJ_LOG(4,(SNAME(sess),  
     788    PJ_LOG(4,(SNAME(sess), 
    571789              "RX STUN message:\n" 
    572               "--- begin STUN message ---" 
     790              "--- begin STUN message ---\n" 
    573791              "%s" 
    574792              "--- end of STUN message ---\n", 
    575793              pj_stun_msg_dump(msg, dump, PJ_STUN_MAX_PKT_LEN, NULL))); 
    576794 
     795    pj_mutex_lock(sess->mutex); 
    577796 
    578797    if (PJ_STUN_IS_RESPONSE(msg->hdr.type) || 
    579798        PJ_STUN_IS_ERROR_RESPONSE(msg->hdr.type)) 
    580799    { 
    581         pj_stun_tx_data *tdata; 
    582  
    583         /* Lookup pending client transaction */ 
    584         tdata = tsx_lookup(sess, msg); 
    585         if (tdata == NULL) { 
    586             LOG_ERR_(sess, "STUN error finding transaction", PJ_ENOTFOUND); 
    587             pj_pool_release(tmp_pool); 
    588             return PJ_ENOTFOUND; 
    589         } 
    590  
    591         /* Pass the response to the transaction.  
    592          * If the message is accepted, transaction callback will be called, 
    593          * and this will call the session callback too. 
    594          */ 
    595         status = pj_stun_client_tsx_on_rx_msg(tdata->client_tsx, msg); 
    596         if (status != PJ_SUCCESS) { 
    597             pj_pool_release(tmp_pool); 
    598             return status; 
    599         } 
    600  
    601         /* If transaction has completed, destroy the transmit data. 
    602          * This will remove the transaction from the pending list too. 
    603          */ 
    604         if (pj_stun_client_tsx_is_complete(tdata->client_tsx)) { 
    605             destroy_tdata(tdata); 
    606             tdata = NULL; 
    607         } 
    608  
    609         pj_pool_release(tmp_pool); 
    610         return PJ_SUCCESS; 
     800        status = on_incoming_response(sess, msg); 
    611801 
    612802    } else if (PJ_STUN_IS_REQUEST(msg->hdr.type)) { 
    613803 
    614         PJ_TODO(HANDLE_INCOMING_STUN_REQUEST); 
     804        status = on_incoming_request(sess, tmp_pool, packet, pkt_size, msg, 
     805                                     src_addr, src_addr_len); 
    615806 
    616807    } else if (PJ_STUN_IS_INDICATION(msg->hdr.type)) { 
    617808 
    618         PJ_TODO(HANDLE_INCOMING_STUN_INDICATION); 
     809        status = on_incoming_indication(sess, tmp_pool, packet, pkt_size, 
     810                                        msg, src_addr, src_addr_len); 
    619811 
    620812    } else { 
    621813        pj_assert(!"Unexpected!"); 
    622     } 
     814        status = PJ_EBUG; 
     815    } 
     816 
     817    pj_mutex_unlock(sess->mutex); 
    623818 
    624819    pj_pool_release(tmp_pool); 
    625     return PJ_ENOTSUP; 
    626 } 
    627  
     820    return status; 
     821} 
     822 
     823 
  • pjproject/trunk/pjlib-util/src/pjstun-srv-test/server_main.c

    r1004 r1021  
    1919#include <pjlib-util.h> 
    2020#include <pjlib.h> 
    21 #include "server.h" 
    2221 
    2322#include <stdio.h> 
     
    2726#define THIS_FILE       "server_main.c" 
    2827#define MAX_THREADS     8 
    29  
    30 struct stun_server_tag server; 
    31  
    32  
    33 pj_status_t server_perror(const char *sender, const char *title,  
    34                           pj_status_t status) 
     28#define MAX_SERVICE     16 
     29#define MAX_PKT_LEN     512 
     30 
     31struct service 
     32{ 
     33    unsigned             index; 
     34    pj_uint16_t          port; 
     35    pj_bool_t            is_stream; 
     36    pj_sock_t            sock; 
     37    pj_ioqueue_key_t    *key; 
     38    pj_ioqueue_op_key_t  recv_opkey, 
     39                         send_opkey; 
     40 
     41    pj_stun_session     *sess; 
     42 
     43    int                  src_addr_len; 
     44    pj_sockaddr_in       src_addr; 
     45    pj_ssize_t           rx_pkt_len; 
     46    pj_uint8_t           rx_pkt[MAX_PKT_LEN]; 
     47    pj_uint8_t           tx_pkt[MAX_PKT_LEN]; 
     48}; 
     49 
     50static struct stun_server 
     51{ 
     52    pj_caching_pool      cp; 
     53    pj_pool_t           *pool; 
     54    pj_stun_endpoint    *endpt; 
     55    pj_ioqueue_t        *ioqueue; 
     56    pj_timer_heap_t     *timer_heap; 
     57    unsigned             service_cnt; 
     58    struct service       services[MAX_SERVICE]; 
     59 
     60    pj_bool_t            thread_quit_flag; 
     61    unsigned             thread_cnt; 
     62    pj_thread_t         *threads[16]; 
     63 
     64} server; 
     65 
     66 
     67static pj_status_t server_perror(const char *sender, const char *title,  
     68                                 pj_status_t status) 
    3569{ 
    3670    char errmsg[PJ_ERR_MSG_SIZE]; 
     
    4377 
    4478 
    45 static pj_status_t create_response(pj_pool_t *pool, 
    46                                    const pj_stun_msg *req_msg, 
    47                                    unsigned err_code, 
    48                                    unsigned uattr_cnt, 
    49                                    pj_uint16_t uattr_types[], 
    50                                    pj_stun_msg **p_response) 
    51 { 
    52     pj_uint32_t msg_type = req_msg->hdr.type; 
    53     pj_stun_msg *response; 
    54     pj_status_t status; 
    55  
    56     status = pj_stun_msg_create_response(pool, req_msg, err_code, NULL, 
    57                                          &response); 
    58     if (status != PJ_SUCCESS) 
    59         return status; 
    60  
    61     /* Add unknown_attribute attributes if err_code is 420 */ 
    62     if (err_code == PJ_STUN_STATUS_UNKNOWN_ATTRIBUTE) { 
    63         pj_stun_unknown_attr *uattr; 
    64  
    65         status = pj_stun_unknown_attr_create(pool, uattr_cnt, uattr_types, 
    66                                              &uattr); 
    67         if (status != PJ_SUCCESS) 
    68             return status; 
    69  
    70         pj_stun_msg_add_attr(response, &uattr->hdr); 
    71     } 
    72  
    73     *p_response = response; 
    74     return PJ_SUCCESS; 
    75 } 
    76  
    77  
    78 static pj_status_t send_msg(struct service *svc, const pj_stun_msg *msg) 
    79 { 
    80     unsigned tx_pkt_len; 
     79/* Callback to be called to send outgoing message */ 
     80static pj_status_t on_send_msg(pj_stun_session *sess, 
     81                               const void *pkt, 
     82                               pj_size_t pkt_size, 
     83                               const pj_sockaddr_t *dst_addr, 
     84                               unsigned addr_len) 
     85{ 
     86    struct service *svc; 
    8187    pj_ssize_t length; 
    8288    pj_status_t status; 
    8389 
    84     /* Print to log */ 
    85     PJ_LOG(4,(THIS_FILE, "TX STUN message: \n" 
    86                          "--- begin STUN message ---\n" 
    87                          "%s" 
    88                          "--- end of STUN message ---\n",  
    89               pj_stun_msg_dump(msg, svc->tx_pkt, sizeof(svc->tx_pkt), NULL))); 
    90  
    91     /* Encode packet */ 
    92     tx_pkt_len = sizeof(svc->tx_pkt); 
    93     status = pj_stun_msg_encode(msg, svc->tx_pkt, tx_pkt_len, 0, 
    94                                 NULL, &tx_pkt_len); 
    95     if (status != PJ_SUCCESS) 
    96         return status; 
    97  
    98     length = tx_pkt_len; 
     90    svc = (struct service*) pj_stun_session_get_user_data(sess); 
    9991 
    10092    /* Send packet */ 
     93    length = pkt_size; 
    10194    if (svc->is_stream) { 
    102         status = pj_ioqueue_send(svc->key, &svc->send_opkey, svc->tx_pkt, 
    103                                  &length, 0); 
     95        status = pj_ioqueue_send(svc->key, &svc->send_opkey, pkt, &length, 0); 
    10496    } else { 
    105         status = pj_ioqueue_sendto(svc->key, &svc->send_opkey, svc->tx_pkt, 
    106                                    &length, 0, &svc->src_addr,  
    107                                    svc->src_addr_len); 
    108     } 
    109  
    110     PJ_LOG(4,(THIS_FILE, "Sending STUN %s %s", 
    111               pj_stun_get_method_name(msg->hdr.type), 
    112               pj_stun_get_class_name(msg->hdr.type))); 
     97#if 0 
     98        pj_pool_t *pool; 
     99        char *buf; 
     100        pj_stun_msg *msg; 
     101 
     102        pool = pj_pool_create(&server.cp.factory, "", 4000, 4000, NULL); 
     103        status = pj_stun_msg_decode(pool, pkt, pkt_size, PJ_STUN_CHECK_PACKET, &msg, NULL, NULL); 
     104        buf = pj_pool_alloc(pool, 512); 
     105        PJ_LOG(3,("", "%s", pj_stun_msg_dump(msg, buf, 512, NULL))); 
     106#endif 
     107        status = pj_ioqueue_sendto(svc->key, &svc->send_opkey, pkt, &length,  
     108                                   0, dst_addr, addr_len); 
     109    } 
    113110 
    114111    return (status == PJ_SUCCESS || status == PJ_EPENDING) ?  
     
    117114 
    118115 
    119 static pj_status_t err_respond(struct service *svc, 
    120                                pj_pool_t *pool, 
    121                                const pj_stun_msg *req_msg, 
    122                                unsigned err_code, 
    123                                unsigned uattr_cnt, 
    124                                pj_uint16_t uattr_types[]) 
    125 { 
    126     pj_stun_msg *response; 
    127     pj_status_t status; 
    128  
    129     /* Create the error response */ 
    130     status = create_response(pool, req_msg, err_code, 
    131                              uattr_cnt, uattr_types, &response); 
     116/* Handle STUN binding request */ 
     117static pj_status_t on_rx_binding_request(pj_stun_session *sess, 
     118                                         const pj_uint8_t *pkt, 
     119                                         unsigned pkt_len, 
     120                                         const pj_stun_msg *msg, 
     121                                         const pj_sockaddr_t *src_addr, 
     122                                         unsigned src_addr_len) 
     123{ 
     124    struct service *svc = (struct service *) pj_stun_session_get_user_data(sess); 
     125    pj_stun_tx_data *tdata; 
     126    pj_stun_auth_policy pol; 
     127    pj_status_t status; 
     128 
     129    /* Create response */ 
     130    status = pj_stun_session_create_response(sess, msg, 0, NULL, &tdata); 
     131    if (status != PJ_SUCCESS) 
     132        return status; 
     133 
     134#if 1 
     135    pj_memset(&pol, 0, sizeof(pol)); 
     136    pol.type = PJ_STUN_POLICY_STATIC_LONG_TERM; 
     137    pol.user_data = NULL; 
     138    pol.data.static_long_term.realm = pj_str("realm"); 
     139    pol.data.static_long_term.username = pj_str("user"); 
     140    pol.data.static_long_term.password = pj_str("password"); 
     141    pol.data.static_long_term.nonce = pj_str("nonce"); 
     142    status = pj_stun_verify_credential(pkt, pkt_len, msg, &pol, tdata->pool,  
     143                                       &tdata->msg); 
     144    if (!tdata->msg) 
     145        return status; 
     146#endif 
     147 
     148    /* Create MAPPED-ADDRESS attribute */ 
     149    status = pj_stun_msg_add_generic_ip_addr_attr(tdata->pool, tdata->msg, 
     150                                                  PJ_STUN_ATTR_MAPPED_ADDR, 
     151                                                  PJ_FALSE, 
     152                                                  src_addr, src_addr_len); 
    132153    if (status != PJ_SUCCESS) { 
    133154        server_perror(THIS_FILE, "Error creating response", status); 
     155        pj_stun_msg_destroy_tdata(sess, tdata); 
    134156        return status; 
    135157    } 
    136158 
    137     /* Send response */ 
    138     status = send_msg(svc, response); 
    139     if (status != PJ_SUCCESS) { 
    140         server_perror(THIS_FILE, "Error sending response", status); 
    141         return status; 
    142     } 
    143  
    144     return PJ_SUCCESS; 
    145 } 
    146  
    147  
    148 static void handle_binding_request(struct service *svc, pj_pool_t *pool,  
    149                                    const pj_stun_msg *rx_msg) 
    150 { 
    151     pj_stun_msg *response; 
    152     pj_stun_generic_ip_addr_attr *m_attr; 
    153     pj_status_t status; 
    154  
    155     status = create_response(pool, rx_msg, 0, 0, NULL, &response); 
    156     if (status != PJ_SUCCESS) { 
    157         server_perror(THIS_FILE, "Error creating response", status); 
    158         return; 
    159     } 
    160  
    161     /* Create MAPPED-ADDRESS attribute */ 
    162     status = pj_stun_generic_ip_addr_attr_create(pool, 
    163                                                  PJ_STUN_ATTR_MAPPED_ADDR, 
    164                                                  PJ_FALSE, 
    165                                                  svc->src_addr_len, 
    166                                                  &svc->src_addr, &m_attr); 
    167     if (status != PJ_SUCCESS) { 
    168         server_perror(THIS_FILE, "Error creating response", status); 
    169         return; 
    170     } 
    171     pj_stun_msg_add_attr(response, &m_attr->hdr); 
    172  
    173159    /* On the presence of magic, create XOR-MAPPED-ADDRESS attribute */ 
    174     if (rx_msg->hdr.magic == PJ_STUN_MAGIC) { 
     160    if (msg->hdr.magic == PJ_STUN_MAGIC) { 
    175161        status =  
    176             pj_stun_generic_ip_addr_attr_create(pool,  
    177                                                 PJ_STUN_ATTR_XOR_MAPPED_ADDRESS, 
    178                                                 PJ_TRUE, 
    179                                                 svc->src_addr_len, 
    180                                                 &svc->src_addr, &m_attr); 
     162            pj_stun_msg_add_generic_ip_addr_attr(tdata->pool, tdata->msg, 
     163                                                 PJ_STUN_ATTR_XOR_MAPPED_ADDRESS, 
     164                                                 PJ_TRUE, 
     165                                                 src_addr, src_addr_len); 
    181166        if (status != PJ_SUCCESS) { 
    182167            server_perror(THIS_FILE, "Error creating response", status); 
    183             return; 
     168            pj_stun_msg_destroy_tdata(sess, tdata); 
     169            return status; 
    184170        } 
    185171    } 
    186172 
    187173    /* Send */ 
    188     status = send_msg(svc, response); 
    189     if (status != PJ_SUCCESS) 
    190         server_perror(THIS_FILE, "Error sending response", status); 
    191 } 
    192  
    193  
    194 static void handle_unknown_request(struct service *svc, pj_pool_t *pool,  
    195                                    pj_stun_msg *rx_msg) 
    196 { 
    197     err_respond(svc, pool, rx_msg, PJ_STUN_STATUS_BAD_REQUEST, 0, NULL); 
    198 } 
    199  
    200  
     174    status = pj_stun_session_send_msg(sess, 0, src_addr, src_addr_len, tdata); 
     175    return status; 
     176} 
     177 
     178 
     179/* Handle unknown request */ 
     180static pj_status_t on_rx_unknown_request(pj_stun_session *sess, 
     181                                         const pj_uint8_t *pkt, 
     182                                         unsigned pkt_len, 
     183                                         const pj_stun_msg *msg, 
     184                                         const pj_sockaddr_t *src_addr, 
     185                                         unsigned src_addr_len) 
     186{ 
     187    pj_stun_tx_data *tdata; 
     188    pj_status_t status; 
     189 
     190    /* Create response */ 
     191    status = pj_stun_session_create_response(sess, msg,  
     192                                             PJ_STUN_STATUS_BAD_REQUEST, 
     193                                             NULL, &tdata); 
     194    if (status != PJ_SUCCESS) 
     195        return status; 
     196 
     197    /* Send */ 
     198    status = pj_stun_session_send_msg(sess, 0, src_addr, src_addr_len, tdata); 
     199    return status; 
     200} 
     201 
     202/* Callback to be called by STUN session on incoming STUN requests */ 
     203static pj_status_t on_rx_request(pj_stun_session *sess, 
     204                                 const pj_uint8_t *pkt, 
     205                                 unsigned pkt_len, 
     206                                 const pj_stun_msg *msg, 
     207                                 const pj_sockaddr_t *src_addr, 
     208                                 unsigned src_addr_len) 
     209{ 
     210    switch (PJ_STUN_GET_METHOD(msg->hdr.type)) { 
     211    case PJ_STUN_BINDING_METHOD: 
     212        return on_rx_binding_request(sess, pkt, pkt_len, msg,  
     213                                     src_addr, src_addr_len); 
     214    default: 
     215        return on_rx_unknown_request(sess, pkt, pkt_len, msg, 
     216                                     src_addr, src_addr_len); 
     217    } 
     218} 
     219 
     220 
     221/* Callback on ioqueue read completion */ 
    201222static void on_read_complete(pj_ioqueue_key_t *key,  
    202223                             pj_ioqueue_op_key_t *op_key,  
     
    204225{ 
    205226    struct service *svc = (struct service *) pj_ioqueue_get_user_data(key); 
    206     pj_pool_t *pool = NULL; 
    207     pj_stun_msg *rx_msg, *response; 
    208     char dump[512]; 
    209227    pj_status_t status; 
    210228 
     
    212230        goto next_read; 
    213231 
    214     pool = pj_pool_create(&server.cp.factory, "service", 4000, 4000, NULL); 
    215  
    216     rx_msg = NULL; 
    217     status = pj_stun_msg_decode(pool, svc->rx_pkt, bytes_read, 0, &rx_msg, 
    218                                 NULL, &response); 
     232    /* Handle packet to session */ 
     233    status = pj_stun_session_on_rx_pkt(svc->sess, svc->rx_pkt, bytes_read, 
     234                                       PJ_STUN_IS_DATAGRAM | PJ_STUN_CHECK_PACKET, 
     235                                       NULL, &svc->src_addr, svc->src_addr_len); 
    219236    if (status != PJ_SUCCESS) { 
    220         server_perror(THIS_FILE, "STUN msg_decode() error", status); 
    221         if (response) { 
    222             send_msg(svc, response); 
    223         } 
    224         goto next_read; 
    225     } 
    226  
    227     PJ_LOG(4,(THIS_FILE, "RX STUN message: \n" 
    228                          "--- begin STUN message ---\n" 
    229                          "%s" 
    230                          "--- end of STUN message ---\n",  
    231               pj_stun_msg_dump(rx_msg, dump, sizeof(dump), NULL))); 
    232  
    233     if (PJ_STUN_IS_REQUEST(rx_msg->hdr.type)) { 
    234         switch (rx_msg->hdr.type) { 
    235         case PJ_STUN_BINDING_REQUEST: 
    236             handle_binding_request(svc, pool, rx_msg); 
    237             break; 
    238         default: 
    239             handle_unknown_request(svc, pool, rx_msg); 
    240         } 
    241          
     237        server_perror(THIS_FILE, "Error processing incoming packet", status); 
    242238    } 
    243239 
    244240next_read: 
    245     if (pool != NULL) 
    246         pj_pool_release(pool); 
    247  
    248241    if (bytes_read < 0) { 
    249242        server_perror(THIS_FILE, "on_read_complete()", -bytes_read); 
     
    266259    pj_status_t status; 
    267260    pj_ioqueue_callback service_callback; 
     261    pj_stun_session_cb sess_cb; 
    268262    pj_sockaddr_in addr; 
    269263 
     
    279273    if (status != PJ_SUCCESS) 
    280274        goto on_error; 
     275 
     276    pj_bzero(&sess_cb, sizeof(sess_cb)); 
     277    sess_cb.on_send_msg = &on_send_msg; 
     278    sess_cb.on_rx_request = &on_rx_request; 
     279    status = pj_stun_session_create(server.endpt, "session",  
     280                                    &sess_cb, &svc->sess); 
     281    if (status != PJ_SUCCESS) 
     282        goto on_error; 
     283 
     284    pj_stun_session_set_user_data(svc->sess, (void*)svc); 
    281285 
    282286    pj_bzero(&service_callback, sizeof(service_callback)); 
     
    317321    while (!server.thread_quit_flag) { 
    318322        pj_time_val timeout = { 0, 50 }; 
     323        pj_timer_heap_poll(server.timer_heap, NULL); 
    319324        pj_ioqueue_poll(server.ioqueue, &timeout); 
    320325    } 
     
    347352    if (status != PJ_SUCCESS) 
    348353        return server_perror(THIS_FILE, "pj_ioqueue_create()", status); 
     354 
     355    status = pj_timer_heap_create(server.pool, 1024, &server.timer_heap); 
     356    if (status != PJ_SUCCESS) 
     357        return server_perror(THIS_FILE, "Error creating timer heap", status); 
     358 
     359    status = pj_stun_endpoint_create(&server.cp.factory, 0,  
     360                                     server.ioqueue, server.timer_heap,  
     361                                     &server.endpt); 
     362    if (status != PJ_SUCCESS) 
     363        return server_perror(THIS_FILE, "Error creating endpoint", status); 
    349364 
    350365    server.service_cnt = 1; 
     
    362377pj_status_t server_main(void) 
    363378{ 
    364 #if 1 
     379#if 0 
    365380    for (;;) { 
    366381        pj_time_val timeout = { 0, 50 }; 
     382        pj_timer_heap_poll(server.timer_heap, NULL); 
    367383        pj_ioqueue_poll(server.ioqueue, &timeout); 
    368384 
     
    414430    } 
    415431 
     432    pj_stun_session_destroy(server.services[0].sess); 
     433    pj_stun_endpoint_destroy(server.endpt); 
    416434    pj_ioqueue_destroy(server.ioqueue); 
    417435    pj_pool_release(server.pool); 
     436 
     437    pj_pool_factory_dump(&server.cp.factory, PJ_TRUE); 
    418438    pj_caching_pool_destroy(&server.cp); 
    419439 
Note: See TracChangeset for help on using the changeset viewer.