Ignore:
Timestamp:
May 14, 2019 9:31:39 AM (5 years ago)
Author:
nanang
Message:

Close #2197: Support TURN extensions for TCP allocations (RFC 6062).

File:
1 edited

Legend:

Unmodified
Added
Removed
  • pjproject/trunk/pjnath/src/pjnath/turn_session.c

    r5983 r5987  
    104104}; 
    105105 
     106struct conn_bind_t 
     107{ 
     108    pj_uint32_t      id;                /* Connection ID.       */ 
     109    pj_sockaddr      peer_addr;         /* Peer address.        */ 
     110    unsigned         peer_addr_len; 
     111}; 
    106112 
    107113/* The TURN client session structure */ 
     
    209215{ 
    210216    pj_bzero(prm, sizeof(*prm)); 
     217    prm->peer_conn_type = PJ_TURN_TP_UDP; 
    211218} 
    212219 
     
    724731                     sess->state<=PJ_TURN_STATE_RESOLVED,  
    725732                     PJ_EINVALIDOP); 
     733    PJ_ASSERT_RETURN(param->peer_conn_type == PJ_TURN_TP_UDP || 
     734                     param->peer_conn_type == PJ_TURN_TP_TCP, 
     735                     PJ_EINVAL); 
    726736 
    727737    /* Verify address family in allocation param */ 
     
    761771    pj_stun_msg_add_uint_attr(tdata->pool, tdata->msg, 
    762772                              PJ_STUN_ATTR_REQ_TRANSPORT,  
    763                               PJ_STUN_SET_RT_PROTO(PJ_TURN_TP_UDP)); 
     773                              PJ_STUN_SET_RT_PROTO(param->peer_conn_type)); 
    764774 
    765775    /* Include BANDWIDTH if requested */ 
     
    9991009    } 
    10001010 
     1011    /* If peer connection is TCP (RFC 6062), send it directly */ 
     1012    if (sess->alloc_param.peer_conn_type == PJ_TURN_TP_TCP) { 
     1013        status = sess->cb.on_send_pkt(sess, pkt, pkt_len, addr, addr_len); 
     1014        goto on_return; 
     1015    } 
     1016 
    10011017    /* See if the peer is bound to a channel number */ 
    10021018    ch = lookup_ch_by_addr(sess, addr, pj_sockaddr_get_len(addr),  
     
    11391155 
    11401156/** 
    1141  * Notify TURN client session upon receiving a packet from server. 
    1142  * The packet maybe a STUN packet or ChannelData packet. 
    1143  */ 
     1157 * Send ConnectionBind request. 
     1158 */ 
     1159PJ_DEF(pj_status_t) pj_turn_session_connection_bind( 
     1160                                            pj_turn_session *sess, 
     1161                                            pj_pool_t *pool, 
     1162                                            pj_uint32_t conn_id, 
     1163                                            const pj_sockaddr_t *peer_addr, 
     1164                                            unsigned addr_len) 
     1165{ 
     1166    pj_stun_tx_data *tdata; 
     1167    struct conn_bind_t *conn_bind; 
     1168    pj_status_t status; 
     1169 
     1170    PJ_ASSERT_RETURN(sess && pool && conn_id && peer_addr && addr_len, 
     1171                     PJ_EINVAL); 
     1172    PJ_ASSERT_RETURN(sess->state == PJ_TURN_STATE_READY, PJ_EINVALIDOP); 
     1173 
     1174    pj_grp_lock_acquire(sess->grp_lock); 
     1175 
     1176    /* Create blank ConnectionBind request */ 
     1177    status = pj_stun_session_create_req(sess->stun,  
     1178                                        PJ_STUN_CONNECTION_BIND_REQUEST, 
     1179                                        PJ_STUN_MAGIC, NULL, &tdata); 
     1180    if (status != PJ_SUCCESS) 
     1181        goto on_return; 
     1182 
     1183    /* Add CONNECTION_ID attribute */ 
     1184    pj_stun_msg_add_uint_attr(tdata->pool, tdata->msg, 
     1185                              PJ_STUN_ATTR_CONNECTION_ID, 
     1186                              conn_id); 
     1187 
     1188    conn_bind = PJ_POOL_ZALLOC_T(pool, struct conn_bind_t); 
     1189    conn_bind->id = conn_id; 
     1190    pj_sockaddr_cp(&conn_bind->peer_addr, peer_addr); 
     1191    conn_bind->peer_addr_len = addr_len; 
     1192 
     1193    /* Send the request, associate connection data structure with tdata  
     1194     * for future reference when we receive the ConnectionBind response. 
     1195     */ 
     1196    status = pj_stun_session_send_msg(sess->stun, conn_bind, PJ_FALSE, 
     1197                                      PJ_FALSE, peer_addr, addr_len, tdata); 
     1198 
     1199on_return: 
     1200    pj_grp_lock_release(sess->grp_lock); 
     1201    return status; 
     1202} 
     1203 
    11441204PJ_DEF(pj_status_t) pj_turn_session_on_rx_pkt(pj_turn_session *sess, 
    11451205                                              void *pkt, 
     
    11471207                                              pj_size_t *parsed_len) 
    11481208{ 
     1209    pj_turn_session_on_rx_pkt_param prm; 
     1210    pj_status_t status; 
     1211     
     1212    pj_bzero(&prm, sizeof(prm)); 
     1213    prm.pkt = pkt; 
     1214    prm.pkt_len = pkt_len; 
     1215    status = pj_turn_session_on_rx_pkt2(sess, &prm); 
     1216    if (status == PJ_SUCCESS && parsed_len) 
     1217        *parsed_len = prm.parsed_len; 
     1218    return status; 
     1219} 
     1220 
     1221/** 
     1222 * Notify TURN client session upon receiving a packet from server. 
     1223 * The packet maybe a STUN packet or ChannelData packet. 
     1224 */ 
     1225PJ_DEF(pj_status_t) pj_turn_session_on_rx_pkt2( 
     1226                                pj_turn_session *sess, 
     1227                                pj_turn_session_on_rx_pkt_param *prm) 
     1228{ 
    11491229    pj_bool_t is_stun; 
    11501230    pj_status_t status; 
     
    11611241 
    11621242    /* Quickly check if this is STUN message */ 
    1163     is_stun = ((((pj_uint8_t*)pkt)[0] & 0xC0) == 0); 
     1243    is_stun = ((((pj_uint8_t*)prm->pkt)[0] & 0xC0) == 0); 
    11641244 
    11651245    if (is_stun) { 
    11661246        /* This looks like STUN, give it to the STUN session */ 
    11671247        unsigned options; 
     1248        const pj_sockaddr_t *src_addr = prm->src_addr? 
     1249                                        prm->src_addr:sess->srv_addr; 
     1250        unsigned src_addr_len = prm->src_addr_len? prm->src_addr_len: 
     1251                                pj_sockaddr_get_len(sess->srv_addr); 
    11681252 
    11691253        options = PJ_STUN_CHECK_PACKET | PJ_STUN_NO_FINGERPRINT_CHECK; 
    11701254        if (is_datagram) 
    11711255            options |= PJ_STUN_IS_DATAGRAM; 
    1172         status=pj_stun_session_on_rx_pkt(sess->stun, pkt, pkt_len, 
    1173                                          options, NULL, parsed_len, 
    1174                                          sess->srv_addr, 
    1175                                          pj_sockaddr_get_len(sess->srv_addr)); 
     1256        status=pj_stun_session_on_rx_pkt(sess->stun, prm->pkt, prm->pkt_len, 
     1257                                         options, NULL, &prm->parsed_len, 
     1258                                         src_addr, src_addr_len); 
    11761259 
    11771260    } else { 
     
    11801263        struct ch_t *ch; 
    11811264 
    1182         if (pkt_len < 4) { 
    1183             if (parsed_len) *parsed_len = 0; 
     1265        if (prm->pkt_len < 4) { 
     1266            prm->parsed_len = 0; 
    11841267            return PJ_ETOOSMALL; 
    11851268        } 
    11861269 
    11871270        /* Decode ChannelData packet */ 
    1188         pj_memcpy(&cd, pkt, sizeof(pj_turn_channel_data)); 
     1271        pj_memcpy(&cd, prm->pkt, sizeof(pj_turn_channel_data)); 
    11891272        cd.ch_number = pj_ntohs(cd.ch_number); 
    11901273        cd.length = pj_ntohs(cd.length); 
    11911274 
    11921275        /* Check that size is sane */ 
    1193         if (pkt_len < cd.length+sizeof(cd)) { 
    1194             if (parsed_len) { 
    1195                 if (is_datagram) { 
    1196                     /* Discard the datagram */ 
    1197                     *parsed_len = pkt_len; 
    1198                 } else { 
    1199                     /* Insufficient fragment */ 
    1200                     *parsed_len = 0; 
    1201                 } 
     1276        if (prm->pkt_len < cd.length+sizeof(cd)) { 
     1277            if (is_datagram) { 
     1278                /* Discard the datagram */ 
     1279                prm->parsed_len = prm->pkt_len; 
     1280            } else { 
     1281                /* Insufficient fragment */ 
     1282                prm->parsed_len = 0; 
    12021283            } 
    12031284            status = PJ_ETOOSMALL; 
    12041285            goto on_return; 
    12051286        } else { 
    1206             if (parsed_len) { 
    1207                 /* Apply padding too */ 
    1208                 *parsed_len = ((cd.length + 3) & (~3)) + sizeof(cd); 
    1209             } 
     1287            /* Apply padding too */ 
     1288            prm->parsed_len = ((cd.length + 3) & (~3)) + sizeof(cd); 
    12101289        } 
    12111290 
     
    12191298        /* Notify application */ 
    12201299        if (sess->cb.on_rx_data) { 
    1221             (*sess->cb.on_rx_data)(sess, ((pj_uint8_t*)pkt)+sizeof(cd),  
     1300            (*sess->cb.on_rx_data)(sess, ((pj_uint8_t*)prm->pkt)+sizeof(cd),  
    12221301                                   cd.length, &ch->addr, 
    12231302                                   pj_sockaddr_get_len(&ch->addr)); 
     
    16431722        } 
    16441723 
     1724    } else if (method == PJ_STUN_CONNECTION_BIND_METHOD) { 
     1725        /* Handle ConnectionBind response */ 
     1726        struct conn_bind_t *conn_bind = (struct conn_bind_t*)token; 
     1727 
     1728        if (status != PJ_SUCCESS || 
     1729            !PJ_STUN_IS_SUCCESS_RESPONSE(response->hdr.type))  
     1730        { 
     1731            pj_str_t reason = {0}; 
     1732            if (status == PJ_SUCCESS) { 
     1733                const pj_stun_errcode_attr *err_attr; 
     1734                err_attr = (const pj_stun_errcode_attr*) 
     1735                           pj_stun_msg_find_attr(response, 
     1736                                                 PJ_STUN_ATTR_ERROR_CODE, 0); 
     1737                if (err_attr) { 
     1738                    status = PJ_STATUS_FROM_STUN_CODE(err_attr->err_code); 
     1739                    reason = err_attr->reason; 
     1740                } else { 
     1741                    status = PJNATH_EINSTUNMSG; 
     1742                } 
     1743            } 
     1744            pj_perror(1, sess->obj_name, status, "ConnectionBind failed: %.*s", 
     1745                      (int)reason.slen, reason.ptr); 
     1746        } 
     1747 
     1748        /* Notify app */ 
     1749        if (sess->cb.on_connection_bind_status) { 
     1750            (*sess->cb.on_connection_bind_status) 
     1751                        (sess, status, conn_bind->id, 
     1752                        &conn_bind->peer_addr, conn_bind->peer_addr_len); 
     1753        } 
    16451754    } else { 
    16461755        PJ_LOG(4,(sess->obj_name, "Unexpected STUN %s response", 
     
    16751784    sess = (pj_turn_session*)pj_stun_session_get_user_data(stun); 
    16761785 
    1677     /* Expecting Data Indication only */ 
     1786    /* ConnectionAttempt Indication */ 
     1787    if (msg->hdr.type == PJ_STUN_CONNECTION_ATTEMPT_INDICATION) { 
     1788        pj_stun_uint_attr *connection_id_attr; 
     1789 
     1790        /* Get CONNECTION-ID attribute */ 
     1791        connection_id_attr = (pj_stun_uint_attr*) 
     1792            pj_stun_msg_find_attr(msg, PJ_STUN_ATTR_CONNECTION_ID, 0); 
     1793 
     1794        /* Get XOR-PEER-ADDRESS attribute */ 
     1795        peer_attr = (pj_stun_xor_peer_addr_attr*) 
     1796            pj_stun_msg_find_attr(msg, PJ_STUN_ATTR_XOR_PEER_ADDR, 0); 
     1797 
     1798        /* Must have both XOR-PEER-ADDRESS and CONNECTION-ID attributes */ 
     1799        if (!peer_attr || !connection_id_attr) { 
     1800            PJ_LOG(4,(sess->obj_name,  
     1801                      "Received ConnectionAttempt indication with missing " 
     1802                      "attributes")); 
     1803            return PJ_EINVALIDOP; 
     1804        } 
     1805 
     1806        /* Notify application */ 
     1807        if (sess->cb.on_connection_attempt) { 
     1808            (*sess->cb.on_connection_attempt) 
     1809                                (sess, 
     1810                                connection_id_attr->value, 
     1811                                &peer_attr->sockaddr, 
     1812                                pj_sockaddr_get_len(&peer_attr->sockaddr)); 
     1813        } 
     1814        return PJ_SUCCESS; 
     1815    } 
     1816 
     1817    /* Next, expecting Data Indication only */ 
    16781818    if (msg->hdr.type != PJ_STUN_DATA_INDICATION) { 
    16791819        PJ_LOG(4,(sess->obj_name, "Unexpected STUN %s indication", 
Note: See TracChangeset for help on using the changeset viewer.