Ignore:
Timestamp:
Aug 27, 2010 6:46:29 AM (14 years ago)
Author:
ming
Message:

Closed ticket #1107: iOS4 background feature

  • pjlib:
    • add support for activesock TCP to work in background mode.
    • add feature in ioqueue to recreate closed UDP sockets.
  • pjsip-apps:
    • ipjsua: add support for iPhone OS 4 background mode
    • ipjsystest: add support for iPhone OS 4 background mode
File:
1 edited

Legend:

Unmodified
Added
Removed
  • pjproject/trunk/pjlib/src/pj/ioqueue_select.c

    r2554 r3299  
    3838#include <pj/compat/socket.h> 
    3939#include <pj/sock_select.h> 
     40#include <pj/sock_qos.h> 
    4041#include <pj/errno.h> 
    4142 
     
    123124#endif 
    124125}; 
     126 
     127/* Proto */ 
     128static pj_status_t replace_udp_sock(pj_ioqueue_key_t *h); 
    125129 
    126130/* Include implementation for common abstraction after we declare 
     
    621625#endif 
    622626 
     627#if defined(PJ_IPHONE_OS_HAS_MULTITASKING_SUPPORT) && \ 
     628    PJ_IPHONE_OS_HAS_MULTITASKING_SUPPORT!=0 
     629static pj_status_t replace_udp_sock(pj_ioqueue_key_t *h) 
     630{ 
     631    enum flags { 
     632        HAS_PEER_ADDR = 1, 
     633        HAS_QOS = 2 
     634    }; 
     635    pj_sock_t old_sock, new_sock = PJ_INVALID_SOCKET; 
     636    pj_sockaddr local_addr, rem_addr; 
     637    int val, addr_len; 
     638    pj_fd_set_t *fds[3]; 
     639    unsigned i, fds_cnt, flags=0; 
     640    pj_qos_params qos_params; 
     641    unsigned msec; 
     642    pj_status_t status; 
     643 
     644    pj_lock_acquire(h->ioqueue->lock); 
     645 
     646    old_sock = h->fd; 
     647 
     648    /* Can only replace UDP socket */ 
     649    pj_assert(h->fd_type == pj_SOCK_DGRAM()); 
     650 
     651    PJ_LOG(4,(THIS_FILE, "Attempting to replace UDP socket %d", old_sock)); 
     652 
     653    /* Investigate the old socket */ 
     654    addr_len = sizeof(local_addr); 
     655    status = pj_sock_getsockname(old_sock, &local_addr, &addr_len); 
     656    if (status != PJ_SUCCESS) 
     657        goto on_error; 
     658     
     659    addr_len = sizeof(rem_addr); 
     660    status = pj_sock_getpeername(old_sock, &rem_addr, &addr_len); 
     661    if (status == PJ_SUCCESS) 
     662        flags |= HAS_PEER_ADDR; 
     663 
     664    status = pj_sock_get_qos_params(old_sock, &qos_params); 
     665    if (status == PJ_SUCCESS) 
     666        flags |= HAS_QOS; 
     667 
     668    /* We're done with the old socket, close it otherwise we'll get 
     669     * error in bind() 
     670     */ 
     671    pj_sock_close(old_sock); 
     672 
     673    /* Prepare the new socket */ 
     674    status = pj_sock_socket(local_addr.addr.sa_family, PJ_SOCK_DGRAM, 0, 
     675                            &new_sock); 
     676    if (status != PJ_SUCCESS) 
     677        goto on_error; 
     678 
     679    /* Even after the socket is closed, we'll still get "Address in use" 
     680     * errors, so force it with SO_REUSEADDR 
     681     */ 
     682    val = 1; 
     683    status = pj_sock_setsockopt(new_sock, SOL_SOCKET, SO_REUSEADDR, 
     684                                &val, sizeof(val)); 
     685    if (status != PJ_SUCCESS) 
     686        goto on_error; 
     687 
     688    /* The loop is silly, but what else can we do? */ 
     689    addr_len = pj_sockaddr_get_len(&local_addr); 
     690    for (msec=20; ; msec<1000? msec=msec*2 : 1000) { 
     691        status = pj_sock_bind(new_sock, &local_addr, addr_len); 
     692        if (status != PJ_STATUS_FROM_OS(EADDRINUSE)) 
     693            break; 
     694        PJ_LOG(4,(THIS_FILE, "Address is still in use, retrying..")); 
     695        pj_thread_sleep(msec); 
     696    } 
     697 
     698    if (status != PJ_SUCCESS) 
     699        goto on_error; 
     700 
     701    if (flags & HAS_QOS) { 
     702        status = pj_sock_set_qos_params(new_sock, &qos_params); 
     703        if (status != PJ_SUCCESS) 
     704            goto on_error; 
     705    } 
     706 
     707    if (flags & HAS_PEER_ADDR) { 
     708        status = pj_sock_connect(new_sock, &rem_addr, addr_len); 
     709        if (status != PJ_SUCCESS) 
     710            goto on_error; 
     711    } 
     712 
     713    /* Set socket to nonblocking. */ 
     714    val = 1; 
     715#if defined(PJ_WIN32) && PJ_WIN32!=0 || \ 
     716    defined(PJ_WIN32_WINCE) && PJ_WIN32_WINCE!=0 
     717    if (ioctlsocket(new_sock, FIONBIO, &val)) { 
     718#else 
     719    if (ioctl(new_sock, FIONBIO, &val)) { 
     720#endif 
     721        status = pj_get_netos_error(); 
     722        goto on_error; 
     723    } 
     724 
     725    /* Replace the occurrence of old socket with new socket in the 
     726     * fd sets. 
     727     */ 
     728    fds_cnt = 0; 
     729    fds[fds_cnt++] = &h->ioqueue->rfdset; 
     730    fds[fds_cnt++] = &h->ioqueue->wfdset; 
     731#if PJ_HAS_TCP 
     732    fds[fds_cnt++] = &h->ioqueue->xfdset; 
     733#endif 
     734 
     735    for (i=0; i<fds_cnt; ++i) { 
     736        if (PJ_FD_ISSET(old_sock, fds[i])) { 
     737            PJ_FD_CLR(old_sock, fds[i]); 
     738            PJ_FD_SET(new_sock, fds[i]); 
     739        } 
     740    } 
     741 
     742    /* And finally replace the fd in the key */ 
     743    h->fd = new_sock; 
     744 
     745    PJ_LOG(4,(THIS_FILE, "UDP has been replaced successfully!")); 
     746 
     747    pj_lock_release(h->ioqueue->lock); 
     748 
     749    return PJ_SUCCESS; 
     750 
     751on_error: 
     752    if (new_sock != PJ_INVALID_SOCKET) 
     753        pj_sock_close(new_sock); 
     754    PJ_PERROR(1,(THIS_FILE, status, "Error replacing socket")); 
     755    pj_lock_release(h->ioqueue->lock); 
     756    return status; 
     757} 
     758#endif 
     759 
    623760 
    624761/* 
Note: See TracChangeset for help on using the changeset viewer.