Bug en manejo de eventos rfc2833 en asterisk

Desde que migré a Asterisk 1.4 no he podido usar mi cuenta de Azulcom para hacer llamadas salientes. No ha sido hasta hoy, después de confirmar que el problema era Asterisk 1.4, que he encontrado la causa del problema.

Todo viene por el tratamiento de eventos RFC2833. Cuando tenemos dtmfmode=rfc2833, cuando asterisk recibe uno de estos paquetes RTP, lo “decodifica”, y se lo reenvía a la otra parte. Es en este momento cuando asterisk interpreta que todo lo que sea RFC2833 debe ser un dígito multifrecuencia (0123456789*#ABCDX, la X es un hook flash), cuando la realidad es que hay muchísimos más eventos que estos 16, y no deben ser interpretados como DTMF.

En el caso concreto que comento, llegaba un evento 0×8f (143), que según el RFC, corresponde a “MF S3″. No sé para qué sirve, pero esta claro que no puede dejarme sin comunicación.

He notificado el bug (#10877) , donde está el parche para descargar, por si alguno está en la misma situación.

Mola el Software Libre, o no? ;)

Actualización 4-10-2007: Ya está arreglado en el trunk, y en la rama 1.4.

Escrito por julianjm el 3/10/2007. | Comments (0)
Tags: , , , , ,

Tráfico RTP directo entre dispositivos con NAT (y parche)

En asterisk, el parámetro “canreinvite=yes” en sip.conf a la hora de definir un dispositivo SIP, indica la disponibilidad de dicho dispositivo a aceptar tráfico RTP directamente desde el otro dispositivo involucrado en la llamada, sin que asterisk tenga que estar en medio de la comunicación, reenviando la información de uno a otro.

En una red local, no hay gran problema… cualquier red que se precie usa cable CAT5 y switches 10/100… más que de sobra como para que afecte ese extra de paquetes circulando. Sin embargo, cuando tenemos un asterisk en una sede, y varios teléfonos SIP en otra sede distinta (conectados mediante ADSL, por ejemplo), la cosa cambia.

El ancho de banda de una ADSL es asimétrico, y aunque tengamos 3 “megas” de bajada, la subida no suele pasar de unos míseros 320kbs (bits, no bytes). De ahi que sea un recurso muy valioso, como para malgastarlo cuando no es realmente necesario. Con este ancho de banda, podemos mantener unas 10 conversaciones con el códec G729, y unas 3 con G711. (Usando esta calculadora de ancho de banda)

Un caso típico

Imaginemos el siguiente escenario:

  • Un servidor asterisk en la sede central
  • Teléfonos SIP en la sede A (A1,A2,A3..An). Todos ellos configurados con nat=yes.
  • Otros tantos en la sede B (B1..Bn).También con nat=yes.
  • En ninguna de las dos sedes se abren puertos hacia los diferentes teléfonos.

diagrama.PNG

Si impedimos el tráfico de paquetes de voz (RTP) directo entre teléfonos (canreinvite=no), al hacer una llamada interna, desde A1 a A2, habría dos flujos de paquetes:

  1. Desde A1 hasta el servidor asterisk, y desde aquí de vuelta a A2
  2. Justo el camino contrario, ya que la comunicación es full-duplex.

Fíjemonos que para una simple conversación entre extensiones, estamos utilizando nuestra conexión ADSL por partida doble. Estamos utilizando 2 de las llamadas simultáneas disponibles con nuestra humilde conexión a internet.

En una llamada desde A1 a B1 pasaría lo mismo, salvo que en este caso es lo que esperamos. A1 y B1 están en sedes distintas, y no hay forma de que se pueda establecer una comunicación directa entre ambos dispositivos. Lo que queremos es que asterisk haga de enlace entre ambos. Cada sede estará gastando un canal de los que tenga disponible.

Queremos evitar este consumo innecesario de ancho de banda cuando los dos teléfonos pueden establecer una comunicación RTP directa. Para ello, activaremos “canreinvite=yes” en la configuración de todos los dispositivos. Repetimos el experimento.

Llamamos desde A1 a A2. Asterisk, que hace de intermediario, indica a A1 que envíe su tráfico RTP a la dirección de A2, y hace lo propio con A2. Las direcciones IP utilizadas son las IP’s locales de cada teléfono (192.168.0.x, por ejemplo), y no la IP pública de la ADSL de la sede.

El beneficio es palpable, mientras asterisk se encarga de la señalización (indicando cuando un teléfono cuelga, cuando se hace una transferencia, etc), el tráfico RTP de voz va directamente de un teléfono a otro, sin salir a Internet en ningún momento, y sin gastar ningún canal.

Pero todo tiene un “pero”. Al hacer una llamada desde A1 a B1, asterisk también indicará a los dispositivos que se envíen el tráfico RTP directamente entre ellos. El problema está en que, al utilizar las IP’s privadas y ser dos redes distintas, separadas, que podrían incluso compartir la misma dirección de red, la llamada se establecerá pero no habrá audio en ningún sentido. Mal asunto.

¿Por qué? En la actualidad, cuando ambos dispositivos están configurados con “canreinvite=yes”, asterisk obedece y siempre que puede intenta que se envíen el tráfico RTP entre ellos directamente. Lamentablemente, cuando están en redes distintas, es imposible. La solución estaría en comprobar, cuando los dispositivos están detrás de routers haciendo NAT, si la dirección IP pública de ambos coincide. Si fuese el caso, podremos estar seguros de que están en la misma red, y podrán encontrarse. Si la IP pública es diferente, asterisk simplemente debe quedarse en medio.

Las llamadas dentro de cada sede funcionarán bien, sin malgastar ancho de banda de la ADSL, mientras que las llamadas entre sedes pasaran a través de asterisk.

Una solución

Y después de esta soberana paliza (que no se cuántos habréis aguantado), os dejo aquí el parche para la revisión r79171 del svn de asterisk/branches/1.4.

Descargar asterisk_nat_rtp_recv_patch_v3.diff

Para aplicar

$ cd /usr/src/asterisk
$ patch -p0 < /ruta/a/asterisk_nat_rtp_recv_patch_v3.diff
$ make
$ make install

Añadimos natonlyreinvitesameip=yes a la sección [general] de nuestro sip.conf.

No he podido testear a fondo este parche, así que si alguien puede reproducir este escenario, agradecería comentarios sobre si funciona o si es una soberana estupidez ;)

