Beispiel #1
0
/* Quick check to determine if there is enough packet to process in the
 * incoming buffer. Return the packet length, or zero if there's no packet.
 */
static unsigned has_packet(pj_turn_sock *turn_sock, const void *buf, pj_size_t bufsize)
{
    pj_bool_t is_stun;

    if (turn_sock->conn_type == PJ_TURN_TP_UDP)
	return (unsigned)bufsize;

    /* Quickly check if this is STUN message, by checking the first two bits and
     * size field which must be multiple of 4 bytes
     */
    is_stun = ((((pj_uint8_t*)buf)[0] & 0xC0) == 0) &&
	      ((GETVAL16H((const pj_uint8_t*)buf, 2) & 0x03)==0);

    if (is_stun) {
	pj_size_t msg_len = GETVAL16H((const pj_uint8_t*)buf, 2);
	return (unsigned)((msg_len+20 <= bufsize) ? msg_len+20 : 0);
    } else {
	/* This must be ChannelData. */
	pj_turn_channel_data cd;

	if (bufsize < 4)
	    return 0;

	/* Decode ChannelData packet */
	pj_memcpy(&cd, buf, sizeof(pj_turn_channel_data));
	cd.length = pj_ntohs(cd.length);

	if (bufsize >= cd.length+sizeof(cd)) 
	    return (cd.length+sizeof(cd)+3) & (~3);
	else
	    return 0;
    }
}
Beispiel #2
0
/**
 * Notify TCP client session upon receiving a packet from server.
 * The packet maybe a STUN packet or ChannelData packet.
 */
PJ_DEF(pj_status_t) pj_tcp_session_on_rx_pkt(pj_tcp_session *sess,
        void *pkt,
        unsigned pkt_len,
        pj_size_t *parsed_len)
{
    pj_bool_t is_stun = PJ_FALSE;
    pj_status_t stun_check;
    pj_status_t status;
    char buf[PJ_INET6_ADDRSTRLEN+20];

    pj_uint16_t data_len;

    /* Packet could be ChannelData or STUN message (response or
     * indication).
     */
    /* Start locking the session */
    pj_lock_acquire(sess->lock);

    /* Quickly check if this is STUN message */
    //is_stun = (((pj_uint16_t*)pkt)[0] != NATNL_UDT_HEADER_MAGIC);
    stun_check = pj_stun_msg_check((const pj_uint8_t*)pkt, pkt_len,
                                   /*PJ_STUN_IS_DATAGRAM | PJ_STUN_CHECK_PACKET*/ 0);

    if (stun_check == PJ_SUCCESS)
        is_stun = PJ_TRUE;

    if (is_stun) {
#if 1
        /* This looks like STUN, give it to the STUN session */
        unsigned options;
        pj_size_t msg_len;

        options = PJ_STUN_CHECK_PACKET | PJ_STUN_NO_FINGERPRINT_CHECK;

        msg_len = GETVAL16H((const pj_uint8_t*)pkt, 2);

        *parsed_len = (msg_len+sizeof(pj_stun_msg_hdr) <= pkt_len) ?
                      msg_len+sizeof(struct pj_stun_msg_hdr) : 0;

        /* Notify application */
        if (sess->cb.on_rx_data) {
            (*sess->cb.on_rx_data)(sess, pkt, pkt_len,
                                   sess->peer_addr, sess->peer_addr_len);
        }
        //DumpPacket(pkt, pkt_len, 0, 5);

        status = PJ_SUCCESS;
#else
        /* This looks like STUN, give it to the STUN session */
        unsigned options;

        options = PJ_STUN_CHECK_PACKET | PJ_STUN_NO_FINGERPRINT_CHECK;
        status=pj_stun_session_on_rx_pkt(sess->stun, pkt, pkt_len,
                                         options, NULL, parsed_len,
                                         sess->peer_addr, sess->peer_addr_len);
#endif
        PJ_LOG(5, (THIS_FILE, "pj_tcp_session_on_rx_pkt() is_stun %s",
                   sess->peer_addr == NULL ? "NULL" :
                   pj_sockaddr_print(sess->peer_addr, buf, PJ_INET6_ADDRSTRLEN, 3)));
    } else {
        PJ_LOG(5, (THIS_FILE, "pj_tcp_session_on_rx_pkt() not_stun %s",
                   sess->peer_addr == NULL ? "NULL" :
                   pj_sockaddr_print(sess->peer_addr, buf, PJ_INET6_ADDRSTRLEN, 3)));

        //DumpPacket(pkt, pkt_len, 0, 7);

        if (((pj_uint16_t*)pkt)[0] != NATNL_UDT_HEADER_MAGIC) {

            if (pkt_len < NATNL_DTLS_HEADER_SIZE) {
                if (parsed_len) {
                    *parsed_len = 0;
                }
                return PJ_ETOOSMALL;
            }

            /* Check that size is sane */
            data_len = pj_ntohs(((pj_uint16_t*)(((pj_uint8_t*)pkt)+11))[0]);
            if (pkt_len < data_len+NATNL_DTLS_HEADER_SIZE) {
                if (parsed_len) {
                    /* Insufficient fragment */
                    *parsed_len = 0;
                }
                status = PJ_ETOOSMALL;
                goto on_return;
            } else {
                if (parsed_len) {
                    /* Apply padding too */
                    *parsed_len = data_len+NATNL_DTLS_HEADER_SIZE;
                }
            }
        } else {

            if (pkt_len < NATNL_UDT_HEADER_SIZE) {
                if (parsed_len) {
                    *parsed_len = 0;
                }
                return PJ_ETOOSMALL;
            }

            /* Check that size is sane */
            data_len = pj_ntohs(((pj_uint16_t*)pkt)[1]);
            if (pkt_len < data_len+NATNL_UDT_HEADER_SIZE) {
                if (parsed_len) {
                    /* Insufficient fragment */
                    *parsed_len = 0;
                }
                status = PJ_ETOOSMALL;
                goto on_return;
            } else {
                if (parsed_len) {
                    /* Apply padding too */
                    *parsed_len = data_len+NATNL_UDT_HEADER_SIZE;
                }
            }
        }

        /* Notify application */
        if (sess->cb.on_rx_data) {
            (*sess->cb.on_rx_data)(sess, pkt, *parsed_len,
                                   sess->peer_addr, sess->peer_addr_len);
        }
        //DumpPacket(pkt, pkt_len, 0, 6);
        status = PJ_SUCCESS;
    }

on_return:
    pj_lock_release(sess->lock);
    return status;
}