Ticket #2091 (closed defect: fixed)

Opened 9 months ago

Last modified 4 months ago

On iOS11, replace_udp_sock() might fail and lead to unusable UDP transport

Reported by: riza Owned by: bennylp
Priority: normal Milestone: release-2.8
Component: pjlib Version: trunk
Keywords: Cc:
Backport to 1.x milestone: Backported: no

Description

Ticket #1107 and #1225, described that iOS will reset UDP socket when app goes to background. The library will then try to recreate the socket by calling replace_udp_sock().

However since iOS11, we see some cases that the method fail and lead to unusable UDP transport or even worst, an unresponsive library state.

Log:

ioq_select !Attempting to replace UDP socket 5 
ioq_select  Error replacing socket: Invalid argument
udp0x127d27e00  Warning: pj_ioqueue_recvfrom: [err 120009] Bad file descriptor

Steps to reproduce:

  • run ipjsua
  • register to a registrar using UDP
  • lock-unlock the phone repeatedly

This ticket will retry the recreate socket/replace_udp_sock() if it fail and add a fallback mechanism (restart transport) from the app callback.

Log:

ioq_select !Attempting to replace UDP socket 5
ioq_select  Error get peer name 120022
ioq_select  Error set qos param 120022
ioq_select  Retry to replace UDP socket 5
ioq_select !Error get peer name 120022
ioq_select  UDP has been replaced successfully!

Change History

comment:1 Changed 9 months ago by riza

  • Status changed from new to closed
  • Resolution set to fixed

In 5737:

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

comment:2 Changed 8 months ago by ming

In 5769:

Re #2091: Removed warning of unused function

comment:3 Changed 8 months ago by ming

In 5778:

Re #2091:

  • Fix possible multiple socket closes and querying already-closed sockets.
  • Also prevent possible exception if replace_udp_sock() fails.

If replace_udp_sock() fails, then key->fd will have already been closed. So when calling pj_ioqueue_unregister(key), it will attempt to close the socket again. This may (but not always) result in an exception, which seems to happen when the socket descriptor has been reused by another app.

Explanation: EXC_GUARD exception happens when you try to close a file descriptor that you don't own.

Stack trace:
Exception Type: EXC_GUARD
Exception Subtype: GUARD_TYPE_FD
Exception Message: CLOSE on file descriptor 11 (guarded with 0x08fd4dbfade2dead)
Exception Note: SIMULATED (this is NOT a crash) requested by (null)
Triggered by Thread: 7

Thread 7 Crashed:
0 libsystem_kernel.dylib 0x0000000183b09224 close + 8
1 0x00000001031b5b58 pj_sock_close + 12
2 0x00000001031b1d58 pj_ioqueue_unregister + 120
3 0x000000010313b018 udp_destroy + 44
4 0x0000000103138bf8 destroy_transport + 220
5 0x000000010313942c pjsip_tpmgr_destroy + 132
6 0x0000000103133a40 pjsip_endpt_destroy + 244
7 0x000000010315a1b8 pjsua_destroy2 + 2640

comment:4 Changed 4 months ago by ming

In 5849:

Re #2091: Fixed crash in pj_ioqueue_poll() when iterating keys with closed sockets, which because of r5778, is now set to PJ_INVALID_SOCKET

Note: the crash will happen in PJ_FD_ISSET(h->fd, ...)

Note: See TracTickets for help on using tickets.