Escrito por julianjm el 12/08/2007. | Comments (16)
Tags: , , ,

Mejoras en la detección de inversiones de polaridad

Como muchos habéis comprobado, cuando hacemos un reload desde la consola de asterisk, perdemos los parámetros answeronpolarityswitch, hanguponpolarityswitch y polarityonanswerdelay. Es decir, volvían a sus valores por defecto y ya no detectabamos los cuelgues remotos. Había además un problema con las llamadas entrantes en las que si nos colgaban rápidamente (antes de haber detectado completamente el callerid), asterisk ignoraba esa inversión y nos dejaba el canal activo (Gracias a SuD por el parche).

En un intento de no despistar a los que vienen desde los buscadores (que sois unos cuantos), el parche actualizado estará disponible en el post anterior, Nuevo parche polaridad para Asterisk 1.4

Escrito por julianjm el 29/06/2007. | Comments (1)
Tags: , ,

Nuevo parche polaridad para Asterisk 1.4

Actualización final (19-dic-2007): A punto para las navidades, han incluido finalmente el parche tanto en la rama 1.4 como el el trunk. La versión 1.4.16 ya lo trae incluido. Gracias a fidojones por el aviso en los comentarios ;) 

Volvemos a la carga. Desde que actualizar a la 1.4.x he notado que en ocasiones las llamadas entrantes que colgaban mientras estaban en cola, llegaban a sonar en los teléfonos. Pasaba pocas veces, quizás recibo pocas llamadas ;), pero después de recibir correos apuntando en la misma dirección, me dispuse a revisar el amado y odiado chan_zap.c. (Por cierto, en openpbx^H^H^H^H^H callweaver lo están reescribiendo desde 0)Resulta que se revirtieron algunos cambios necesarios para que funcione bien en las líneas de Telefónica de España. Las llamadas entrantes, una vez que se descuelgan con Answer(), no detectan el cuelgue remoto. No ocurría lo mismo con las llamadas que no se han contestado aún.

En cualquier caso, aquí os dejo el parche. Si va bien, lo intentaremos meter de nuevo en el svn ;)Parche chan_zap.c rama 1.4 version4

Descargar chan_zap.c-1.4-polarity-v5.diff

Para aplicarlo:

$ cd /usr/src/asterisk$ patch -p0 < /ruta/al/chan_zap.c-1.4-polarity-v5.diff

A continuación, recompilar, reinstalar y reiniciar asterisk, probar si funciona, y dejar un comentario ;)

Versiones anteriores:

Actualizado (5 horas después de la publicación) :) : Como casi siempre, las primeras versiones nunca fueron buenas… Al corregir este fallo, introduje otro con las llamadas salientes… Corregido en la versión 2 del parche.

Actualización (12 de mayo): Según confirme Jose L. Villalon en los comentarios, el parche también funciona con asterisk 1.2.18. Habrá que ver a partir de qué versión de asterisk es necesario parchear.

Actualización (25 de junio): Gracias a SuD, que nos comenta acerca de un parámetro, polarityonanswerdelay, que tiene un valor por defecto demasiado alto, y que podría traer problemas al ignorarse ciertos cambios de polaridad. Para resultados óptimos, añadir polarityonanswerdelay=1 a vuestro zapata.conf (antes de la línea channel=> correspondiente).

Actualización (29 de junio): Adaptado a asterisk svn r72609. No se pierden los valores de answeronpolarityswitch, hanguponpolarityswitch ni polarityonanswerdelay al hacer un reload. Se contenmpla la detección de colgado dentro de la rutina de detección de callerid, según parche proporcionado por SuD.

Actualización (19 de julio): Adaptado a asterisk svn r75893.

Actualización (20 de julio): He abierto el bug #10238 en bugs.digium.com, para intentar que incluyan este parche en el código de asterisk y no tener que parchear cada nueva versión. Si estás interesado, deja allí tu experiencia con el parche.

Escrito por julianjm el 9/05/2007. | Comments (76)
Tags: , ,