Enviado por admin el
El módulo TM (Transaction Manager) es uno de los componentes más críticos de Kamailio. Se encarga de la gestión completa de transacciones SIP, proporcionando funcionalidades esenciales como el reenvío de mensajes, manejo de respuestas, timeouts, y la implementación de características avanzadas como el forking paralelo y secuencial.
Configuración Básica del Módulo
Carga del Módulo
loadmodule "tm.so"
Parámetros Principales
# Tiempo de espera para transacciones (en segundos)
modparam("tm", "fr_timer", 30)
# Tiempo de espera para respuestas INVITE (en segundos)
modparam("tm", "fr_inv_timer", 120)
# Habilitar/deshabilitar el reenvío automático de ACK
modparam("tm", "auto_inv_100", 1)
# Tamaño del hash table para transacciones
modparam("tm", "hash_size", 2048)
# Número máximo de ramas (forking)
modparam("tm", "max_branches", 10)
Funciones Principales del Módulo TM
1. t_relay()
La función más utilizada del módulo TM. Reenvía el mensaje actual creando una nueva transacción.
route[REENVIO_BASICO] {
xlog("L_INFO", "Reenviando mensaje $rm desde $si:$sp\n");
if (!t_relay()) {
xlog("L_ERR", "Error al reenviar mensaje\n");
sl_reply_error();
exit;
}
xlog("L_INFO", "Mensaje reenviado exitosamente\n");
exit;
}
2. t_relay_to_udp() y t_relay_to_tcp()
Funciones para reenviar mensajes especificando el protocolo de transporte.
route[REENVIO_PROTOCOLO] {
if ($ru =~ "transport=tcp") {
xlog("L_INFO", "Forzando reenvío por TCP a $ru\n");
if (!t_relay_to_tcp()) {
xlog("L_ERR", "Fallo en reenvío TCP\n");
t_reply("500", "Error interno del servidor");
}
} else {
xlog("L_INFO", "Enviando por UDP a $ru\n");
if (!t_relay_to_udp()) {
xlog("L_ERR", "Fallo en reenvío UDP\n");
t_reply("500", "Error interno del servidor");
}
}
exit;
}
3. t_reply()
Genera respuestas SIP desde el servidor.
route[RESPUESTA_PERSONALIZADA] {
if ($rU == "test") {
xlog("L_INFO", "Respondiendo a solicitud de prueba\n");
t_reply("200", "Servicio de prueba activo");
exit;
}
if (!lookup("location")) {
xlog("L_INFO", "Usuario $rU no encontrado en registro\n");
t_reply("404", "Usuario no disponible");
exit;
}
}
4. t_check_trans()
Verifica si el mensaje actual pertenece a una transacción existente.
request_route {
# Verificar transacciones existentes
if (t_check_trans()) {
xlog("L_INFO", "Mensaje pertenece a transacción existente\n");
exit;
}
xlog("L_INFO", "Nuevo mensaje: $rm desde $si\n");
# Continuar procesamiento para nuevos mensajes...
}
5. t_newtran()
Crea una nueva transacción manualmente.
route[CREAR_TRANSACCION] {
if (!t_newtran()) {
xlog("L_ERR", "Error al crear nueva transacción\n");
sl_reply_error();
exit;
}
xlog("L_INFO", "Nueva transacción creada para $rm\n");
# Procesar la transacción...
}
6. t_cancel_branch()
Cancela una rama específica en caso de forking.
failure_route[CANCELAR_RAMA] {
xlog("L_INFO", "Procesando fallo en failure_route\n");
if (t_was_cancelled()) {
xlog("L_INFO", "Transacción ya cancelada\n");
exit;
}
if (t_check_status("408")) {
xlog("L_INFO", "Timeout detectado, cancelando rama\n");
t_cancel_branch();
}
}
Configuración de Forking
Forking Paralelo
route[FORKING_PARALELO] {
if (!lookup("location")) {
t_reply("404", "Usuario no encontrado");
exit;
}
# Si hay múltiples contactos, se envía a todos simultáneamente
xlog("L_INFO", "Iniciando forking paralelo para $rU\n");
t_on_failure("MANEJO_FALLO_FORKING");
if (!t_relay()) {
xlog("L_ERR", "Error en forking paralelo\n");
t_reply("500", "Error interno");
}
exit;
}
failure_route[MANEJO_FALLO_FORKING] {
xlog("L_INFO", "Respuesta de fallo: $T_reply_code $T_reply_reason\n");
if (t_check_status("486|600")) {
xlog("L_INFO", "Usuario ocupado o rechaza llamada\n");
# Continuar con próxima rama si existe
exit;
}
}
Forking Secuencial
route[FORKING_SECUENCIAL] {
# Cargar contactos ordenados por prioridad
if (!lookup("location")) {
t_reply("404", "No registrado");
exit;
}
# Configurar para forking secuencial
$avp(contador_intentos) = 0;
t_on_failure("SIGUIENTE_CONTACTO");
xlog("L_INFO", "Intentando primer contacto para $rU\n");
t_relay();
exit;
}
failure_route[SIGUIENTE_CONTACTO] {
$avp(contador_intentos) = $avp(contador_intentos) + 1;
xlog("L_INFO", "Intento $avp(contador_intentos) falló: $T_reply_code\n");
if ($avp(contador_intentos) < 3 && t_check_status("408|486|603")) {
xlog("L_INFO", "Probando siguiente contacto\n");
# Lógica para seleccionar siguiente destino
append_branch();
t_relay();
exit;
}
xlog("L_INFO", "Todos los contactos fallaron\n");
}
Manejo Avanzado de Transacciones
Timeouts Personalizados
route[TIMEOUTS_PERSONALIZADOS] {
# Configurar timeouts específicos según el destino
if ($rd =~ "gateway-lento\.com") {
xlog("L_INFO", "Configurando timeout extendido para gateway lento\n");
t_set_fr(0, 180000); # 3 minutos para INVITE
} else {
xlog("L_INFO", "Usando timeout estándar\n");
t_set_fr(0, 30000); # 30 segundos estándar
}
t_relay();
exit;
}
Reintento Automático
route[REINTENTO_AUTOMATICO] {
$avp(intentos) = 0;
t_on_failure("LOGICA_REINTENTO");
xlog("L_INFO", "Primer intento de envío a $rd\n");
t_relay();
exit;
}
failure_route[LOGICA_REINTENTO] {
$avp(intentos) = $avp(intentos) + 1;
xlog("L_INFO", "Fallo en intento $avp(intentos): $T_reply_code\n");
if ($avp(intentos) < 3 && t_check_status("5[0-9][0-9]")) {
xlog("L_INFO", "Reintentando envío (intento $avp(intentos))\n");
# Esperar un poco antes del reintento
sleep("2");
if (t_relay()) {
xlog("L_INFO", "Reintento enviado exitosamente\n");
} else {
xlog("L_ERR", "Fallo en reintento\n");
}
exit;
}
xlog("L_INFO", "Máximo de reintentos alcanzado\n");
}
Integración con Otros Módulos
Con Módulo Dispatcher
route[TM_CON_DISPATCHER] {
if (!ds_select_dst("1", "4")) {
xlog("L_ERR", "No hay destinos disponibles en dispatcher\n");
t_reply("503", "Servicio no disponible");
exit;
}
xlog("L_INFO", "Destino seleccionado: $du\n");
t_on_failure("FAILOVER_DISPATCHER");
if (!t_relay()) {
xlog("L_ERR", "Error al reenviar via dispatcher\n");
t_reply("500", "Error interno");
}
exit;
}
failure_route[FAILOVER_DISPATCHER] {
if (t_check_status("5[0-9][0-9]|4[0-9][0-9]")) {
xlog("L_INFO", "Probando siguiente servidor en dispatcher\n");
if (ds_next_dst()) {
xlog("L_INFO", "Nuevo destino: $du\n");
t_relay();
exit;
}
}
xlog("L_ERR", "Todos los servidores fallaron\n");
}
Con Módulo Dialog
route[TM_CON_DIALOG] {
if (is_method("INVITE")) {
xlog("L_INFO", "Creando diálogo para llamada $ci\n");
# Crear diálogo antes de reenviar
create_dialog();
# Configurar callbacks de diálogo
dlg_manage();
t_on_failure("FALLO_DIALOG");
}
t_relay();
exit;
}
failure_route[FALLO_DIALOG] {
xlog("L_INFO", "Fallo en llamada con diálogo: $T_reply_code\n");
# El módulo dialog manejará automáticamente la limpieza
}
Monitoreo y DEBUG
Logging Detallado de Transacciones
route[LOGGING_TRANSACCIONES] {
# Log antes del procesamiento
xlog("L_INFO", "=== INICIO TRANSACCION ===\n");
xlog("L_INFO", "Método: $rm | Call-ID: $ci\n");
xlog("L_INFO", "Origen: $si:$sp | Destino: $rd:$rp\n");
xlog("L_INFO", "Usuario: $fU -> $rU\n");
t_on_failure("LOG_FAILURE");
t_on_reply("LOG_REPLY");
if (!t_relay()) {
xlog("L_ERR", "FALLO AL CREAR TRANSACCION\n");
xlog("L_ERR", "=== FIN TRANSACCION (ERROR) ===\n");
t_reply("500", "Error interno del servidor");
exit;
}
xlog("L_INFO", "Transacción creada exitosamente\n");
exit;
}
onreply_route[LOG_REPLY] {
xlog("L_INFO", "RESPUESTA: $rs $rr desde $si\n");
xlog("L_INFO", "Tiempo transcurrido: $TV(s) segundos\n");
}
failure_route[LOG_FAILURE] {
xlog("L_ERR", "FALLO FINAL: $T_reply_code $T_reply_reason\n");
xlog("L_ERR", "=== FIN TRANSACCION (FALLO) ===\n");
}
Mejores Prácticas
-
Siempre verificar transacciones existentes con t_check_trans() al inicio del request_route
-
Usar failure_route apropiadamente para manejar fallos y implementar lógica de failover
-
Configurar timeouts adecuados según el tipo de destino y red
-
Implementar logging detallado para facilitar la depuración
-
Limitar el número de branches en forking para evitar sobrecarga
-
Usar onreply_route para procesamiento de respuestas cuando sea necesario
Conclusión
El módulo TM es fundamental para el funcionamiento de Kamailio como proxy SIP. Su correcta configuración y uso determina la confiabilidad, rendimiento y capacidades avanzadas del servidor. La comprensión profunda de sus funciones permite implementar soluciones SIP robustas y escalables.
Las funciones aquí descritas cubren los casos de uso más comunes, pero el módulo TM ofrece muchas más capacidades para escenarios específicos y avanzados.
Comentarios recientes