Ignore:
Timestamp:
Feb 15, 2018 1:57:11 PM (17 months ago)
Author:
riza
Message:

Fix #2091: On iOS11, replace_udp_sock() might fail and lead to unusable UDP transport.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • pjproject/trunk/pjmedia/src/pjmedia/transport_udp.c

    r5654 r5737  
    7070    unsigned            tx_drop_pct;    /**< Percent of tx pkts to drop.    */ 
    7171    unsigned            rx_drop_pct;    /**< Percent of rx pkts to drop.    */ 
     72    pj_ioqueue_t        *ioqueue;       /**< Ioqueue instance.              */ 
    7273 
    7374    pj_sock_t           rtp_sock;       /**< RTP socket                     */ 
     
    152153static pj_status_t transport_destroy  (pjmedia_transport *tp); 
    153154 
     155static pj_status_t transport_restart  (pj_bool_t is_rtp,  
     156                                       struct transport_udp *udp); 
     157 
    154158 
    155159static pjmedia_transport_op transport_udp_op =  
     
    387391        goto on_error; 
    388392 
     393    tp->ioqueue = ioqueue; 
    389394 
    390395    /* Done */ 
     
    441446 
    442447/* Notification from ioqueue about incoming RTP packet */ 
    443 static void on_rx_rtp( pj_ioqueue_key_t *key,  
    444                        pj_ioqueue_op_key_t *op_key,  
    445                        pj_ssize_t bytes_read) 
     448static void on_rx_rtp(pj_ioqueue_key_t *key, 
     449                      pj_ioqueue_op_key_t *op_key, 
     450                      pj_ssize_t bytes_read) 
    446451{ 
    447452    struct transport_udp *udp; 
     
    451456 
    452457    udp = (struct transport_udp*) pj_ioqueue_get_user_data(key); 
     458 
     459#if defined(PJ_IPHONE_OS_HAS_MULTITASKING_SUPPORT) && \ 
     460            PJ_IPHONE_OS_HAS_MULTITASKING_SUPPORT!=0 
     461    if (-bytes_read == PJ_ESOCKETSTOP) { 
     462        /* Try to recover by restarting the transport. */ 
     463        PJ_LOG(4, (udp->base.name, "Restarting RTP transport")); 
     464        status = transport_restart(PJ_TRUE, udp); 
     465        if (status == PJ_SUCCESS) { 
     466            PJ_LOG(4, (udp->base.name, "Success restarting RTP transport")); 
     467        } else { 
     468            PJ_PERROR(1, (udp->base.name, status,  
     469                          "Error restarting RTP transport")); 
     470        } 
     471        return; 
     472    } 
     473#endif 
    453474 
    454475    do { 
     
    565586 
    566587    udp = (struct transport_udp*) pj_ioqueue_get_user_data(key); 
     588 
     589#if defined(PJ_IPHONE_OS_HAS_MULTITASKING_SUPPORT) && \ 
     590            PJ_IPHONE_OS_HAS_MULTITASKING_SUPPORT!=0 
     591    if (-bytes_read == PJ_ESOCKETSTOP) { 
     592        /* Try to recover by restarting the transport. */ 
     593        PJ_LOG(4, (udp->base.name, "Restarting RTCP transport")); 
     594        status = transport_restart(PJ_FALSE, udp); 
     595        if (status == PJ_SUCCESS) { 
     596            PJ_LOG(4, (udp->base.name, "Success restarting RTCP transport")); 
     597        } else { 
     598            PJ_PERROR(1, (udp->base.name, status,  
     599                          "Error restarting RTCP transport")); 
     600        } 
     601        return; 
     602    } 
     603#endif 
    567604 
    568605    do { 
     
    9961033} 
    9971034 
     1035static pj_status_t transport_restart(pj_bool_t is_rtp, 
     1036                                     struct transport_udp *udp) 
     1037{ 
     1038    pj_ioqueue_key_t *key = (is_rtp ? udp->rtp_key : udp->rtcp_key); 
     1039    pj_sock_t *sock = (is_rtp ? &udp->rtp_sock : &udp->rtcp_sock); 
     1040    pj_status_t status; 
     1041    int af; 
     1042    pj_sockaddr *addr; 
     1043    pj_ioqueue_callback cb; 
     1044    pj_ssize_t size; 
     1045 
     1046    /* Destroy existing socket, if any. */     
     1047    if (key) { 
     1048        /* This will block the execution if callback is still 
     1049         * being called. 
     1050         */ 
     1051        pj_ioqueue_unregister(key); 
     1052        if (is_rtp) { 
     1053            udp->rtp_key = NULL; 
     1054        } else { 
     1055            udp->rtcp_key = NULL; 
     1056        } 
     1057    } else if (*sock != PJ_INVALID_SOCKET) { 
     1058        pj_sock_close(*sock); 
     1059    } 
     1060    *sock = PJ_INVALID_SOCKET; 
     1061 
     1062    /* Create socket */ 
     1063    af = udp->rtp_addr_name.addr.sa_family; 
     1064    status = pj_sock_socket(af, pj_SOCK_DGRAM(), 0, sock); 
     1065 
     1066    if (status != PJ_SUCCESS) 
     1067        goto on_error; 
     1068 
     1069    addr = (is_rtp) ? &udp->rtp_addr_name : &udp->rtcp_addr_name; 
     1070    status = pj_sock_bind(*sock, addr, pj_sockaddr_get_len(addr)); 
     1071    if (status != PJ_SUCCESS) 
     1072        goto on_error; 
     1073 
     1074    /* Set buffer size for RTP socket */ 
     1075#if PJMEDIA_TRANSPORT_SO_RCVBUF_SIZE 
     1076    { 
     1077        unsigned sobuf_size = PJMEDIA_TRANSPORT_SO_RCVBUF_SIZE; 
     1078 
     1079        status = pj_sock_setsockopt_sobuf(udp->rtp_sock, pj_SO_RCVBUF(), 
     1080                                          PJ_TRUE, &sobuf_size); 
     1081        if (status != PJ_SUCCESS) { 
     1082            pj_perror(3, udp->base.name, status, "Failed setting SO_RCVBUF"); 
     1083        } else { 
     1084            if (sobuf_size < PJMEDIA_TRANSPORT_SO_RCVBUF_SIZE) { 
     1085                PJ_LOG(4, (udp->base.name, 
     1086                           "Warning! Cannot set SO_RCVBUF as configured, " 
     1087                           "now=%d, configured=%d", 
     1088                           sobuf_size, PJMEDIA_TRANSPORT_SO_RCVBUF_SIZE)); 
     1089            } else { 
     1090                PJ_LOG(5, (udp->base.name, "SO_RCVBUF set to %d", sobuf_size)); 
     1091            } 
     1092        } 
     1093    } 
     1094#endif 
     1095#if PJMEDIA_TRANSPORT_SO_SNDBUF_SIZE 
     1096    { 
     1097        unsigned sobuf_size = PJMEDIA_TRANSPORT_SO_SNDBUF_SIZE; 
     1098 
     1099        status = pj_sock_setsockopt_sobuf(udp->rtp_sock, pj_SO_SNDBUF(), 
     1100                                          PJ_TRUE, &sobuf_size); 
     1101        if (status != PJ_SUCCESS) { 
     1102            pj_perror(3, udp->base.name, status, "Failed setting SO_SNDBUF"); 
     1103        } else { 
     1104            if (sobuf_size < PJMEDIA_TRANSPORT_SO_SNDBUF_SIZE) { 
     1105                PJ_LOG(4, (udp->base.name, 
     1106                           "Warning! Cannot set SO_SNDBUF as configured, " 
     1107                           "now=%d, configured=%d", 
     1108                           sobuf_size, PJMEDIA_TRANSPORT_SO_SNDBUF_SIZE)); 
     1109            } else { 
     1110                PJ_LOG(5, (udp->base.name, "SO_SNDBUF set to %d", sobuf_size)); 
     1111            } 
     1112        } 
     1113    } 
     1114#endif 
     1115    pj_bzero(&cb, sizeof(cb)); 
     1116    if (is_rtp) 
     1117        cb.on_read_complete = &on_rx_rtp; 
     1118    else  
     1119        cb.on_read_complete = &on_rx_rtcp; 
     1120 
     1121    if (is_rtp) { 
     1122        status = pj_ioqueue_register_sock(udp->pool, udp->ioqueue, *sock, udp, 
     1123                                          &cb, &udp->rtp_key); 
     1124    } else { 
     1125        status = pj_ioqueue_register_sock(udp->pool, udp->ioqueue, *sock, udp, 
     1126                                          &cb, &udp->rtcp_key);     
     1127    } 
     1128 
     1129    if (status != PJ_SUCCESS) 
     1130        goto on_error; 
     1131 
     1132    if (is_rtp) { 
     1133        size = sizeof(udp->rtp_pkt); 
     1134        status = pj_ioqueue_recvfrom(udp->rtp_key, &udp->rtp_read_op, 
     1135                                     udp->rtp_pkt, &size,  
     1136                                     PJ_IOQUEUE_ALWAYS_ASYNC, 
     1137                                     &udp->rtp_src_addr, &udp->rtp_addrlen); 
     1138    } else { 
     1139        size = sizeof(udp->rtcp_pkt); 
     1140        status = pj_ioqueue_recvfrom(udp->rtcp_key, &udp->rtcp_read_op, 
     1141                                     udp->rtcp_pkt, &size,  
     1142                                     PJ_IOQUEUE_ALWAYS_ASYNC, 
     1143                                     &udp->rtcp_src_addr, &udp->rtcp_addr_len); 
     1144    } 
     1145    if (status != PJ_EPENDING) 
     1146        goto on_error; 
     1147 
     1148 
     1149    return PJ_SUCCESS; 
     1150on_error: 
     1151    if (*sock != PJ_INVALID_SOCKET) { 
     1152        pj_sock_close(*sock); 
     1153        *sock = PJ_INVALID_SOCKET; 
     1154    } 
     1155    return status; 
     1156} 
Note: See TracChangeset for help on using the changeset viewer.