Ignore:
Timestamp:
Dec 8, 2009 1:11:25 PM (13 years ago)
Author:
bennylp
Message:

Fixed ticket #999:

Several bug fixes to the TURN client library and icedemo sample application:

  1. ICE stream transport reports ICE initialization/candidate gathering stage as successful even when TURN client TCP connection has failed.
  2. Bad ChannelData? framing when TCP is used. PJNATH did not properly add padding to the TURN ChannelData? packet if TCP is used and the data is not aligned to four bytes boundary. Similarly incoming ChannelData? with padding (over TCP) may not be handled correctly.
  3. Incoming data over TCP may be delayed. PJNATH only processed one frame (be it request, indication, or ChannelData?) on an incoming stream, so if the stream contains more than one frames, the processing of subsequent frames will be delayed until more stream is received on the TCP transport.
  4. The icedemo sample application overwrites the incoming packet buffer with NULL character ('\0') before printing the message to console. If there is another packet after current packet (as often happens when TCP is used), the subsequent packet will get corrupted.

The combinations of bugs above may cause PJNATH to return "Invalid STUN message length (PJNATH_EINSTUNMSGLEN)" error when processing incoming TURN ChannelData? message over TCP.

And a small enhancement:

  1. Add logging to file option to icedemo sample.

Thanks Sarun Nandakumar for the report.

File:
1 edited

Legend:

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

    r2966 r3028  
    274274                     pj_status_t status) 
    275275{ 
    276     char errmsg[PJ_ERR_MSG_SIZE]; 
    277  
    278     if (status != PJ_SUCCESS) { 
    279         pj_strerror(status, errmsg, sizeof(errmsg)); 
    280         PJ_LOG(4,(turn_sock->obj_name, "%s: %s", title, errmsg)); 
    281     } else { 
    282         PJ_LOG(4,(turn_sock->obj_name, "%s", title, errmsg)); 
    283     } 
     276    PJ_PERROR(4,(turn_sock->obj_name, status, title)); 
    284277} 
    285278 
     
    289282{ 
    290283    show_err(turn_sock, title, status); 
    291     if (turn_sock->sess) 
    292         pj_turn_session_destroy(turn_sock->sess); 
     284    if (turn_sock->sess) { 
     285        pj_turn_session_destroy(turn_sock->sess, status); 
     286    } 
    293287} 
    294288 
     
    495489} 
    496490 
     491static pj_uint16_t GETVAL16H(const pj_uint8_t *buf, unsigned pos) 
     492{ 
     493    return (pj_uint16_t) ((buf[pos + 0] << 8) | \ 
     494                          (buf[pos + 1] << 0)); 
     495} 
     496 
     497/* Quick check to determine if there is enough packet to process in the 
     498 * incoming buffer. Return the packet length, or zero if there's no packet. 
     499 */ 
     500static unsigned has_packet(pj_turn_sock *turn_sock, const void *buf, pj_size_t bufsize) 
     501{ 
     502    pj_bool_t is_stun; 
     503 
     504    if (turn_sock->conn_type == PJ_TURN_TP_UDP) 
     505        return bufsize; 
     506 
     507    /* Quickly check if this is STUN message, by checking the first two bits and 
     508     * size field which must be multiple of 4 bytes 
     509     */ 
     510    is_stun = ((((pj_uint8_t*)buf)[0] & 0xC0) == 0) && 
     511              ((GETVAL16H((const pj_uint8_t*)buf, 2) & 0x03)==0); 
     512 
     513    if (is_stun) { 
     514        pj_size_t msg_len = GETVAL16H((const pj_uint8_t*)buf, 2); 
     515        return (msg_len+20 <= bufsize) ? msg_len+20 : 0; 
     516    } else { 
     517        /* This must be ChannelData. */ 
     518        pj_turn_channel_data cd; 
     519 
     520        if (bufsize < 4) 
     521            return 0; 
     522 
     523        /* Decode ChannelData packet */ 
     524        pj_memcpy(&cd, buf, sizeof(pj_turn_channel_data)); 
     525        cd.length = pj_ntohs(cd.length); 
     526 
     527        if (bufsize >= cd.length+sizeof(cd))  
     528            return (cd.length+sizeof(cd)+3) & (~3); 
     529        else 
     530            return 0; 
     531    } 
     532} 
     533 
    497534/* 
    498535 * Notification from ioqueue when incoming UDP packet is received. 
     
    505542{ 
    506543    pj_turn_sock *turn_sock; 
    507     pj_size_t parsed_len; 
    508544    pj_bool_t ret = PJ_TRUE; 
    509545 
     
    512548 
    513549    if (status == PJ_SUCCESS && turn_sock->sess) { 
    514         /* Report incoming packet to TURN session */ 
    515         parsed_len = (unsigned)size; 
    516         pj_turn_session_on_rx_pkt(turn_sock->sess, data,  size, &parsed_len); 
    517         if (parsed_len < (unsigned)size) { 
    518             *remainder = size - parsed_len; 
    519             pj_memmove(data, ((char*)data)+parsed_len, *remainder); 
    520         } else { 
    521             *remainder = 0; 
     550        /* Report incoming packet to TURN session, repeat while we have 
     551         * "packet" in the buffer (required for stream-oriented transports) 
     552         */ 
     553        unsigned pkt_len; 
     554 
     555        //PJ_LOG(5,(turn_sock->pool->obj_name,  
     556        //        "Incoming data, %lu bytes total buffer", size)); 
     557 
     558        while ((pkt_len=has_packet(turn_sock, data, size)) != 0) { 
     559            pj_size_t parsed_len; 
     560            //const pj_uint8_t *pkt = (const pj_uint8_t*)data; 
     561 
     562            //PJ_LOG(5,(turn_sock->pool->obj_name,  
     563            //        "Packet start: %02X %02X %02X %02X",  
     564            //        pkt[0], pkt[1], pkt[2], pkt[3])); 
     565 
     566            //PJ_LOG(5,(turn_sock->pool->obj_name,  
     567            //        "Processing %lu bytes packet of %lu bytes total buffer", 
     568            //        pkt_len, size)); 
     569 
     570            parsed_len = (unsigned)size; 
     571            pj_turn_session_on_rx_pkt(turn_sock->sess, data,  size, &parsed_len); 
     572 
     573            /* parsed_len may be zero if we have parsing error, so use our 
     574             * previous calculation to exhaust the bad packet. 
     575             */ 
     576            if (parsed_len == 0) 
     577                parsed_len = pkt_len; 
     578 
     579            if (parsed_len < (unsigned)size) { 
     580                *remainder = size - parsed_len; 
     581                pj_memmove(data, ((char*)data)+parsed_len, *remainder); 
     582            } else { 
     583                *remainder = 0; 
     584            } 
     585            size = *remainder; 
     586 
     587            //PJ_LOG(5,(turn_sock->pool->obj_name,  
     588            //        "Buffer size now %lu bytes", size)); 
    522589        } 
    523590    } else if (status != PJ_SUCCESS &&  
Note: See TracChangeset for help on using the changeset viewer.