Está en la página 1de 143

Trabajo Fin de Máster

Máster Universitario en Ingeniería de


Telecomunicación

Aplicación P2P de comunicación y organización de


grupos con compartición de ficheros

Autor: Pedro Cano Vázquez


Tutor: Francisco José Fernández Jiménez

Equation Chapter 1 Section 1

Departamento de Ingeniería Telemática


Escuela Técnica Superior de Ingeniería
Universidad de Sevilla
Sevilla, 2020
ii
Trabajo Fin de Máster
Máster Universitario en Ingeniería de Telecomunicación

Aplicación P2P de comunicación y organización de


grupos con compartición de ficheros

Autor:
Pedro Cano Vázquez

Tutor:
Francisco José Fernández Jiménez
Profesor colaborador

Departamento de Telemática
Escuela Técnica Superior de Ingeniería
Universidad de Sevilla
Sevilla, 2020

iii
iv
Trabajo Fin de Máster: Aplicación P2P de comunicación y organización de grupos con compartición de
ficheros

Autor: Pedro Cano Vázquez

Tutor: Francisco José Fernández Jiménez

El tribunal nombrado para juzgar el Trabajo Fin de Máster arriba indicado, compuesto por los siguientes
miembros:

Presidente:

Vocales:

Secretario:

Acuerdan otorgarle la calificación de:

Sevilla, 2020
El Secretario del Tribunal

v
vi
A mi pasado, presente y futuro
A las personas presentes en ellos

vii
viii
Resumen

En este documento se lleva a cabo la evolución de una aplicación de mensajería P2P siguiendo el marco de
metodologías ágiles más utilizado en la actualidad: SCRUM.
Los objetivos de mejora de la aplicación son cuatro: implementar una interfaz gráfica para mejorar la
accesibilidad de la aplicación, que actualmente dispone de una interfaz de consola; agregar la funcionalidad de
compartición de ficheros a través de la aplicación; proporcionar una solución para la comunicación entre
nodos que no tienen visión directa entre ellos (por estar ubicados en redes con reglas NAT); y securizar el
canal de comunicaciones utilizado por la aplicación, para evitar que la información transmitida pueda verse
comprometida.
Para afrontar el proyecto siguiendo el marco SCRUM, estos objetivos serán transformados en Historias de
Usuario que describan claramente los requisitos funcionales y el valor que aportan al producto final. Estas
Historias de Usuario serán introducidas en la pila del producto (lista de requisitos funcionales aceptados para
su implementación) para ser desarrolladas posteriormente a lo largo de cuatro Sprints. Cada Sprint comenzará
con una sesión de planificación, donde se desglosarán las tareas a realizar para dar por hecha la Historia de
Usuario. Después, estas tareas serán desarrolladas durante el Sprint. Por último, se realizará una sesión de
revisión del Sprint, donde se comprobará la funcionalidad implementada y podrá generarse un incremento del
producto final, que podrá ser entregado.
El resultado final del trabajo expuesto en este documento es un producto software que ha sido mejorado para
satisfacer las nuevas necesidades identificadas, mediante un método que favorece la flexibilidad ante los
cambios para mantener la ventaja competitiva del producto requerido por el cliente. Además, se detectan
nuevas necesidades que son introducidas en la pila del producto para futuras iteraciones.

ix
x
Abstract

This document proposes the evolution of a P2P messaging application following the most widely used agile
methodologies framework today: SCRUM.
There are four improvements to be achieved: a GUI to increase the accessibility; a file sharing functionality; a
solution for communication between nodes located in NAT networks; and a securized communication channel
to prevent the information transmitted from being compromised.
To face the project following the SCRUM framework, these needs will be transformed into User Stories that
clearly describe the functional requirements and the value they bring to the final product. These User Stories
will be included into the Product Backlog to be developed over four Sprints. Each Sprint will begin with the
Sprint Planning, where the User History will be broken down into tasks. These tasks will need to be completed
during the Srpint in order to get the User History done. Finally, in the Sprint Review, the implemented
functionality will be checked to approve the product increment, which can be delivered.
The final result of the work presented in this document is a software product that has been improved to satisfy
the new identified needs, through a method that favors flexibility in the face of changes to maintain the
competitive advantage of the product required by the client. In addition, new needs are detected and included
into the Product Backlog for future iterations.

xi
xii
Índice

Resumen ix
Abstract xi
Índice xiii
Índice de Tablas xv
Índice de Figuras xvii
1 Introducción 1
1.1 Contexto del Proyecto 1
1.2 Escenario motivador 3
1.3 Objetivos 4
1.4 Metodología de trabajo 5
1.5 Organización de la memoria 7
2 Marco contextual 9
2.1 Redes P2P 9
2.1.1 Redes P2P no estructuradas 10
2.1.2 Redes P2P estructuradas 13
2.1.3 Aplicaciones de mensajería en redes P2P 18
2.1.4 Redes P2P en este TFM 20
2.2 Metodologías de desarrollo ágil 20
2.2.1 El Manifiesto Ágil 21
2.2.2 Metodología SCRUM 22
2.2.3 Agilidad en este TFM 25
3 Estado anterior del proyecto 27
3.1 P2P Messenger 27
3.1.1 Objetivos 28
3.2 Marco tecnológico 28
3.3 Diseño según el patrón MVC (Modelo-Vista-Controlador) 29
3.4 Resultados 34
3.4.1 Líneas de mejora identificadas 35
4 Trabajo realizado 37
4.1 Pila del Producto 37
4.2 Sprint 1. Implementación de una interfaz gráfica 38
4.2.1 Definición de la Historia de Usuario 39
4.2.2 Tecnología implicada 39
4.2.3 Planificación del Sprint 41
4.2.4 Desarrollo del Sprint 41
4.2.5 Revisión del Sprint 72
4.3 Sprint 2. Compartición de ficheros 72
xiii
4.3.1 Definición de la Historia de Usuario 73
4.3.2 Tecnología implicada 73
4.3.3 Planificación del Sprint 74
4.3.4 Desarrollo del Sprint 74
4.3.5 Revisión del Sprint 85
4.4 Sprint 3. Comunicación de nodos en redes con NAT 86
4.4.1 Definición de la Historia de Usuario 86
4.4.2 Tecnología implicada 86
4.4.3 Planificación del Sprint 87
4.4.4 Desarrollo del Sprint 88
4.4.5 Revisión del Sprint 97
4.5 Sprint 4. Seguridad en canal de comunicación entre pares 98
4.5.1 Definición de la Historia de Usuario 98
4.5.2 Tecnología implicada 98
4.5.3 Planificación del Sprint 98
4.5.4 Desarrollo del Sprint 99
4.5.5 Revisión del Sprint 105
5 Conclusiones y trabajo futuro 107
Referencias 109
ANEXO I. Instalación, ejecución y dependencias 113
ANEXO II. Configuraciones de Sprint 2 115
ANEXO III. Configuraciones de Sprint 3 117

xiv
ÍNDICE DE TABLAS

Tabla 1. Comparativa entre metodologías de desarrollo software tradicionales y ágiles [29]. 21


Tabla 2. Rendimiento de inicio de la aplicación P2P Messenger en una muestra de 30 inicios [9]. 34
Tabla 3. Definición de la Historia de Usuario relativa al Objetivo 1 39
Tabla 4. Estimación de tareas para la Historia de Usuario relativa al Objetivo 1 41
Tabla 5. Código para prueba de concepto de conectores con JavaFX 45
Tabla 6. Ejemplo de refactorización VistaConsola.java a VistaConsolaPublic.java para utilizar métodos del
controlador en forma de API 67
Tabla 7. Pruebas de validación de pantalla de registro de IP de Pastry 68
Tabla 8. Pruebas de validación de pantalla de inicio de sesión 68
Tabla 9. Pruebas de validación de pantalla de registro de usuario 69
Tabla 10. Pruebas de validación de la pantalla de sesión iniciada 72
Tabla 11. Definición de la Historia de Usuario relativa al Objetivo 2 73
Tabla 12. Estimación de tareas para la Historia de Usuario relativa al Objetivo 2 74
Tabla 13. Informe de resultados de los tests Junit pasados a la clase GoogleDriveController en formato XML
83
Tabla 14. Pruebas de validación de la funcionalidad de compartición de ficheros 85
Tabla 15. Definición de la Historia de Usuario relativa al Objetivo 3 86
Tabla 16. Estimación de tareas para la Historia de Usuario relativa al Objetivo 3 88
Tabla 17. Tipos de redes privadas en IPv4 89
Tabla 18. Pruebas de validación de la configuración de escenario para comunicación de nodos mediante VPN
97
Tabla 19. Definición de la Historia de Usuario relativa al Objetivo 4 98
Tabla 20. Estimación de tareas para la Historia de Usuario relativa al Objetivo 4 99
Tabla 21. Código de tutorial SSL FreePastry. Establecimiento de capa de transporte segura. 100
Tabla 22. Código de tutorial SSL FreePastry. Obtención de almacén de claves. 101
Tabla 23. Código de tutorial SSL FreePastry. Configuración de almacén de claves. 101
Tabla 24. Comandos para creación de certificado y almacén de claves para ejecución de tutorial FreePastry
SSL 101
Tabla 25. Definición de nueva Historia de Usuario detectada en Sprint 4 106
Tabla 26. Dependencias necesarias para ejecución del proyecto 114

xv
xvi
ÍNDICE DE FIGURAS

Figura 1. Vista de menú de consola de la aplicación de mensajería P2P previa al TFM. 4


Figura 2. Tablero Kanban de la herramienta Trello utilizado para la gestión del proyecto. 6
Figura 3. Mapa mental de herramientas de soporte general para la realización del TFM. 7
Figura 4. Posible distribución de los nodos de una red P2P no estructurada [2]. 10
Figura 5. Ejemplo recorrido por Inundación de una solicitud en una red P2P no estructurada [2]. 11
Figura 6. Ejemplos recorrido por Caminos aleatorios de una solicitud en una red P2P no estructurada [2].
11
Figura 7. Distribución de probabilidad del grado de los nodos en redes P2P estructuradas con topología
aleatoria (izquierda) y libre de escala (derecha) [2]. 12
Figura 8. Transmisión de un fichero utilizando Napster [1]. 13
Figura 9. Topología basada en supernodos, utilizada por FastTrack [1]. 13
Figura 10. Concepto de Tabla Hash Distribuida. 14
Figura 11. Ejemplo de encaminamiento básico en red P2P Chord [1]. 15
Figura 12. Ejemplo de tabla de dedos para un nodo dentro de una red Chord con N=9 y m=7 [1]. 15
Figura 13. Ejemplo de información de encaminamiento (conjunto de hojas, tabla de encaminamiento y
conjunto de vecindario) en un nodo dentro de una red P2P Pastry [25]. 16
Figura 14. Encaminamiento de mensajes de inclusión de objetos (A) y de búsqueda de un objeto (B) en red
Tapestry [2]. 17
Figura 15. Interfaz gráfica de la aplicación Tonic 19
Figura 16. Intefaz gráfica de la aplicación Ricochet 19
Figura 17. Interfaz gráfica de qTox (versión escritorio de TOX Chat) 20
Figura 18. Fases del método de desarrollo software “En cascada”. 20
Figura 19. Resumen gráfico del marco de trabajo SCRUM. 24
Figura 20. Metodologías ágiles más utilizadas en mayo de 2020. 24
Figura 21. Usuarios activos de las aplicaciones de mensajería más utilizadas en octubre 2020. 27
Figura 22. Esquema de la base de datos utilizada en la aplicación P2PMessenger [9]. 30
Figura 23. Máquina de estados de la vista de P2PMessenger [9]. 30
Figura 24. Vista Android para registrar un nuevo usuario (izquierda), mostrar lista de contactos (centro) y
mostrar conversación (derecha) [9]. 31
Figura 25. Vista del modo consola para el menú principal (arriba) y el menú de funcionalidades del modo
conversación (abajo) [9]. 31
Figura 26. Interacciones necesarias a través de la vista de consola de P2PMessenger para abrir una
conversación y enviar un mensaje a la misma [9]. 31

xvii
Figura 27. Diagrama de estados del controlador de la aplicación P2PMessenger [9]. 32
Figura 28. Diagrama de paso de mensajes en establecimiento de conversación en P2PMessenger [9]. 32
Figura 29. Diagrama de paso de mensajes para unión a un grupo en aplicación P2PMessenger [9]. 33
Figura 30. Flujo de recuperación de mensajes importantes de un grupo 33
Figura 31. Distribución del retardo de 10700 mensajes de eco entre dos instancias de máquinas en la nube
(arriba) y entre una instancia Android y otra de escritorio en una misma red Wifi (abajo) [9]. 35
Figura 32. Representación gráfica de la pila del producto. 38
Figura 33. Comparación de aspecto de una interfaz gráfica de Java AWT (izquierda) con una interfaz gráfica
de una aplicación actual (derecha). 42
Figura 34. Ejemplo de interfaz gráfica de aplicación Java creada con Swing 42
Figura 35. Ejemplo de interfaz gráfica de aplicación Java creada con JavaFX 43
Figura 36. Utilización de conectores para manejar eventos en un componente WebView de JavaFX 44
Figura 37. Prueba de concepto de comunicación en JavaFX antes de la llamada desde el conector Javascript
del front-end (arriba) y después, con el resultado devuelto por el conector Java del back-end (abajo) 45
Figura 38. Prototipos para la pantalla de registro IP de red Pastry (izquierda), de inicio de sesión (centro) 46
Figura 39. Prototipo para la pantalla de sesión iniciada 47
Figura 40. Prototipo para el componente de diálogo con mensaje informativo (izquierda) e indicador de acción
en curso (derecha) 47
Figura 41. Prototipo para el componente de conversación abierta 48
Figura 42. Prototipo para el componente de mensaje enviado (izquierda) y recibido (derecha) 48
Figura 43. Prototipo para el componente de mensajes importantes (izquierda) y el de agenda (derecha) 49
Figura 44. Prototipo para el componente de contacto (arriba), de unión a grupo (centro) y de código de
invitación a grupo (abajo) 50
Figura 45. Estructura del directorio web creado para ubicar el código relativo a la interfaz gráfica 51
Figura 46. Capturya (izquierda) y flujo asociado (derecha) a la pantalla de inicio 51
Figura 47. Captura (izquierda) y flujo asociado (derecha) a la pantalla de registro de IP de Pastry 52
Figura 48. Captura de la pantalla de inicio de sesión (izquierda) y el componente de diálogo con mensaje
informativo asociado (derecha) 52
Figura 49. Flujo asociado al control de “Iniciar sesión” (izquierda) y “Registrar nuevo usuario” (derecha) de la
pantalla de inicio de sesión 53
Figura 50. Captura de la pantalla de registro de nuevo usuario (izquierda) y el componente de diálogo con
mensaje informativo asociado (derecha) 53
Figura 51. Flujo asociado al control de “Registrar usuario” (izquierda) e “Iniciar sesión” (derecha) de la
pantalla de registro de un nuevo usuario 54
Figura 52. Captura de la pantalla de sesión iniciada sin conversaciones abiertas ni conversación seleccionada
(izquierda) y el componente de indicador de acción en curso (derecha) 54
Figura 53. Captura de la pantalla de sesión iniciada con el componente de agenda abierto sin contactos, con el
formulario de creación de contacto (izquierda) y con un componente de contacto agregado (derecha) 55
Figura 54. Captura de la pantalla de sesión iniciada con una conversación abierta y seleccionada con mensaje
recibido y enviado 55
Figura 55. Captura de la pantalla de sesión iniciada con el componente de agenda abierto, con formulario de
crear grupo (izquierda) y con el componente de código de invitación a grupo (derecha) 55

xviii
Figura 56. Captura de la pantalla de sesión iniciada con el componente de unión a grupo (izquierda) y una
conversación de grupo con mensajes normales e importantes (derecha) 56
Figura 57. Captura de la pantalla de sesión iniciada con el componente de mensajes importantes mostrando el
primer bloque (izquierda) y el segundo bloque (derecha) 56
Figura 58. Flujo asociado al control de refresco de conversaciones 57
Figura 59. Flujo asociado al control de mostrar agenda 57
Figura 60. Flujo asociado al control de cerrar sesión 57
Figura 61. Flujo asociado al control de seleccionar una conversación 58
Figura 62. Flujos asociados al control de “Enviar mensaje” (arriba) y “Generar código de invitación a grupo”
(abajo) del componente de “Conversación seleccionada” 58
Figura 63. Flujo asociado a los controles del componente de Mensajes importantes. 59
Figura 64. Flujos asociados al control de “Guardar contacto” (izquierda) y “Crear grupo” (derecha) del
componente de “Agenda” 59
Figura 65. Flujos asociados al control de “Eliminar contacto” (izquierda), “Iniciar conversación” (centro) y
“Unirse a grupo” (derecha) del componente de “Contacto” 59
Figura 66. Flujo asociado al control de “Unirse a grupo” del componente de “Unión a grupo” 60
Figura 67. Flujo simplificado del método Start de la clase VistaGUI que lanza la interfaz gráfica 60
Figura 68. Flujo simplificado del método iniciarServicio (izquierda) y conectarPastry (derecha) de la clase
JavaConector que conecta la interfaz gráfica con el controlador 61
Figura 69. Flujos simplificados de los métodos iniciarSesion (izquierda) y accederRegistroUsuario (derecha)
de la clase JavaConector que conecta la interfaz gráfica con el controlador 61
Figura 70. Flujos simplificados de los métodos registrarUsuario (izquierda) y accederInicioSesion (derecha)
de la clase JavaConector que conecta la interfaz gráfica con el controlador 62
Figura 71. Flujo simplificado del método refrescarConversaciones de la clase JavaConector que conecta la
interfaz gráfica con el controlador 62
Figura 72. Flujo simplificado del método obtenerMensajesConversacionesSeleccionadas de la clase
JavaConector que conecta la interfaz gráfica con el controlador 63
Figura 73. Flujo simplificado del método obtenerListaContactos de la clase JavaConector que conecta la
interfaz gráfica con el controlador 63
Figura 74. Flujo simplificado del método cerrarSesion (arriba), generarCodigoInvitacionGrupo (centro) y
obtenerPrimerBloqueMensajesImportantes (abajo) de la clase JavaConector que conecta la interfaz gráfica
con el controlador 64
Figura 75. Flujo simplificado del método obtenerMensajesImportantes de la clase JavaConector que conecta
la interfaz gráfica con el controlador 64
Figura 76. Flujo simplificado del método crearContacto de la clase JavaConector que conecta la interfaz
gráfica con el controlador 65
Figura 77. Flujo simplificado del método crearGrupo de la clase JavaConector que conecta la interfaz gráfica
con el controlador 65
Figura 78. Flujo simplificado del método eliminarContacto (izquierda) y unirseAGrupo (derecha) de la clase
JavaConector que conecta la interfaz gráfica con el controlador 66
Figura 79. Captura de la consola de Google APIs donde se muestra la API creada para la Prueba de Concepto
con Google Drive API 76
Figura 80. Prueba de concepto realizada con la API de Google Drive. Autenticación requerida por Google
(arriba) y listado de ficheros encontrados en el directorio de Google Drive (abajo) 76

xix
Figura 81. Prototipo de la pantalla de sesión iniciada con el nuevo control para compartir ficheros 78
Figura 82. Prototipo del componente para seleccionar el fichero a compartir en la aplicación 78
Figura 83. Prototipo del componente de mensaje (enviado) que incluye un fichero compartido 79
Figura 84. Captura de la pantalla de sesión iniciada con el nuevo control para compartir ficheros 79
Figura 85. Elemento input de HTML de tipo file para adjuntar archivos en páginas web 79
Figura 86. Componente de navegador de ficheros para seleccionar el fichero a compartir 80
Figura 87. Captura del componente de mensaje con fichero adjunto. 80
Figura 88. Diagramas de flujo tras accionar el control de compartir fichero (izquierda) y el de descargar fichero
(derecha) 80
Figura 89. Autenticación de la aplicación para usar la API de Google Drive 82
Figura 90. Informe de resultados de los tests Junit pasados a la clase GoogleDriveController en formato
HTML 82
Figura 91. Directorio y archivo creados mediante tests unitarios con Junit 83
Figura 92. Flujo asociado al método enviarArchivoDrive de la clase JavaConnector 84
Figura 93. Flujo asociado al método buscarDirectorioDrive (izquierda) y descargarArchivo (derecha) de la
clase JavaConnector 84
Figura 94. Ejemplo de escenario de redes privadas domésticas con mismo direccionamiento en distintos
puntos del mundo 88
Figura 95. Porcentaje de usuarios de Google que acceden a través de IPv6 89
Figura 96. Esquema de VPN entre dos redes privadas distintas a través de Internet 90
Figura 97. Escenario utilizado para validar la propuesta de comunicación de nodos a través de VPN 91
Figura 98. Subredes creadas en Google Cloud Platform para ubicar servidor VPN (tfm-subred) y para ubicar
nodo P2P (tfm-subred-nodosp2p) 93
Figura 99. Instancias de VM creadas en Google Cloud Platform 93
Figura 100. Captura del servicio OpenVPN ejecutándose en el servidor de Google Cloud Platform 93
Figura 101. Configuración de red del nodo servidor VPN. Dispone de IP local (ens4) y de IP en VPN (tun0)
94
Figura 102. Configuración de red de la VM de desarrollo TFM. Dispone de IP local (enp0s3) y de IP en VPN
(tun0) 94
Figura 103. Configuración de red de la VM de Google Cloud Platform que alberga un nodo P2P. Dispone de
IP local (ens4) y de IP en VPN (tun0) 94
Figura 104. Prueba de comunicación a través de VPN en VM de desarrollo TFM. Ping a servidor VPN
seguido de ping a VM par nodo P2P alojado en Google Cloud Platform 95
Figura 105. Prueba de comunicación a través de VPN en VM para nodo P2P alojado en Google Cloud
Platform. Ping a servidor VPN seguido de ping a VM de desarrollo TFM 95
Figura 106. Captura de uso de la aplicación de mensajería P2P entre dos nodos sin visión directa 96
Figura 107. Captura de tráfico VPN en máquina de desarrollo del TFM (arriba) y en VM donde se aloja el
servidor VPN (abajo) 96
Figura 108. Intercambio de mensajes en negociación TLS 100
Figura 109. Escenario para ejecución de tutorial FreePastry SSL 101
Figura 110. Resultado de ejecución de tutorial FreePastry SSL (arriba) y captura de tráfico cifrado con

xx
Wireshark (abajo) 102
Figura 111. Excepción java.nio.BufferOverflowException obtenida al ejecutar la aplicación con TLS 103
Figura 112. Fragmento de código de SSLSocketManager.java donde se aprecia un potencial desbordamiento
de buffer (izquierda) y cambio para evitarlo (derecha) 103
Figura 113. Ejecución de aplicación de mensajería de consola cifrando el canal con SSL/TLS 104
Figura 114. Captura Wireshark de ejecución de aplicación de mensajería de consola cifrando el canal con TLS
1.3 104

xxi
xxii
1 INTRODUCCIÓN

Keep it simple, stupid!


Kelly Johnson.

E
n este capítulo se pretende dar a conocer al lector de una forma breve el contexto del proyecto, la
motivación del mismo y los objetivos a cumplir con su realización. Además, se mostrará la metodología
que se ha utilizado para realizar el trabajo y la organización de la memoria del TFM.

1.1 Contexto del Proyecto


Las redes P2P (Peer To Peer) [1], también conocidas como redes de pares o redes entre iguales, son redes de
ordenadores que se comportan como iguales entre sí. Los distintos elementos que participan en la red se
denominan Nodos. Los nodos de una red P2P pueden actuar como servidores y como clientes. Esta es la
principal diferencia con el modelo de redes basado en conexiones cliente-servidor, donde un nodo central
(servidor) acepta conexiones de otros nodos de la red (clientes) para la comunicación entre ambas partes. En
las redes P2P, cualquier nodo puede comunicarse con otro nodo activo en la red para el intercambio de
información en cualquier formato.
Las redes P2P presentan una serie de características principales [2] , listadas a continuación:
• Topología descentralizada. La organización de la red no depende de un sistema central, sino que es
responsabilidad de todos los nodos que la componen. Los nodos cooperan entre sí para mantener la
información de la red actualizada. De esta forma, la indisponibilidad de un nodo concreto no afecta al
funcionamiento de la red.
• Simetría de roles. Como se ha mencionado anteriormente, en una red P2P todos los nodos tienen las
mismas capacidades funcionales. Así, cualquier nodo puede almacenar información de otros pares,
aceptar peticiones y encaminar mensajes.
• Alta escalabilidad. Las redes P2P deben soportar bien tanto el incremento de pares (aumentando la
red hasta en 100 órdenes de magnitud) como la dispersión geográfica de los pares que la componen
(repartidos a lo largo de otra red pública, como Internet).
• Autonomía de los nodos. Cada nodo determina sus capacidades basándose en sus propios recursos.
Los nodos deciden cuándo se unen a la red, qué peticiones hacer y cuándo salir de ella. Esta
característica provoca que los servicios ofrecidos por la red sean, en cierto modo, impredecibles.

1
• Compartición de recursos. Una red P2P proporciona un conjunto de recursos compartidos, tales
como ciclos de CPU, almacenamiento en disco y ancho de banda, que son proporcionados por los
distintos nodos que la forman. Para acceder a la red, cada nodo debe contribuir con un umbral mínimo
establecido de recursos.
• Robustez. En las redes P2P, la topología cambia dinámicamente, con la conexión y desconexión de
los distintos nodos que la componen. Por ello, es necesario implementar mecanismos que puedan
mantener actualizada la información de estado de la red.
La historia de las redes P2P tiene un largo recorrido. Una de las primeras aplicaciones basadas en redes P2P es
Usenet [1], creada en la década de los 80 con el objetivo de compartir información de forma libre. Nacida en el
ámbito universitario, sirvió como medio de compartición de conocimiento y discusión, siendo el origen de los
famosos “foros” de internet. Los mensajes compartidos, o noticias, se ordenan por grupos jerarquizados, de tal
forma que permiten a los usuarios filtrar la información según sus intereses (comp.* para temas de
ordenadores o sci.* para temas científicos, por ejemplo). En la actualidad, Usenet sigue en funcionamiento
aunque el principal uso que tiene es la compartición de ficheros de forma distribuida.
Un ejemplo más reciente de aplicaciones P2P es Napster [3], que nació como una red P2P con el objetivo de
compartir archivos de música en formato MP3 y que consiguió la cifra de 26 millones de usuarios en un solo
año. El rotundo éxito de esta aplicación se vio mermado por las acciones legales emprendidas ese mismo año
por la industria musical, que alegaba pérdidas millonarias en su negocio debido a la compartición de archivos
con derechos de autor a través de redes P2P. En España, la industria discográfica trató de criminalizar la
“piratería” ante los cambios de patrones de consumo musical originados en esta época. David Bravo hace un
gran análisis de este tema en su libro [4]. Actualmente, Napster ha evolucionado hacia un servicio de música
bajo demanda por suscripción, tal como Spotify [5] o Apple Music [6].
Por último, otro ejemplo de uso de redes P2P en la actualidad son las transacciones monetarias con
criptomonedas. El caso más conocido es el de Bitcoin [7]. Fue concebido en 2008 como un sistema para
realizar transacciones electrónicas sin depender de un tercero de confianza (entidad financiera). A través de
una red P2P, los nodos (denominados mineros) colaboran para generar una cadena de bloques que permite
registrar de forma pública las transacciones que se llevan a cabo. La robustez del algoritmo de Bitcoin reside
en la utilización de una Prueba de trabajo (proof-of-work) como requisito para poder generar nuevos bloques.
Una prueba de trabajo es un cálculo computacionalmente complejo de resolver, pero fácil de comprobar. En
una red con una mayoría de nodos honestos, incluir una transacción fraudulenta en la cadena de bloques tiene
una dificultad que aumenta exponencialmente conforme se añaden nuevos bloques a la cadena (que también
deben ser calculados para la inclusión de la transacción fraudulenta) [8].
Para terminar la sección, se pretende dar a conocer algunos problemas que presentan las redes P2P y que se
convertirán en el foco de estudio para la consecución de algunos objetivos de este Trabajo Fin de Máster:
• Los nodos en una red P2P requieren de visión directa entre ellos para conseguir la característica de
simetría de roles. Es decir, para que un nodo pueda actuar como cliente necesitará establecer
conexiones contra otros nodos en calidad de servidores, mientras que para actuar como servidor
necesitará aceptar conexiones provenientes de otros nodos en calidad de clientes. Si entre dos nodos
existe un sistema que restringe las conexiones en uno u otro sentido (como un firewall), el nodo
aislado tras dicho sistema no podrá formar parte de la red P2P [2]. Este escenario es muy común y se
da, por ejemplo, en prácticamente todas las redes privadas domésticas del mundo. La búsqueda de
una solución para este tipo de escenario, aplicado al trabajo realizado con anterioridad sobre la
misma línea de contribución, se convertirá en uno de los objetivos de este TFM.
• La distribución de la información a lo largo de la red hace que, en determinadas aplicaciones, como
la mensajería, sea crucial implementar medidas de seguridad para evitar que se haga un uso indebido
de la misma. En la línea de contribución sobre la que se desarrolla este TFM se lleva a cabo la
implementación de cifrado de los mensajes enviados, pero las comunicaciones siguen siendo
vulnerables en cuanto a ataques contra la autenticación, integridad y confidencialidad de estas. La
utilización de una capa segura de transporte en la red P2P se convertirá en otro de los objetivos de
este TFM.
En la siguiente sección, se presentará al lector un resumen del trabajo realizado con anterioridad sobre la línea

2
de contribución de este TFM. Se trata, en concreto, de una aplicación de mensajería que utiliza una red P2P
para la transmisión de la información.

1.2 Escenario motivador


La línea de contribución que evoluciona con el desarrollo del presente Trabajo Fin de Máster comienza con la
realización de un Trabajo Fin de Grado por parte de Domingo Fernández Píriz [9]. Dicho trabajo tiene como
objetivo principal la implementación de una aplicación de mensajería que utiliza una red P2P para la
distribución de los mensajes. En esta sección se dará un breve resumen introductorio para la contextualización
del lector, pudiéndose encontrar más detalle en el capítulo Estado anterior del proyecto de este TFM.
La aplicación de mensajería de [9] fue desarrollada utilizando el lenguaje de programación Java [10] y
siguiendo el paradigma de programación MVC (Modelo-Vista-Controlador) [11]. Los elementos principales
del modelo de datos de la aplicación son:
• ID. Identificador único utilizado para los nodos de la red y para los objetos del modelo.
• Usuario. Envía y recibe mensajes.
• Mensaje. Objeto base para almacenar la información que se quiere comunicar entre usuarios.
• Mensaje cifrado. Objeto que encapsula un objeto Mensaje, para la transmisión segura del mismo.
• Grupo. Objeto dedicado para la difusión de mensajes. Los usuarios pueden seguir un grupo para
recibir los mensajes que se publican en el mismo.
• Contacto. Objeto que almacena un usuario de la red como conocido. Sólo se puede enviar y recibir
mensajes entre usuarios que se reconozcan como contactos mutuos.
• Conversación. Objeto que identifica el hilo al que pertenece un conjunto de mensajes.
A través de la vista, el usuario puede acceder a las distintas funcionalidades de la aplicación. El trabajo
contempla una vista para escritorio y una vista para terminales móviles (Android). En ambas, las posibilidades
son iguales y, básicamente, son las siguientes:
• Unión a una red Pastry. A partir de la IP y el puerto de un nodo perteneciente a la red conocido de
antemano.
• Registro e inicio de sesión local. De forma local, se almacenan unas credenciales que permiten hacer
uso de la aplicación.
• Gestión de contactos. Ver, agregar y borrar contactos de la aplicación.
• Gestión de grupos. Ver, agregar y borrar grupos de la aplicación.
• Gestión de conversaciones. Ver, crear y borrar conversaciones de la aplicación.
• Envío de mensajes. A conversaciones individuales o grupales.
El controlador tiene implementada una serie de flujos que permiten ejecutar las acciones necesarias para
ofrecer las funcionalidades de la vista, a través de la interacción con el modelo de datos.
Para la transmisión de los mensajes se hace uso de Pastry [12] . Pastry es una red P2P middleware basado en
una tabla hash distribuida, con interfaz DHT (Distributed Hash Table). La topología de red se asemeja a un
círculo o a un árbol basado en prefijos donde las hojas pueden ser los GUID (Globally Unique Identifier) de
nodos o claves. Los objetos son gestionados por los k nodos más próximos numéricamente, siendo k el número
de replicación. Para llegar hasta un nodo, se compara qué parte inicial del GUID coincide con el del nodo
actual y se reenvía a un nodo que tenga el prefijo al menos un carácter más largo: 𝑂(𝑙𝑜𝑔2𝑏 𝑚) saltos. Si no es
posible, se reenvía al nodo más cercano numéricamente. La información de encaminamiento servirá para
distribuir el árbol de búsqueda entre los nodos y priorizar los nodos más cercanos en la capa de red. Para la
utilización de este tipo de red, se ha empleado la implementación de código abierto FreePastry [13].
La vista de la aplicación de escritorio consiste en una consola donde se puede acceder a las distintas

3
funcionalidades a través de interacciones con un menú (pulsando el número de opción). A continuación, se
muestra una captura de dicha vista.

Figura 1. Vista de menú de consola de la aplicación de mensajería P2P previa al TFM.


La Experiencia de Usuario puede verse gravemente mermada al utilizar este tipo de interfaz, por la
complejidad de uso y las constantes interrupciones ocasionadas por los registros de log generados por la propia
aplicación en las interacciones de los nodos con la red P2P. Aunque también se dispone de una vista para
terminales móviles, el coste del mantenimiento de la conexión P2P es elevado y, con el objeto de mantener
siempre un objeto conectado que mantenga viva la red P2P es preferente el uso de la aplicación en un equipo
de escritorio. Por ello, surge la necesidad de modificar la vista de la aplicación para que la interfaz de usuario
sea gráfica, mejorando su usabilidad y accesibilidad. Éste será uno de los objetivos de este TFM.
La aplicación descrita en esta sección permite el envío de mensajes de texto plano, pero no se permite la
compartición de ficheros. Esta funcionalidad es básica en cualquier aplicación de mensajería actual y, por ello,
su incorporación a la aplicación también se convertirá en uno de los objetivos a cubrir con el desarrollo de este
TFM.
En la siguiente sección se dará una visión clara de los objetivos del TFM, para concretar la línea de evolución
de la aplicación expuesta en la presente sección.

1.3 Objetivos
Una vez introducido el contexto donde se desarrolla el Trabajo Fin de Máster, y el escenario que motiva la
realización de este, es hora de exponer los objetivos que se pretenden alcanzar con el trabajo desarrollado. A
continuación, se enumeran estos objetivos:
1. Implementación de interfaz gráfica para la aplicación. El uso de una aplicación de mensajería a
través de la consola puede degradar en gran medida la Experiencia de Usuario. Por ello, sería
conveniente disponer de una interfaz gráfica que facilite el acceso a las diversas funcionalidades de la
aplicación.
2. Añadir la posibilidad de compartir archivos a través de la aplicación. Para permitir el envío de
archivos además de texto plano.
3. Proporcionar una solución para la comunicación de nodos en redes con NAT. En una red P2P,
los nodos requieren visibilidad directa entre ellos para establecer conexiones en ambos sentidos. Si un
nodo se encuentra tras una red con reglas NAT, éste no podrá ejercer de servidor a menos que se
apliquen técnicas de NAT Traversal [2]. En la mayoría de los escenarios, los usuarios no tendrán la
posibilidad de modificar la configuración del firewall que aplica las reglas NAT. Por ello, se requiere
el estudio de una solución en este escenario típico para permitir las comunicaciones sin necesidad de
realizar cambios en configuraciones externas al propio equipo que ejecuta la aplicación.
4. Proporcionar seguridad en el canal de comunicación. Para garantizar la confidencialidad e
integridad de los datos transferidos a través de la capa de transporte, además de garantizar la
autentificación entre pares en las comunicaciones.
4
1.4 Metodología de trabajo
Para el desarrollo del TFM, se han seguido una serie de fases:
1. Estudio del marco contextual del proyecto. En primer lugar, se ha procedido al estudio de
bibliografía referente a las redes P2P para disponer de un conocimiento claro acerca de la temática a
tratar dentro del TFM.
2. Análisis del estado anterior del proyecto. En segundo lugar, se ha analizado el trabajo realizado con
anterioridad en la misma línea de contribución del presente TFM. En concreto, se trata del Trabajo Fin
de Grado realizado por parte de Domingo Fernández Píriz [9], donde se lleva a cabo el desarrollo de
una aplicación de mensajería P2P.
3. Formulación de objetivos a conseguir. Tras el análisis realizado en la fase anterior, ha sido
necesario llevar a cabo el establecimiento de los objetivos a conseguir para continuar la evolución de
la línea de contribución en la que toma lugar este TFM.
4. Desarrollo del trabajo necesario para cumplir los objetivos. Implementación de los cambios
necesarios en el trabajo analizado en la segunda fase para cumplir los objetivos formulados en la fase
anterior. En esta fase, se ha tratado de realizar un desarrollo software ágil. Cada objetivo ha sido
definido como una Historia de Usuario que plantea un requisito a conseguir mediante un incremento
del producto existente. Se mostrarán con más detalle estos aspectos relacionados con el desarrollo ágil
en el capítulo Marco contextual.
Durante estas fases, se ha utilizado de forma general una serie de herramientas como soporte. Estas
herramientas podrían diferenciarse según su ámbito de aplicación:
• Adquisición de información. Para la adquisición de información se han utilizado los buscadores
recomendados en el Curso Virtual sobre TFM [14] ofrecido por la Universidad de Sevilla. Entre estos
buscadores, se encuentra el catálogo FAMA [15] de la biblioteca de la Universidad de Sevilla y
Google Académico [16], entre otros. Además, se han consultado artículos de blogs y foros
relacionados con los distintos ámbitos del proyecto para la resolución de dudas concretas. En el
capítulo de Referencias quedan recogidos todos los artículos consultados.
• Gestión del proyecto. Para una organización efectiva del proyecto, se ha utilizado la herramienta
Trello [17]. Esta herramienta permite crear tableros Kanban [18] para controlar el estado de un
proyecto a través de una interfaz sencilla. Cada proyecto dispone de un tablero dividido en un número
determinado de columnas. Conforme avanza el proyecto, se crean tarjetas que se ubican dentro de una
columna concreta. Así, por ejemplo, se puede controlar el estado de una determinada tarea pasando de
la columna “Pendiente” a “En curso” y, finalmente, a “Finalizada”. En el caso de este TFM, se ha
creado un tablero con 6 columnas:
o Objetivos TFM. Cada objetivo del TFM tendrá asignada una tarjeta que se ubicará en esta
columna. Servirá para tener presente en todo momento el alcance y estado actual del
proyecto, ya que las tarjetas estarán siempre visibles y los objetivos cumplidos se etiquetarán
de color verde.
o Referencias. En esta columna se crearán tarjetas que contendrán referencias utilizadas
durante el desarrollo del proyecto, para disponer de ellas a la hora de documentar el trabajo.
o Pendientes. Cuando se crea una tarea, pasa a esta columna hasta que se comienza su
resolución.
o En proceso. Una vez que se da comienzo a una tarea, se mueve su tarjeta asociada a esta
columna. También es posible que se mueva la tarjeta correspondiente a una tarea que estaba
en la columna “Bloqueadas” y ya puede continuar resolviéndose.
o Bloqueadas. Si la resolución de una tarea se deja en espera (por falta de información o por
dependencia con otra tarea, por ejemplo), su tarjeta asociada pasa a ubicarse en esta columna.
o Completadas. Una vez que se valida que una tarea ha sido finalizada, pasará a esta columna.
En la siguiente figura se muestra el tablero creado para el proyecto, donde se aprecian las distintas
5
columnas creadas y algunas tarjetas ubicadas en ellas.

Figura 2. Tablero Kanban de la herramienta Trello utilizado para la gestión del proyecto.
• Desarrollo software. En cuanto al desarrollo software, se ha decidido poner en práctica el estilo de
desarrollo ágil de una forma simplificada. Se ha tomado la aplicación como un producto que
evoluciona mediante incrementos (filosofía SCRUM [19]). Cada incremento corresponde a la
consecución de un objetivo del TFM. Los objetivos han sido convertidos en Historias de Usuario, que
se desglosan en tareas que deben completarse para cumplir los criterios de aceptación impuestos en la
Historia de Usuario. Se dará una visión más profunda sobre el desarrollo ágil en el capítulo de Marco
contextual. Para las implementaciones de código, se ha utilizado el IDE Visual Studio Code [20]. Se
trata de un IDE gratuito, propiedad de Microsoft, con gran cantidad de plugins para dar soporte a
diversos lenguajes de programación, así como a la visualización, depuración y ejecución de código.
Para llevar el control del versionado del software se ha utilizado la herramienta Git [21], por ser la
herramienta mejor conocida por el autor del TFM, gracias a la formación recibida durante sus estudios
de Grado y Máster, además de su utilización durante su trayectoria profesional. Además, se ha creado
un repositorio online [22] en la herramienta de alojamiento de proyectos software Github [23] para
disponer del código y su versionado en cualquier lugar con conexión a internet.
• Pruebas con máquinas virtuales. Para las pruebas de la aplicación se han utilizado máquinas
virtuales a través de VirtualBox [24]. Este software, propiedad de Oracle, además de ser gratuito se
encuentra en constante evolución y dispone de una interfaz sencilla, además de fácil usabilidad.
También se han utilizado máquinas virtuales de Google Cloud Platform1 en determinados escenarios
donde se ha requerido la separación geográfica para realizar pruebas. Esta plataforma ofrece un año de
computación gratis (con un límite de facturación) y permite una gestión sencilla de las máquinas
virtuales.
En la siguiente imagen se muestra un mapa mental que plasma las herramientas utilizadas de forma general
para el desarrollo de este TFM.

1 https://cloud.google.com/

6
Figura 3. Mapa mental de herramientas de soporte general para la realización del TFM.

1.5 Organización de la memoria


Este Trabajo Fin de Máster se encuentra dividido en 5 capítulos:
1. Introducción. En el primer capítulo se ha dado al lector una breve y concisa introducción acerca del
contenido de este Trabajo Fin de Máster. La intención del capítulo es realizar una primera inmersión
en el contexto de desarrollo del TFM, del escenario que motiva su realización, los objetivos a cumplir
y la metodología de trabajo utilizada para la búsqueda de una solución.
2. Marco contextual. El segundo capítulo está dedicado a la exposición del marco contextual del TFM.
En este capítulo se darán a conocer los conceptos necesarios para la comprensión del problema
planteado y la solución aportada. Se tratarán en profundidad las redes P2P y las metodologías de
desarrollo ágil para mostrar el marco tecnológico fundamental y el marco de trabajo utilizado para
abordar el problema.
3. Estado anterior del proyecto. El tercer capítulo servirá para exponer de forma resumida el trabajo
realizado por otro alumno en su Trabajo Fin de Grado, con el objetivo de dar a conocer el punto de
partida para el desarrollo del TFM. Se describirá, por tanto, el producto que se quiere evolucionar
mediante incrementos.
4. Trabajo realizado. En este capítulo se detalla el trabajo realizado para completar los objetivos
marcados en el TFM. Cada objetivo será tratado en una sección independiente, proporcionando una
descripción para el mismo y exponiendo la tecnología implicada y el desarrollo llevado a cabo para su
consecución. Así, la consecución de un objetivo podrá visualizarse como un incremento
independiente del producto desarrollado.
5. Conclusiones. El capítulo final servirá para valorar el trabajo realizado conforme a los objetivos
fijados en un principio, y proponer mejoras futuras de cara a la continua evolución del producto.

7
8
2 MARCO CONTEXTUAL

Humans were always far better at inventing tools than using them wisely.
Yuval Noah Harari. 21 Lessons for the 21st Century.

E
n este capítulo se pretende ubicar al lector en el contexto tecnológico sobre el que trata el TFM. Para
ello, será necesario dar a conocer el marco de las comunicaciones P2P, mostrando sus características,
ventajas, desventajas y diferencias con respecto a las comunicaciones a través de servidores
centralizados. Además, se pretende dar nociones acerca de las metodologías de desarrollo ágil, debido al uso
de estas para afrontar la consecución de los distintos objetivos del TFM. Se profundizará en el marco de
trabajo SCRUM, el más utilizado en el mundo a la hora de llevar a cabo un desarrollo ágil.

2.1 Redes P2P


Las redes P2P (Peer To Peer) [1], también conocidas como redes de pares o redes entre iguales, son redes de
ordenadores que se comportan como iguales entre sí. Los distintos elementos que participan en la red se
denominan Nodos. Los nodos interactúan entre sí de tal forma que unas veces actúan como servidores de
información y otras como clientes que solicitan información. Esta es la principal diferencia con el modelo
tradicional de comunicación entre ordenadores, donde un elemento central actúa como servidor de
información, aceptando y gestionando las peticiones de información recibidas por parte de otros elementos,
denominados clientes. De esta forma, la responsabilidad de almacenamiento y administración de la
información se reparte entre todos los nodos que forman parte de ella. Las redes P2P se encuentran
superpuestas a una red pública (por ejemplo, Internet) y un nodo puede comunicarse con cualquier otro nodo
de la red, para intercambiar información en cualquier formato.
Las redes P2P presentan una serie de características principales [2] , listadas a continuación:
• Topología descentralizada. La organización de la red no depende de un sistema central, sino que es
responsabilidad de todos los nodos que la componen. Los nodos cooperan entre sí para mantener la
información de la red actualizada. De esta forma, la indisponibilidad de un nodo concreto no afecta al
funcionamiento de la red.
• Simetría de roles. Como se ha mencionado anteriormente, en una red P2P todos los nodos tienen las
mismas capacidades funcionales. Así, cualquier nodo puede almacenar información de otros pares,
aceptar peticiones y enrutar mensajes.
• Alta escalabilidad. Las redes P2P deben soportar bien tanto el incremento de pares (aumentando la

9
red hasta en 100 órdenes de magnitud) como la dispersión geográfica de los pares que la componen
(repartidos a lo largo de otra red pública, como Internet).
• Autonomía de los nodos. Cada nodo determina sus capacidades basándose en sus propios recursos.
Los nodos deciden cuándo se unen a la red, qué peticiones hacer y cuándo salir de ella. Esta
característica provoca que los servicios ofrecidos por la red sean, en cierto modo, impredecibles.
• Compartición de recursos. Una red P2P proporciona un conjunto de recursos compartidos, tales
como ciclos de CPU, almacenamiento en disco y ancho de banda, que son proporcionados por los
distintos nodos que la forman. Para acceder a la red, cada nodo debe contribuir con un umbral mínimo
establecido de recursos.
• Robustez. En las redes P2P, la topología cambia dinámicamente, con la conexión y desconexión de
los distintos nodos que la componen. Por ello, es necesario implementar mecanismos que puedan
mantener actualizada la información de estado de la red.

2.1.1 Redes P2P no estructuradas


Se denominan redes P2P no estructuradas a aquellas que no definen la forma en que los nodos se interconectan
entre ellos, es decir que la distribución de estos es aleatoria. En la siguiente figura se puede observar una
posible distribución para este tipo de redes P2P.

Figura 4. Posible distribución de los nodos de una red P2P no estructurada [2].
Cada nodo dispone de una lista de nodos conocidos (denominados vecinos). El número de vecinos que forman
esta lista es conocido como el grado del nodo. Cuanto mayor sea el grado de los nodos, menor será la ruta más
larga entre un nodo y otro, pero mayor será el almacenamiento necesario en cada nodo. La lista de vecinos se
inicializa en el momento de unirse a la red (por ejemplo, copiando la misma lista del primer nodo al que se
conecta) y se actualiza a lo largo del tiempo apoyándose en las listas de los vecinos (para agregar nuevos
vecinos) y en la ausencia de respuesta a los mensajes keep-alive a los vecinos actuales (eliminándolos).

2.1.1.1 Transmisión de mensajes en redes P2P no estructuradas

Una vez conectado a la red, un nodo puede comenzar a intercambiar mensajes con sus vecinos. Un tipo de
mensaje importante es la solicitud de una información a partir de un criterio de búsqueda (como un nombre de
fichero, por ejemplo). Como, a priori, se desconoce qué nodo puede disponer de esa información (si es que
alguno dispone de ella), el nodo solicitante podría optar por enviar la petición a todos sus vecinos. Éstos, al
recibir la petición podrían reenviarla a sus vecinos en caso de no disponer de la información solicitada. Para
evitar que las solicitudes sean reenviadas indefinidamente, éstas disponen de un atributo TTL (Time To Live)
que limita el número de veces que puede ser reenviada. Cada nodo decrementa el valor del atributo TTL de la
solicitud antes de reenviarla. Si el valor del TTL es igual a 0, el nodo no reenviará la solicitud. También, para
evitar bucles, cada nodo puede almacenar una lista de los mensajes reenviados durante un periodo de tiempo,
evitando reenviar los que lleguen más de una vez. Este algoritmo de transmisión se denomina Inundación. En
la siguiente figura puede observarse el camino que seguiría una solicitud a través de una red P2P no
estructurada siguiendo este algoritmo.

10
Figura 5. Ejemplo recorrido por Inundación de una solicitud en una red P2P no estructurada [2].
Mediante el algoritmo de Inundación, cuando un nodo dispone de la información solicitada, se envía la
respuesta al nodo solicitante. Si el nodo destino se encuentra rápidamente, la solicitud seguirá propagándose
por el resto de caminos hasta que se agote el TTL o también se pueda dar respuesta a la solicitud. Esto puede
generar redundancia innecesaria en la transmisión de mensajes, lo cual es perjudicial para la red a nivel de
rendimiento. Una forma de combatir esta situación consiste en utilizar un TTL pequeño para el envío de la
solicitud. Si la búsqueda no tiene éxito, se enviará desde el origen otra vez la solicitud, esta vez con un TTL un
poco mayor. Esta técnica de inundación se conoce como Anillo expandido y es particularmente efectiva
cuando hay múltiples copias de los objetos de información. Otra técnica para reducir el grado de inundación de
mensajes en la red es la denominada como Caminos aleatorios, donde los mensajes se envían solamente a un
vecino de la lista escogido de forma aleatoria (evitando, por supuesto, al nodo que lanza la solicitud). Así, cada
solicitud sigue un camino único a través de la red (no se bifurca). Si la solicitud no tiene éxito, el nodo origen
puede enviarla de nuevo a través de otro camino aleatorio. Para mejorar el tiempo de respuesta de esta técnica,
el nodo origen puede lanzar la solicitud en paralelo a través de varios caminos. En la siguiente figura se
muestra el recorrido de una solicitud que es encaminada siguiendo un camino aleatorio (izquierda) o varios en
paralelo (derecha).

Figura 6. Ejemplos recorrido por Caminos aleatorios de una solicitud en una red P2P no estructurada [2].

2.1.1.2 Topología de redes P2P no estructuradas

La morfología de las redes P2P no estructuradas depende de la distribución de los distintos nodos que la
componen, junto con las conexiones entre ellos. Así, la forma en que se distribuye el grado de los nodos afecta
a la distribución de la carga, mientras que el diámetro de la gráfica afecta al número de saltos necesarios para
la transmisión de solicitudes. Atendiendo a estos dos parámetros, las redes P2P muestran principalmente dos
topologías [2]:
• Aleatoria. Las interconexiones entre pares de nodos se distribuyen de forma aleatoria. La
probabilidad de que un nodo tenga un grado k sigue una distribución de Poisson, de media k. Esta
topología sirve en la teoría por sus propiedades analíticas, pero en la práctica la mayoría de las redes
(entre las que se encuentra Internet) presentan una topología libre de escala.
• Libre de escala. En esta topología, la probabilidad de que un nodo tenga un grado k sigue una función
de potencia 𝑃(𝑘)~𝑘 − 𝛾 . Esto implica que hay un número muy pequeño de nodos que tienen un grado
muy alto. Podría verse como una topología basada en supernodos que disponen de un gran número de
conexiones con otros nodos de la red. Esta topología ha sido ampliamente utilizada en aplicaciones de
compartición de ficheros.

11
En la siguiente figura puede observarse la distribución de probabilidad del grado de los nodos en una red P2P
no estructurada con topología aleatoria (izquierda) y libre de escala (derecha).

Figura 7. Distribución de probabilidad del grado de los nodos en redes P2P estructuradas con topología
aleatoria (izquierda) y libre de escala (derecha) [2].
Se observa que las topologías aleatorias disponen de un reparto de las interconexiones más equitativo, mientras
que las topologías libres de escala presentan un reparto orientado a la existencia de unos pocos supernodos que
disponen de una gran cantidad de interconexiones con otros nodos de la red. Esta última topología, en una red
P2P, permite su escalabilidad. Al disponer de unos pocos nodos de alto grado, la media de saltos de las rutas
de distribución de mensajes no varía significativamente conforme se incrementa el tamaño de la red. A
continuación, se expondrán algunas aplicaciones que utilizan redes P2P no estructuradas, donde se verán las
características de ambas topologías en la realidad.

2.1.1.3 Aplicaciones de redes P2P no estructuradas

La principal aplicación de uso para redes P2P no estructuradas es la compartición de ficheros, donde cada
nodo almacena un conjunto de ficheros que pueden ser solicitados por cualquier nodo de la red. En la práctica,
una persona utiliza una aplicación de este tipo para buscar un archivo que le interese (una canción, un libro,
una película) y obtiene la información que concuerda con su búsqueda por parte de todos los nodos a los que
haya llegado la solicitud. Entonces, esta persona selecciona el contenido que más le convence y entonces se
lanza la solicitud al nodo que contiene el archivo para realizar la transmisión. En el momento en que ésta
finaliza, el nodo receptor dispone de una copia de este archivo y se convierte, por lo tanto, en servidor de este.
A continuación, se nombran algunas de las aplicaciones más relevantes en este campo:
• Napster. Aplicación para compartición de ficheros que utiliza un servidor central que mantiene un
índice global de la red. Se encarga de realizar las búsquedas y ofrecer los resultados (nombre del
fichero y nodo donde se encuentra) al nodo que envía la solicitud. Se lanzó en 1999 y alcanzó gran
popularidad en muy poco tiempo, consiguiendo la cifra de 26 millones de usuarios en 2001. Ese
mismo año, la aplicación fue clausurada debido a confrontaciones legales relacionadas con los
derechos de propiedad intelectual. A continuación, se resumen sus fortalezas y debilidades [1]:
o Fortalezas. El servidor central conoce en todo momento el estado de la red, de tal forma que
tiene visibilidad tanto de los nodos conectados, como de los archivos disponibles en un
momento determinado. Además, las búsquedas son mucho más rápidas, al inundar
rápidamente la red con una consulta.
o Debilidades. El servidor central se convierte en punto único de fallo. Si éste cae, la red
desaparece. Además, la capacidad de procesamiento que requiere este nodo debe ser muy
alta. Al fin y al cabo, la primera interacción (búsqueda) es prácticamente igual que en el
modelo tradicional de cliente-servidor.
En la siguiente figura se muestra un ejemplo de transmisión de un fichero a través de Napster.

12
Figura 8. Transmisión de un fichero utilizando Napster [1].
• Gnutella. Primera aplicación de compartición de ficheros donde se utiliza el protocolo P2P puro. En
sus primeras versiones (hasta la 0.4) se utilizaba una red P2P no estructurada con topología de nodos
aleatoria y la transmisión de solicitudes se realizaba por inundación, aplicando un TTL (Time-To-
Live) para evitar bucles. Presenta las mismas fortalezas y debilidades que se han descrito
anteriormente en esta sección para este tipo de redes [1]:
o Fortalezas. Gracias a su total distribución, Gnutella es robusta frente a desconexiones de los
distintos nodos.
o Debilidades. Debido a la transmisión mediante inundación con limitación de TTL, las
búsquedas resultan ineficientes y presenta problemas de escalabilidad. En versiones
posteriores (a partir de la 0.6), se adopta una topología libre de escala con supernodos que
centralizan el rutado de las solicitudes, mejorando el rendimiento de la red.
• FastTrack. Aplicación que utiliza una red P2P con una topología libre de escala, donde hay dos tipos
de nodos: ordinarios y supernodos. Los supernodos tienen un grado mucho mayor que el de los nodos
ordinarios (que dispone de una lista de supernodos a los que conectarse), y sirven para rutar las
solicitudes que provienen de los nodos ordinarios a través de la capa de supernodos, mediante
inundación. A continuación, se muestran sus principales fortalezas y debilidades:
o Fortalezas. Combina la bondad de Napster (eficiencia de búsqueda), con la bondad de
Gnutella (robustez frente a caídas de los supernodos).
o Debilidades. Presentan puntos críticos de fallo (los supernodos), aunque no se trata de un
punto único como en Napster. Igual que ésta, se enfrenta a continuos problemas legales
relacionados con los derechos de propiedad intelectual.
En la siguiente figura se muestra la topología libre de escala basada en supernodos, utilizada por
FastTrack.

Figura 9. Topología basada en supernodos, utilizada por FastTrack [1].

2.1.2 Redes P2P estructuradas


Para cubrir las limitaciones de las redes P2P no estructuradas, surge un nuevo tipo que combina una estructura
geométrica concreta para la distribución de los nodos con mecanismos apropiados de rutado y mantenimiento
de la red [2]. Se trata de las redes P2P estructuradas.

13
Las redes P2P estructuradas permiten encaminar las solicitudes mediante mecanismos basados en claves, de
tal forma que no se almacena información acerca de los objetos almacenados en la red, sino de los nodos que
son responsables de las réplicas de dichos objetos. Para facilitar el almacenamiento de objetos y su búsqueda
en redes P2P estructuradas, se presentan principalmente dos interfaces (API): Distributed Hash Table (DHT) y
Distributed Object Location and Routing (DOLR).

2.1.2.1 Distributed Hash Table (DHT)

Las tablas de hash distribuidas (DHT, Distributed Hash Table) son estructuras de datos donde se almacenan
pares clave-valor. El valor asociado a una clave se obtiene al aplicarle a ésta una función hash (genera un valor
dentro de un rango finito a partir de un valor de entrada), y representa la posición donde se almacena el objeto
representado por la clave. La tabla es dividida y repartida entre los nodos de la red, de tal forma que cada nodo
es responsable de una parte de la misma. Cuando se recibe una consulta para encontrar un objeto (clave), se
debe aplicar un mecanismo de encaminamiento para encontrar el nodo que es responsable de dicho objeto (se
obtiene su identificador al aplicar la función hash a la clave del objeto buscado). En la siguiente figura se
muestra el concepto de DHT de una forma gráfica.

Figura 10. Concepto de Tabla Hash Distribuida2.


La forma en que se lleva a cabo el encaminamiento de la consulta será fundamental para determinar el
esfuerzo necesario para encontrar el nodo responsable del objeto buscado. Si cada nodo almacenase una tabla
que permitiese llegar al resto de nodos en un sólo salto, el esfuerzo sería O(1), pero el almacenamiento de la
tabla sería muy costoso cuando la red creciese. En la interfaz DHT se dispone de las siguientes operaciones:
• put(GUID, datos). Guarda los datos replicados en todos los objetos responsables del GUID.
• remove(GUID). Elimina todas las réplicas del objeto GUID.
• valor = get(GUID). Obtiene los datos asociados al GUID.
En las subsecciones 2.1.2.3 y 2.1.2.4 se estudian dos tipos de redes P2P estructuradas y la forma en que
resuelven el encaminamiento de consultas a través de la DHT: Chord y Pastry.

2.1.2.2 Distributed Object Location and Routing (DOLR)

Mediante la interfaz DOLR, se mantiene una relación entre el GUID de un objeto y la referencia del nodo
donde se pueden encontrar réplicas de dicho objeto. Las solicitudes para un GUID son encaminadas hacia el
nodo más cercano que dispone de una réplica del objeto. La capa P2P no decide dónde se almacena un objeto,
sino que los nodos que disponen del objeto se encargan de notificar que lo tienen disponible. Las operaciones
disponibles a través de esta API son:
• publish(GUID). El nodo publica que tiene una réplica del objeto GUID.
• unpublish(GUID). El objeto GUID deja de ser accesible a través del nodo.
• sendToObj(msg, GUID, [n]). Se envía un mensaje al objeto GUID (paradigma orientado a objetos).
Opcionalmente se envía el mismo mensaje a “n” réplicas.
En la subsección 2.1.2.5 se hablará de Tapestry, una implementación de red P2P que utiliza la interfaz DOLR.

2 Referencia de la imagen: https://en.wikipedia.org/wiki/Distributed_hash_table

14
2.1.2.3 Chord

Chord organiza los nodos a lo largo de un anillo con identificadores formados por m bits y presenta dos formas
de encaminamiento:
• Básico. Cada nodo reenvía la petición al nodo sucesor hasta encontrar el nodo responsable del
identificador de la petición. Este encaminamiento presenta un esfuerzo de O(N), donde N es el
número de nodos que componen la red, por lo que presenta un problema claro de ineficiencia de
búsqueda conforme la red crece. En la siguiente figura se muestra este encaminamiento de forma
gráfica con un ejemplo.

Figura 11. Ejemplo de encaminamiento básico en red P2P Chord [1].


• Basado en tabla de dedos (finger table). Cada nodo mantiene una tabla con m posiciones que hacen
referencia a otros nodos, además de mantener una referencia a su nodo predecesor. Cada nodo será
responsable de las claves contenidas entre su identificador y el identificador de su predecesor. De esta
forma, las búsquedas conllevan un esfuerzo de O(logN) donde N es el número de nodos que
componen la red. En el peor de los casos, donde la red estará compuesta por 2m nodos, las búsquedas
se completarán en un máximo de m saltos. En la siguiente figura se muestra un ejemplo de tabla de
dedos en una red Chord con N=9 nodos y m=7 bits para los identificadores.

Figura 12. Ejemplo de tabla de dedos para un nodo dentro de una red Chord con N=9 y m=7 [1].
A la hora de manejar los eventos inesperados relativos a conexiones o desconexiones de nodos, Chord utiliza
las referencias de la tabla de dedos y de su sucesor para mantener la información de estado de la red:
• Conexión de un nuevo nodo. El nuevo nodo, con identificador X, debe anotar el identificador de su
nodo inmediatamente sucesor dentro de la red y generar su tabla de dedos en base a la de su sucesor.
Al incluirse este nuevo nodo, será necesario actualizar la tabla de dedos de los m nodos predecesores
con identificador X-2i (i=0, 1, m-1).
• Desconexión de un nodo. Los nodos de la red comprueban periódicamente el estado de su primer
nodo sucesor y su primer nodo predecesor. Además, mantienen una lista de sucesores con r nodos
que se corresponden con los siguientes dentro del anillo. Cuando se detecta el fallo del nodo sucesor,
se actualiza con el primer nodo activo encontrado entre su tabla de dedos y su lista de sucesores.

15
2.1.2.4 Pastry

Pastry organiza la red de tal forma que podría verse como un círculo o como un árbol, donde los vértices o las
hojas pueden ser identificadores de nodos o claves de objetos. Los datos de los objetos son gestionados por el
nodo más cercano numéricamente. Los identificadores están en base 2b y normalmente se utiliza una base
hexadecimal (b=4) con identificadores de 128 bits (identificadores de 32 dígitos hexadecimales). El
encaminamiento está basado en búsqueda por prefijo, comparando en cada iteración el identificador buscado
con el identificador del nodo actual para comprobar el prefijo común de ambos. Después, el nodo actual
reenvía la solicitud a un nodo que tenga, al menos, un dígito más en común con el identificador buscado. Si
algún nodo de su conjunto de hojas (nodos con identificador próximo al identificador del nodo actual) coincide
con el identificador buscado, lo envía directamente a dicho nodo. Con este mecanismo de encaminamiento, la
búsqueda converge en un máximo de 𝑂(𝑙𝑜𝑔2𝑏 𝑚) saltos. Para saber a qué nodo debe reenviarse la solicitud, en
Pastry, los nodos disponen de la siguiente información de encaminamiento:
• Conjunto de hojas (leaf set) L. Se trata de una lista de nodos cercanos numéricamente
(identificadores próximos al identificador del nodo). El tamaño de la lista es l, y contiene l/2 sucesores
y l/2 predecesores.
• Conjunto de vecindario (neighborhood set) V. Se trata de una lista de nodos cercanos según alguna
métrica de red, como la latencia o el número de saltos necesarios para ser alcanzados. Se utiliza como
una caché de v candidatos para sustituir los nodos de la tabla de encaminamiento que dejen de estar
disponibles.
• Tabla de encaminamiento R. En esta tabla se almacena información de encaminamiento hacia nodos
lejanos numéricamente, basado en sus identificadores. Tiene 𝑙𝑜𝑔2𝑏 𝑚 filas y 2𝑏 − 1 columnas. Con
los valores típicos comentados anteriormente (m=128 bits y b=4), la tabla de encaminamiento tiene un
total de 32 filas y 15 columnas. En cada posición R(p,i) se almacena el enlace al nodo más cercano
numéricamente (si existe) cuyo identificador comparte un prefijo p dígitos con el nodo actual y cuyo
primer dígito distinto es i.
En la siguiente figura se muestra un ejemplo de información de encaminamiento (sin incluir las IPs asociadas a
cada nodo) para un nodo dentro de una red Pastry con b=2 (dígitos del identificador de 0 a 3) y l=8 nodos
dentro del conjunto de hojas (leaf set).

Figura 13. Ejemplo de información de encaminamiento (conjunto de hojas, tabla de encaminamiento y


conjunto de vecindario) en un nodo dentro de una red P2P Pastry [25].
A la hora de manejar los eventos inesperados relativos a conexiones o desconexiones de nodos, en Pastry se
actúa de la siguiente forma:
• Conexión de un nuevo nodo. Para que un nodo X se una a la red, debe conocer otro nodo A que ya
pertenezca a la misma. En primer lugar, el nodo X calcula su identificador y envía un mensaje de tipo
join al nodo A. Este mensaje es encaminado con normalidad y los distintos nodos por los que pasa el
mensaje envían su conjunto de hojas y parte de su tabla de encaminamiento al nodo X. Éste construye

16
su tabla de encaminamiento basándose en esta información, y el conjunto de hojas será prácticamente
igual al del nodo final donde llegue el mensaje (por ser el más próximo numéricamente al nodo X). El
conjunto de vecindario es copiado del primer nodo al que se envía el mensaje (nodo A), entendiéndose
que es próximo a nivel de red por ser conocido. El nodo X envía su conjunto de hojas y su tabla de
encaminamiento a todos los nodos conocidos en el proceso de unión, para que éstos puedan actualizar
la información. El proceso conlleva la transmisión de 𝑂(𝑙𝑜𝑔𝑁) mensajes.
• Desconexión de un nodo. Para controlar las desconexiones o fallos en los nodos de la red,
periódicamente se envían mensajes de comprobación a los nodos del conjunto de hojas. Cuando se
detecta un fallo en un nodo del conjunto de hojas, se busca un nodo que esté activo y sea próximo al
nodo con fallo. Después, se solicita el conjunto de hojas de este nuevo nodo y se sustituye el nodo con
fallo dentro del conjunto de hojas propio con alguno del conjunto recibido. En caso de fallo en un
nodo de la tabla de encaminamiento, la solicitud se reenviará a otro nodo de la misma fila. Si esto
último también falla, se reenvía a otro nodo de la siguiente fila.
Pastry dispone de una implementación de código libre, Freepastry [13], que será la utilizada en este TFM para
la transmisión de mensajes entre los distintos nodos de la red.

2.1.2.5 Tapestry

Tapestry utiliza la interfaz DOLR, con identificadores de 160 bits y el mecanismo de encaminamiento, como
en Pastry, está basado en prefijos (funciona como una DHT). Cuando se introduce un objeto con un
identificador determinado, se encamina el mensaje de notificación de la inclusión hasta el nodo raíz, que es el
nodo más próximo numéricamente al identificador del objeto introducido. En cada salto, el nodo que reenvía
el mensaje guarda una referencia hacia el nodo que contiene el objeto introducido. Cuando se solicite dicho
objeto, se encaminará el mensaje hasta el nodo raíz, hasta que un nodo intermedio disponga de una referencia
al nodo que almacena el objeto, reenviándolo directamente a éste y ahorrando el resto de saltos hasta el nodo
raíz. En la siguiente figura se muestra el proceso de inclusión de un objeto en la red Tapestry y el proceso de
encaminamiento de una solicitud de búsqueda de dicho objeto.

Figura 14. Encaminamiento de mensajes de inclusión de objetos (A) y de búsqueda de un objeto (B) en red
Tapestry [2].
A la hora de manejar los eventos inesperados relativos a conexiones o desconexiones de nodos, en Tapestry se
actúa de la siguiente forma:
• Conexión de un nuevo nodo. El nuevo nodo contacta con el nodo que tiene el identificador más
cercano al suyo y copia su tabla de vecinos. Después, envía un mensaje de difusión hacia todos los
nodos que comparten el mismo prefijo que el nuevo nodo y su nodo más cercano. Los nodos
alcanzados actualizan su información de encaminamiento si es necesario con la información del nuevo
nodo. Si el nuevo nodo se convierte en el nodo raíz de un objeto, será necesario mover las referencias

17
a esos objetos al nuevo nodo.
• Desconexión voluntaria de un nodo. Cuando un nodo decide abandonar la red, lo notifica a los
nodos que tienen referencias hacia este y a su nodo sustituto. Después, los nodos que tienen
referencias hacia el nodo que se va, envían mensajes de publicación de los objetos que le pertenecían
a este nodo y a su sustituto, para actualizar la información de encaminamiento.
• Desconexión involuntaria (fallo) de un nodo. Para controlar los fallos en los nodos de la red, se
dispone de un nodo de respaldo para cada entrada de la tabla de encaminamiento. Para detectar los
fallos en los nodos de la tabla de encaminamiento, se envían mensajes periódicamente. Cuando se
detecta un fallo, se envían mensajes de información de la localización de los objetos que eran
responsabilidad del nodo que ha fallado.
En cuestión de eficiencia de las búsquedas, Tapestry es similar a Pastry. El número de saltos máximo que se
requiere para encontrar un objeto es 𝑂(𝑙𝑜𝑔𝛽 𝑁), donde N es el número de nodos que componen la red y 𝛽 es la
base de codificación de los identificadores.

2.1.2.6 Aplicaciones de redes P2P estructuradas

Para terminar la sección dedicada a redes P2P estructuradas, se muestran 3 ejemplos de aplicaciones que
utilizan cada uno de los tipos estudiados anteriormente.
• Squirrel [26]. Creada por los mismos desarrolladores de Pastry en 2001. Se trata de una aplicación
de caché web P2P para usar en redes locales. Cada equipo de la red local actúa como un nodo de la
red P2P. Las claves son las URL web, a las que se le aplica una función hash SHA-1 para obtener el
identificador correspondiente. En el modo más sencillo de trabajo, cada nodo almacena los objetos
con GUID más próximos. Con esta aplicación, se consigue una reducción del tráfico externo y de la
latencia percibida por el usuario similares a la que se consigue utilizando un servidor central, y
requiere pocos recursos por parte de los distintos equipos que componen la red P2P.
• OceanStore [27]. Aplicación de almacenamiento de ficheros distribuidos creada por los mismos
desarrolladores de Tapestry en el año 2000. Los datos están encriptados por su propietario y las
actualizaciones se llevan a cabo siguiendo un protocolo de consenso bizantino3 entre un grupo de
nodos. Cada bloque está dividido en m fragmentos, y cada fragmento se codifica con n fragmentos
denominados códigos de borrado (n > m). Los bloques pueden reconstruirse a partir de una pequeña
porción de los códigos de borrado, en concreto podrían perderse n-m códigos de borrado sin
problema. Se distinguen 3 tipos de identificadores: AGUID, que identifica la secuencia completa de
todas las versiones de un fichero; BGUID, que es el hash de los datos de un bloque; y VGUID, que es
el BGUID del bloque raíz de una versión. Se trata de un sistema muy fiable, pero lento.
• Ivy [28]. Es una aplicación de almacenamiento de ficheros distribuidos que utiliza Chord para
almacenar los datos. Fue creada por integrantes del MIT (Massachusetts Institute of Technology) en
2002. Cada nodo almacena un registro de cambios realizado por él mismo. Para reconstruir un
fichero, deben consultarse todos los cambios realizados en dicho fichero. Como los cambios
realizados por un nodo sólo son almacenados por él, se pueden realizar modificaciones a los ficheros
sin bloqueos, resolviendo los conflictos que pudiesen aparecer por dos modificaciones distintas de
forma manual o automática.

2.1.3 Aplicaciones de mensajería en redes P2P


Una de las aplicaciones de las redes P2P, y que está relacionada con este TFM, es el envío de mensajes de
forma descentralizada. A diferencia de las aplicaciones de mensajería basadas en servidores centralizados,
donde la información de los usuarios y los datos transferidos se encuentran en manos de la empresa propietaria
del servicio, las aplicaciones de mensajería P2P favorecen la privacidad y seguridad de la información de los
usuarios. Cada dispositivo es responsable del almacenamiento de la información del usuario que lo utiliza y, si
se cifran las comunicaciones, los datos transmitidos no pueden ser interceptados ni monitorizados por terceros.

3 Información sobre el problema de los generales bizantinos en https://es.wikipedia.org/wiki/Problema_de_los_generales_bizantinos

18
Esto hace muy difícil que una brecha de seguridad en un servidor concreto ponga en compromiso la
información personal de millones de personas4. Además, de esta forma se asegura la privacidad de los usuarios
al comunicarse entre ellos, evitando que su actividad pueda ser utilizada para fines comerciales con terceros.
A continuación, se exponen algunas aplicaciones de mensajería P2P disponibles en la actualidad:
• Tonic5. Aplicación para comunicarse con usuarios dentro de la misma red LAN. Ofrece una interfaz
muy sencilla, a través de la cual se puede ver quién está conectado a la aplicación dentro de la misma
red LAN. Sólo permite el envío de mensajes de texto plano. La última versión apareció en 2006, tras
lo cual se anunció el abandono de su desarrollo. En la siguiente figura se muestra la interfaz de esta
aplicación.

Figura 15. Interfaz gráfica de la aplicación Tonic


• Ricochet6. Aplicación para comunicarse con usuarios dentro de la red Tor7. Tor es una red
superpuesta a Internet que podría asemejarse a las redes de supernodos comentadas anteriormente
(FastTrack). Los usuarios se unen a la red Tor, que dispone de una serie de nodos encargados de
encaminar el tráfico cifrándolo desde el primer router hasta el último (entre el supernodo y el usuario,
no hay cifrado). Los usuarios de Ricochet disponen de un identificador único, que puede utilizarse por
otros usuarios para agregarlos como contactos y enviarles mensajes. Sólo permite el envío de
mensajes de texto plano, aunque anuncian que próximamente estará disponible el envío de ficheros.
La última versión (1.1.4) fue lanzada en noviembre de 2016. A continuación, se muestra la interfaz
gráfica de esta aplicación.

Figura 16. Intefaz gráfica de la aplicación Ricochet


• TOX8. Aplicación de mensajería P2P multiplataforma que permite la transferencia de ficheros
además de texto plano en los mensajes. También ofrece la posibilidad de realizar llamadas y
videollamadas, además de compartir la pantalla del dispositivo en el chat. Los usuarios se unen
automáticamente a una red P2P única, a través de alguno de los nodos públicos9 disponibles para
arrancar. Es decir, que los usuarios no tienen la posibilidad de crear sus propias redes P2P. Cada
usuario tiene un identificador único compuesto por 76 dígitos hexadecimales (304 bits), que debe ser
conocido por otro usuario para poder agregarlo como contacto. Su desarrollo comenzó en 2014 y la
última versión es de octubre de 2020, por lo que es una aplicación en constante evolución. En la

4 https://www.csoonline.com/article/2130877/the-biggest-data-breaches-of-the-21st-century.html
5 https://www.r2.com.au/page/products/show/tonic/
6 https://ricochet.im/
7 https://2019.www.torproject.org/about/overview.html.en

8 https://tox.chat/
9 https://nodes.tox.chat/

19
siguiente figura se muestra la interfaz de uno de los clientes disponibles para escritorio (qtox).

Figura 17. Interfaz gráfica de qTox (versión escritorio de TOX Chat)


Como puede apreciarse, en la actualidad se dispone de diversas soluciones para la mensajería a través de redes
P2P. Es importante hacer notar que las aplicaciones de mensajería más utilizadas a nivel mundial se apoyan en
el uso de servidores centralizados (ver Figura 21) y que disponen de soluciones de gran calidad para la
transferencia de archivos y mensajes de voz, así como la capacidad de realizar llamadas de voz y vídeo o crear
salas de reuniones para varios participantes. La razón es que, mientras que la mayoría de aplicaciones de
mensajería P2P son desarrolladas por una comunidad libre, las aplicaciones punteras de mensajería son
propiedad de empresas con grandes recursos para desarrollarlas, evolucionarlas y promocionarlas a una
velocidad y escala muy superior. Si bien es cierto que es prácticamente imposible competir con Whatsapp en
margen de mercado, el desarrollo de alternativas que permitan ofrecer funcionalidades similares protegiendo la
información personal de los usuarios sirve para mantener la esperanza en un futuro donde las grandes
corporaciones apuesten por la descentralización paulatina de sus sistemas de información, aunque sólo sea por
el ahorro que puede suponerles este escenario ante brechas de seguridad.

2.1.4 Redes P2P en este TFM


En este TFM, las redes P2P toman relevancia debido a que son utilizadas en el desarrollo realizado
previamente en la línea de contribución donde se ubica el trabajo. En concreto, se desarrolló una aplicación de
mensajería que utiliza una red P2P Pastry (a través de su implementación Freepastry) para el encaminamiento
de los mensajes. Por tanto, ha sido necesario conocer en gran medida los conceptos generales relacionados con
este tipo de redes y, más específicamente, los relacionados con las redes P2P estructuradas. Además, es
necesario este conocimiento para entender la problemática que se pretende resolver con la consecución de los
objetivos de este TFM.

2.2 Metodologías de desarrollo ágil


El desarrollo de software ha seguido tradicionalmente el método secuencial denominado “En cascada”. Este
método se basa en la descomposición de un proyecto en una secuencia de fases que van completándose una a
una y que, una vez completadas, no tienen marcha atrás. Además, está orientado hacia la planificación rigurosa
de todas estas fases, dejando poco o ningún margen para cambios y con poca comunicación con el cliente una
vez superada la fase inicial de análisis de requisitos [29]. En la siguiente imagen se muestra la secuencia de
fases que atraviesa un proyecto de desarrollo software siguiendo el método “En cascada”.

Figura 18. Fases del método de desarrollo software “En cascada”.

20
Este tipo de metodología ha demostrado ser efectivo y necesario en proyectos con un alto grado de coste en
cuanto a tiempo y recursos. En el caso de proyectos pequeños o medianos, la rigidez de esta metodología
puede suponer un obstáculo a la hora de generar soluciones centradas en aportar valor al negocio del cliente,
en un entorno que cambia constantemente y donde el deseo de predecir requisitos desde el inicio debe dejar
paso al deseo de adaptarse a los nuevos requisitos de cada momento. Es aquí donde cobran sentido las
metodologías de ágiles de desarrollo software, que surgieron en la década de los 90 con estas premisas básicas:
adaptarse (no predecir) y orientarse a las personas (no a los procesos).
Las metodologías ágiles de desarrollo software tratan un proyecto como un conjunto de proyectos más
pequeños, que se abordan en periodos de tiempo cortos (pocas semanas). Con esto, se consigue un flujo
constante de entregas de software al cliente, con el que se mantiene la comunicación durante todo el ciclo de
vida del proyecto. Esta retroalimentación permite adaptar los objetivos del proyecto constantemente a las
necesidades del negocio del cliente de una manera muy flexible, y sin perder tiempo en la generación de
extensa documentación que acaba quedando obsoleta. Las metodologías ágiles buscan maximizar la ventaja
competitiva de sus clientes por encima del cumplimiento de un proceso rígido de desarrollo de software.
En la siguiente tabla se resumen las diferencias entre el enfoque tradicional “En cascada” y el enfoque ágil del
desarrollo software.

Metodologías tradicionales Metodologías ágiles

Predictivos Adaptativos

Orientados a procesos Orientados a personas

Proceso rígido Proceso flexible

Un proyecto es subdividido en varios


Se concibe como un proyecto
proyectos más pequeños

Poca comunicación con el cliente Comunicación constante con el cliente

Entrega de software al finalizar el


Entregas constantes de software
desarrollo

Documentación extensa Poca documentación

Tabla 1. Comparativa entre metodologías de desarrollo software tradicionales y ágiles [29].

2.2.1 El Manifiesto Ágil


En febrero de 2001 [30], un grupo de diecisiete personas se reunieron en Utah (EEUU) para redactar el
Manifiesto para el desarrollo de software ágil [31], que sentaría las bases de la filosofía de la agilidad aplicada
al desarrollo de software. Ese mismo año, tras la reunión, algunos de los autores originales del manifiesto,
junto con algunas personas adicionales formaron una organización sin ánimo de lucro para difundir
información sobre Agile: la Agile Alliance.
El manifiesto ágil se sustenta en cuatro valores básicos [31]:
• Individuos e interacciones sobre procesos y herramientas.
• Software funcionando sobre documentación extensiva.
• Colaboración con el cliente sobre negociación contractual.
• Respuesta ante el cambio sobre seguir un plan.
Estos valores dan lugar a los doce principios del manifiesto ágil [31]:
• Nuestra mayor prioridad es satisfacer al cliente mediante la entrega temprana y continua de

21
software con valor.
• Aceptamos que los requisitos cambien, incluso en etapas tardías del desarrollo. Los procesos Ágiles
aprovechan el cambio para proporcionar ventaja competitiva al cliente.
• Entregamos software funcional frecuentemente, entre dos semanas y dos meses, con preferencia al
periodo de tiempo más corto posible.
• Los responsables de negocio y los desarrolladores trabajamos juntos de forma cotidiana durante
todo el proyecto.
• Los proyectos se desarrollan en torno a individuos motivados. Hay que darles el entorno y el apoyo
que necesitan, y confiarles la ejecución del trabajo.
• El método más eficiente y efectivo de comunicar información al equipo de desarrollo y entre sus
miembros es la conversación cara a cara.
• El software funcionando es la medida principal de progreso.
• Los procesos Ágiles promueven el desarrollo sostenible. Los promotores, desarrolladores y usuarios
debemos ser capaces de mantener un ritmo constante de forma indefinida.
• La atención continua a la excelencia técnica y al buen diseño mejora la Agilidad.
• La simplicidad, o el arte de maximizar la cantidad de trabajo no realizado, es esencial.
• Las mejores arquitecturas, requisitos y diseños emergen de equipos autoorganizados.
• A intervalos regulares el equipo reflexiona sobre cómo ser más efectivo para a continuación ajustar
y perfeccionar su comportamiento en consecuencia.
En las siguientes secciones se repasarán dos de las metodologías ágiles más extendidas en la actualidad:
SCRUM y XP.

2.2.2 Metodología SCRUM


Scrum es un marco de trabajo a través del cual las personas pueden abordar problemas complejos adaptativos,
a la vez que se entregan productos de forma eficiente y creativa con el máximo valor [32]. Surgió a principios
de los 90 en el ámbito de gestión y desarrollo de productos y hoy en día es ampliamente utilizado en proyectos
de desarrollo software.
Esta metodología parte de la base del empirismo, asegurando que las decisiones se toman en base al
conocimiento, y que este conocimiento se adquiere por la experiencia. Además, se emplea un enfoque iterativo
e incremental que otorga un mayor control sobre el riesgo de un proyecto.
La implementación de procesos empíricos dispone de tres pilares fundamentales:
• Transparencia. Los aspectos significativos del proceso deben ser visibles para todos los
responsables del resultado. Además, la transparencia requiere que estos aspectos sean definidos bajo
un estándar común, para que todos los observadores un criterio único.
• Inspección. Los Artefactos de Scrum (elementos para el registro de información) deben ser
inspeccionados frecuentemente para detectar variaciones indeseadas, de tal forma que se mantenga el
rumbo hacia la aportación de valor con el producto.
• Adaptación. Si se determina que el producto resultante del proceso será inaceptable debido al desvío
de algún aspecto, éste deberá ajustarse cuanto antes para evitar desviaciones mayores.
Los equipos SRUM se caracterizan por ser autoorganizados y multifuncionales, por lo que no necesitan
dirección por parte de personas externas a los mismos. Los equipos están formados por una serie de roles [29]:
• Propietario del producto (Product Owner). Es un rol que sólo puede estar asignado a una persona y
que tiene como responsabilidad convertir las peticiones del cliente en requisitos que se introducen en
la Pila del Producto (Product Backlog). Este rol es el responsable de priorizar los elementos de la Pila

22
del Producto, y que dichos elementos se entienden perfectamente por parte del equipo de desarrollo.
• Equipo de desarrollo. El equipo de desarrollo está compuesto por una serie de profesionales (entre
tres y nueve) que se encargan de realizar el trabajo necesario para completar una iteración del
Producto. En SCRUM todos los componentes del equipo de desarrollo son desarrolladores, es decir,
que no se reconoce título ni jerarquía en los mismos.
• Scrum Master. Este rol se encarga de que el equipo SCRUM utilicen la metodología de la forma
correcta. Debe ser un líder que resuelva conflictos y ayude a la comprensión de los objetivos a
cumplir. El Scrum Master está en contacto directo con el Propietario del producto, el equipo de
desarrollo y la organización.
Además, SCRUM define una serie de artefactos con los que trabaja el equipo para disponer de dirección y
transparencia [29]:
• Pila del producto (Product Backlog). Se trata de una lista de requisitos gestionada por el dueño del
producto. Éste se encarga de crear, actualizar y priorizar la pila del producto a lo largo de toda la
duración del proyecto.
• Pila del Sprint (Sprint Backlog). Es un subconjunto de elementos de la pila del producto que son
seleccionados para su desarrollo a lo largo de un periodo de trabajo (Sprint). El dueño del producto se
encarga de decidir qué elementos deben incluirse en la pila del sprint y el equipo de desarrollo se
encarga de estimar el tiempo que llevará terminar cada elemento. Es posible que, tras dicha
estimación, sea necesario reajustar la pila del Sprint para devolver algún elemento a la pila del
producto o para incluir más elementos (dependiendo de si se estima que el alcance establecido por el
dueño del producto fue demasiado optimista o demasiado pesimista).
• Incremento. Es la suma de todos los elementos de la pila del Sprint que han sido terminados al
finalizar un periodo de trabajo (Sprint). El incremento es, por tanto, la unidad de entrega constante que
se realiza al cliente en la metodología SCRUM.
Para terminar, es necesario comentar la forma en que se organiza un proyecto en el tiempo siguiendo la
metodología SCRUM. Para ello, se define una serie de eventos [32]:
• Sprint. Se trata de un periodo de tiempo durante el cual se trabaja para la consecución de un
incremento del producto, desarrollando los elementos de la pila del Sprint. El producto dispone de una
nueva versión funcional al terminar cada uno de los Sprints del proyecto. Según SCRUM, los Sprints
deben tener una duración máxima de un mes. De esta forma, se garantiza la entrega continua de valor
al cliente.
• Planificación del Sprint. Es una reunión donde todo el equipo SCRUM trabaja en la definición de la
pila del Sprint y la forma en que se conseguirá implementar cada uno de los elementos de la misma.
El dueño del producto indica cuál es el objetivo del Sprint y propone los elementos a incluir en la pila
del Sprint, y el equipo de desarrollo se encarga de desglosar el trabajo necesario para su consecución.
Si el objetivo impuesto implica menos (o más) trabajo del que puede soportar el equipo, se podrá
renegociar con el dueño del producto el alcance final del Sprint. Una vez acordado dicho alcance, no
debe ser modificado durante el Sprint (así se favorece la inspección durante este periodo). La duración
recomendada para esta reunión es de 8 horas para un Sprint de un mes (para Sprints más cortos, se
recomienda asignar el tiempo de manera proporcional).
• Daily Scrum. Se trata de una reunión diaria del equipo de desarrollo de quince minutos, con el fin de
conocer los avances desde la última Daily Scrum, lo que se pretende hacer antes de la siguiente y los
obstáculos que se han presentado. Es importante que esta reunión no se extienda en el tiempo. Si un
integrante del equipo tiene una idea para resolver el problema presentado por otro, deberán tratarlo
después de la reunión para no bloquear el avance del resto del equipo.
• Revisión del Sprint. Esta reunión tiene lugar al finalizar el Sprint, y sirve para inspeccionar el
incremento conseguido y adaptar la pila del producto si fuese necesario. Se demuestra por parte del
equipo de trabajo este incremento y se exponen los problemas surgidos durante el Sprint y cómo
fueron resueltos. Esta reunión favorece la transparencia dentro del equipo SCRUM. Tiene una
duración recomendada de 4 horas para un Sprint de un mes (para Sprints más cortos, se recomienda

23
asignar el tiempo de manera proporcional).
• Retrospectiva del Sprint. Es una reunión que tiene lugar tras la revisión del Sprint y que sirve al
equipo SCRUM para analizar cómo fue el último Sprint en cuanto a personas, relaciones, procesos y
herramientas. Al finalizar la reunión, el equipo debería disponer de un plan para llevar a cabo mejoras
detectadas con este ejercicio y que permitan asegurar la mejora continua de los procesos, propiciando
así la mejora de calidad de los productos. Esta reunión favorece la capacidad de adaptación del equipo
SCRUM. Tiene una duración recomendada de 3 horas para un Sprint de un mes (para Sprints más
cortos, se recomienda asignar el tiempo de manera proporcional).
En la siguiente imagen, se muestra el póster del marco de trabajo SCRUM, donde se resume gran parte de lo
explicado en esta sección.

Figura 19. Resumen gráfico del marco de trabajo SCRUM10.


Los cambios continuos dentro del entorno actual donde se desarrolla la mayoría de proyectos hace que
SCRUM sea idóneo para su aplicación, debido a los tres pilares que lo sustentan (transparencia, inspección y
adaptación). Según una encuesta [33] realizada a unos 40000 profesionales que trabajan con metodologías
ágiles, SCRUM es, de largo, el marco de trabajo predominante en la actualidad.

Figura 20. Metodologías ágiles más utilizadas en mayo de 202011.


Debido a su importancia en la actualidad, el empleo de una metodología ágil como SCRUM para la
organización del trabajo a desarrollar en el TFM podría aportarle un punto diferencial con respecto a las
formas tradicionales.

10 Fuente de la imagen: https://www.scrum.org/resources/scrum-framework-poster


11 Fuente de la imagen: https://stateofagile.com/home

24
2.2.3 Agilidad en este TFM
Con el fin de dar un toque original a este Trabajo Fin de Máster, se ha planteado la organización de su
desarrollo siguiendo la filosofía de las metodologías ágiles. Para ello, tras estudiar el contexto de agilidad, la
forma en que se lleva a cabo en entornos de desarrollo de software y el marco de trabajo que marca tendencia
en la actualidad, se pretende adaptar en la medida de lo posible este enfoque al desarrollo del proyecto. Para
ello, cada objetivo de los planteados al inicio se tratará como un elemento de la pila del producto que se
pretende evolucionar. Así, a través de varios Sprints de trabajo se irá incrementando el valor entregado por el
producto. Al finalizar cada Sprint, se podrá demostrar el incremento conseguido (objetivo del TFM) y
reflexionar sobre el trabajo realizado. Evidentemente, no podrá aplicarse SCRUM al 100%, principalmente
porque el equipo SCRUM al completo está representado por una sola persona: el autor del TFM.

25
26
3 ESTADO ANTERIOR DEL PROYECTO

You know the problem with people who run tech companies? They have too much power!
Jamie. Devs

E
n este capítulo se introduce el trabajo realizado con anterioridad sobre la línea de contribución en la que
se desarrolla el presente TFM. En concreto, se pretende dar a conocer la aplicación de mensajería
desarrollada por Domingo Fernández Píriz en su Trabajo Fin de Grado [9]. Así, el lector podrá tener
claro el producto que se pretende evolucionar con el desarrollo de este Trabajo Fin de Máster.

3.1 P2P Messenger


La aplicación desarrollada por Domingo parte de la necesidad de disponer de un medio de comunicación
electrónico que no dependa de un servidor centralizado para su funcionamiento. La motivación principal de
esta idea es la de otorgar privacidad a los usuarios en sus conversaciones, cifrando los mensajes enviados
mediante claves simétricas que sólo podrán ser desencriptados en el destino final del mensaje. Como se puede
ver en la siguiente figura, las dos aplicaciones de mensajería que concentran más del 50% del total de usuarios
activos en este ámbito pertenecen a un solo proveedor (Facebook).

Figura 21. Usuarios activos de las aplicaciones de mensajería más utilizadas en octubre 202012.

12 Fuente de la imagen: https://www.statista.com/statistics/258749/most-popular-global-mobile-messenger-apps/

27
Las aplicaciones que aparecen en la figura anterior funcionan bajo el paradigma cliente-servidor. Según la
información proporcionada por las webs de Whatsapp13, Facebook Messenger14, WeChat15 y Telegram16, los
mensajes viajan encriptados. En Whatsapp, los mensajes son cifrados extremo a extremo por defecto. En
Facebook Messenger y Telegram, el cifrado extremo a extremo no es activado por defecto, sino que el usuario
debe iniciar un “Chat secreto” explícitamente. En WeChat no se dispone de cifrado extremo a extremo.
Cuando no se utiliza el cifrado extremo a extremo, los mensajes son encriptados dos veces: una entre el origen
y el servidor central y otra entre el servidor central y el destino del mensaje. Así, el propietario de las
aplicaciones tiene una visión clara de los mensajes que circulan entre sus usuarios, pudiendo explotar esta
información con fines comerciales o políticos. De Snapchat y QQ no se ha encontrado información sobre
cifrado de mensajes en sus respectivos espacios web, lo cual hace sospechar que ni siquiera es materia de
interés la seguridad de los mensajes de más de 1000 millones de usuarios.

3.1.1 Objetivos
Los objetivos que se pretendían cubrir con el desarrollo de la aplicación P2P Messenger eran los siguientes:
• Diseño y desarrollo de una aplicación de mensajería distribuida basada en el paradigma de conexión
P2P.
• Permitir la funcionalidad de mensajería a un destinatario o a varios (a través de grupos de difusión).
• Implementación de una vista de escritorio y una vista móvil (Android).
• Securización del contenido de los mensajes transmitidos.
• Probar el rendimiento conseguido por la aplicación.

3.2 Marco tecnológico


Para el desarrollo de la aplicación P2P Messenger, se tuvo que realizar un estudio previo del marco
tecnológico a utilizar para la consecución de los objetivos propuestos. A continuación, se exponen los distintos
ámbitos tecnológicos de los que dependía el desarrollo del TFG y las decisiones tomadas al respecto:
• Tecnología P2P. Con el objetivo de realizar una aplicación de mensajería distribuida, surge el
planteamiento de las redes P2P como tecnología subyacente para el almacenamiento y
encaminamiento de mensajes. Para abordar de manera fiable el envío de mensajes, las redes P2P
estructuradas aportan unas mejores características, haciendo uso de tablas de encaminamiento
distribuidas que hacen responsable a todos los nodos de la red de un fragmento de la misma. En
concreto, para este TFG se utiliza la red Pastry a través de su implementación de código libre
Freepastry.
• Sistemas Operativos. Como se pretende implementar una vista para escritorio y una vista para
dispositivos móviles, y como los recursos disponibles para la realización de un trabajo académico del
estilo de un TFG o TFM son limitados, es necesario buscar la opción más viable bajo los recursos
disponibles. Teniendo en cuenta que se disponía de terminal Android y que las aplicaciones de este
Sistema Operativo móvil son desarrolladas en Java (lo cual elimina la dependencia de un Sistema
Operativo de escritorio), se decide utilizar este Sistema Operativo móvil. Como se ha comentado,
cualquier Sistema Operativo de escritorio podrá ejecutar la aplicación siempre y cuando disponga de
una JVM (Java Virtual Machine) con la versión Java mínima necesaria.
• Lenguaje de programación. El lenguaje de programación utilizado fue Java, por requisito de
compatibilidad con el Sistema Operativo Android y por su validez para cualquier tipo de Sistema
Operativo de escritorio.

13 https://faq.whatsapp.com/general/security-and-privacy/end-to-end-encryption/?lang=es
14 https://www.facebook.com/help/messenger-app/1084673321594605
15https://help.wechat.com/cgi-

bin/micromsgbin/oshelpcenter?opcode=2&plat=1&lang=en&id=1208117b2mai1410243yyQFZ&Channel=helpcenter
16 https://telegram.org/faq#p-como-cifran-los-datos

28
• Criptografía. Para proporcionar seguridad a los mensajes transmitidos a través de la aplicación, éstos
son cifrados utilizando el algoritmo de cifrado mediante claves simétricas AES17. De esta forma,
ambos extremos utilizan la misma clave para encriptar y desencriptar, y deben acordarla al inicio del
establecimiento de la comunicación.
• Base de datos. Para el almacenamiento de información local (descrita en la siguiente sección) se
utiliza una base de datos SQLite, que es la librería utilizada en Android para el almacenamiento local
de datos de una aplicación. En la versión de escritorio, se dispone del driver SQLite JDBC18.
• Paradigma de desarrollo software. Para el desarrollo de la aplicación, se siguió el patrón MVC
(Modelo-Vista-Controlador). Este patrón de arquitectura software es ampliamente utilizado en la
actualidad y permite separar la lógica de negocio (modelo) de su representación ante el usuario (vista).
Para la comunicación entre el modelo y la vista (peticiones de información, actualización de datos,
etc) entra en juego un sistema que gestiona los eventos relativos a estas comunicaciones (controlador)
y permite entregar las funcionalidades definidas de la aplicación.
Una vez conocido el entorno tecnológico utilizado para el desarrollo del trabajo anterior al presente TFM, se
expondrá de forma ilustrativa el diseño de la misma.

3.3 Diseño según el patrón MVC (Modelo-Vista-Controlador)


Como se ha comentado en la sección anterior, la aplicación P2PMessenger desarrollada por Domingo
Fernández Píriz utiliza el patrón MVC (Modelo-Vista-Controlador) para el desarrollo de la misma. Así,
consigue separar modularmente el desarrollo de los distintos componentes y se favorece el mantenimiento de
los mismos ante evoluciones futuras. La vista sirve como interfaz funcional para el usuario y, a través del
controlador, puede interactuar con el modelo para extraer información solicitada o para actualizar los datos
almacenados en el mismo. A continuación, se muestran los aspectos más importantes de cada componente en
la aplicación P2PMessenger:
• Modelo. Está constituido por el sistema gestor de base de datos (SQLite), cuyo fin es proporcionar
almacenamiento seguro, persistente y ordenado de la información manejada por la aplicación. Los
tipos de datos utilizados son los siguientes:
o ID. Representa un identificador de Pastry. Sirve para identificar los nodos dentro de la red,
así como los objetos almacenados en la misma.
o Usuario. Representa a un usuario de la aplicación, que puede enviar y recibir mensajes a sus
contactos y grupos guardados. Las credenciales de un usuario son almacenadas de forma
local.
o Contacto. Representa un usuario conocido de la red. Este objeto permite asignar un alias al
identificador Pastry de un determinado usuario, mejorando la usabilidad de la aplicación. No
es lo mismo identificar una conversación con “Paco compañero Máster” que con
“AD445AB112D390FD125602EC6C7A8D99”.
o Grupo. Representa un canal de difusión de mensajes que es recibido por todos los usuarios
que se suscriben a dicho grupo.
o Conversación. Representa una comunicación abierta con otro usuario o con un grupo.
Permite recuperar los mensajes de dicha comunicación, en el orden correcto.
o Mensaje. Es el tipo de dato que almacena la información enviada por los distintos usuarios
de la red. Se definen mensajes de comunicación individual, comunicación de grupo y de
control.
o Mensaje cifrado. Objeto que encapsula un mensaje cifrado con una clave simétrica acordada
entre los intervinientes de la conversación.

17 Publicación original del estándar: https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.197.pdf


18 Repositorio de SQLite JDBC Driver: https://github.com/xerial/sqlite-jdbc

29
o Direcciones de arranque. Sirve para almacenar información de nodos conocidos dentro de
la red Pastry para realizar la unión a la misma.
En la siguiente figura se muestra el esquema de base de datos local utilizado dentro de la aplicación.

Figura 22. Esquema de la base de datos utilizada en la aplicación P2PMessenger [9].


• Vista. La vista permite al usuario interactuar con la aplicación, accediendo a sus conversaciones,
agenda de contactos y ordenando el envío de mensajes. Se dispone de una vista con interfaz gráfica
para la versión Android y una vista basada en línea de comandos para la versión de escritorio. Esta
última, aunque cumple los requisitos funcionales, presenta problemas de Experiencia de Usuario, por
la dificultad de acceso a las distintas funcionalidades. Ambas vistas comparten a grandes rasgos los
estados disponibles. En la siguiente figura se muestra la máquina de estados y sus transiciones en la
versión Android. La versión de escritorio tiene estados similares, aunque las clases que se utilizan
tengan distinto nombre.

Figura 23. Máquina de estados de la vista de P2PMessenger [9].


A modo ilustrativo, se muestra en la siguiente figura la interfaz para la versión Android de tres de las
principales funcionalidades de la aplicación (acceso, listado de contactos y conversación).

30
Figura 24. Vista Android para registrar un nuevo usuario (izquierda), mostrar lista de contactos (centro) y
mostrar conversación (derecha) [9].
Además, se muestra también a modo ilustrativo el aspecto de la vista en modo consola de comandos.
En la siguiente figura se muestran las vistas disponibles para seleccionar las funcionalidades a utilizar.

Figura 25. Vista del modo consola para el menú principal (arriba) y el menú de funcionalidades del modo
conversación (abajo) [9].
Por último, para tener una visión de los problemas de usabilidad derivados de una vista en modo
consola de comandos, se muestra en la siguiente figura la interacción necesaria para abrir una
conversación y enviar un mensaje a la misma (interacciones pulsando opciones de menú e
introduciendo información mediante teclado).

Figura 26. Interacciones necesarias a través de la vista de consola de P2PMessenger para abrir una
conversación y enviar un mensaje a la misma [9].
De esta pequeña demostración se entiende necesaria la implementación de una interfaz gráfica para la
versión de escritorio, que de hecho es uno de los objetivos del presente TFM.
• Controlador. El controlador de la aplicación P2PMessenger dispone de una máquina de estados
sencilla y unas transiciones que tienen lugar conforme el usuario interactúa con la aplicación a

31
través de la vista. El controlador arranca en un estado “MODO_APAGADO” donde se comprueba
si hay direcciones de arranque disponibles (direcciones de nodos conocidos de la red Pastry). En
caso de existir estas direcciones, podrá pasar al estado “MODO_INICIO_SESIÓN”, desde el cual
podrá registrarse un nuevo usuario en la red (comprobando si existe previamente en la red), a través
del estado “MODO_REGISTRO” o acceder a las funcionalidades de mensajería para un usuario
concreto, a través del estado “MODO_SESION_INICIADA”. En caso de no disponer de dirección
de arranque, del estado “MODO_APAGADO” se pasará al estado
“MODO_NECESARIA_DIRECCIÓN” donde permanecerá hasta que el usuario introduzca la
dirección de un nodo conocido de la red Pastry, en la forma IP:puerto. En la siguiente imagen se
muestra el diagrama de estados del controlador.

Figura 27. Diagrama de estados del controlador de la aplicación P2PMessenger [9].


En cuanto a las funcionalidades de mensajería disponibles en el estado
“MODO_SESION_INICIADA” se distingue entre:
o Mensajería entre usuarios. Para que dos usuarios puedan comunicarse entre ellos, primero
deben conocerse mutuamente (agregándose como contactos a través del nombre de usuario
registrado en la red). Una vez cumplido este requisito, el nodo origen sólo tiene que encontrar
el ID asociado al nombre del usuario destino y enviar los mensajes que serán encaminados a
través de la red Pastry. Los mensajes son cifrados con una clave de sesión que es establecida
antes de iniciar la conversación. Cada nodo genera un certificado propio, que sirve para
encriptar la clave simétrica en el nodo destino, asegurando así que no puede ser
comprometida. En el siguiente diagrama se muestra el paso de mensajes entre usuarios que
establecen una conversación.

Figura 28. Diagrama de paso de mensajes en establecimiento de conversación en P2PMessenger [9].

32
o Mensajería entre grupos. Para esta funcionalidad se utiliza Scribe [34], un sistema
implementado por los mismos desarrolladores de FreePastry que permite la comunicación de
grupos a través de suscripción y la generación de eventos en una red Pastry. Para utilizar
Scribe es necesario que un usuario se suscriba a un canal de difusión. En la aplicación
desarrollada en el TFG de Domingo Fernández Píriz, se utiliza el ID del grupo como
identificador del canal. Cada grupo dispone de una clave de cifrado, que es necesario conocer
para enviar y recibir mensajes a través del canal de difusión. Para obtener la clave de cifrado
de un grupo, es necesario recibir un código de invitación por parte de un usuario conocido y
que ya pertenezca a dicho grupo. Cuando un nodo recibe un mensaje de petición de unión al
grupo, debe comprobar que el código es válido antes de enviar la clave del grupo al nuevo
integrante. Este intercambio también es seguro, utilizando el mecanismo de mensajería entre
usuarios. En el siguiente diagrama se muestra el paso de mensajes para la inclusión en un
grupo.

Figura 29. Diagrama de paso de mensajes para unión a un grupo en aplicación P2PMessenger [9].

Figura 30. Flujo de recuperación de mensajes importantes de un grupo


o Mensajes importantes. Una característica diferenciadora de la aplicación, es que permite el
envío de mensajes importantes a un grupo. Estos mensajes importantes son almacenados en
la red Pastry utilizando el algoritmo de BlockChain y, por tanto, pueden ser recuperados por
33
un usuario del grupo aunque se enviase cuando estaba desconectado. La recuperación de
mensajes importantes puede hacerse a partir del identificador del grupo o a partir del
identificador de un bloque. Cada bloque tiene una referencia al bloque anterior y al siguiente,
lo cual permite avanzar en la cadena de bloques para extraer todos los mensajes importantes
enviados. En la Figura 30 se muestra el diagrama de flujo de recuperación de mensajes
importantes.
Tras mostrar el diseño de la aplicación siguiendo el patrón MVC, en la siguiente sección se expondrán los
resultados publicados en el TFG relativo a la aplicación desarrollada con anterioridad en la línea de
contribución del presente TFM.

3.4 Resultados
Para poner a prueba el desarrollo realizado, en el TFG de Domingo Fernández Píriz se utilizan varios
escenarios:
• Escenario local escritorio. Se lleva a cabo la verificación de todas las funcionalidades de la
aplicación utilizando la vista de consola, en el PC utilizado para desarrollo. Este escenario no se utiliza
para extraer resultados de rendimiento, sino para comprobar que la aplicación funciona como se
espera.
• Escenario local Android. De forma análoga al anterior escenario, se lleva a cabo la verificación de
todas las funcionalidades de la aplicación utilizando la vista de Android, en el terminal disponible por
el desarrollador de la aplicación. Este escenario no se utiliza para extraer resultados de rendimiento,
sino para comprobar que la aplicación funciona como se espera.
• Escenario en la nube. Se crean dos redes privada en la plataforma Google Cloud Platform, con 8
instancias de máquinas CentOS7 en una y 8 instancias Debian Jessie en la otra. Todas las máquinas
tienen visión directa sin necesidad de NAT. Este escenario permite simular el comportamiento de la
aplicación en un entorno cercano a la realidad.
• Integración versión Android – versión Consola. Este último escenario permite comprobar que la
aplicación funciona correctamente cuando los nodos que participan en la red P2P utilizan tanto la
versión de la vista de Consola como la versión de la vista de Android. Se utilizan 3 Smartphones
distintos y el PC utilizado para el desarrollo.
Como resultados de rendimiento, en el TFG se expone lo siguiente:
• Relativo al tiempo de inicio de la aplicación. Se cronometra el tiempo necesario en ambas versiones
desde que se abre la aplicación hasta que el usuario puede realizar alguna opción. En la siguiente tabla
se anotan estos resultados. Se aprecia un rendimiento mejor en la versión de escritorio.

Versión analizada Tiempo medio (s) Tiempo máximo (s) Tiempo mínimo (s)

Android 8.3 20.8 3

Consola 3.2 9.7 1.1

Tabla 2. Rendimiento de inicio de la aplicación P2P Messenger en una muestra de 30 inicios [9].
• Relativo al retardo entre envío y recepción de mensajes. Se lleva a cabo el envío de 10700 mensajes
de eco y su respuesta a través de la aplicación, utilizando primero el escenario en la nube (mensaje
entre dos de las instancias) y entre un smartphone Android y el PC utilizado para el desarrollo (ambos
en una misma red Wifi). En las gráficas de la siguiente figura se observa la distribución de los
paquetes para un determinado retraso (en ms) para ambos escenarios. El escenario donde se utilizan
las instancias en la nube obtiene mejores resultados, aunque hay que tener en cuenta que son más
nodos en la red y que el segundo escenario tiene una conexión Wifi (mayores retardos de por sí).

34
Figura 31. Distribución del retardo de 10700 mensajes de eco entre dos instancias de máquinas en la nube
(arriba) y entre una instancia Android y otra de escritorio en una misma red Wifi (abajo) [9].

3.4.1 Líneas de mejora identificadas


Tras llevar a cabo el desarrollo de la aplicación, su prueba y análisis una vez puesta en funcionamiento, se
extraen las conclusiones pertinentes a la evolución de la misma. A continuación, se muestran las líneas de
mejora que fueron identificadas en el TFG de Domingo Fernández Píriz y que se han tomado como referencia
a la hora de llevar a cabo el planteamiento de los objetivos del presente TFM:
• Inclusión de la funcionalidad de compartición de ficheros además de texto plano en la aplicación. Es
necesario tener en cuenta que el almacenamiento de ficheros de gran tamaño en la red Pastry puede
provocar problemas de rendimiento en la misma.
• Pruebas de rendimiento con mayor número de usuarios y en entornos de red con latencia y pérdida de
paquetes similares al mundo real.
• Aunque el contenido de los mensajes está cifrado, las comunicaciones a nivel de transporte no lo
están, utilizándose paquetes en TCP/UDP sin cifrar. Sería conveniente utilizar protocolos de cifrado
de esta capa como SSL/TLS.
• Implementación de una vista gráfica para la versión de escritorio. Como se ha comentado, una
aplicación de mensajería que funciona a través de una consola de comandos puede resultar poco
intuitiva y su usabilidad puede ser de una complejidad alta para usuarios que no estén habituados a
este entorno.
Tras conocer el trabajo realizado con anterioridad en la línea de contribución en la que se desarrolla este TFM,
es hora de exponer el trabajo desarrollado para la consecución de los objetivos definidos. En el siguiente
capítulo, a través de varias secciones, se desglosa el análisis y desarrollo realizado para cada objetivo. Cada
sección se corresponde con un Sprint de SCRUM donde se genera un incremento sobre la funcionalidad del
producto representado por la aplicación P2P Messenger mostrada en este capítulo. Así, se verá la evolución del
valor aportado por el producto en iteraciones ágiles del mismo.

35
36
4 TRABAJO REALIZADO

It’s not magic, it’s talent and sweat.


Bertram Gilfoyle. Silicon Valley.

E
n este capítulo se mostrará el trabajo realizado para cumplir cada uno de los objetivos propuestos del
presente Trabajo Fin de Máster. Como se comentó en el capítulo de introducción, se ha seguido el
marco de trabajo SCRUM para acometer el desarrollo del trabajo. Se dará comienzo al capítulo
mostrando la pila del producto, con los objetivos descritos como Historias de Usuario. Las Historias de
Usuario son utilizadas en las metodologías ágiles para describir brevemente requisitos funcionales desde el
punto de vista de quien lo necesita. Normalmente, una Historia de Usuario consta de una frase que comienza
presentando al usuario que reclama el requisito (“Como dueño del producto,...”) seguido de la funcionalidad
que necesita (quiero disponer de una interfaz gráfica) y finalizando con la justificación de valor que aporta
dicha funcionalidad (para que las funcionalidades de la aplicación de escritorio sean más accesibles). Una vez
planteada la pila del producto, cada Historia de Usuario será desarrollada en un Sprint de trabajo. Cada Sprint
comenzará con la planificación del Sprint, donde se realizará un esfuerzo de análisis para descomponer la
Historia de Usuario en una secuencia de tareas con un esfuerzo estimado, expresado en horas. Después, se
realizarán las tareas durante el Sprint y se presentarán finalmente los resultados a modo de revisión del Sprint,
para demostrar el incremento de valor conseguido para el producto. De esta forma, se pretende afrontar el
trabajo académico con un enfoque propio del mundo laboral actual, para salvar la distancia que suele haber
entre estos ámbitos (el académico y el profesional).

4.1 Pila del Producto


La pila del producto representa la lista de requisitos que gestiona el dueño del producto y que suponen un
incremento en el valor funcional del mismo. En este Trabajo Fin de Máster, se parte de 4 objetivos que deben
ser adaptados para su inclusión en la pila del producto. Esta adaptación consiste en la redacción de cada
objetivo como una Historia de Usuario. Así, se asegura que el valor representado por cada objetivo es
claramente entendible por el equipo de desarrollo, que será el encargado de realizar el trabajo necesario para
conseguir el incremento del producto que contenga esta funcionalidad. Las Historias de Usuario estarán
compuestas por un título identificativo y una descripción que seguirá el siguiente patrón:

“𝐂𝐨𝐦𝐨 𝑟𝑜𝑙 𝑑𝑒𝑙 𝑠𝑜𝑙𝑖𝑐𝑖𝑡𝑎𝑛𝑡𝑒, 𝐪𝐮𝐢𝐞𝐫𝐨 𝑓𝑢𝑛𝑐𝑖𝑜𝑛𝑎𝑙𝑖𝑑𝑎𝑑 𝑟𝑒𝑞𝑢𝑒𝑟𝑖𝑑𝑎 𝐩𝐚𝐫𝐚 𝑣𝑎𝑙𝑜𝑟 𝑎𝑝𝑜𝑟𝑡𝑎𝑑𝑜 𝑝𝑜𝑟 𝑙𝑎 𝑓𝑢𝑛𝑐𝑖𝑜𝑛𝑎𝑙𝑖𝑑𝑎𝑑”

37
Haciendo uso de estos criterios, se lleva a cabo la definición de las Historias de Usuario que componen la pila
del producto:
1. Implementación de una interfaz gráfica: “Como dueño del producto, quiero disponer de una
interfaz gráfica en la aplicación de escritorio para que sus funcionalidades sean más accesibles”.
2. Compartición de ficheros: “Como dueño del producto, quiero enviar y recibir archivos para disponer
de compartición multimedia en la aplicación”.
3. Comunicación de nodos en redes con NAT: “Como dueño del producto, quiero utilizar la aplicación
desde una red con NAT para que la configuración de red no restrinja mi uso de la aplicación”.
4. Seguridad en canal de comunicación entre pares: “Como dueño del producto, quiero que se cifre el
canal de comunicación entre nodos de la red para que no pueda interceptarse ni controlarse mi
actividad en la aplicación”.
Una práctica común para que las Historias de Usuario sean compactas y claras, es utilizar como espacio
máximo un Post-it. En la siguiente figura se representa la pila del producto siguiendo esta práctica.

Figura 32. Representación gráfica de la pila del producto.


En las siguientes secciones del capítulo, se expondrá el trabajo realizado a lo largo de los 4 Sprints en los que
se ha dividido el desarrollo, uno para abordar cada Historia de Usuario.

4.2 Sprint 1. Implementación de una interfaz gráfica


En esta sección se detalla el trabajo realizado durante el primer Sprint de evolución del producto para
conseguir un incremento que permita acceder a las funcionalidades de la versión de escritorio a través de una
interfaz gráfica. El contenido de la sección se divide, para facilitar la lectura, en subsecciones. Se define en
primera instancia la Historia de Usuario que se incluye en la pila del Sprint. Después, se muestra la tecnología
implicada en el trabajo del equipo de desarrollo. En la siguiente subsección se muestra la planificación del
Sprint, seguida del desarrollo del mismo (mostrando el detalle de las tareas realizadas). La última subsección
está dedicada a la sesión de revisión del Sprint, para comprobar el incremento conseguido sobre el producto.

38
4.2.1 Definición de la Historia de Usuario
El primer objetivo es introducido en la pila del producto como la siguiente Historia de Usuario:

𝐈𝐌𝐏𝐋𝐄𝐌𝐄𝐍𝐓𝐀𝐂𝐈Ó𝐍 𝐃𝐄 𝐔𝐍𝐀 𝐈𝐍𝐓𝐄𝐑𝐅𝐀𝐙 𝐆𝐑Á𝐅𝐈𝐂𝐀

“𝐂𝐨𝐦𝐨 𝑑𝑢𝑒ñ𝑜 𝑑𝑒𝑙 𝑝𝑟𝑜𝑑𝑢𝑐𝑡𝑜,


𝐪𝐮𝐢𝐞𝐫𝐨 𝑑𝑖𝑠𝑝𝑜𝑛𝑒𝑟 𝑑𝑒 𝑢𝑛𝑎 𝑖𝑛𝑡𝑒𝑟𝑓𝑎𝑧 𝑔𝑟á𝑓𝑖𝑐𝑎 𝑒𝑛 𝑙𝑎 𝑎𝑝𝑙𝑖𝑐𝑎𝑐𝑖ó𝑛 𝑑𝑒 𝑒𝑠𝑐𝑟𝑖𝑡𝑜𝑟𝑖𝑜
𝐩𝐚𝐫𝐚 𝑞𝑢𝑒 𝑠𝑢𝑠 𝑓𝑢𝑛𝑐𝑖𝑜𝑛𝑎𝑙𝑖𝑑𝑎𝑑𝑒𝑠 𝑠𝑒𝑎𝑛 𝑚á𝑠 𝑎𝑐𝑐𝑒𝑠𝑖𝑏𝑙𝑒𝑠”

Tabla 3. Definición de la Historia de Usuario relativa al Objetivo 1


De esta forma, se traslada al equipo de desarrollo de forma clara y concisa el requisito funcional que tendrá
que implementar, esto es, proporcionar una interfaz para interactuar de forma gráfica con la aplicación, y el
valor que aportará al producto una vez logrado el incremento al finalizar el Sprint, esto es, conseguir una mejor
accesibilidad de las funcionalidades y, por consiguiente, mejorar la experiencia de usuario percibida con el uso
de la aplicación. Una forma empírica de comprobar el incremento de accesibilidad de la aplicación es
midiendo el número de interacciones necesarias por parte del usuario para llevar a cabo una determinada
acción (como enviar un mensaje a un nuevo contacto). Además, las interfaces gráficas, por su propia
naturaleza, mejoran la experiencia del usuario medio en materia de accesibilidad y usabilidad, ya que es más
fácil recordar un gesto (hacer clic en un botón) que recordar un comando o una secuencia de opciones de
menú.

4.2.2 Tecnología implicada


Los elementos tecnológicos a tener en cuenta para entender la fase de desarrollo del Sprint son:
• JavaFX. Para la creación de una aplicación gráfica en Java.
• Microsoft Powerpoint. Para la creación de prototipos de interfaz gráfica y diagramas de flujo.
• Tecnologías de desarrollo web. HTML, CSS y Javascript son utilizados para la creación de la
interfaz gráfica con la que interactúa el usuario.
• Bootstrap. Librería para facilitar el diseño web.
• Fontawesome. Librería de iconos para una mejor renderización de los mismos y una reducción del
tamaño de los recursos para mostrar en la interfaz gráfica.
En las siguientes subsecciones se detalla la tecnología implicada en este Sprint.

4.2.2.1 JavaFX

Para la implementación de una interfaz gráfica de la versión de escritorio es necesario


utilizar alguna librería que ofrezca los medios para manejar gráficos dentro de la
aplicación. Debido a que la implementación inicial está escrita en lenguaje Java, lo más
conveniente será buscar alguna librería que garantice la compatibilidad necesaria para cubrir los requisitos del
proyecto. La librería escogida ha sido JavaFX. JavaFX es propiedad de Oracle y ofrece un conjunto de
paquetes de gráficos y medios que permiten diseñar, crear y probar aplicaciones de cliente enriquecido en
diversas plataformas. Aunque los controles y el diseño de la vista han sido finalmente realizados con
tecnología web (HTML,CSS y JS), mediante esta librería se ha creado la aplicación gráfica base, y se ha
dotado de un conector entre vista y controlador.

4.2.2.2 Microsoft Powerpoint

Powerpoint es una herramienta de creación de presentaciones, propiedad de Microsoft. Es parte del


paquete de herramientas ofimáticas Microsoft Office, que incluye herramientas tan conocidas como
el procesador de textos Microsoft Word o el procesador de hojas de cálculo Microsoft Excel. En este
proyecto, además de para crear la presentación de la defensa del mismo, Powerpoint será utilizado tanto para

39
la creación de prototipos de interfaz gráfica como para la realización de esquemas conceptuales y de
escenarios de pruebas.

4.2.2.3 HTML

HTML (HyperText Markup Language) es el lenguaje de etiquetas utilizado para el desarrollo de


páginas web. Es un estándar del World Wide Web Consortium (W3C)19 que permite estructurar el
contenido de un documento web para su posterior interpretación por parte de un navegador web,
que lo mostrará de forma gráfica al usuario. Aunque la primera especificación de este estándar se
lanzó en 1992, está en constante evolución debido al auge actual de las aplicaciones web. Esto se
debe a que el único requisito que debe cumplir un usuario para acceder a este tipo de aplicaciones es disponer
de un navegador web actualizado, evitando así dependencias de Sistema Operativo, Hardware, etc. En este
proyecto, la estructura de la interfaz gráfica y el diseño de los distintos componentes que formarán parte de ella
se han desarrollado utilizando el lenguaje HTML.

4.2.2.4 CSS

CSS (Cascading Style Sheets) es el lenguaje que se utiliza para definir el estilo de presentación que
tendrá el contenido de un documento escrito con lenguaje de etiquetas (como HTML) y es un
estándar perteneciente al W3C20. Es ampliamente utilizado para el diseño de la apariencia de
documentos web. Mientras que con HTML se define la estructura y los componentes que forman
parte de la página web, con CSS se aplican los estilos visuales para personalizarla. Además, CSS
permite el desarrollo web adaptativo, crítico en la actualidad debido al amplio abanico de dispositivos con
acceso a aplicaciones web. De esta forma, CSS permite la correcta visualización de una aplicación
independientemente del tamaño de la pantalla, adaptando el tamaño y la ubicación de los distintos
componentes en función de este. En este proyecto, CSS es utilizado para el diseño de los estilos visuales de la
interfaz gráfica y su correcta adaptación a distintos tipos de pantalla.

4.2.2.5 Javascript

Javascript es un lenguaje de programación interpretado y orientado a objetos que ha sido


ampliamente utilizado para el desarrollo de scripts para páginas web, ejecutados en el lado del
cliente. Esto, junto con su ligereza, permite llevar a cabo determinadas acciones sin necesidad de
realizar peticiones al servidor web. Un ejemplo claro es la validación de un formulario, donde
puede comprobarse de forma prácticamente instantánea si los campos se han rellenado
correctamente antes de enviar la petición al servidor, optimizando los recursos de este y dotando a las
aplicaciones de una mejor experiencia de usuario. En la actualidad, Javascript también es utilizado en el lado
servidor para la implementación de APIs y aplicaciones web fácilmente escalables. En este proyecto,
Javascript es utilizado en la vista para hacer comprobaciones de formularios, implementar navegación entre
componentes (como la apertura de la agenda de contactos) y disponer de un conector para la comunicación de
la vista con el controlador.

4.2.2.6 Bootstrap

Bootstrap21 es una librería CSS de código abierto que sirve como marco de trabajo para el diseño de
páginas web. Facilita en gran medida la maquetación de una página web y permite al desarrollador
obtener un diseño adaptativo y limpio mediante la agregación de determinadas clases a los
componentes HTML de la página web. En este proyecto, se utiliza Bootstrap como marco de trabajo para
conseguir una interfaz limpia y adaptativa para la aplicación de escritorio.

19 https://www.w3.org/html/
20 https://www.w3.org/Style/CSS/
21 https://getbootstrap.com/

40
4.2.2.7 Fontawesome

Font Awesome22 es una librería de iconos vectoriales de licencia libre, basada en CSS,
para su uso en páginas web. Los iconos son introducidos mediante un elemento HTML
(<i>, etiqueta para modificar el estilo de texto a cursiva) a los que se le aplica una
determinada clase de CSS (que identifica el icono a mostrar). De esta forma, se reduce el
tiempo de carga de la página web, ya que los iconos vectoriales se renderizan y no tienen
que ser descargados del servidor. En este proyecto, se utiliza Font Awesome para los distintos iconos
utilizados en la vista de la interfaz gráfica.

4.2.3 Planificación del Sprint


La Historia de Usuario planteada hace referencia a la necesidad de permitir la interacción con la aplicación a
través de una interfaz gráfica, de tal forma que las distintas funcionalidades no sean accesibles a través de un
menú de consola sino a través de controles gráficos (tales como botones, formularios, etc). Para ello, en primer
lugar, será necesario estudiar las alternativas disponibles en cuanto a tecnologías de desarrollo de interfaces
gráficas en aplicaciones Java. Después, de forma justificada, se deberá establecer una de las alternativas
estudiadas para llevar a cabo el desarrollo. Antes de llevar a cabo la implementación de la interfaz con la
alternativa seleccionada, para actuar de la forma más próxima a un escenario profesional real, será conveniente
realizar un prototipo de la misma, que deberá ser aceptado por el dueño del producto en consonancia con las
expectativas del cliente. Una vez establecidas las expectativas mediante el prototipo, comenzarán los trabajos
de implementación que contemplarán tanto desarrollo front-end (es decir, de la vista) como back-end (es decir,
del controlador y/o del modelo). Por último, deberá comprobarse el cumplimiento de expectativas en cuanto a
funcionalidad mediante pruebas de validación. A continuación, se muestra el desglose de tareas en forma de
tabla, incluyendo el esfuerzo estimado por el equipo para el desarrollo de las mismas.

Tarea Esfuerzo estimado (horas)

Estudiar alternativas para GUI en aplicación Java 7

Establecer alternativa escogida 3

Realizar prototipo de la vista 12

Desarrollar el front-end necesario para GUI 24

Desarrollar el back-end necesario para GUI 24

Realizar pruebas de validación 12

Tabla 4. Estimación de tareas para la Historia de Usuario relativa al Objetivo 1

4.2.4 Desarrollo del Sprint


En esta sección se pretende exponer el trabajo realizado durante el Sprint para conseguir el incremento de
valor en el producto a través de la funcionalidad descrita en la Historia de Usuario incluida en la pila del
Sprint. Para ello, se dedicará una subsección por cada tarea realizada.

4.2.4.1 Tarea: Estudiar alternativas para GUI en aplicación Java

El objetivo de esta tarea es realizar un análisis de las alternativas disponibles para implementar una interfaz
gráfica para la vista de la versión de escritorio. En primer lugar, lo que se tiene en cuenta es el lenguaje de
programación utilizado en la aplicación: Java. Lo ideal, por tanto, será buscar alternativas de desarrollo que
permitan esta compatibilidad. En este aspecto, se contemplan tres alternativas:

22 https://fontawesome.com/

41
• Abstract Window Toolkit (AWT)23. Se trata del primer conjunto de herramientas estándar de Java
para la implementación de interfaces visuales para aplicaciones Java. Su última versión salió en 2002,
y se abandonó su desarrollo por problemas de portabilidad entre Sistemas Operativos, al utilizar
controles nativos del Sistema Operativo donde se desarrolla una aplicación concreta. Teniendo en
cuenta que uno de los fundamentos de Java es la independencia de la plataforma que ejecuta un
programa, el hecho de que su librería de elementos gráficos no permita ejecutar una aplicación en
cualquier plataforma con una máquina virtual Java instalada justifica la búsqueda de una alternativa
por parte de la compañía. Además, por la antigüedad de la librería, el aspecto de sus interfaces no
tiene nada que ver con los cánones actuales. En la siguiente figura se puede observar la brecha que
separa una interfaz implementada con AWT y una interfaz de una aplicación actual.

Figura 33. Comparación de aspecto de una interfaz gráfica de Java AWT (izquierda) con una interfaz gráfica
de una aplicación actual (derecha).
En la propia página de tutoriales de Java24 se recomienda el uso de dos librerías alternativas para la
creación de interfaces gráficas de usuario: Swing y JavaFX.
• Swing. Esta librería25 fue desarrollada como evolución de AWT, para proporcionar componentes de
interfaz gráfica de usuario compatibles con cualquier plataforma, emulando los controles nativos del
Sistema Operativo donde se ejecuta la aplicación. Además, la librería permite cierto grado de
personalización del estilo de los componentes. En la siguiente figura se muestra un ejemplo de
aplicación desarrollada con Swing.

Figura 34. Ejemplo de interfaz gráfica de aplicación Java creada con Swing26
• JavaFX. Esta librería27 también es propiedad de Oracle y ofrece un conjunto de paquetes de gráficos

23 https://docs.oracle.com/javase/1.5.0/docs/guide/awt/
24 https://docs.oracle.com/javase/tutorial/index.html
25 https://docs.oracle.com/javase/8/docs/technotes/guides/swing/
26 Fuente de la imagen: https://es.wikipedia.org/wiki/Swing_(biblioteca_gr%C3%A1fica)#/media/Archivo:Gui-widgets.png

42
y medios que permiten diseñar, crear y probar aplicaciones Java en diversas plataformas (no solo
escritorio). Surgió como una forma de dar soporte a los desarrolladores web que quisieran trabajar con
tecnología Java. Entre las principales características diferenciales que presenta, se incluyen los estilos
personalizados basados en hojas de estilo CSS (igual que en el desarrollo web), una herramienta para
la construcción interactiva de interfaces (Scene Builder), soporte para gráficos 3D y soporte para
integración de contenido web. En la siguiente figura se muestra un ejemplo de aplicación desarrollada
con JavaFX.

Figura 35. Ejemplo de interfaz gráfica de aplicación Java creada con JavaFX28
Además del factor de compatibilidad con el lenguaje Java, es necesario tener en cuenta la experiencia del
equipo de desarrollo con respecto a la creación de interfaces gráficas. En este aspecto, las preferencias giran en
torno a las interfaces desarrolladas con tecnologías web (HTML, CSS y Javascript), ya que han sido las más
utilizada por el único componente real del equipo de desarrollo (y autor del presente TFM) tanto en el plano
académico, como personal y profesional. Esto implica que el desarrollo será más rápido y tendrá una mayor
calidad si se puede implementar la interfaz utilizando HTML, CSS y Javascript, que si es necesario aprender a
utilizar por completo una nueva librería de componentes de interfaz gráfica. Afortunadamente, JavaFX
dispone de un componente, denominado WebView29, que permite integrar un navegador web dentro de la
aplicación y no sólo permite visualizar páginas a través de URLs de internet, sino que permite acceder a
archivos HTML ubicados dentro del directorio del proyecto. Es decir, JavaFX permite tratar la vista de la
aplicación como si fuese una interfaz web.
Una limitación que se plantea en este momento es la comunicación entre la vista y el controlador. Si se aboga
por la utilización de un visor web para mostrar la interfaz, no se podrán gestionar los eventos originados por la
interacción del usuario con los componentes de la misma (por ejemplo, el usuario hace click en un botón de la
página HTML, pero no está controlado por JavaFX). Afortunadamente, tras estudiar el problema e indagar por
Internet, se encuentra una posible solución para este problema [35]. Básicamente, se crea una clase en la parte
Java de la vista (donde se utiliza JavaFX) que funcionará como conector con la parte Web de la vista
(componente WebView). A su vez, en el código Javascript se instancia una clase que funcionará como conector
con la parte Java de la vista. Así, cuando se genere un evento a raíz de una interacción con el usuario, el
conector Javascript se lo comunicará al conector Java, que realizará las acciones necesarias con el controlador
y hará llegar al usuario el resultado a través del conector Javascript de nuevo. En la siguiente figura se muestra
un esquema simplificado de este enfoque.

27 https://docs.oracle.com/javase/8/javafx/get-started-tutorial/jfx-overview.htm#JFXST784
28 Fuente de la imagen: https://www.javacodegeeks.com/wp-content/uploads/2016/07/screen-shot-2016-04-01-at-10-17-33.png
29 https://docs.oracle.com/javase/8/javafx/api/javafx/scene/web/WebView.html

43
Figura 36. Utilización de conectores para manejar eventos en un componente WebView de JavaFX
Con el análisis realizado sobre las librerías disponibles para la implementación de la interfaz gráfica de la
aplicación, junto con las cualidades y preferencias del equipo de desarrollo en este aspecto, se da por finalizada
la tarea actual. En la siguiente se establecerá, justificadamente, la alternativa escogida finalmente.

4.2.4.2 Tarea: Establecer alternativa escogida

Tras analizar las posibilidades para trabajar en la implementación de la interfaz gráfica, es necesario sopesar
qué opción puede ser la más interesante para conseguir el objetivo propuesto. Debido a las cualidades del
equipo de desarrollo en materia de desarrollo web, si JavaFX permite una integración sencilla de una interfaz
web en la aplicación mediante el uso de conectores descrito en la anterior sección, ésta sería la candidata
favorita. Para probar esto, se lleva a cabo una pequeña Prueba de Concepto utilizando el tutorial disponible en
[35], cuyo código se muestra a continuación.
/***************************************************************************/
/* CÓDIGO JAVA */
/***************************************************************************/

package com.sothawo.test;

import javafx.application.Application;
import javafx.concurrent.Worker;
import javafx.scene.Scene;
import javafx.scene.web.WebEngine;
import javafx.scene.web.WebView;
import javafx.stage.Stage;
import netscape.javascript.JSObject;

import java.io.File;
import java.net.URL;

/**
* @author P.J. Meisch (pj.meisch@sothawo.com).
*/
public class WebViewApplication extends Application {

/** for communication to the Javascript engine. */


private JSObject javascriptConnector;

/** for communication from the Javascript engine. */


private JavaConnector = new JavaConnector();;

@Override
public void start(Stage primaryStage) throws Exception {
URL = new File("./js-sample.html").toURI().toURL();

WebView = new WebView();


final WebEngine webEngine = webView.getEngine();

// set up the listener


webEngine.getLoadWorker().stateProperty().addListener((observable, oldValue, newValue) -> {
if (Worker.State.SUCCEEDED == newValue) {
// set an interface object named 'javaConnector' in the web engine's page
JSObject window = (JSObject) webEngine.executeScript("window");
window.setMember("javaConnector", javaConnector);

// get the Javascript connector object.


javascriptConnector = (JSObject) webEngine.executeScript("getJsConnector()");
}
});

Scene scene = new Scene(webView, 300, 150);


primaryStage.setScene(scene);
primaryStage.show();

// now load the page


webEngine.load(url.toString());
}

public class JavaConnector {


/**
* called when the JS side wants a String to be converted.
*
* @param value
* the String to convert
*/
public void toLowerCase(String value) {
if (null != value) {
javascriptConnector.call("showResult", value.toLowerCase());
}
}
}

/***************************************************************************/
/* CÓDIGO HTML-JAVASCRIPT */
/***************************************************************************/

44
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Sample</title>
</head>
<body>
<main>

<div><input id="input" type="text"></div>


<button onclick="sendToJava();">to lower case</button>
<div id="result"></div>

</main>

<script type="text/javascript">
function sendToJava () {
var s = document.getElementById('input').value;
javaConnector.toLowerCase(s);
};

var jsConnector = {
showResult: function (result) {
document.getElementById('result').innerHTML = result;
}
};

function getJsConnector() {
return jsConnector;
};
</script>
</body>
</html>

Tabla 5. Código para prueba de concepto de conectores con JavaFX


En el código anterior, se crea una clase WebViewApplication que hereda de la clase Application de JavaFX.
Esta clase dispone de un método start que se encarga de lanzar la aplicación, instanciando el componente
WebView que albergará la vista HTML. Además, se dispone de una clase interna JavaConnector con un
método toLowerCase que toma como parámetro una variable de tipo String y devuelve el mismo contenido de
dicha variable con todos los caracteres en minúscula. Por otro lado, se dispone de un fichero en formato
HTML que contiene sólo 3 elementos: una entrada de texto donde se introducirá la cadena a convertir a
minúsculas; un botón para generar el evento de comunicación con el conector Java; y un contenedor donde se
mostrará el resultado devuelto por dicho conector. Dispone además de una sección de Javascript, donde se
define el método sendToJava que llamará al método toLowerCase antes indicado del conector Java, una
variable jsConnector que representa el conector en el componente WebView (ver Figura 36) y un método
getJsConnector que permitirá a JavaFX obtener la referencia a dicho conector. Volviendo al método start de la
clase WebViewApplication de JavaFX, se puede observar que se maneja el objeto WebView creado a través de
su atributo WebEngine para instanciar un objeto javaConnector y asignándole la instancia de tipo
JavaConnector creada al inicio de la aplicación (lo cual permite llamar al conector Java desde el código
Javascript). Además, instancia un objeto de tipo JSOBject llamado javascriptConnector y le asigna un valor
llamando al método getJsConnector de la parte Javascript. Con esto, la información puede fluir desde una
parte de la vista a la otra sin problemas. En la siguiente figura se muestra el resultado de la prueba de concepto
realizada.

Figura 37. Prueba de concepto de comunicación en JavaFX antes de la llamada desde el conector Javascript
del front-end (arriba) y después, con el resultado devuelto por el conector Java del back-end (abajo)
Ante el resultado favorable de la Prueba de Concepto, se demuestra que es posible crear una vista basada en
tecnología web (HTML,CSS y Javascript) para una aplicación Java, utilizando el componente WebView de
JavaFX y creando enlaces de comunicación a través de objetos conectores en ambas partes de la vista para la
transmisión de información. Es por ello por lo que se decide utilizar esta vía como propuesta para el desarrollo
de la interfaz gráfica de la aplicación.

45
4.2.4.3 Tarea: Realizar prototipo de la vista

Una vez decidida la tecnología a emplear para el desarrollo de la vista, se comienza con el prototipo de la
misma. El uso de prototipos es bastante conocido en el mundo de desarrollo software, para alinear las
expectativas del cliente y del usuario final con la implementación que se llevará a cabo. Sobre todo en el
ámbito de interfaces de usuario, esta labor es importante para minimizar los cambios necesarios en el producto
para ser aceptado finalmente. En las metodologías ágiles, el prototipado es una técnica habitual para conseguir
un mejor cumplimiento de las Historias de Usuario que requieren de modificaciones en la parte front-end de
un producto software.
La interfaz gráfica deberá dar acceso a las distintas funcionalidades de la vista, para lo que será necesario
implementar varias pantallas y componentes visuales. En primer lugar, se propone un conjunto de 4 pantallas
que harán referencia a los distintos modos del controlador (ver Figura 27):
• Pantalla de registro de IP de red Pastry. Será mostrada cuando el controlador se encuentre en
MODO_NECESARIA_DIRECCION. Permitirá al usuario introducir la IP y el puerto de escucha de un
nodo conocido de la red Pastry a la que se pretende conectar, a través de un formulario con dos
campos y un botón para realizar la acción de registro. En la Figura 38 se muestra el prototipo para esta
pantalla.
• Pantalla de inicio de sesión. Será mostrada cuando el controlador se encuentre en
MODO_INICIO_SESION. Permitirá al usuario acceder a la red Pastry utilizando sus credenciales
registradas localmente, mediante un formulario con dos campos (uno de texto para el usuario y otro de
texto oculto para la contraseña) y un botón para realizar la acción de inicio de sesión. Además,
dispondrá de un enlace a la pantalla de registro de usuario. En la Figura 38 se muestra el prototipo
para esta pantalla.
• Pantalla de registro de usuario en red Pastry. Será mostrada cuando el controlador se encuentre en
MODO_REGISTRO. Permitirá al usuario registrarse en la red Pastry utilizando un nombre de usuario
(que no esté en uso) y una contraseña. Se mostrará un formulario con 3 campos: uno de tipo texto para
el nombre de usuario; otro de tipo texto oculto (los caracteres no se mostrarán en claro, sino utilizando
asteriscos) para la contraseña; y otro de tipo texto oculto para confirmar la contraseña escogida.
Presentará además un botón para realizar la acción de registro y un enlace para navegar a la pantalla
de inicio de sesión. En la Figura 38 se muestra el prototipo para esta pantalla.

Figura 38. Prototipos para la pantalla de registro IP de red Pastry (izquierda), de inicio de sesión (centro)
y de registro de usuario (derecha)
• Pantalla de sesión iniciada. Será mostrada cuando el controlador se encuentre en
MODO_SESION_INICIADA. Esta pantalla será la que contemple la mayor parte de las
funcionalidades. Será la más compleja y la que requerirá un mayor número de componentes para
facilitar la accesibilidad a todas las funcionalidades. Será dividida en dos partes. La parte derecha será
un componente que tendrá como objetivo dar acceso a las funcionalidades dentro de una
conversación: leer mensajes; enviar un mensaje; obtener el código de invitación a un grupo; y leer
mensajes importantes de un grupo. La parte izquierda presentará las conversaciones abiertas y unos

46
controles para manejar la lista de contactos y la lista de grupos (ver, editar, agregar contactos o
grupos) y para cerrar la sesión activa. En la siguiente figura se muestra el prototipo para esta pantalla.

Figura 39. Prototipo para la pantalla de sesión iniciada


Por otra parte, una vez establecidos los prototipos para las 4 pantallas que compondrán la interfaz gráfica, se
definen los componentes que serán necesarios para el manejo de la aplicación. La mayoría de estos
componentes son utilizados en la pantalla de sesión iniciada:
• Componente de diálogo con mensaje informativo. Este componente es utilizado en todas las
pantallas y su objetivo es ofrecer información al usuario acerca del resultado de las acciones. Se
prototipa como un componente sencillo, que disponga del mensaje informativo a mostrar y un botón
para cerrar el diálogo. En la Figura 40 se muestra el prototipo para este componente.
• Componente de indicador de acción en curso. Este componente, al igual que el anterior, es
utilizado en todas las pantallas. Su objetivo es bloquear la acción del usuario mientras se está llevando
a cabo alguna acción que necesita sincronización con el controlador (como el inicio de sesión). Se
prototipa como un componente sencillo, que disponga de un icono y un mensaje informativo y que
permita bloquear la interacción del usuario con la aplicación. En la Figura 40 se muestra el prototipo
para este componente.

Figura 40. Prototipo para el componente de diálogo con mensaje informativo (izquierda) e indicador de acción
en curso (derecha)
• Componente de conversación abierta. Este componente sólo aparecerá en la pantalla de sesión
iniciada. Servirá para representar un objeto de conversación abierta por el usuario con uno de sus
contactos, o uno de los grupos a los que está suscrito. En el componente se mostrará un mínimo de
información acerca de la conversación: el contacto o grupo relativo a la conversación; el último
mensaje de la misma (o una visión compactada, si es muy largo); la hora de recepción/envío del
último mensaje o la fecha si fue recibido/enviado antes del día actual; y un control para eliminar la
conversación de la lista (o salir del grupo). A través de este componente, se permitirá la selección de
la conversación representada por el mismo, a través de la generación de un evento que terminará
ubicando el contenido de la conversación en el componente de “Conversación seleccionada” y
47
permitirá así la interacción con la misma (leer, escribir y enviar mensajes). Se cree oportuno que este
evento se lance al hacer click el usuario sobre el componente (fuera del control de eliminación de la
conversación). En la siguiente figura se muestra el prototipo para este componente.

Figura 41. Prototipo para el componente de conversación abierta


• Componente de mensaje enviado. Este componente sólo aparecerá en la pantalla de sesión iniciada.
En concreto, servirá para identificar los mensajes que han sido enviados por el usuario en el
componente “Conversación seleccionada”. Será un componente sencillo, que estará formado por el
texto del mensaje, un distintivo que aparecerá si el mensaje es importante (en grupos) y la hora de
envío/recepción del mismo, acompañada de la fecha si fue recibido/enviado antes del día actual. Este
componente es similar al de mensaje recibido (visto a continuación), pero se podrán diferenciar por la
alineación y el color de fondo. Los mensajes enviados estarán alineados a la izquierda. Se propone
utilizar una paleta de colores basada en la insignia de la Universidad de Sevilla, otorgando a los
mensajes enviados una tonalidad roja. En la Figura 42 se muestra el prototipo para este componente.
• Componente de mensaje recibido. Este componente sólo aparecerá en la pantalla de sesión iniciada.
En concreto, servirá para identificar los mensajes que han sido recibidos por el usuario en el
componente “Conversación seleccionada”. Será un componente sencillo, que estará formado por el
texto del mensaje, un distintivo que aparecerá si el mensaje es importante (en grupos) y la hora de
envío/recepción del mismo, acompañada de la fecha si fue recibido/enviado antes del día actual. En el
caso de conversaciones de grupo, el componente tendrá un campo de texto para identificar el
remitente del mensaje. Este componente es similar al de mensaje enviado (visto anteriormente), pero
se podrán diferenciar por la alineación y el color de fondo. Los mensajes recibidos estarán alineados a
la derecha. Se propone utilizar una paleta de colores basada en la insignia de la Universidad de
Sevilla, otorgando a los mensajes enviados una tonalidad amarilla. En la Figura 42 se muestra el
prototipo para este componente.

Figura 42. Prototipo para el componente de mensaje enviado (izquierda) y recibido (derecha)
• Componente de mensajes importantes. Este componente sólo aparecerá en la pantalla de sesión
iniciada. Tiene como objetivo permitir al usuario acceder a los mensajes importantes que han sido
enviados al grupo de la conversación seleccionada. Se dispondrá de dos controles para navegar a los
bloques de mensajes importantes anterior y siguiente (si los hubiera) y otro control para recargar los
mensajes importantes del bloque actual. En la Figura 43 se muestra el prototipo para este componente.
• Componente de agenda. Este componente sólo aparecerá en la pantalla de sesión iniciada. Tiene
como objetivo permitir al usuario acceder a las funcionalidades relativas a la gestión de contactos y
grupos:
o Listar contactos guardados. Mediante una lista que contenga todos los contactos guardados
por el usuario. Para la representación de un contacto en la lista, se utilizará el componente de
contacto (descrito más tarde en esta misma sección).
o Agregar un nuevo contacto. A través de un formulario donde se indique el nombre del
usuario en la red Pastry y un alias personalizado para guardarlo como contacto.

48
o Eliminar un contacto. A través de un control sencillo dentro del componente de contacto
(descrito más tarde en esta misma sección).
o Iniciar conversación con un contacto. A través de un control sencillo dentro del
componente de contacto (descrito más tarde en esta misma sección).
o Crear un nuevo grupo. A través de un formulario donde se indique el nombre del grupo a
crear.
o Unirse a un grupo. A través de un control sencillo dentro del componente de unión a grupo
(descrito más tarde en esta misma sección).
Este componente aparecerá al utilizar el control representado en la Figura 39 con el rótulo de “Abrir
componente agenda”. Dispondrá además de un control para cerrarlo en la esquina superior derecha.
En la Figura 43 se muestra el prototipo para este componente.

Figura 43. Prototipo para el componente de mensajes importantes (izquierda) y el de agenda (derecha)
• Componente de contacto. Este componente sólo aparecerá en la pantalla de sesión iniciada. En
concreto, aparecerá dentro de la lista de contactos ubicada en el componente de agenda. El
componente presentará el alias del contacto guardado y el nombre de usuario registrado en la red
Pastry para dicho contacto. Además, se presentará una serie de controles para: unirse a un grupo
mediante un código de invitación recibido por el contacto, lo cual activará el componente de unión a
grupo (visto a continuación); iniciar una conversación con el contacto; y eliminar el contacto. En la
Figura 44 se muestra el prototipo para este componente.
• Componente de unión a grupo. Este componente sólo aparecerá en la pantalla de sesión iniciada. En
concreto, aparecerá tras utilizarse uno de los controles del componente de contacto (visto
anteriormente): el control para unirse a un grupo mediante un código de invitación recibido por el
contacto al que hace referencia el componente. El componente de unión a grupo será un formulario
sencillo, donde se podrá introducir el código de invitación recibido y un botón para registrar la acción
de unión al grupo. Además, dispondrá de un control para cerrarlo en la esquina superior derecha, igual
que el componente de agenda. En la Figura 44 se muestra el prototipo para este componente.
• Componente de código de invitación de grupo. Este componente sólo aparecerá en la pantalla de
sesión iniciada. En concreto, aparecerá dentro del componente de “Conversación seleccionada”,
cuando se trate de una conversación de grupo y el usuario haga uso del control para generar el código
de invitación al grupo. El componente consistirá sencillamente en un campo de texto que contendrá el
código de invitación generado, y deberá ubicarse cerca del control utilizado para su generación, de tal
forma que se asocie claramente la relación entre el componente mostrado y la acción solicitada. En la
Figura 44 se muestra el prototipo para este componente.

49
Figura 44. Prototipo para el componente de contacto (arriba), de unión a grupo (centro) y de código de
invitación a grupo (abajo)
Con esta serie de prototipos, se establece el camino a seguir para la implementación de la interfaz gráfica. Para
ello, será necesario crear código front-end (relativo a la vista, que interactúa con el usuario) y código back-end
(relativo al funcionamiento interno de la aplicación). En las siguientes secciones se desarrollan detalladamente
estas tareas.

4.2.4.4 Tarea: Desarrollar el front-end necesario para GUI

En esta tarea se desarrollará el código para implementar la parte de la vista que interactúa con el usuario. Se ha
decidido utilizar tecnologías de desarrollo web, por lo que en el desarrollo se distinguirán 3 partes:
• Código HTML. Será utilizado para crear las estructuras de las distintas pantallas y componentes de la
interfaz gráfica.
• Código CSS. Será utilizado para personalizar el estilo de presentación de las distintas pantallas y
componentes de la interfaz gráfica.
• Código Javascript. Será utilizado para capturar eventos generados tanto por el usuario como por la
propia aplicación, para aplicar una lógica determinada y actuar en consecuencia.
Además, se utilizará la librería FontAwesome [36] para la inclusión de iconos en algunos controles de la
interfaz. También se utilizará la librería Bootstrap [37] como soporte para el diseño de estilos. Se utilizan estas
librerías por la familiaridad del equipo de desarrollo con las mismas y por su fácil utilización.
Para la organización del código, se opta por crear un directorio “web” dentro del directorio relativo a la vista
de la aplicación: “app\src\main\java\us\tfg\p2pmessenger\view”. Dentro de este directorio nuevo, se creará un
directorio para el código HTML, otro para el CSS y otro para el Javascript. Además, se crea otro directorio
para almacenar imágenes “img”. Por último, se almacena también en este directorio el código de la librería
FontAwesome utilizada para los iconos. En la siguiente figura se muestra un esquema de los directorios
creados y los ficheros que dispondrán los directorios HTML, CSS y JS.

50
Figura 45. Estructura del directorio web creado para ubicar el código relativo a la interfaz gráfica
En el esquema mostrado en la figura anterior, se puede apreciar que hay un archivo “.html” y un archivo “.js”
por cada pantalla. Además, se incluye un archivo Javascript global “tfm.js” que contendrá al conector
javascript con todos los métodos que podrán ser llamados desde el conector Java para el paso de información
desde el back-end. Además, dispone de métodos comunes a todas las pantallas, como por ejemplo para
mostrar/ocultar componentes (recuérdese el componente de diálogo con mensaje informativo descrito
anteriormente). Hay, además, una pantalla que no fue tenida en cuenta en los prototipos (index.html – index.js).
Esta pantalla sólo se utiliza como pantalla de carga mientras se inicia la aplicación, para que el usuario sepa
que la aplicación está arrancando. En cuanto a CSS, el estilo personalizado se aloja por completo en un solo
fichero denominado estilo-tfm.css.
A continuación, se detalla el trabajo desarrollado en cada una de las pantallas:
• index.html-index.js. Esta pantalla se ha incluido sin que se hubiese tenido en cuenta en la fase de
prototipado. Es una pantalla simple que sólo contiene el logo de la Universidad de Sevilla, el nombre
de la aplicación y un mensaje que permite saber que la aplicación está arrancando. En esta pantalla no
hay se genera ningún evento, simplemente se llama desde el conector de Javascript a un método del
conector Java para iniciar el servicio. En la siguiente figura se muestra una captura de esta pantalla y
su diagrama de flujo asociado.

Figura 46. Capturya (izquierda) y flujo asociado (derecha) a la pantalla de inicio


• nuevaDireccion.html-nuevaDireccion.js. El diseño de esta pantalla se ha realizado siguiendo el
prototipo de la Figura 38. Se ha tratado de dejar una interfaz limpia, y se ha agregado el logo de la
Universidad de Sevilla. En cuanto a eventos, en esta pantalla se dispone de un control para enviar la
IP y el puerto de un nodo conocido en la red Pastry a la que se desea conectar. Este control, en forma
de botón, desencadenará la validación del formulario y, si la IP y el puerto tienen un formato correcto,
se llamará al método conectarPastry(ip,puerto) del conector Java (mostrando antes el componente de
indicador de acción en curso). Si la validación del formulario no tiene éxito, se mostrará al usuario el
componente de diálogo con mensaje informativo avisando del error. En la siguiente figura puede
observarse tanto la pantalla como el flujo asociado a esta pantalla.

51
Figura 47. Captura (izquierda) y flujo asociado (derecha) a la pantalla de registro de IP de Pastry
• inicioSesion.html-inicioSesion.js. El diseño de esta pantalla se ha realizado siguiendo el prototipo de
la Figura 38. Se ha tratado de dejar una interfaz limpia, y se ha agregado el logo de la Universidad de
Sevilla. A continuación, se muestra una captura de esta pantalla.

Figura 48. Captura de la pantalla de inicio de sesión (izquierda) y el componente de diálogo con mensaje
informativo asociado (derecha)
En esta pantalla, el usuario dispone de un control para acceder a la pantalla de registro de usuario. Al
hacer click en el botón correspondiente, se mostrará el componente de indicador de acción en curso y
se hará una llamada al método accederRegistroUsuario del conector Java. Además, dispone de un
control para realizar una llamada al método iniciarSesion(usuario, password) del conector Java
(mostrando antes el componente de indicador de acción en curso). Antes de llamar a este método, se
hace una validación del formulario, comprobando que ninguno de los campos esté vacío. Si la
validación del formulario no tiene éxito, se mostrará al usuario el componente de diálogo con
mensaje informativo avisando del error. En la siguiente figura puede observarse el flujo de estos
eventos.

52
Figura 49. Flujo asociado al control de “Iniciar sesión” (izquierda) y “Registrar nuevo usuario” (derecha) de la
pantalla de inicio de sesión
• registro.html-registro.js. El diseño de esta pantalla se ha realizado siguiendo el prototipo de la
Figura 38. Se ha tratado de dejar una interfaz limpia, y se ha agregado el logo de la Universidad de
Sevilla. A continuación, se muestra una captura de esta pantalla.

Figura 50. Captura de la pantalla de registro de nuevo usuario (izquierda) y el componente de diálogo con
mensaje informativo asociado (derecha)
Los eventos de esta pantalla son similares a los de la pantalla de inicio de sesión. Dispone de un
control para acceder a la pantalla de inicio de sesión. Al hacer click en el botón correspondiente, se
mostrará el componente de indicador de acción en curso y se hará una llamada al método
accederInicioSesion del conector Java. Además, dispone de un control para llamar al método
registrarUsuario(usuario, password) del conector Java, previa validación de los campos del
formulario (ningún campo vacío y, además, el campo “Contraseña” y “Confirmar contraseña” deben
coincidir). Si la validación del formulario no tiene éxito, se mostrará al usuario el componente de
diálogo con mensaje informativo avisando del error. En la siguiente figura puede observarse el flujo
de estos eventos.

53
Figura 51. Flujo asociado al control de “Registrar usuario” (izquierda) e “Iniciar sesión” (derecha) de la
pantalla de registro de un nuevo usuario
• appWindow.html-appWindow.js. Esta pantalla es la más compleja de la interfaz gráfica, por la
cantidad de componentes que aloja. Su diseño se ha realizado basándose en el prototipo mostrado en
la Figura 39. Todos los componentes están declarados en el fichero “.html”, en forma de plantilla. De
esta forma, cuando se envía un mensaje nuevo en la lista de mensajes del componente “Conversación
seleccionada”, se toma el bloque con el identificador “mensajeDivEnviadoPlantilla” y se
personalizan los distintos campos con la información del mensaje. Este trabajo es realizado por la
parte del código Javascript ante los distintos eventos que se contemplan. En primer lugar, se muestra
en las siguientes figuras la pantalla y los distintos componentes que forman parte de ella.

Figura 52. Captura de la pantalla de sesión iniciada sin conversaciones abiertas ni conversación seleccionada
(izquierda) y el componente de indicador de acción en curso (derecha)

54
Figura 53. Captura de la pantalla de sesión iniciada con el componente de agenda abierto sin contactos, con el
formulario de creación de contacto (izquierda) y con un componente de contacto agregado (derecha)

Figura 54. Captura de la pantalla de sesión iniciada con una conversación abierta y seleccionada con mensaje
recibido y enviado

Figura 55. Captura de la pantalla de sesión iniciada con el componente de agenda abierto, con formulario de
crear grupo (izquierda) y con el componente de código de invitación a grupo (derecha)

55
Figura 56. Captura de la pantalla de sesión iniciada con el componente de unión a grupo (izquierda) y una
conversación de grupo con mensajes normales e importantes (derecha)

Figura 57. Captura de la pantalla de sesión iniciada con el componente de mensajes importantes mostrando el
primer bloque (izquierda) y el segundo bloque (derecha)
En cuanto a los eventos, esta pantalla contempla bastantes casuísticas, por las que se verán detalladamente por
componente:
• Pantalla general. La pantalla general presenta varios controles en la parte izquierda. En la parte
derecha presenta el componente de conversación seleccionada, que será visto posteriormente. Entre
los controles de la parte izquierda, se encuentran:
o Control de refresco de conversaciones. Este control permite generar un evento para
actualizar de forma manual la información de las conversaciones abiertas y seleccionada. Se
interactúa con el conector Java para obtener los datos necesarios. En la siguiente figura se
muestra el flujo asociado a este control.

56
Figura 58. Flujo asociado al control de refresco de conversaciones
o Control para mostrar componente de agenda. Este control permite generar un evento para
obtener la lista actualizada de contactos a través del conector Java y mostrar el componente
de agenda si el método no tiene errores. En la siguiente figura se muestra el flujo asociado a
este control.

Figura 59. Flujo asociado al control de mostrar agenda


o Control para cerrar sesión. Este control genera un evento cuando el usuario hace click en
él que llama al método cerrarSesion del conector Java (mostrando antes el componente de
indicador de acción en curso). Después de esto, el conector se encargará de cambiar la
pantalla mostrada y no será necesaria ninguna acción más por parte del conector Javascript.
En la siguiente figura se muestra el flujo asociado a este control.

Figura 60. Flujo asociado al control de cerrar sesión


o Control para seleccionar una conversación. Este control está asociado a cada uno de los
57
componentes de tipo “Conversación abierta” que se muestran en la lista de la izquierda de la
pantalla de sesión iniciada. Cuando el usuario hace click en una conversación de las que
tiene abiertas, se interactúa con el conector Java para obtener los mensajes de dicha
conversación y actualizar el componente de la parte derecha de la pantalla de sesión iniciada,
con los mensajes asociados a dicha conversación. En la siguiente figura se muestra el flujo
asociado a este control.

Figura 61. Flujo asociado al control de seleccionar una conversación


• Componente conversación seleccionada. Este componente dispone de un control para el envío de
un mensaje a la conversación seleccionada (en el caso de que sea un grupo, dispone de un
modificador para indicar que el mensaje es importante y que pasará como parámetro extra al método
de envío) y dos controles que sólo aparecen cuando la conversación es de un grupo. Uno de estos
controles es utilizado para obtener el código de invitación al grupo y el otro para abrir el componente
de mensajes importantes. En la siguiente figura se muestran los flujos asociados a dichos controles.

Figura 62. Flujos asociados al control de “Enviar mensaje” (arriba) y “Generar código de invitación a grupo”
(abajo) del componente de “Conversación seleccionada”
• Componente de mensajes importantes. El componente de mensajes importantes dispone de tres
controles, que permitirán refrescar los mensajes del bloque que se está visualizando, obtener los
mensajes del bloque anterior y obtener los mensajes del bloque siguiente (si los hubiera). En la
siguiente figura se muestran los flujos asociados a dichos controles.

58
Figura 63. Flujo asociado a los controles del componente de Mensajes importantes.
• Componente de agenda y contacto. El componente de agenda dispone de dos controles, para la
creación de contactos y para la creación de grupos. El componente de contacto dispone de controles
para eliminar el contacto, iniciar una conversación con el mismo o acceder al componente de “Unión
a grupo” asociado al contacto. En las siguientes figuras se muestran los flujos asociados a dichos
controles.

Figura 64. Flujos asociados al control de “Guardar contacto” (izquierda) y “Crear grupo” (derecha) del
componente de “Agenda”

Figura 65. Flujos asociados al control de “Eliminar contacto” (izquierda), “Iniciar conversación” (centro) y

59
“Unirse a grupo” (derecha) del componente de “Contacto”
• Componente Unión a grupo. Este componente dispone de un único control que genera un evento
para llamar al método correspondiente del conector Java para la unión al grupo asociado a la
combinación contacto-código invitación. En la siguiente figura se muestran los flujos asociados a
dicho control.

Figura 66. Flujo asociado al control de “Unirse a grupo” del componente de “Unión a grupo”

4.2.4.5 Tarea: Desarrollar el back-end necesario para GUI

En esta tarea se ha llevado a cabo el desarrollo de la parte interna de la aplicación que da soporte a las
interacciones del usuario con el front-end, mostrado en la sección anterior. Se ha decidido crear una nueva
clase (VistaGUI.java) en el repositorio que permita lanzar la aplicación mediante la librería JavaFX, utilizando
un componente WebView para alojar la capa de interacción con el usuario. En la siguiente figura se muestra el
flujo que sigue esta clase en su método start, método de la librería JavaFX que sirve para el lanzamiento de la
aplicación gráfica.

Figura 67. Flujo simplificado del método Start de la clase VistaGUI que lanza la interfaz gráfica
Así mismo, esta clase dispone de una clase interna (JavaConnector) que permitirá la comunicación con dicha
capa de interacción, recibiendo peticiones para la ejecución de métodos y realizando llamadas (callbacks) para

60
la actualización de la información mostrada al usuario. A continuación, se listan los distintos métodos de back-
end desarrollados, y que son mencionados en los flujos del front-end mostrados en la sección anterior. Para
cada método, se mostrará su flujo asociado.
• Método iniciarServicio. Este método se llama desde la pantalla “index”, como se puede apreciar en
la Figura 46. En la Figura 68 se muestra el flujo asociado a dicho método.
• Método conectarPastry. Este método se llama desde la pantalla “nuevaDireccion”, como se puede
apreciar en la Figura 47. En la Figura 68 se muestra el flujo asociado a dicho método.

Figura 68. Flujo simplificado del método iniciarServicio (izquierda) y conectarPastry (derecha) de la
clase JavaConector que conecta la interfaz gráfica con el controlador
• Métodos iniciarSesion y accederRegistroUsuario. Estos métodos se llaman desde la pantalla
“inicioSesion”, como se puede apreciar en la Figura 49. A continuación, se muestran los flujos
asociados a dichos métodos.

Figura 69. Flujos simplificados de los métodos iniciarSesion (izquierda) y accederRegistroUsuario


(derecha) de la clase JavaConector que conecta la interfaz gráfica con el controlador
• Métodos registrarUsuario y accederInicioSesion. Estos métodos se llaman desde la pantalla
61
“registro”, como se puede apreciar en la Figura 51. A continuación, se muestran los flujos asociados a
dichos métodos.

Figura 70. Flujos simplificados de los métodos registrarUsuario (izquierda) y accederInicioSesion


(derecha) de la clase JavaConector que conecta la interfaz gráfica con el controlador
• Método refrescarConversaciones. Este método se llama desde la pantalla “appWindow”, como se
puede apreciar en la Figura 58. A continuación se muestra el flujo asociado a dicho método.

Figura 71. Flujo simplificado del método refrescarConversaciones de la clase JavaConector que
conecta la interfaz gráfica con el controlador
• Método obtenerMensajesConversacionSeleccionada. Este método se llama desde la pantalla
“appWindow”, como se puede apreciar en la Figura 58. A continuación se muestra el flujo asociado a
dicho método.

62
Figura 72. Flujo simplificado del método obtenerMensajesConversacionesSeleccionadas de la clase
JavaConector que conecta la interfaz gráfica con el controlador
• Método obtenerListaContactos. Este método se llama desde la pantalla “appWindow”, como se
puede apreciar en la Figura 59. A continuación se muestra el flujo asociado a dicho método.

Figura 73. Flujo simplificado del método obtenerListaContactos de la clase JavaConector que
conecta la interfaz gráfica con el controlador
• Método cerrarSesion. Este método se llama desde la pantalla “appWindow”, como se puede apreciar
en la Figura 60. En la Figura 74 se muestra el flujo asociado a dicho método.
• Método generarCodigoInvitacionGrupo. Este método se llama desde la pantalla “appWindow”,

63
como se puede apreciar en la Figura 62. En la Figura 74 se muestra el flujo asociado a dicho método.
• Método obtenerPrimerBloqueMensajesImportantes. Este método se llama desde la pantalla
“appWindow”, como se puede apreciar en la Figura 62. En la Figura 74 se muestra el flujo asociado a
dicho método.

Figura 74. Flujo simplificado del método cerrarSesion (arriba), generarCodigoInvitacionGrupo


(centro) y obtenerPrimerBloqueMensajesImportantes (abajo) de la clase JavaConector que conecta
la interfaz gráfica con el controlador
• Método obtenerMensajesImportantes. Este método se llama desde el componente de Mensajes
importantes (ver Figura 63) y desde el método obtenerPrimerBloqueMensajesImportantes (ver
Figura 74). A continuación, se muestra el flujo asociado a dicho método.

Figura 75. Flujo simplificado del método obtenerMensajesImportantes de la clase JavaConector que conecta
la interfaz gráfica con el controlador
• Método crearContacto. Este método se llama desde la pantalla “appWindow” dentro del
componente de agenda, como se puede apreciar en la Figura 64. A continuación se muestra el flujo
asociado a dicho método.

64
Figura 76. Flujo simplificado del método crearContacto de la clase JavaConector que conecta la
interfaz gráfica con el controlador
• Método crearGrupo. Este método se llama desde la pantalla “appWindow” dentro del componente
de agenda, como se puede apreciar en la Figura 64. A continuación se muestra el flujo asociado a
dicho método.

Figura 77. Flujo simplificado del método crearGrupo de la clase JavaConector que conecta la
interfaz gráfica con el controlador
• Método eliminarContacto. Este método se llama desde la pantalla “appWindow” dentro del
componente de contacto, como se puede apreciar en la Figura 65. En la Figura 78 se muestra el flujo
asociado a dicho método.
• Método unirseGrupo. Este método se llama desde la pantalla “appWindow” dentro del componente
de unión a grupo, como se puede apreciar en la Figura 66. En la Figura 78 se muestra el flujo
asociado a dicho método.

65
Figura 78. Flujo simplificado del método eliminarContacto (izquierda) y unirseAGrupo (derecha) de
la clase JavaConector que conecta la interfaz gráfica con el controlador
Por último, ha sido necesaria la creación de otra clase VistaConsolaPublic.java que básicamente actúa como
una API para llamar a métodos del controlador. La justificación para utilizar esta nueva clase en vez de la que
disponía el producto (VistaConsola.java) y que implementaba la vista en modo consola es que dicha clase
dispone de métodos privados e interactúa con la instancia de controlador directamente (la instancia es privada
también), en base a las opciones de menú utilizadas. Por ello, no es posible llevar a cabo una instancia en
modo servicio y llamar a sus métodos para las distintas funcionalidades. A continuación, se muestra un
ejemplo del código anterior y de la refactorización realizada en este sentido.

/* Código de la versión de consola (VistaConsola.java) donde se muestra la funcionalidad de envío de mensaje*/


public class VistaConsola implements Vista
{
/*...
.....
...*/
private ControladorApp app; //Variable privada, no accesible desde fuera de la clase
/*...
.....
...*/

public static void main(String args[])


{
/*...
.....
...*/
VistaConsola servicio = new VistaConsola(ip, puerto);
/*...
.....
...*/

private void modoMensajes()


{
boolean seguir = true;
String msg = "";
Conversacion actual = null;
String nombreConversacion = "";

int tipoMsj=0;

int opcion;

while (seguir)
{
if (actual != null)
{
nombreConversacion = actual.getAlias();
}
System.out.println("");
System.out.println("0) Listar conversaciones abiertas");
System.out.println("1) Seleccionar conversacion a la que dirigirse");
System.out.println("2) Abrir conversacion "+nombreConversacion);

66
System.out.println("3) Escribir mensaje");
System.out.println("4) Enviar mensaje a la conversacion " + nombreConversacion);
System.out.println("5) Cerrar la conversacion: " + nombreConversacion);
System.out.println("6) Nueva conversacion");
System.out.println("7) Obtiene codigo invitación");
System.out.println("99) Salir del modo mensajes");

/*...
.....
...*/
case 4:
System.out.println("Enviando...");
app.enviaMensaje(tipoMsj, msg, actual.getId(), actual.getTipo() != Conversacion.TIPO_GRUPO);

/*...
.....
...*/
}
/*...
.....
...*/
}

/* Código de la nueva versión (VistaConsolaPublic.java) donde se publica la funcionalidad de envío de mensaje*/


public class VistaConsolaPublic implements Vista
{
/*...
.....
...*/

private ControladorApp app; //Variable privada, no accesible desde fuera de la clase


/*...
.....
...*/

public void appEnviarMensaje(String mensaje){


int tipoMensaje;
if(getConversacionSeleccionada().getTipo() != Conversacion.TIPO_GRUPO){
tipoMensaje = Mensaje.INDIVIDUAL_NORMAL;
}else{
tipoMensaje = Mensaje.GRUPO_NORMAL;
}
app.enviaMensaje(tipoMensaje, mensaje, getConversacionSeleccionada().getId(), getConversacionSeleccionada().getTipo()
!= Conversacion.TIPO_GRUPO);
}
/*...
.....
...*/
}

/* Código de la nueva versión gráfica donde se instancia un servicio como API y se accede a los métodos de forma externa*/
public class VistaGUI extends Application{
/*...
.....
...*/
private VistaConsolaPublic servicio;
/*...
.....
...*/
servicio = new VistaConsolaPublic(ip,puerto);
/*...
.....
...*/
public void enviarMensajeAConversacionSeleccionada(String mensaje){
servicio.appEnviarMensaje(mensaje);
javascriptConnector.call("actualizarPanelesAppWindowTrasEnvioMensaje", servicio.getConversacionSeleccionada().getAlias());
}
/*...
.....
...*/
}

Tabla 6. Ejemplo de refactorización VistaConsola.java a VistaConsolaPublic.java para utilizar métodos del


controlador en forma de API

Como se observa en el código anterior, en la versión antigua se actúa directamente sobre una instancia privada
del controlador (ControladorApp app) porque la ejecución se realiza sobre la propia clase que la contiene. En
la versión actual, la clase VistaGUI.java instancia una clase de tipo VistaConsolaPublic.java y los métodos del
controlador no pueden llamarse directamente (la instancia privada y sus métodos sólo son accesibles desde
donde son instanciados, es decir, desde VistaConsolaPublic.java). Por ello, para acceder a métodos como el de
envío de mensaje, desde VistaGUI.java no puede hacerse una llamada del tipo
servicio.app.enviaMensaje(parámetros), sino que hay que disponer un método público del tipo
servicio.appEnviarMensaje(parámetros) en VistaConsolaPublic para acceder a este método.

4.2.4.6 Tarea: Realizar pruebas de validación

La última tarea del Sprint contempla las pruebas realizadas para validar que la interfaz gráfica construida

67
permite realizar las funciones requeridas de la aplicación de mensajería. Las pruebas se planifican estipulando
las pruebas que habrá que realizar por cada pantalla y componente, anotando la descripción de la prueba a
realizar y el resultado esperado. A continuación, se muestran en forma de tablas todas las pruebas preparadas
para la validación, y que han sido utilizadas como criterio para dar por aceptado el desarrollo.

Prueba Resultado esperado

Muestra componente de diálogo informativo con


Accionar control de registro con ambos campos
mensaje “Por favor, proporcione una IP y puerto en
del formulario vacíos
formato válido”

Muestra componente de diálogo informativo con


Accionar control de registro con algún campo
mensaje “Por favor, proporcione una IP y puerto en
del formulario vacío
formato válido”

Accionar control de registro con ambos campos


Navega a pantalla de inicio de sesión
rellenos

Tabla 7. Pruebas de validación de pantalla de registro de IP de Pastry

Prueba Resultado esperado

Accionar control de acceso a registro de usuario Navega a pantalla de registro de usuario

Muestra componente de diálogo informativo con


Accionar control de inicio de sesión con ambos
mensaje “Por favor, proporcione un usuario y una
campos del formulario vacíos
contraseña”

Muestra componente de diálogo informativo con


Accionar control de inicio de sesión con algún
mensaje “Por favor, proporcione un usuario y una
campo del formulario vacío
contraseña”

Muestra componente de diálogo informativo con


Accionar control de inicio de sesión con
mensaje “Usuario o contraseña no válidos. Por favor,
credenciales no válidas
inténtelo de nuevo”

Éxito en petición: Navega a pantalla de sesión


iniciada
Accionar control de inicio de sesión con
credenciales válidas Fallo en petición: Muestra componente de diálogo
informativo con mensaje “Error al iniciar sesión. Por
favor, inténtelo de nuevo”

Tabla 8. Pruebas de validación de pantalla de inicio de sesión

Prueba Resultado esperado

Accionar control de acceso a inicio de sesión Navega a pantalla de inicio de sesión

Accionar control de registro de usuario con Muestra componente de diálogo informativo con
ambos campos del formulario vacíos mensaje “Por favor, proporcione un usuario y una
contraseña. Además, el campo \"Confirmar

68
contraseña\" debe coincidir con el campo
\"Contraseña\"”

Muestra componente de diálogo informativo con


mensaje “Por favor, proporcione un usuario y una
Accionar control de registro de usuario con algún
contraseña. Además, el campo \"Confirmar
campo del formulario vacío
contraseña\" debe coincidir con el campo
\"Contraseña\"”

Muestra componente de diálogo informativo con


Accionar control de registro de usuario con los mensaje “Por favor, proporcione un usuario y una
campos “Contraseña” y “Confirmar Contraseña” contraseña. Además, el campo \"Confirmar
rellenos con distintos valores contraseña\" debe coincidir con el campo
\"Contraseña\"”

Tabla 9. Pruebas de validación de pantalla de registro de usuario

Prueba Resultado esperado

PANTALLA GENERAL

Accionar control de Refresco de Muestra el componente de indicador de acción en curso mientras


conversaciones se trata la petición.
Éxito en petición: Oculta el componente de indicador de acción
en curso y aparece la información actualizada
Fallo en petición: Muestra componente de diálogo informativo
con mensaje “Error al obtener las conversaciones abiertas”

Accionar control de Cerrar sesión Navega a pantalla de inicio de sesión

Accionar control de abrir agenda Muestra el componente de indicador de acción en curso mientras
se trata la petición.
Éxito en petición: Muestra el componente de agenda con la lista
de contactos disponible
Fallo en petición: Muestra componente de diálogo informativo
con mensaje “Ocurrió un error al obtener los contactos
guardados”

COMPONENTE DE CONVERSACIÓN ABIERTA

Accionar control de borrar Éxito en petición: El componente desaparece de la lista de


conversación conversaciones abiertas
Fallo en petición: Muestra componente de diálogo informativo
con mensaje “Error al eliminar la conversación”

Accionar control de seleccionar Éxito en petición: Se actualiza el componente de Conversación


conversación (click en componente) seleccionada con los datos asociados a la misma (contacto
remitente, mensajes de la conversación y control de generación
de código de unión a grupo en caso de ser conversación de
grupo).
Fallo en petición: Muestra componente de diálogo informativo

69
con mensaje “Error al iniciar una nueva conversación”

COMPONENTE DE CONVERSACIÓN SELECCIONADA

Accionar control de enviar mensaje sin No hace nada


introducir texto en el formulario

Accionar control de enviar mensaje Actualiza la lista de mensajes del componente de conversación
introduciendo texto en el formulario seleccionada con el mensaje enviado

Accionar control de enviar mensaje Actualiza la lista de mensajes del componente de conversación
introduciendo texto en el formulario, seleccionada con el mensaje importante enviado
con el control de mensaje importante
activado (sólo disponible en
conversación de grupo)

Accionar control de generar código de Mostrar componente de código de invitación a grupo con el
invitación (click en componente, para código generado
conversaciones de grupo)

Accionar control de abrir mensajes Muestra el componente de indicador de acción en curso mientras
importantes se trata la petición.
Éxito en petición: Muestra el componente de mensajes
importantes con el primer mensaje importante del grupo
Fallo en petición: Muestra componente de diálogo informativo
con mensaje “Ocurrió un error al obtener los mensajes
importantes”

COMPONENTE DE MENSAJES IMPORTANTES

Accionar control de cerrar componente Oculta el componente de mensajes importantes

Accionar control de recargar mensajes Muestra el componente de indicador de acción en curso mientras
importantes del bloque actual se trata la petición.
Éxito en petición: Oculta el componente de indicador de acción
en curso y muestra los mensajes actualizados del bloque actual
Fallo en petición: Oculta el componente de indicador de acción
en curso y muestra el componente de diálogo informativo con
mensaje “Ocurrió un error al obtener los mensajes importantes”.

Accionar control de cargar mensajes Muestra el componente de indicador de acción en curso mientras
importantes del bloque anterior se trata la petición.
Éxito en petición: Oculta el componente de indicador de acción
en curso y muestra los mensajes actualizados del bloque anterior
Fallo en petición: Oculta el componente de indicador de acción
en curso y muestra el componente de diálogo informativo con
mensaje “Ocurrió un error al obtener los mensajes importantes”.

Accionar control de cargar mensajes Muestra el componente de indicador de acción en curso mientras
importantes del bloque siguiente se trata la petición.
Éxito en petición: Oculta el componente de indicador de acción

70
en curso y muestra los mensajes actualizados del bloque siguiente
Fallo en petición: Oculta el componente de indicador de acción
en curso y muestra el componente de diálogo informativo con
mensaje “Ocurrió un error al obtener los mensajes importantes”.

COMPONENTE DE AGENDA

Accionar control de crear contacto con Muestra componente de diálogo informativo con mensaje “Por
ambos campos del formulario vacío favor, rellene los campos de Usuario y Alias”

Accionar control de crear contacto con Muestra componente de diálogo informativo con mensaje “Por
algún campo del formulario vacío favor, rellene los campos de Usuario y Alias”

Accionar control de crear contacto con Muestra el componente de indicador de acción en curso mientras
un usuario que no existe en la red se trata la petición.
Pastry
Éxito en petición: Muestra componente de diálogo informativo
con mensaje “El usuario introducido no existe”
Fallo en petición: Muestra componente de diálogo informativo
con mensaje “Error al crear el contacto”

Accionar control de crear contacto con Muestra el componente de indicador de acción en curso mientras
un usuario que sí existe en la red Pastry se trata la petición.
Éxito en petición: Cierra el componente de agenda y aparece la
conversación del grupo creada en el componente de
Conversación seleccionada.
Fallo en petición: Muestra componente de diálogo informativo
con mensaje “Error al crear el grupo”

Accionar control de crear grupo con el Muestra componente de diálogo informativo con mensaje “Por
campo del formulario vacío favor, rellene el campo de Nombre del grupo”

Accionar control de crear grupo con el Muestra el componente de indicador de acción en curso mientras
campo del formulario relleno se trata la petición.
Éxito en petición: Aparece el nuevo contacto en la lista de
contactos del componente de agenda
Fallo en petición: Muestra componente de diálogo informativo
con mensaje “Error al crear el contacto”

Accionar control de cerrar componente Oculta el componente de agenda

COMPONENTE DE CONTACTO

Accionar control de eliminar contacto Muestra el componente de indicador de acción en curso mientras
se trata la petición.
Éxito en petición: Desaparece el contacto eliminado de la lista
de contactos del componente de agenda
Fallo en petición: Muestra componente de diálogo informativo
con mensaje “Error al eliminar el contacto”

Accionar control de iniciar Ocultar componente de agenda y tramitar la petición.


conversación con contacto
Éxito en petición: Aparece la conversación con el contacto en la

71
lista de conversaciones abiertas y aparece también en el
componente de Conversación seleccionada..
Fallo en petición: Muestra componente de diálogo informativo
con mensaje “Error al crear la conversación”

Accionar control de unirse a grupo Muestra el componente de Unión a grupo

COMPONENTE DE UNIÓN A GRUPO

Accionar control de unirse a grupo sin Muestra componente de diálogo informativo con mensaje “Por
rellenar el formulario favor, rellene el campo de código de invitación”

Accionar control de unirse a grupo Ocultar componente de agenda y tramitar la petición.


rellenando el formulario
Éxito en petición: Aparece la conversación del grupo en la lista
de conversaciones abierta.
Fallo en petición: Muestra componente de diálogo informativo
con mensaje “Error al unirse al grupo”

Accionar control de cerrar componente Oculta el componente de unión a grupo


Tabla 10. Pruebas de validación de la pantalla de sesión iniciada

4.2.5 Revisión del Sprint


Tras la finalización del periodo relativo al desarrollo del Sprint, se lleva a cabo la revisión del mismo. En esta
sección se debe comprobar el incremento entregado por parte del equipo de desarrollo, comparándolo con la
planificación realizada al inicio. De esta forma, se valoran las funcionalidades que pueden considerarse como
terminadas y que, por tanto, pasan a formar parte del producto en producción.
En este Sprint, se estableció como alcance la consecución de la Historia de Usuario mostrada en la Tabla 3.
En las secciones anteriores se ha mostrado el trabajo desarrollado para la consecución de esta Historia de
Usuario, donde se pone de manifiesto la consecución de una interfaz gráfica que permite acceder a todas las
funcionalidades de la versión anterior del producto a través de controles gráficos, haciéndolas más accesibles
para el usuario.
La Historia de Usuario puede darse por terminada y la rama creada sobre el repositorio del producto puede
fusionarse para formar parte, a partir de este momento, de la versión en producción del producto. En la
siguiente iteración se realizará un nuevo trabajo de desarrollo, esta vez para realizar un incremento en cuanto al
número de funcionalidades disponibles, agregando la posibilidad de compartir ficheros a través de la propia
aplicación.

4.3 Sprint 2. Compartición de ficheros


En esta sección se detalla el trabajo realizado durante el segundo Sprint de evolución del producto para
conseguir un incremento que permita compartir ficheros a través de la aplicación. El contenido de la sección se
divide, para facilitar la lectura, en subsecciones. Se define en primera instancia la Historia de Usuario que se
incluye en la pila del Sprint. Después, se muestra la tecnología implicada en el trabajo del equipo de
desarrollo. En la siguiente subsección se muestra la planificación del Sprint, seguida del desarrollo del mismo
(mostrando el detalle de las tareas realizadas). La última subsección está dedicada a la sesión de revisión del
Sprint, para comprobar el incremento conseguido sobre el producto.

72
4.3.1 Definición de la Historia de Usuario
El segundo objetivo es introducido en la pila del producto como la siguiente Historia de Usuario:

𝐂𝐎𝐌𝐏𝐀𝐑𝐓𝐈𝐂𝐈Ó𝐍 𝐃𝐄 𝐅𝐈𝐂𝐇𝐄𝐑𝐎𝐒

“𝐂𝐨𝐦𝐨 𝑑𝑢𝑒ñ𝑜 𝑑𝑒𝑙 𝑝𝑟𝑜𝑑𝑢𝑐𝑡𝑜,


𝐪𝐮𝐢𝐞𝐫𝐨 𝑒𝑛𝑣𝑖𝑎𝑟 𝑦 𝑟𝑒𝑐𝑖𝑏𝑖𝑟 𝑎𝑟𝑐ℎ𝑖𝑣𝑜𝑠
𝐩𝐚𝐫𝐚 𝑑𝑖𝑠𝑝𝑜𝑛𝑒𝑟 𝑑𝑒 𝑐𝑜𝑚𝑝𝑎𝑟𝑡𝑖𝑐𝑖ó𝑛 𝑚𝑢𝑙𝑡𝑖𝑚𝑒𝑑𝑖𝑎 𝑒𝑛 𝑙𝑎 𝑎𝑝𝑙𝑖𝑐𝑎𝑐𝑖ó𝑛”

Tabla 11. Definición de la Historia de Usuario relativa al Objetivo 2

De esta forma, se traslada al equipo de desarrollo de forma clara y concisa el requisito funcional que tendrá
que implementar, esto es, proporcionar un método para enviar y recibir archivos a través de la aplicación, y el
valor que aportará al producto una vez logrado el incremento al finalizar el Sprint, esto es, la inclusión de una
nueva funcionalidad en la aplicación para dar soporte a la compartición multimedia, algo ampliamente
extendido en la mayoría de aplicaciones de mensajería actuales.

4.3.2 Tecnología implicada


Los elementos tecnológicos a tener en cuenta para entender la fase de desarrollo del Sprint son:
• API Google Drive. Para la compartición de ficheros a través de API de terceros.
• Junit. Para las pruebas unitarias de componentes.
• Tecnología implicada en Sprint 1. Como este Sprint también incluye desarrollo software tanto de
front-end como de back-end, la tecnología implicada en el Sprint 1 también tiene importancia en este.
En las siguientes subsecciones se detalla la tecnología implicada en este Sprint y que no ha sido presentada aún
en el TFM.

4.3.2.1 API Google Drive

La API (Application Programming Interface) de Google Drive [38] es una interfaz de


programación que permite a los desarrolladores de aplicaciones móviles, web y de escritorio
realizar operaciones de lectura, escritura y sincronización sobre archivos alojados en Google
Drive. Actualmente se encuentra en su versión 3, y permite el acceso seguro de los usuarios a su
alojamiento en la nube gracias al protocolo de autenticación OAuth 2.030 a través del servicio Google Sign-
In31, que se integra en la aplicación de forma transparente para el desarrollador. En este proyecto, se hace uso
de esta API para conseguir la compartición de archivos a través de la aplicación.

4.3.2.2 JUnit

JUnit es un marco de trabajo para realizar pruebas en aplicaciones Java32. Es ampliamente


utilizado en proyectos de desarrollo modulares, para comprobar de forma automática en cada
compilación que, tras los cambios en el código, se siguen cumpliendo los requisitos
funcionales de cada módulo independiente (pruebas unitarias) y los requisitos a nivel de interacción entre
módulos (pruebas de integración). En este proyecto, al introducir un nuevo módulo que controla la interacción
con la API de Google Drive, se utiliza este marco de trabajo para realizar las pruebas del mismo de forma
automática.

30 https://oauth.net/
31 https://developers.google.com/identity/sign-in/web/sign-in
32 https://junit.org/junit5/

73
4.3.2.3 Gradle

Gradle [39] es una herramienta que permite gestionar la construcción y ejecución de proyectos
software de forma automática. Otras herramientas de este estilo son Ant o Maven. De hecho,
Ant es la herramienta que se utilizaba en la anterior versión del proyecto. La razón de utilizar
Gradle es la posibilidad de inclusión de librerías a través de enlaces a repositorios, lo que
permite compilar y ejecutar los proyectos con las últimas versiones de las dependencias. Además, tiene un
lenguaje muy parecido al utilizado en Ant, por lo que el esfuerzo de aprendizaje tras utilizar Ant es
relativamente bajo. En este proyecto será utilizado para sustituir a Ant como gestor de construcción y
ejecución de código.

4.3.3 Planificación del Sprint


La Historia de Usuario planteada hace referencia a la inclusión de una nueva funcionalidad en la aplicación.
En concreto, se pretende permitir el envío de contenido multimedia a través de la aplicación que, en la
actualidad, sólo permite el envío de mensajes de texto plano. Para conseguir esto pueden plantearse varias
alternativas. En primer lugar, podría emplearse la propia red P2P como medio de almacenamiento de estos
archivos compartidos, y permitiendo el acceso a los mismos a través de su identificador Pastry y lanzando la
petición a través de la red. Otra alternativa podría ser la integración con un servicio de almacenamiento en la
nube para compartir los archivos a través de una plataforma independiente. En cualquier caso, esto será parte
de la primera tarea a llevar a cabo, estudiar las alternativas disponibles. Después, se seleccionará
justificadamente una de ellas y se dará paso al prototipado de la funcionalidad. Para esto, se empleará una
técnica de desarrollo del producto enfocado en el usuario, denominada “Customer Journey”. Con esta técnica,
se plasmará la interacción del usuario con la aplicación para identificar la mejor forma de agregar valor al
cubrir la necesidad descubierta. Una vez aceptado el prototipo, se realizarán los trabajos de desarrollo
pertinentes tanto en el front-end (incluyendo los elementos necesarios para la interacción con el usuario) como
en el back-end (modificando el controlador y/o el modelo de datos para soportar la nueva funcionalidad). Por
último, será necesario realizar las pruebas de validación pertinentes para comprobar el cumplimiento de las
expectativas del usuario. A continuación, se muestra el desglose de tareas en forma de tabla, incluyendo el
esfuerzo estimado por el equipo para el desarrollo de las mismas.

Tarea Esfuerzo estimado (horas)

Estudiar alternativas para compartir ficheros en aplicación Java 5

Establecer alternativa escogida 2

Definir funcionalidad mediante Mapa de experiencia del usuario 3

Desarrollar el front-end necesario para compartir archivos 12

Desarrollar el back-end necesario para compartir archivos 12

Realizar pruebas de validación 6

Tabla 12. Estimación de tareas para la Historia de Usuario relativa al Objetivo 2

4.3.4 Desarrollo del Sprint


En esta sección se pretende exponer el trabajo realizado durante el Sprint para conseguir el incremento de
valor en el producto a través de la funcionalidad descrita en la Historia de Usuario incluida en la pila del
Sprint. Para ello, se dedicará una subsección por cada tarea realizada.

4.3.4.1 Tarea: Estudiar alternativas para compartir ficheros en aplicación Java

Entre las alternativas disponibles, se contemplan:

74
• Almacenar los ficheros compartidos en la red Pastry. La primera opción que se presenta es la de
utilizar la propia red de pares como un sistema de ficheros distribuidos, de tal forma que todos los
nodos sean responsables de mantener dicho sistema. La compartición de ficheros, a priori, constaría
de dos partes: subir el fichero (o buscar uno que ya esté subido) a la red Pastry como un objeto que
dispondría de un identificador para acceder al mismo, y el acceso al contenido se realizaría a través de
este identificador (para más detalle sobre el funcionamiento de sistemas de ficheros distribuidos, ver la
sección Redes P2P del capítulo Marco contextual); y compartir el identificador del fichero que se
desea compartir con el contacto deseado a través de un mensaje de la aplicación. Esta opción puede
ser interesante, pero presenta algunos inconvenientes. Para empezar, un sistema de ficheros
distribuidos con pocos nodos podría suponer un alto coste de almacenamiento para los nodos y, por
otro lado, no podría garantizarse la disponibilidad si no hay suficientes réplicas y no hay cierta
estabilidad en el número de nodos conectados.
• Utilizar un servicio de almacenamiento en la nube externo y compartición mediante enlace. Otra
opción podría ser integrar algún servicio de almacenamiento externo que permita a los usuarios de la
aplicación compartir ficheros subiéndolos a este servicio y compartiendo un enlace de descarga
mediante un mensaje de la aplicación al contacto deseado. De esta forma, la red P2P no tiene
responsabilidad sobre la gestión de esos ficheros y la garantía de disponibilidad corre a cargo del
servicio externo. Hay muchos servicios de almacenamiento en la nube, (como Google Drive33,
Dropbox34 o Microsoft OneDrive35) que ofrecen tasas de disponibilidad del servicio cercanas al 100%
y disponen de una API para su integración en aplicaciones de terceros. Para esta integración, los
usuarios de la aplicación deben estar registrados en este servicio externo.
Para la consecución de la primera alternativa, debería utilizarse PAST [40]. PAST es una utilidad de
almacenamiento de ficheros punto a punto a gran escala, que proporciona una compartición de recursos
siempre disponible, seguro, cooperativo y escalable. Los ficheros en Past son inmutables, y pueden ser
compartidos a discreción del dueño de los mismos. Está desarrollada por los mismos desarrolladores de
FreePastry y, de hecho, está diseñada para funcionar sobre dicha red. En la aplicación actual se utiliza para el
almacenamiento de los objetos persistentes dentro de la red Pastry, esto es, todo lo que tiene entidad de objeto
Pastry (identificadores de usuario, identificadores de grupos y bloques de mensajes). Por lo tanto, debería
desarrollarse un conjunto de métodos que permitan, en el back-end, realizar la inclusión de nuevos objetos
(ficheros) y modificar el modelo de datos para contemplar estos nuevos objetos. En el front-end sería necesario
hacer accesible para los usuarios esta nueva funcionalidad en el componente de conversación seleccionada
(tanto la funcionalidad de compartir un fichero, como la de obtener dicho fichero compartido).
En cuanto a la segunda alternativa, el trabajo a realizar pasaría por la selección de un proveedor de servicio de
almacenamiento en la nube y la definición de la interacción necesaria con la API del servicio externo de
almacenamiento en la nube. Después, sería necesaria la creación de un nuevo componente en el back-end que
controlase dicha interacción. Además, sería necesario hacer accesible esta nueva funcionalidad en el
componente de conversación seleccionada del front-end (tanto la funcionalidad de compartir un fichero, como
la de obtener dicho fichero compartido). Entre las tres alternativas de proveedores de servicios de
almacenamiento en la nube, tras analizar la documentación de las APIs y la facilidad de integración con Java,
se decide que, en caso de seleccionar esta opción para el desarrollo de la funcionalidad, se utilizará Google
Drive por disponer de un SDK específico para Java de su API (Dropbox también) y la cantidad de
documentación y tutoriales disponibles para facilitar el aprendizaje (En Dropbox se dispone de menos
documentación guiada).
Tras analizar ambas alternativas, el equipo de desarrollo deberá seleccionar en la siguiente tarea la alternativa
con la que se pretende abordar la Historia de Usuario y el planteamiento inicial a seguir.

4.3.4.2 Tarea: Establecer alternativa escogida

En esta tarea se debe recoger la alternativa tecnológica escogida para llevar a cabo el incremento del producto
que permita a los usuarios compartir ficheros a través de la aplicación. Para evitar problemas de disponibilidad

33 https://www.google.es/drive/apps.html
34 https://www.dropbox.com/es
35 https://www.microsoft.com/es-es/microsoft-365/onedrive/online-cloud-storage

75
de los ficheros y reducir la complejidad de la solución a aplicar, se decide abogar por la integración de un
servicio de almacenamiento en la nube externo. Así, la complejidad quedará reducida a la interacción con una
API actualizada (la última versión de PAST es de 2001), y los problemas que puedan aparecer quedarán
reducidos al ámbito de integración con la API, pues la compartición con los distintos contactos de un fichero
se hará a través de un mensaje de la aplicación, algo ya implementado y probado.
Como se comentó en la subsección anterior, el proveedor preferido para realizar la integración es Google
Drive. Este proveedor dispone de una documentación completa de la API [38] de compartición de archivos,
además de la API [41] de cliente Java, necesaria para la autenticación de los usuarios y el uso de la API de
Google Drive. Por último, se proporciona un conjunto extenso de tutoriales de introducción y adquisición de
los conocimientos básicos para su uso. La primera toma de contacto como Prueba de Concepto se ha llevado a
cabo a través del tutorial Java Quickstart [42], a través del cual se da de alta una API de prueba, se crea un
proyecto Java con Gradle y se crea una clase de ejemplo que autentica un usuario mediante su cuenta Google y
lista los ficheros contenidos en su directorio raíz de Google Drive. En la siguiente captura de pantalla se
muestra la API que se ha dado de alta para esta prueba, en la consola de Google APIs36 para desarrolladores.

Figura 79. Captura de la consola de Google APIs donde se muestra la API creada para la Prueba de Concepto
con Google Drive API
En la siguiente imagen se muestra la ejecución de la clase de prueba y la pantalla de autenticación de Google
que se lanza antes de poder mostrar los ficheros del directorio de Google Drive.

Figura 80. Prueba de concepto realizada con la API de Google Drive. Autenticación requerida por Google
(arriba) y listado de ficheros encontrados en el directorio de Google Drive (abajo)
Una vez probado el funcionamiento básico de la API de Google Drive, se comienza con las tareas relativas al
prototipado de la funcionalidad. En este Sprint, se utilizará un recurso de definición de la funcionalidad
mediante un recurso de las metodologías ágiles llamado Mapa de experiencia del usuario.

36 https://console.developers.google.com/apis/

76
4.3.4.3 Tarea: Definir funcionalidad mediante Mapa de experiencia del usuario

Para entender el requisito funcional desde el punto de vista del usuario, se utilizará una técnica relativa al
desarrollo de productos denominada Mapa de experiencia del usuario (en inglés, Customer journey). El
Customer Journey o Mapa de la Experiencia del Cliente define las distintas actividades que desarrolla un
usuario en el uso de un producto o servicio [43]. El Customer Journey tiene varias variantes. Esas actividades
pueden venir acompañadas de las necesidades del cliente para cada momento, y de los "touchpoints" o puntos
de contacto entre él y la empresa detrás del producto o servicio. Igualmente esas actividades pueden estar
posicionadas según el grado de satisfacción del cliente. Es una herramienta muy eficaz para diseñar una
solución, o para detectar puntos conflictivos de un producto o servicio existentes que pudieran requerir una
mejora.
Así, mediante esta técnica se pasa a describir la interacción esperada desde el punto de vista de un usuario con
esta nueva funcionalidad. Como existen multitud de aplicaciones de mensajería a través de servidores
centralizados que disponen de la funcionalidad de compartir ficheros, es sencillo analizar cómo interactúa un
usuario con esta funcionalidad en algunas de ellas.
Habitualmente, la interacción del usuario con esta funcionalidad en otras aplicaciones sigue los siguientes
pasos:
1. El usuario accede a la interfaz gráfica de la aplicación
2. Se dispone de un control para acceder a la funcionalidad, bien en una botonera general de la
aplicación o a través de un botón/icono ubicado dentro del contexto de la conversación con el contacto
con el que se quiere compartir el fichero.
3. El usuario acciona el control descrito en el anterior paso
4. La interfaz gráfica le permite seleccionar el fichero a compartir mediante un componente de
navegación de directorios que puede ser nativo de la plataforma en la que se ejecuta o está
desarrollado específicamente para la aplicación.
5. El usuario navega hasta encontrar el fichero deseado.
6. El usuario selecciona el fichero y dispone de un control para confirmar la acción.
7. Tras procesarse en back-end la acción, la conversación con el contacto seleccionado se actualiza,
mostrando el archivo enviado con algún formato específico (un mensaje saliente con un enlace, un
icono, etc).
8. El usuario que recibe el archivo visualiza el mensaje recibido donde dispone de un control para
realizar la descarga en el directorio de descargas por defecto o, en algunos casos, pudiendo seleccionar
el directorio donde desea almacenar el archivo.
En base al Mapa de Experiencia de usuario descrito anteriormente, se establecen una serie de requisitos de
back-end y front-end que deberán cumplirse para proporcionar correctamente la funcionalidad de compartición
de ficheros. A continuación, se detallan estos requisitos:
• Back-end. Será necesario crear un componente nuevo en el controlador que permita interactuar con la
API del proveedor de servicio de almacenamiento en la nube para:
o Autenticar un usuario en el servicio de almacenamiento en la nube.
o Subir un fichero al servicio de almacenamiento en la nube.
o Obtener un enlace al fichero subido al servicio de almacenamiento en la nube, para poder
compartirlo en un mensaje.
o Descargar un fichero del servicio de almacenamiento en la nube, y ubicarlo en un directorio
local específico.
• Front-end. Será necesario modificar la interfaz gráfica y agregar nuevos componentes para que el
usuario pueda enviar ficheros y descargar ficheros recibidos. En concreto, se necesita:
o Control para acceder a la funcionalidad de compartición de ficheros.

77
o Componente para seleccionar fichero a compartir.
o Componente para representar un mensaje que incluye un fichero compartido, que disponga
de un control para realizar la descarga del fichero.
Para terminar la definición de la interacción, se proponen los prototipos para la interfaz gráfica de los
componentes y controles identificados en el Mapa de experiencia de usuario:
• Control para acceder a funcionalidad de compartir ficheros. Se propone un control accesible
dentro del componente de conversación seleccionada, representado por un icono de un clip. El clip es
ampliamente utilizado en aplicaciones de mensajería (como el correo electrónico) para identificar la
presencia de ficheros adjuntos o para realizar la acción de adjuntar un fichero. A continuación se
muestra el prototipo de la pantalla de sesión iniciada con la inclusión del icono descrito.

Figura 81. Prototipo de la pantalla de sesión iniciada con el nuevo control para compartir ficheros
• Componente para seleccionar el fichero a compartir. Nuevo componente que permite al usuario
seleccionar un fichero para compartirlo a través de la aplicación. Debería disponer de una sección para
navegar por los directorios locales y dos controles: uno para confirmar la selección de un fichero; y
otro para cancelar la acción de compartir un fichero y volver a la pantalla de sesión iniciada. A
continuación se muestra el prototipo para este componente.

Figura 82. Prototipo del componente para seleccionar el fichero a compartir en la aplicación
• Componente de mensaje con fichero adjunto. Se trata de una modificación del componente
mensaje (enviado o recibido) que identifique claramente que se trata de un mensaje que contiene un
fichero adjunto y que disponga de un control para realizar la descarga del mismo en el sistema de
ficheros local. A continuación se muestra el prototipo para este componente en el caso de mensaje
enviado. El prototipo para el caso de mensaje recibido sólo varía en el color de fondo.

78
Figura 83. Prototipo del componente de mensaje (enviado) que incluye un fichero compartido
Tras definir los requisitos y los prototipos relativos a los cambios en la interfaz gráfica, con el apoyo de la
técnica de Mapa de Experiencia de Usuario, el equipo de desarrollo deberá realizar las implementaciones
necesarias para conseguir el incremento del producto que incluya la funcionalidad de compartición de ficheros.

4.3.4.4 Tarea: Desarrollar el front-end necesario para compartir archivos

En esta tarea se desarrollará el código para implementar la parte de la vista que interactúa con el usuario. Para
esta nueva funcionalidad, se llevan a cabo los siguientes cambios:
• Modificación de componente de conversación seleccionada. Se incluye el control para compartir
un fichero a través de la aplicación, siguiendo las directrices del prototipo de la Figura 81. En la
siguiente figura se muestra una captura del aspecto final de la pantalla con este nuevo control.

Figura 84. Captura de la pantalla de sesión iniciada con el nuevo control para compartir ficheros
• Componente de navegador de ficheros. Es el componente que permite seleccionar el fichero para
compartir a través de la aplicación. Se ha decidido utilizar el explorador nativo de la plataforma en la
que se ejecute la aplicación, por la sencillez de integración con la misma. Sólo ha sido necesario
declarar un bloque HTML input de tipo file. Este elemento HTML permite almacenar un fichero
seleccionado del sistema de directorios local al hacer click en él37. En la siguiente figura se muestra el
aspecto de este elemento.

Figura 85. Elemento input de HTML de tipo file para adjuntar archivos en páginas web38
En el código del proyecto, se ha incluido un elemento de este tipo, pero oculto. El evento de click
sobre este elemento se ha asociado mediante Javascript al click sobre el control descrito en el punto
anterior, que ha sido incluido en el componente de conversación seleccionada para compartir ficheros.

37 https://www.w3schools.com/tags/att_input_type_file.asp
38 Referencia de la imagen: https://www.w3schools.com/tags/tryit.asp?filename=tryhtml5_input_type_file

79
Una vez seleccionado un fichero, éste y sus propiedades (nombre, fecha de última modificación, etc)
son accesibles como objetos Javascript. En la siguiente figura se muestra el explorador de archivos
que aparece en el equipo utilizado para el desarrollo de código.

Figura 86. Componente de navegador de ficheros para seleccionar el fichero a compartir


• Componente de mensaje con fichero adjunto. Se trata de una modificación del componente de
mensaje, para mostrar como contenido del mismo el nombre del fichero compartido y un control para
lanzar la descarga del mismo en el sistema de ficheros local. Un mensaje que contiene un fichero
compartido siempre seguirá el patrón “Archivo compartido: NOMBREFICHERO | ID:
IDFICHERODRIVE”. Cuando se muestren los mensajes en el componente de conversación
compartida, para cada mensaje, se comprobará si contiene un archivo compartido o no. En ese caso, el
componente se mostrará como se muestra en la siguiente figura.

Figura 87. Captura del componente de mensaje con fichero adjunto.


Para entender el flujo que sigue la aplicación una vez que se interactúa con el control de compartición de
ficheros y con el de descarga de un fichero compartido, se muestran a continuación los diagramas de flujo
asociados a la parte front-end.

Figura 88. Diagramas de flujo tras accionar el control de compartir fichero (izquierda) y el de descargar fichero
(derecha)

80
4.3.4.5 Tarea: Desarrollar el back-end necesario para compartir archivos

En cuanto a las tareas de back-end, en primer lugar ha sido necesario habilitar la API asociada al proyecto,
para integrar las funciones de Google Drive. Esto se realiza de una forma sencilla desde la consola de APIs de
Google39, creando un nuevo proyecto y, después, habilitando la API de Google Drive y descargando las
credenciales de uso en formato JSON (proceso detallado en el ANEXO I. Instalación, ejecución y
dependencias). El fichero JSON con las credenciales de autenticación OAuth se ubica en la ruta
app/src/main/res y será necesario para que la aplicación pueda autenticar a los usuarios en Google para el uso
de la API.
Por otro lado, se ha creado una nueva clase dentro del controlador GoogleDriveController.java que permitirá
la interacción con la API de Google Drive a través de los siguientes métodos:
• getCredentials. Método que permite obtener un objeto de la clase Credential y que se utiliza para
construir el servicio de Drive en cada interacción con la API. Este método se ha tomado directamente
de la página oficial de la documentación40.
• listarArchivos. Crea una instancia de servicio Drive para interactuar con la API y devuelve el listado
de ficheros ubicados en el directorio raíz de la cuenta de Google autenticada. Este método se ha
tomado de la documentación oficial, a modo de prueba29.
• crearDirectorio. Crea una instancia de servicio Drive para interactuar con la API y crea un directorio
con un determinado nombre (pasado por parámetros) dentro del directorio raíz de la cuenta de Google
autenticada. Se utiliza el método Drives.Files.Create de la API41.
• crearArchivoDesdeRuta. Crea una instancia de servicio Drive para interactuar con la API. Después
instancia un objeto java.io.File a partir de la ruta pasada por parámetro y se utiliza como parámetro
del método Drives.Files.Create de la API42, tras convertirlo a la clase
com.google.api.client.http.FileContent.
• buscarArchivosDirectorios. Crea una instancia de servicio Drive para interactuar con la API y
devuelve el listado de ficheros o directorios obtenidos mediante el método Drives.Files.list de la
API43, pasando una cadena de caracteres por parámetros que actúa como filtro, de la forma
“name=NOMBREARCHIVOODIR and mimeType=FORMATOARCHIVOODIR”.
• obtenerEnlaceCompartirArchivo. Crea una instancia de servicio Drive para interactuar con la API
y obtiene la propiedad webContentLink del fichero cuyo ID se pasa por parámetros. Esta propiedad
contiene la URL para descargar el archivo desde un navegador.
• descargarArchivo. Crea una instancia de servicio Drive para interactuar con la API. Después
instancia un objeto de la clase java.io.FileOutputStream para almacenar el contenido del archivo a
descargar, a partir de la ruta local pasada por parámetros. Por último, utiliza el método
.files().get(id).executeMediaAndDownloadTo(fileoutputstream) de la API44 para descargar el fichero
cuyo identificador se recibe por parámetros en el fichero instanciado anteriormente.
El componente controlador de Google Drive es creado al iniciar la aplicación. El usuario deberá autenticarse
entonces en Google para poder utilizar la aplicación. Para ello, la propia librería de la API lanza el navegador
por defecto del equipo con la página de autenticación, donde se darán los permisos necesarios a la aplicación

39 https://console.developers.google.com
40 https://developers.google.com/drive/api/v3/quickstart/java#step_3_set_up_the_sample
41https://developers.google.com/resources/api-

libraries/documentation/drive/v3/java/latest/com/google/api/services/drive/Drive.Files.html#create-
com.google.api.services.drive.model.File-
42https://developers.google.com/resources/api-

libraries/documentation/drive/v3/java/latest/com/google/api/services/drive/Drive.Files.html#create-
com.google.api.services.drive.model.File-
43https://developers.google.com/resources/api-

libraries/documentation/drive/v3/java/latest/com/google/api/services/drive/Drive.Files.html#list--
44 https://developers.google.com/resources/api-
libraries/documentation/drive/v3/java/latest/com/google/api/services/drive/Drive.Files.Get.html#executeMediaAndDownloadTo-
java.io.OutputStream-

81
para la compartición de ficheros. En la siguiente figura se muestra una captura de pantalla de la autenticación
con Google.

Figura 89. Autenticación de la aplicación para usar la API de Google Drive


Además, se ha creado un fichero de pruebas unitarias GoogleDriveTest.java para la realización de pruebas
automáticas con el framework de JUnit en cada compilación del código. De esta forma, si un cambio provoca
que alguno de los métodos del nuevo componente deje de funcionar, podrá tomarse una acción
inmediatamente. De hecho, el archivo “.jar” no será generado si las pruebas no son superadas. El fichero de
pruebas se ubica en la ruta app/test/java/us/tfg/p2pmessenger, y lleva a cabo la ejecución en secuencia de las
siguientes acciones:
1. Listar los ficheros del directorio raíz de Google Drive
2. Buscar un directorio en el directorio raíz (“P2P-Messenger-test”)
3. Crear un directorio en el directorio raíz (“P2P-Messenger-test”)
4. Crear un archivo (“test-archivo.txt”) dentro del directorio creado anteriormente.
5. Buscar el archivo creado anteriormente.
6. Obtener el enlace para compartir el archivo creado anteriormente.
Cada una de estas pruebas es un método de la clase GoogleDriveTest y se ejecutan automáticamente en el
proceso de compilación, al incluir la directiva @Test justo antes de la declaración del método. Una vez
realizados los tests, se genera un informe en el directorio build/reports/tests/test/classes en formato HTML que
puede abrirse con un navegador. En la siguiente figura se muestra el aspecto de este informe.

Figura 90. Informe de resultados de los tests Junit pasados a la clase GoogleDriveController en formato
HTML
Este informe da la posibilidad de ver la salida específica de cada uno de los tests, haciendo click sobre el botón
“Standard output”. A continuación, se muestra la salida en bruto de los tests:
Constructor DRive Controller
Please open the following address in your browser:

82
https://accounts.google.com/o/oauth2/auth?access_type=offline&client_id=497983782705-
vo11fjr4trq9tjfphpa2emvhd1pfnnd9.apps.googleusercontent.com&redirect_uri=http://localhost:8888/Callback&response_type=code&scope=https://
www.googleapis.com/auth/drive.file
Attempting to open that address in the default browser now...
FIN Constructor DRive Controller
----------------------------------
----- TEST testCrearArchivo---
----------------------------------
Archivo creado con id= 1_JZeD8iXaNU5MZ8zH9Mab56CTGqVPuYo
name= test-archivo.txt
Constructor DRive Controller
FIN Constructor DRive Controller
----------------------------------
----- TEST testBuscarDirectorio---
----------------------------------
name='P2P-Messenger-test' and mimeType = 'application/vnd.google-apps.folder'
Contenido encontrado: P2P-Messenger-test (1U-DiIRi27vqwN0OWqmMWLI0CMnl7PNhr)
Constructor DRive Controller
FIN Constructor DRive Controller
----------------------------------
----- TEST testCompartirArchivo---
----------------------------------
name='test-archivo.txt'
Enlace para compartir archivo: https://drive.google.com/uc?id=1_JZeD8iXaNU5MZ8zH9Mab56CTGqVPuYo&export=download
Constructor DRive Controller
FIN Constructor DRive Controller
----------------------------------
----- TEST testListarArchivos---
----------------------------------
Files:
test-archivo.txt (1_JZeD8iXaNU5MZ8zH9Mab56CTGqVPuYo)
P2P-Messenger-test (1U-DiIRi27vqwN0OWqmMWLI0CMnl7PNhr)
1247375.jpg (18T5TfwACQ6dlRydaPPwiRVmezKiHFbjB)
test.txt (1lx384FRHZ4YPEgmIRCMoKb03WCH_DPi5)
1247375.jpg (1OAnHlcbvpH00LuhbQfAB1IwvfqknkzTW)
1247375.jpg (1kQDvsQE0WBnf6BmzCOLaB7KxUQZkdXbv)
1247375.jpg (13sp5ZfLgnEEwLtuMA2c6jqIfI9nvzk2b)
test.txt (1BsGlYbghxgPtkA40EN4mbFLPBGt6wa-s)
1247375.jpg (1V5XlRy6T7C9T_BJj0c2MLaw-sCy2kGTg)
1247375.jpg (1bekpMabuo_GJmYITqBkAnRcCHL3v9j-N)
Constructor DRive Controller
FIN Constructor DRive Controller
----------------------------------
----- TEST testCrearDirectorio---
----------------------------------
Created folder with id= 1BOETkGwzkLexKb67EDQ8KjQZf3Tr8_wc
name= P2P-Messenger-test
Constructor DRive Controller
FIN Constructor DRive Controller
----------------------------------
----- TEST testBuscarArchivo---
----------------------------------
name='test-archivo.txt'
Contenido encontrado: test-archivo.txt (1_JZeD8iXaNU5MZ8zH9Mab56CTGqVPuYo)

Tabla 13. Informe de resultados de los tests Junit pasados a la clase GoogleDriveController en formato XML
En la siguiente figura se muestra cómo se ha creado correctamente el directorio de test y se ha creado y
ubicado un archivo de test.

Figura 91. Directorio y archivo creados mediante tests unitarios con Junit
Por último, ha sido necesario modificar el código de la clase JavaConnector para trasladar las peticiones
originadas mediante la interacción del usuario con la interfaz gráfica al controlador y devolver información
acerca del resultado de las acciones llevadas a cabo. Se agregan los siguientes métodos:
• enviarArchivoDrive. Este método se lanza al recibir la solicitud de compartir un fichero por parte del
front-end. Se busca recursivamente en el sistema de ficheros local el fichero que concuerda en nombre
y fecha de última modificación con las propiedades pasadas por parámetros desde el front-end. Si no
lo encuentra, se notificará al usuario (componente de diálogo de mensaje informativo) de que no pudo
compartirse el fichero. Si lo encuentra, subirá el fichero al directorio de Drive de la aplicación
(creando dicho directorio en caso de no existir aún). Si ocurriese alguna excepción durante este
proceso, se notificará al usuario (componente de diálogo de mensaje informativo) de que no pudo

83
compartirse el fichero. Finalmente, se formateará un mensaje con fichero adjunto y se enviará a la
conversación seleccionada, refrescando después el componente para que aparezca el nuevo mensaje
con el fichero compartido. A continuación se muestra el flujo de este método.

Figura 92. Flujo asociado al método enviarArchivoDrive de la clase JavaConnector


• buscarDirectorioDrive. Este método es auxiliar al anterior. Sirve para obtener el identificador del
directorio de Google Drive con un determinado nombre, haciendo una llamada al método del
controlador disponible para ello (buscarArchivosDirectorios, descrito al inicio de sección). Devuelve
el ID del directorio o NULL si no se encuentra. En la Figura 93 se muestra el flujo de este método.
• descargarArchivo. Al recibir la solicitud de descargar un fichero desde el front-end, con el ID del
fichero de Drive y el nombre del fichero local (será el mismo que el nombre del fichero ubicado en
Google Drive), se lanza el método de descarga del controlador. Si el método termina sin ninguna
excepción, se notificará al usuario, mediante el componente de diálogo de mensaje informativo, que
su fichero ya ha sido descargado y está disponible en el directorio de ejecución de la aplicación. Si se
lanza alguna excepción se notificará del error al usuario mediante el componente de diálogo de
mensaje informativo. En la Figura 93 se muestra el flujo de este método.

Figura 93. Flujo asociado al método buscarDirectorioDrive (izquierda) y descargarArchivo (derecha) de la


clase JavaConnector

84
4.3.4.6 Tarea: Realizar pruebas de validación

La última tarea del Sprint contempla las pruebas realizadas para validar que los cambios realizados en la
interfaz gráfica permiten realizar las funciones requeridas por la Historia de Usuario incluida en la pila del
Sprint. Las pruebas se planifican estipulando las pruebas que habrá que realizar en la pantalla de sesión
iniciada y sus nuevos componentes, anotando la descripción de la prueba a realizar y el resultado esperado. A
continuación, se muestran en una tabla todas las pruebas preparadas para la validación, y que han sido
utilizadas como criterio para dar por aceptado el desarrollo.

Ubicación Prueba Resultado esperado

Accionar control de compartición Muestra componente de navegador de


Pantalla general
de ficheros ficheros para seleccionar fichero a compartir

Oculta componente de navegador de ficheros


y, según resultado de petición de
compartición de fichero:
Éxito en petición: muestra la conversación
Componente Accionar control de confirmación
actualizada con el componente de mensaje
navegador de ficheros tras seleccionar un fichero
enviado con fichero adjunto.
Fallo en petición: muestra el componente de
mensaje informativo con el texto devuelto
por el controlador.

Componente Ocultar componente de navegador de


Accionar control de cancelación
navegador de ficheros ficheros

Ejecuta petición al controlador para


descargar el fichero:
Éxito en la petición: muestra componente de
mensaje informativo para notificar que el
Componente mensaje Accionar control de descarga de
fichero se descargó correctamente (en el
con fichero adjunto fichero
directorio de ejecución).
Fallo en la petición: muestra componente de
mensaje informativo con el texto de error
devuelto por el controlador.

Tabla 14. Pruebas de validación de la funcionalidad de compartición de ficheros

4.3.5 Revisión del Sprint


Tras la finalización del periodo relativo al desarrollo del Sprint, se lleva a cabo la revisión del mismo. En esta
sección se debe comprobar el incremento entregado por parte del equipo de desarrollo, comparándolo con la
planificación realizada al inicio. De esta forma, se valoran las funcionalidades que pueden considerarse como
terminadas y que, por tanto, pasan a formar parte del producto en producción.
En este Sprint, se estableció como alcance la consecución de la Historia de Usuario mostrada en la Tabla 11.
En las secciones anteriores se ha mostrado el trabajo desarrollado para la consecución de esta Historia de
Usuario, donde se pone de manifiesto la inclusión de una función para compartir archivos a través de la
aplicación, haciendo uso de un servicio de almacenamiento en la nube (Google Drive). El receptor de los
ficheros puede descargarlos directamente desde la aplicación en el directorio de ejecución de su aplicación.
La Historia de Usuario puede darse por terminada y la rama creada sobre el repositorio del producto puede

85
fusionarse para formar parte, a partir de este momento, de la versión en producción del producto. En la
siguiente iteración se buscará solución a la problemática que se presenta cuando los usuarios que utilizan la
aplicación no se encuentran en una red con visibilidad directa entre los nodos (como una organización), para
que, independientemente de la configuración de la red, puedan crear una red de comunicación a través de
Pastry.

4.4 Sprint 3. Comunicación de nodos en redes con NAT


4.4.1 Definición de la Historia de Usuario
El tercer objetivo es introducido en la pila del producto como la siguiente Historia de Usuario:

𝐂𝐎𝐌𝐔𝐍𝐈𝐂𝐀𝐂𝐈Ó𝐍 𝐃𝐄 𝐍𝐎𝐃𝐎𝐒 𝐄𝐍 𝐑𝐄𝐃𝐄𝐒 𝐂𝐎𝐍 𝐍𝐀𝐓

“𝐂𝐨𝐦𝐨 𝑑𝑢𝑒ñ𝑜 𝑑𝑒𝑙 𝑝𝑟𝑜𝑑𝑢𝑐𝑡𝑜,


𝐪𝐮𝐢𝐞𝐫𝐨 𝑢𝑡𝑖𝑙𝑖𝑧𝑎𝑟 𝑙𝑎 𝑎𝑝𝑙𝑖𝑐𝑎𝑐𝑖ó𝑛 𝑑𝑒𝑠𝑑𝑒 𝑢𝑛𝑎 𝑟𝑒𝑑 𝑐𝑜𝑛 𝑁𝐴𝑇
𝐩𝐚𝐫𝐚 𝑞𝑢𝑒 𝑙𝑎 𝑐𝑜𝑛𝑓𝑖𝑔𝑢𝑟𝑎𝑐𝑖ó𝑛 𝑑𝑒 𝑟𝑒𝑑 𝑛𝑜 𝑟𝑒𝑠𝑡𝑟𝑖𝑛𝑗𝑎 𝑚𝑖 𝑢𝑠𝑜 𝑑𝑒 𝑙𝑎 𝑎𝑝𝑙𝑖𝑐𝑎𝑐𝑖ó𝑛”

Tabla 15. Definición de la Historia de Usuario relativa al Objetivo 3


De esta forma, se traslada al equipo de desarrollo de forma clara y concisa el requisito funcional que tendrá
que implementar, esto es, permitir que los nodos puedan conectarse y comunicarse en la red P2P aunque no
tengan visión directa entre ellos, y el valor que aportará al producto una vez logrado el incremento al finalizar
el Sprint, esto es, que el funcionamiento de la aplicación no se vea restringido por la configuración de la red
donde se encuentra ubicado un usuario concreto. Es necesario tener en cuenta que la aplicación en su estado
actual puede funcionar perfectamente para la comunicación dentro de una organización (por ejemplo, una
empresa), pero no para la comunicación entre usuarios que no tienen una relación de este tipo (por ejemplo,
dos amigos que quieren comunicarse desde sus respectivas casas). En la actualidad, la mayoría de los hogares
con conexión a Internet disponen de una red privada donde el router instalado por su proveedor de servicios
impide las conexiones hacia dentro. Aunque la configuración puede cambiarse en muchos casos, esta es una
solución válida para usuarios con conocimientos de redes (no es el perfil de usuario medio) y, aun así, implica
acciones independientes a la aplicación, ofreciendo una mala experiencia de usuario.

4.4.2 Tecnología implicada


Los elementos tecnológicos a tener en cuenta para entender la fase de desarrollo del Sprint son:
• OpenVPN. Para establecer una Red Privada Virtual (VPN) entre nodos que no tienen visión directa.
• Google Cloud Platform. Para disponer de una red externa donde ubicar nodos que no tienen visión
directa con el nodo donde se lleva a cabo el desarrollo y para alojar el servidor VPN.
• WireShark. Para analizar el tráfico de red y comprobar que la comunicación se establece
correctamente y la aplicación funciona a través de VPN.
En las siguientes subsecciones se detalla la tecnología implicada en este Sprint y que no ha sido presentada aún
en el TFM.

4.4.2.1 OpenVPN

OpenVPN es un protocolo de código abierto para el establecimiento de redes privadas


virtuales (Virtual Private Network, VPN) punto-contra-punto y sede-contra-sede45. Mediante
una VPN, se puede establecer un canal de comunicación segura sobre una red insegura (como
Internet). Uno de los usos más extendidos de este tipo de redes es el acceso a redes

45 https://openvpn.net/

86
corporativas desde el exterior, a través de un cliente VPN que configure la interfaz de red del equipo.
OpenVPN utiliza la librería OpenSSL junto con el protocolo TLS para el cifrado del tráfico. En este proyecto,
OpenVPN es seleccionado como solución para permitir el correcto funcionamiento de la aplicación en
situaciones donde los nodos no tienen visión directa y, por lo tanto, no pueden establecer conexiones en ambos
sentidos.

4.4.2.2 Google Cloud Platform

Google Cloud Platform es el conjunto de servicios de computación en la nube de Google46.


Ofrece tanto servicios IaaS (Infrastructure as a Service) como PaaS (Platform as a Service),
lo cual implica que puede utilizarse tanto para consumir recursos de computación en bruto
(por ejemplo, máquinas virtuales con un Sistema Operativo y una cantidad de recursos
determinada), como para desplegar aplicaciones y servicios sin preocuparse de la infraestructura que debe
soportarlos. En este proyecto, se utiliza Google Cloud Platform para disponer de una red privada con un nodo
donde se ejecutará la aplicación de mensajería P2P, además de alojar un servidor OpenVPN que permitirá
probar la aplicación entre nodos sin visión directa.

4.4.2.3 Wireshark

Wireshark47 es un analizador de protocolos que permite capturar el tráfico cursado en una


red de ordenadores, mostrándolo de forma intuitiva para las personas y dando la
posibilidad de visualizarlo con gran cantidad de detalle de forma interactiva. Es
ampliamente utilizado a nivel mundial tanto en el plano académico como en el plano profesional, debido a su
licencia de código abierto y sus versiones para distintas plataformas (Windows, macOS, Linux y UNIX). En
este proyecto se utiliza Wireshark para comprobar cómo se comunican efectivamente dos nodos que se
encuentran en redes sin visión directa (una vez establecida la VPN con OpenVPN). Además, será utilizado
para corroborar la consecución del último objetivo, relativo a la securización del canal de comunicaciones
utilizado por la aplicación.

4.4.3 Planificación del Sprint


La Historia de Usuario planteada hace referencia al problema que presentan las redes P2P cuando los nodos
que quieren formar parte de la red no tienen visión directa con el resto de nodos. Como se vio en el capítulo de
Marco contextual, los nodos de las redes P2P actúan a veces como servidores y a veces como clientes. Para
que un nodo pueda actuar como servidor, debe ser capaz de recibir peticiones de conexión del resto de nodos.
Cuando un nodo se encuentra en una red (física) donde hay un elemento de red que aplica reglas NAT
(traducción de direcciones de red) para el acceso a otra red, como Internet, las conexiones entrantes de otros
nodos de la red P2P no son posibles. Aunque se pueden establecer reglas para reenviar el tráfico a una
determinada dirección de la red privada, este no es el escenario común ni más fácil de conseguir para la
mayoría de usuarios. Por ello, se plantea la búsqueda de una solución para que la aplicación sea soportada en
este tipo de ámbitos. Esta búsqueda será la primera tarea a realizar en el Sprint, dando paso a la selección de
una alternativa de forma justificada. Esta Historia de Usuario, en principio, no implica cambios en la interfaz
con el usuario. En todo caso, llevará asociado un desarrollo relativo al back-end. Lo que parece seguro es que
será necesario plantear un escenario para validar la propuesta y llevar a cabo una serie de configuraciones para
ponerlo en práctica y poder validar la propuesta. A continuación, se muestra el desglose de tareas en forma de
tabla, incluyendo el esfuerzo estimado por el equipo para el desarrollo de las mismas.

Tarea Esfuerzo estimado (horas)

Estudiar alternativas para comunicación sin visión directa 7

Establecer alternativa escogida 3

46 https://cloud.google.com/?hl=es-419
47 https://www.wireshark.org/

87
Definir el escenario de validación de la propuesta 10

Configurar el escenario de validación de la propuesta 20

Desarrollo back-end 10

Realizar pruebas de validación de la propuesta 6

Tabla 16. Estimación de tareas para la Historia de Usuario relativa al Objetivo 3

4.4.4 Desarrollo del Sprint


En esta sección se pretende exponer el trabajo realizado durante el Sprint para conseguir el incremento de
valor en el producto a través de la funcionalidad descrita en la Historia de Usuario incluida en la pila del
Sprint. Para ello, se dedicará una subsección por cada tarea realizada.

4.4.4.1 Estudiar alternativas para comunicación sin visión directa

El problema de base de la Historia de Usuario planteada para este Sprint reside en las propiedades del
protocolo de red IPv4 [44]. Las direcciones de red de IPv4 tienen un tamaño de 32 bits, lo que supone que el
espacio de direccionamiento es de 232 = 4.294.967.296 direcciones únicas. Teniendo en cuenta que se
estima que 2020 finalizará con 50 mil millones de dispositivos conectados a Internet [45], entre otras cosas,
por la irrupción del Internet de las Cosas (IoT) que contempla la conexión a internet desde un reloj hasta un
enchufe. Para garantizar la conectividad de todos los dispositivos, IPv4 dispone de segmentos de red
denominados como redes privadas que no son accesibles desde Internet y, por ello, pueden reutilizarse en
distintos ámbitos. Un ejemplo claro es una red privada doméstica, donde habitualmente se utiliza el
direccionamiento 192.168.1.0/24 y donde el router instalado proporcionado por el proveedor de internet (ISP)
tiene la IP 192.168.1.1 y asigna IPs del rango mediante protocolo DHCP [46]. En la siguiente figura se
muestra este escenario de forma gráfica, donde se aprecia que en distintas partes del mundo, los distintos
dispositivos comparten IPv4, pero todos pueden acceder a Internet.

Figura 94. Ejemplo de escenario de redes privadas domésticas con mismo direccionamiento en distintos
puntos del mundo
En la figura anterior, el elemento clave es el router que proporciona el ISP. Dicho dispositivo tiene una IP
dentro del rango de la red doméstica a la que da servicio, mientras que dispone de una IP única en Internet, lo
que hace posible la conexión de la red doméstica a internet a través del mismo. Los dispositivos comparten en
Internet la dirección IP única de su router, gracias a la capacidad de traducción de direcciones del mismo

88
(NAT). Mediante este mecanismo, el router mantiene una lista de conexiones salientes desde los dispositivos
de la red interna, y cambia la IP origen de la conexión por su IP única en Internet. Cuando se recibe respuesta a
esta conexión, el router se encarga de hacer la traducción inversa y entregar el paquete al dispositivo que
generó la conexión.
En la siguiente tabla se muestran los distintos tipos de redes privadas en IPv4:

Tipo Rango libertad Rango de IPs IPs disponibles Ámbito aplicación

10.0.0.0-
Clase A 24 bits 16.777.214 Corporaciones gigantes
10.255.255.255

172.16.0.0- Organizaciones de medio tamaño


Clase B 20 bits 1.048.574
172.31.255.255 (Universidades o grandes empresas)

192.168.0.0- Redes pequeñas y medianas (domésticas,


Clase C 16 bits 65.534
192.168.255.255 negocios pequeños y medianos)

Tabla 17. Tipos de redes privadas en IPv4


Según lo comentado, en el ámbito de la comunicación dentro de una red corporativa (como una empresa, un
campus universitario, etc), la aplicación actual no presentará problemas. En cambio, si se crea una comunidad
de usuarios que quieren comunicarse desde distintos puntos del mundo desde redes privadas separadas, no
podrán hacerlo a través de la aplicación en su estado actual. Para solucionar este problema, se plantean dos
alternativas:
• Uso de IPv6. IPv6 [47] es la evolución del Protocolo de Internet versión 4 y nace con el objetivo
principal de solventar el problema del agotamiento del espacio de direccionamiento de IPv4. Para ello,
se proponen direcciones de 128 bits, lo que implica un espacio de direccionamiento de 2128
direcciones (340.282.366.920.938.463.463.374.607.431.768.211.456 direcciones). Este espacio de
direccionamiento permite, de lejos, asignar una dirección IP a cada dispositivo con conexión a
Internet. Aunque el protocolo fue liberado en 1998, la implantación del mismo se está retrasando en el
tiempo debido a la incompatibilidad con el protocolo IPv4 y el coste asociado a la sustitución de todos
los elementos de red que no soportan IPv6, lo cual genera reticencias en proveedores de internet y
empresas, que prefieren retrasar un gasto de este calibre. Para dar una visión de esta evolución, en la
siguiente figura se muestra el grado de adopción de IPv6 entre usuarios de Google desde 2009.
Aunque 2020 va a finalizar con un 35% de usuarios que disponen de IPv6 (aproximadamente), hace
sólo 4 años el índice era inferior al 10%.

Figura 95. Porcentaje de usuarios de Google que acceden a través de IPv648


En el ámbito del proyecto, esta alternativa supondría la necesidad de realizar un desarrollo para

48 Fuente de la imagen: https://www.google.com/intl/es/ipv6/statistics.html

89
permitir el uso de IPv6 a la hora de crear los nodos de la red. En principio, el mayor esfuerzo de
desarrollo caería en la parte back-end, mientras que en la parte front-end sólo sería necesario
actualizar algún texto para mostrar la disponibilidad de esta opción.
• Uso de VPN. Otra alternativa para abordar esta Historia de Usuario podría ser la utilización de una
VPN para aportar visión directa entre nodos que se encuentran en redes privadas separadas. Una VPN
(Virtual Private Network) o Red Privada Virtual es una extensión de una red privada superpuesta a
una red pública (como Internet) [48], permitiendo la comunicación entre dos dispositivos a través de
una red pública emulando las propiedades de una conexión directa dentro de una red privada. Para
ello, la información es encapsulada en tramas cuya cabecera permite el encaminamiento hasta el
destino viajando por la red pública. Para conseguir que la comunicación se realice de la misma forma
que en un enlace de red privada, la información es encriptada, de tal forma que no se vea
comprometida en caso de ser interceptada. La parte de esta conexión que genera el encapsulamiento
se conoce como túnel VPN y la parte donde se encripta la información es conocida como conexión
VPN. En la siguiente figura se muestra un esquema de conexión VPN entre dos redes privadas
distintas a través de Internet.

Figura 96. Esquema de VPN entre dos redes privadas distintas a través de Internet49
Así, si los distintos usuarios que utilizan la aplicación de mensajería utilizan una conexión VPN para
tener visibilidad directa con el resto de nodos de la red P2P, podrán salvar el obstáculo de estar en
redes privadas separadas y con reglas NAT. Para llevar a cabo esta alternativa, sólo será necesario
disponer de un servidor VPN y configurar un cliente VPN en el dispositivo de cada usuario. Por
supuesto, esto implica que el funcionamiento de la aplicación va a tener un punto único de fallo. Si el
servidor VPN se encuentra indisponible, los nodos perderán la visibilidad. Pero al menos se dispone
de un método de interconexión entre los nodos sin necesidad de tener visión directa.
Una vez conocidas las alternativas planteadas, el equipo de desarrollo debe decidir cuál será la escogida para
afrontar la Historia de Usuario para evolucionar el producto.

4.4.4.2 Establecer alternativa escogida

Tras analizar las dos alternativas contempladas en la tarea realizada anteriormente, el equipo de desarrollo
toma la decisión de escoger la alternativa de comunicación entre los nodos mediante el uso de VPN. A
continuación, se listan las razones que llevan al equipo a tomar esta decisión:
• El uso de IPv6 plantea un desarrollo específico del código de aplicación para dar soporte
• La implantación de IPv6 como protocolo de Internet común aún se encuentra en una fase temprana y,
por lo tanto, podría no servir como solución para un determinado número de usuarios. Sobre todo, hay
que tener en cuenta que si el proveedor de Internet no encamina tráfico IPv6, los usuarios seguirán
con un problema sin solucionar y sobre el que no pueden actuar (como en el caso de las redes con
reglas NAT).
• El uso de una VPN sólo requiere tareas de configuración, no de desarrollo. En concreto, sería
necesario configurar un servidor VPN y crear una configuración por cada cliente a conectarse. Los
usuarios sólo tendrían que generar su fichero de configuración y utilizar un software para activar la
VPN, por lo que no dependerían de terceros.
Por estas razones, se decide llevar a cabo la solución basada en comunicación a través de VPN. En la siguiente

49Fuente de la imagen: https://docs.microsoft.com/es-es/previous-versions/windows/it-pro/windows-2000-


server/images/bb742566.bug28130-fig3-sm(en-us,technet.10).gif

90
tarea, el equipo de desarrollo tendrá que darle forma a la propuesta de solución basada en esta tecnología y
dejar claro los puntos de configuración necesarios.

4.4.4.3 Definir el escenario de validación de la propuesta

Para llevar a cabo la propuesta de comunicación a través de VPN, se disponen una serie de requisitos a
satisfacer. A continuación, se listan estos requisitos y la forma en que se tratarán de cumplir:
• Red privada distinta a la utilizada para el desarrollo del proyecto. Será necesario disponer de
algún nodo en otra ubicación distinta a la red donde se encuentra el equipo de desarrollo del proyecto.
Para ello, se propone la utilización de Google Cloud Platform. A través de este servicio, se creará una
red privada en la nube, donde se desplegarán los nodos oportunos para probar las comunicaciones.
• Nodos dentro de la red privada distinta a la utilizada para el desarrollo del proyecto. Dentro de
la red privada creada en Google Cloud Platform, se desplegarán máquinas virtuales para actuar como
nodos de la red P2P en esa red privada.
• Servidor VPN. Es necesario disponer de un servidor VPN que sirva como punto de establecimiento
de la red VPN que interconectará las distintas redes privadas del escenario de pruebas. Se propone la
utilización de una máquina virtual dentro de una nueva red privada creada en Google Cloud Platform,
que será configurado para actuar como servidor VPN.
• Acceso a la VPN. Los usuarios de la aplicación deberán conectarse a la VPN mediante algún
software que permita habilitar la interfaz de red a partir de la configuración de cliente generada. Se
propone el uso del software OpenVPN para la conexión de los clientes a la VPN. De esta forma, antes
de ejecutar la aplicación, los usuarios sólo tendrán que realizar la conexión a través de este software.
Para disponer de una visión global del escenario de pruebas, se muestra a continuación un diagrama con todos
los aspectos comentados anteriormente.

Figura 97. Escenario utilizado para validar la propuesta de comunicación de nodos a través de VPN
En la figura anterior se muestra la red que compartirán todos los nodos de la red P2P. Se trata de una red con
direccionamiento 10.8.0.0/24, lo que permite albergar hasta 254 nodos para la red P2P (suficiente para las
pruebas). Estos nodos que están ubicados en redes totalmente separadas a nivel físico tendrán visión directa y
podrán utilizar la aplicación de mensajería tratada en este TFM. Para hacer este escenario posible, es necesario
llevar a cabo la configuración de las distintas partes nombradas. Este trabajo será realizado en una tarea
posterior.

4.4.4.4 Desarrollar el back-end necesario para implantación de propuesta

Como finalmente se ha optado por la solución basada en el uso de VPN, no es necesario llevar a cabo
desarrollo en la aplicación. Así, esta tarea que se tuvo en cuenta en la planificación del Sprint queda
91
automáticamente descartada. Esta es una de las ventajas de SCRUM, se da por sentado que cualquier aspecto
del proyecto puede cambiar y, en vez de afrontar el hecho como algo negativo, se toma como una oportunidad
para adaptarse a las necesidades reales para aportar valor al producto. En la siguiente tarea, el equipo de
desarrollo lleva a cabo la configuración del escenario planteado para la propuesta de comunicación mediante
VPN.

4.4.4.5 Configurar el escenario de validación de la propuesta

En el escenario propuesto intervienen una serie de elementos que deben ser configurados para formar parte del
mismo. En esta tarea, se lleva a cabo dicha configuración. Para no extender demasiado la subsección, se
expondrá el trabajo realizado a un alto nivel, referenciando al lector al ANEXO III. Configuraciones de Sprint
3 si quiere conocer el detalle de los pasos a seguir para realizar la configuración descrita. A continuación, se
muestran los elementos de configuración implicados y la forma en que se han planteado:
• Red privada Desarrollo TFM. La red privada donde se ha llevado a cabo el desarrollo del TFM
dispone de un direccionamiento 192.168.1.0/24, igual que la mayoría de las redes privadas
domésticas. El equipo donde se realiza el desarrollo tiene la IP 192.168.1.230/24. En este equipo, se
crea una máquina virtual que tiene la IP 192.168.1.138/24. La asignación de IPs es totalmente
irrelevante, y podría hacerse de forma automática (por DHCP) o manual. La puerta de enlace de esta
red tiene la IP típica de una red doméstica (192.168.1.1/24).
• Red privada Google Cloud Platform para servidor VPN. La red privada donde se alojará el
servidor VPN está ubicada en Google Cloud Platform. Dicha red tendrá el direccionamiento
10.154.10.0/24. En esta red se creará una máquina virtual para alojar el servidor VPN y tendrá la IP
10.154.10.2/24. La puerta de enlace de esta red tiene la IP 10.154.10.1/24. En el ANEXO III.
Configuraciones de Sprint 3 se expone el detalle de configuración de una red en Google Cloud
Platform.
• Red privada Google Cloud Platform para alojar nodo. La red privada donde se alojará el otro
nodo para probar la comunicación con la aplicación a través de VPN está ubicada en Google Cloud
Platform. Dicha red tendrá el direccionamiento 10.154.0.0/24. En esta red se creará una máquina
virtual para alojar un nodo P2P con la aplicación del TFM instalada y tendrá la IP 10.154.0.2/24. La
puerta de enlace de esta red tiene la IP 10.154.0.1/24. En el ANEXO III. Configuraciones de Sprint 3
se expone el detalle de configuración de una red en Google Cloud Platform.
• Red VPN. La red privada virtual (VPN) que se creará para comunicar los nodos que se encuentran en
distintas redes sin visión directa tendrá el direccionamiento 10.8.0.0/24. Esto permitirá alojar un
máximo de 253 clientes, ya que se trata de un rango de 256 IPs, a las que hay que descontar la IP de
subred (10.8.0.0), de difusión (10.8.0.255) y del servidor VPN (tendrá la 10.8.0.1/24). La
configuración de esta red se hace al mismo tiempo que la configuración del servidor VPN. En el
ANEXO III. Configuraciones de Sprint 3 se expone el detalle de configuración completa del servidor
VPN (incluyendo lo relativo a la red VPN).
• Máquina virtual en red privada de desarrollo TFM para alojar un nodo. Se crea una máquina
virtual dentro del dispositivo utilizado para el desarrollo del TFM, utilizando el software VirtualBox
[24]. Dicha máquina virtual dispondrá de un Sistema Operativo Linux ligero (Lubuntu) con 4 GB de
RAM. En dicha máquina virtual se clonará el repositorio del TFM y se instalará el software
OpenVPN para la conexión al servidor VPN. En el ANEXO III. Configuraciones de Sprint 3 se
expone una sección para la configuración de esta máquina virtual, además de una sección dedicada a
la instalación y configuración del cliente OpenVPN. Además, en el ANEXO I. Instalación, ejecución
y dependencias se dispone de información para instalar y ejecutar el TFM en esta máquina.
• Máquina virtual en red privada Google Cloud Platform para alojar el servidor VPN. Se crea
una máquina virtual en la red 10.154.10.0/24 (Google Cloud Platform) para alojar el servidor VPN
que permitirá la comunicación entre nodos de distintas redes sin visión directa. Esta máquina virtual
se crea desde la consola de Google Cloud Platform, en el módulo Compute Engine, donde se manejan
las instancias de máquinas virtuales. Esta máquina virtual deberá ser accesible desde Internet (para
permitir las conexiones VPN), y dispondrá de un Sistema Operativo Ubuntu. En el ANEXO III.

92
Configuraciones de Sprint 3 se detalla el proceso seguido para la creación de la misma.
• Máquina virtual en red privada Google Cloud Platform para alojar un nodo. Se crea una
máquina virtual en la red 10.154.0.0/24 (Google Cloud Platform) con Sistema Operativo Ubuntu para
alojar un nodo de la aplicación P2P del TFM. Al igual que la máquina mencionada anteriormente, se
creará desde la consola de Google Cloud Platform, con la diferencia de que no será visible desde
Internet (para una simulación más fidedigna de un escenario real). Además, esta máquina deberá
disponer del código de la aplicación de mensajería del TFM y del cliente OpenVPN (igual que la
máquina virtual de la red de desarrollo del TFM). En el ANEXO III. Configuraciones de Sprint 3 se
detalla el proceso seguido para la creación de la máquina, mientras que el proceso de configuración
del cliente OpenVPN y de instalación de la aplicación de mensajería del TFM es igual que el seguido
en el caso de la máquina virtual de la red privada de desarrollo del TFM.
• Configuración de servidor OpenVPN. Para la configuración del servidor OpenVPN en la máquina
virtual de Google Cloud Platform (10.154.10.2/24) se ha tomado como guía el artículo de [49],
haciendo las modificaciones necesarias para adaptarla a las necesidades del proyecto. En el ANEXO
III. Configuraciones de Sprint 3 se detalla el proceso seguido para la configuración y puesta a punto
del servidor OpenVPN.
• Configuración de cliente OpenVPN. Para la configuración de los clientes OpenVPN en las
máquinas virtuales que alojan los nodos P2P en el escenario de la propuesta (10.154.0.2/24 y
192.168.1.133/24) se ha tomado como guía el artículo de [49], haciendo las modificaciones necesarias
para adaptarla a las necesidades del proyecto. En el ANEXO III. Configuraciones de Sprint 3 se
detalla el proceso seguido para la configuración y puesta a punto de los clientes OpenVPN.
A continuación, se muestran los distintos elementos configurados y las pruebas de comunicación realizadas
para comprobar que la comunicación por VPN se realiza correctamente.
• Subredes creadas en consola Google Cloud Platform

Figura 98. Subredes creadas en Google Cloud Platform para ubicar servidor VPN (tfm-subred) y para ubicar
nodo P2P (tfm-subred-nodosp2p)
• Instancias de VM creadas en consola Google Cloud Platform

Figura 99. Instancias de VM creadas en Google Cloud Platform


• Estado de servicio OpenVPN activo en Nodo Servidor VPN

Figura 100. Captura del servicio OpenVPN ejecutándose en el servidor de Google Cloud Platform
• Configuración de red de VM Servidor VPN

93
Figura 101. Configuración de red del nodo servidor VPN. Dispone de IP local (ens4) y de IP en VPN (tun0)
• Configuración de red de VM desarrollo TFM

Figura 102. Configuración de red de la VM de desarrollo TFM. Dispone de IP local (enp0s3) y de IP en VPN
(tun0)
• Configuración de red de VM Nodo P2P Google Cloud

Figura 103. Configuración de red de la VM de Google Cloud Platform que alberga un nodo P2P. Dispone de
IP local (ens4) y de IP en VPN (tun0)
• Prueba de comunicación desde VM desarrollo TFM a través de VPN

94
Figura 104. Prueba de comunicación a través de VPN en VM de desarrollo TFM. Ping a servidor VPN
seguido de ping a VM par nodo P2P alojado en Google Cloud Platform
• Prueba de comunicación desde VM Nodo P2P Google Cloud a través de VPN

Figura 105. Prueba de comunicación a través de VPN en VM para nodo P2P alojado en Google Cloud
Platform. Ping a servidor VPN seguido de ping a VM de desarrollo TFM
Con el escenario plenamente configurado, se prueba que la aplicación se ejecuta correctamente tanto en la VM
de Google Cloud como en la VM de la red de desarrollo TFM. En la VM de Google Cloud se ejecuta la
versión de consola, por no disponer de entorno gráfico. En la siguiente figura se muestra una captura en cada
nodo.

95
Figura 106. Captura de uso de la aplicación de mensajería P2P entre dos nodos sin visión directa
Por último, se muestra el tráfico capturado con Wireshark en la máquina de desarrollo del TFM. Se puede
apreciar que el tráfico en este punto de intercepción está cifrado (OpenVPN). Esto no es así en la VM donde se
ejecuta el servidor VPN, que controla el tráfico y puede interceptar los mensajes de aplicación. Es decir, que el
operador de la VPN puede controlar la actividad de los distintos usuarios aunque no conozca el contenido
concreto de los mensajes (a menos que intercepte las claves de cifrado). En la siguiente figura se muestra la
captura de tráfico en ambos escenarios.

Figura 107. Captura de tráfico VPN en máquina de desarrollo del TFM (arriba) y en VM donde se aloja el
servidor VPN (abajo)
Con esta tarea se alcanza un hito importante dentro del Sprint, al haber conseguido finalmente habilitar a
usuarios en redes privadas que no tienen visibilidad directa para comunicarse a través de la aplicación P2P de
mensajería, sin depender de la configuración de su red.

4.4.4.6 Realizar pruebas de validación de la propuesta

Para validar la propuesta realizada en este Sprint, habrá que realizar todas las pruebas de validación de los 2
Sprints anteriores (ver sección Tarea: Realizar pruebas de validación del Sprint 1 y sección Tarea: Realizar
pruebas de validación del Sprint 2), para comprobar que la funcionalidad de la aplicación no se ha visto
mermada en ningún aspecto. Las pruebas que implican interacción con contactos (agregar contacto, enviar
mensaje, etc) deberán realizarse utilizando un nodo dentro de la red privada del TFM y otro nodo dentro de la
red privada de Google Cloud Platform.
Además de las pruebas de validación funcional de la aplicación, es necesario validar la correcta configuración
del escenario construido en la tarea anterior. Para ello, se propone una lista de tareas que permiten comprobar
que la solución se aplica correctamente. A continuación, se muestran en tablas las distintas pruebas realizadas
para validar la correcta configuración del escenario.

Ubicación Prueba Resultado esperado

Arrancar servicio openvpn El servicio openvpn aparece como activo


Servidor VPN
Comando: sudo service openvpn start Comando: service openvpn status

96
Parar servicio openvpn El servicio openvpn aparece como inactivo
Servidor VPN
Comando: sudo service openvpn stop Comando: service openvpn status

Se configura la interfaz de red con IP dentro


Ejecutar OpenVPN con archivo de del rango de VPN y las rutas
VM TFM
configuración de cliente correspondientes para tener visibilidad de la
red VPN (10.8.0.0/24)

Ping a IP de servidor VPN tras


establecer conexión con OpenVPN Echo reply recibido por parte de la IP del
VM TFM
servidor VPN (10.8.0.1)
Comando: ping 10.8.0.1

Ping a IP de VM GCPlatform tras Echo reply recibido por parte de la IP de la


VM TFM establecer conexión con OpenVPN máquina virtual que alojará el nodo P2P en
Comando: ping IPVMGCPlatform Google Cloud Platform

Se configura la interfaz de red con IP dentro


Ejecutar OpenVPN con archivo de del rango de VPN y las rutas
VM GCPlatform
configuración de cliente correspondientes para tener visibilidad de la
red VPN (10.8.0.0/24)

Ping a IP de servidor VPN tras


establecer conexión con OpenVPN Echo reply recibido por parte de la IP del
VM GCPlatform
servidor VPN (10.8.0.1)
Comando: ping 10.8.0.1

Ping a IP de VM TFM tras establecer


conexión con OpenVPN Echo reply recibido por parte de la IP de la
VM GCPlatform
máquina virtual de desarrollo TFM
Comando: ping IPVMTFM

Tabla 18. Pruebas de validación de la configuración de escenario para comunicación de nodos mediante VPN

4.4.5 Revisión del Sprint


Tras la finalización del periodo relativo al desarrollo del Sprint, se lleva a cabo la revisión del mismo. En esta
sección se debe comprobar el incremento entregado por parte del equipo de desarrollo, comparándolo con la
planificación realizada al inicio. De esta forma, se valoran las funcionalidades que pueden considerarse como
terminadas y que, por tanto, pasan a formar parte del producto en producción.
En este Sprint, se estableció como alcance la consecución de la Historia de Usuario mostrada en la Tabla 15.
En las secciones anteriores se ha mostrado el trabajo desarrollado para la consecución de esta Historia de
Usuario, donde se ha facilitado una solución para que los usuarios que se encuentren en redes privadas
separadas donde se apliquen reglas NAT (los nodos no tienen visión directa) también puedan utilizar la
aplicación de mensajería sin depender del operador de su red privada. Dicha solución consiste en el
establecimiento de una red privada virtual (VPN) a la que los usuarios pueden conectarse utilizando un
software específico (OpenVPN) para disponer de visión directa con el resto de usuarios conectados a la VPN.
La Historia de Usuario puede darse por terminada y la rama creada sobre el repositorio del producto puede
fusionarse para formar parte, a partir de este momento, de la versión en producción del producto. En la
siguiente iteración se buscará solución al problema general de securización del canal de comunicaciones que
permite controlar la actividad de los usuarios incluso cuando se utiliza una VPN para la comunicación (el

97
operador de la VPN intercepta el tráfico y puede analizar la actividad de los usuarios, aunque el contenido de
los mensajes esté cifrado).

4.5 Sprint 4. Seguridad en canal de comunicación entre pares


4.5.1 Definición de la Historia de Usuario
El último objetivo es introducido en la pila del producto como la siguiente Historia de Usuario:

𝐒𝐄𝐆𝐔𝐑𝐈𝐃𝐀𝐃 𝐄𝐍 𝐂𝐀𝐍𝐀𝐋 𝐃𝐄 𝐂𝐎𝐌𝐔𝐍𝐈𝐂𝐀𝐂𝐈Ó𝐍 𝐄𝐍𝐓𝐑𝐄 𝐏𝐀𝐑𝐄𝐒

“𝐂𝐨𝐦𝐨 𝑑𝑢𝑒ñ𝑜 𝑑𝑒𝑙 𝑝𝑟𝑜𝑑𝑢𝑐𝑡𝑜,


𝐪𝐮𝐢𝐞𝐫𝐨 𝑞𝑢𝑒 𝑠𝑒 𝑐𝑖𝑓𝑟𝑒 𝑒𝑙 𝑐𝑎𝑛𝑎𝑙 𝑑𝑒 𝑐𝑜𝑚𝑢𝑛𝑖𝑐𝑎𝑐𝑖ó𝑛 𝑒𝑛𝑡𝑟𝑒 𝑛𝑜𝑑𝑜𝑠 𝑑𝑒 𝑙𝑎 𝑟𝑒𝑑
𝐩𝐚𝐫𝐚 𝑞𝑢𝑒 𝑛𝑜 𝑝𝑢𝑒𝑑𝑎 𝑖𝑛𝑡𝑒𝑟𝑐𝑒𝑝𝑡𝑎𝑟𝑠𝑒 𝑛𝑖 𝑐𝑜𝑛𝑡𝑟𝑜𝑙𝑎𝑟𝑠𝑒 𝑚𝑖 𝑎𝑐𝑡𝑖𝑣𝑖𝑑𝑎𝑑 𝑒𝑛 𝑙𝑎 𝑎𝑝𝑙𝑖𝑐𝑎𝑐𝑖ó𝑛"

Tabla 19. Definición de la Historia de Usuario relativa al Objetivo 4


De esta forma, se traslada al equipo de desarrollo de forma clara y concisa el requisito funcional que tendrá
que implementar, esto es, asegurar que las comunicaciones entre dos nodos se cifran a nivel de capa de
transporte (canal de comunicaciones), y el valor que aportará al producto una vez logrado el incremento al
finalizar el Sprint, esto es, la protección de la información de los usuarios de la aplicación, impidiendo que se
controle o intercepte la actividad de los mismos.

4.5.2 Tecnología implicada

4.5.2.1 SSL/TLS

SSL (Secure Sockets Layer) es un protocolo50 publicado por la IETF (Internet Engineering
Task Force) que proporciona seguridad a la capa de transporte de una red insegura, como
Internet. Su aplicación proporciona autenticación y privacidad a la información transmitida
entre los dos extremos de una conexión, mediante el uso de criptografía. Normalmente, sólo es necesaria la
autenticación del servidor y está basada en el uso de certificados digitales para el cifrado a través de una clave
pública, proporcionada tras la negociación del algoritmo de cifrado a utilizar. TLS (Transport Layer Security)
es el protocolo que sustituye a SSL (publicado51 también por la IETF), tras quedar obsoleto por
vulnerabilidades de seguridad (como ataques Man In The Middle aprovechando renegociaciones, resueltos en
TLS con la finalización de una conexión intercambiando un hash que resume toda la información
intercambiada). En este proyecto, se utiliza el protocolo TLS para aportar seguridad al canal de
comunicaciones establecido entre dos nodos que utilizan la aplicación de mensajería.

4.5.2.2 OpenSSL

OpenSSL52 es un paquete de herramientas y librerías de criptografía, que dan soporte al


manejo de los protocolos SSL y TLS. Entre otras funcionalidades, permite crear
certificados digitales para servidores que requieren seguridad en la capa de transporte. Se trata de un software
de código abierto y en este proyecto será utilizado para la creación de certificados digitales y almacenes de
claves necesarios para la securización del canal de comunicaciones entre los nodos de la red P2P.

4.5.3 Planificación del Sprint


La Historia de Usuario hace referencia a un tema de seguridad de la información manejada por la aplicación.
En la versión actual, los mensajes enviados a través de la red son cifrados, pero las comunicaciones (capa de

50 https://tools.ietf.org/html/rfc6101
51 https://tools.ietf.org/html/rfc8446
52 https://www.openssl.org/

98
transporte) no son cifradas. Es decir, aunque un atacante no pueda ver un mensaje en claro, sí que puede
capturar y analizar el tráfico de los distintos usuarios de la red P2P. En el Sprint anterior se adoptó la
utilización de OpenVPN como solución para los entornos donde los nodos no tienen visión directa. Esto
conlleva el cifrado del canal de comunicaciones, pero hay que tener en cuenta que es una solución que no tiene
por qué utilizarse (por ejemplo en entornos corporativos no sería necesario) y que, además, el proveedor del
servidor VPN podría interceptar el tráfico, de la misma forma que los servicios basados en servidor central
pueden interceptar el tráfico de sus usuarios. Como en anteriores Sprints, será necesario realizar un análisis de
las alternativas disponibles para abordar el problema y escoger de forma justificada una de ellas. En este
Sprint, al igual que en el anterior, no se prevé necesidad de desarrollo front-end. En cambio, se prevé que
habrá que hacer cambios en el back-end para dar soporte a la alternativa de securización del canal que se
escoja, ya que la versión actual no implementa nada al respecto. Por último, como siempre, será necesario
realizar la validación de la propuesta mediante pruebas.

Tarea Esfuerzo estimado (horas)

Estudiar alternativas para securizar canal de comunicaciones 6

Establecer alternativa escogida 2

Desarrollar el back-end necesario para implantación de propuesta 10

Realizar pruebas de validación de la propuesta 6

Tabla 20. Estimación de tareas para la Historia de Usuario relativa al Objetivo 4

4.5.4 Desarrollo del Sprint


En esta sección se pretende exponer el trabajo realizado durante el Sprint para conseguir el incremento de
valor en el producto a través de la funcionalidad descrita en la Historia de Usuario incluida en la pila del
Sprint. Para ello, se dedicará una subsección por cada tarea realizada.

4.5.4.1 Estudiar alternativas para securizar canal de comunicaciones

En este Sprint, el estudio de alternativas es relativamente simple. En la actualidad, las aplicaciones y servicios
que se ofrecen a través de una red pública (como Internet) utilizan el protocolo TLS para proporcionar
seguridad a las comunicaciones establecidas entre clientes y servidores. TLS (Transport Layer Security) [50]
es un protocolo criptográfico aplicado sobre la capa de transporte. Gracias a este protocolo, las conexiones sólo
pueden establecerse una vez que se autentican ambas partes. Antes de establecer la conexión, se lleva a cabo
un proceso de negociación, donde cliente y servidor se ponen de acuerdo en los algoritmos de cifrado a utilizar
y se establece la clave con la que se encriptarán los mensajes intercambiados en la sesión. Para que la clave no
pueda ser interceptada, el cliente la encripta con la clave pública del certificado que le proporciona el servidor
antes de compartirla con él. En la Figura 108 se visualiza con claridad el intercambio de mensajes durante la
negociación previa a la comunicación con TLS.
Una vez establecido el canal seguro, la interceptación de mensajes no pondrá en compromiso la información
transferida. TLS es la evolución del protocolo SSL (Secure Socket Layer) [51], que quedó obsoleto en su
versión 3.0 por vulnerabilidades de seguridad (como ataques Man In The Middle aprovechando
renegociaciones, resueltos en TLS con la finalización de una conexión intercambiando un hash que resume
toda la información intercambiada). La versión actual de TLS es la 1.3 y, como es de esperar, se recomienda
su utilización para aplicaciones de nuevo desarrollo además de la actualización de aplicaciones que utilicen
versiones anteriores, para ofrecer las máximas garantías disponibles en materia de seguridad.

99
Figura 108. Intercambio de mensajes en negociación TLS53
En este TFM, es necesario estudiar cómo puede implantarse la capa de seguridad con TLS en la aplicación.
Investigando la librería FreePastry, se encuentra un tutorial que podría arrojar luz sobre la forma de llevar a
cabo esta implantación. El tutorial se encuentra en la ruta rice/tutorial/ssl y, básicamente, crea una aplicación
que encamina 10 mensajes a su conjunto de vecinos. A la hora de instanciar la fábrica de nodos, se realiza una
sobreescritura del método utilizado para establecer la capa de transporte, de tal forma que la capa de transporte
sea de la clase org.mpisws.p2p.transport.ssl.SSLTransportLayer (utiliza las librerías de javax.net.ssl para cifrar
la capa de transporte) en vez de org.mpisws.p2p.transport.sourceroute.SourceRouteTransportLayer (capa de
transporte utilizada por defecto). A continuación se muestra el fragmento de código donde se aprecia este
cambio:
/*...*/
PastryNodeFactory factory = new SocketPastryNodeFactory(nidFactory, bindport, env) {
@Override
protected TransportLayer<SourceRoute<MultiInetSocketAddress>, ByteBuffer> getSourceRouteTransportLayer(
TransportLayer<MultiInetSocketAddress, ByteBuffer> etl,
PastryNode pn,
MultiAddressSourceRouteFactory esrFactory) {

// get the default layer by calling super


TransportLayer<SourceRoute<MultiInetSocketAddress>, ByteBuffer> sourceRoutingTransportLayer =
super.getSourceRouteTransportLayer(etl, pn, esrFactory);

try {
// return our layer
return new SSLTransportLayerImpl<SourceRoute<MultiInetSocketAddress>, ByteBuffer>
(sourceRoutingTransportLayer,store,store,pn.getEnvironment());
} catch (IOException ioe) {
throw new RuntimeException(ioe);
}
}
/*...*/
};
/*...*/

Tabla 21. Código de tutorial SSL FreePastry. Establecimiento de capa de transporte segura.
Al utilizar las librerías de java para el cifrado de la capa de transporte, se utiliza el protocolo TLS en su última
versión (1.3). En el código anterior se puede observar que, al crear la capa de transporte segura, se pasa por
parámetros una variable llamada store. Esta variable es una instancia de la clase java.security.KeyStore
(almacén de claves o llavero) y almacena el certificado y las claves privadas del nodo. Así, cuando actúe como
servidor, el certificado servirá para que el cliente encripte su clave privada, mientras que cuando actúe como
cliente, encriptará su clave privada con el certificado del servidor con el que inicie la negociación para el
establecimiento de la conexión. El fichero donde se encuentra el almacén de claves se obtiene a partir de su

53 Fuente de la imagen: https://www.researchgate.net/figure/HTTPS-message-sequence-diagram-with-detailed-TLS-handshaking-


steps_fig1_306187575

100
ruta, que debe introducirse como parámetro de ejecución de la clase del tutorial. En el siguiente fragmento de
código se muestra el momento en que se instancia el objeto de la clase java.io.File a partir de la ruta pasada
por parámetro de ejecución.
/*...*/

public static void main(String[] args) throws Exception {

/*...*/

// get the keystore file


String keystoreFileName = args[3];
File keystoreFile = new File(keystoreFileName);
if (!keystoreFile.exists()) throw new IllegalArgumentException("The file: "+keystoreFileName+" was not found.");

// launch our node!


DistTutorial dt = new DistTutorial(bindport, bootaddress, env, keystoreFile);
}

/*...*/

Tabla 22. Código de tutorial SSL FreePastry. Obtención de almacén de claves.


Por último, tras disponer del fichero del almacén de claves, se carga en la instancia de la clase
java.security.KeyStore y se establece la librería criptográfica “Bouncy Castle”, además de utilizar “UBER”
como tipo de almacén de claves. Como se comentará más tarde, la versión actual de Java no requiere del uso
de una librería criptográfica externa. A continuación, se muestra el fragmento de código donde se establece
esta configuración.
/*...*/

// Add the bouncycastle security provider


Security.addProvider(new BouncyCastleProvider());

// create the keystore


final KeyStore store = KeyStore.getInstance("UBER", "BC");

store.load(new FileInputStream(keyStoreFile), "".toCharArray());

/*...*/

Tabla 23. Código de tutorial SSL FreePastry. Configuración de almacén de claves.


Para la ejecución del tutorial es necesario crear, en primera instancia, el almacén de claves que contenga el
certificado y la clave privada. El tipo de almacén de claves seleccionado será PKCS12 [52], que es el estándar
para el intercambio de información personal (comúnmente utilizado para los certificados digitales personales).
Para ello se utiliza OpenSSL, a través de los siguientes comandos:
#Creación de certificado autofirmado y clave privada asociada (myCert.pem, myKey.pem).
openssl req -x509 -newkey rsa:4096 -keyout myKey.pem -out myCert.pem -days 365 -nodes
#Creación de almacén en formato PKCS12 (nodo1.p12). Se crea sin contraseña, para que el tutorial funcione.
openssl pkcs12 -export -out nodo1.p12 -inkey myKey.pem -in myCert.pem -name nodo1 -noiter -nomaciter

Tabla 24. Comandos para creación de certificado y almacén de claves para ejecución de tutorial FreePastry
SSL
Los 3 ficheros resultantes son ubicados en un directorio nuevo, llamado certs, en la raíz del proyecto. Para
probar el tutorial, se dispone de la máquina virtual Virtualbox utilizada en el Sprint anterior, además del
equipo propio de desarrollo. En la siguiente figura se muestra el escenario utilizado para probar el tutorial:

Figura 109. Escenario para ejecución de tutorial FreePastry SSL


Los comandos ejecutados en ambas máquinas se muestran a continuación:
#Comando ejecutado en PC Desarrollo (192.168.1.230) para lanzar el tutorial Freepastry SSL
java -cp "lib/*" rice.tutorial.ssl.DistTutorial 9001 192.168.1.230 9001 certs/nodo1.p12
#Comando ejecutado en MV Virtualbox (192.168.1.133) para lanzar el tutorial Freepastry SSL
java -cp "lib/*" rice.tutorial.ssl.DistTutorial 9003 192.168.1.230 9001 certs/nodo1.p12

En los comandos mostrados anteriormente se observa la configuración del classpath donde se ubican las clases
compiladas de Pastry. Además, se pasan 4 parámetros: el puerto local de ejecución de la aplicación; la IP y el
puerto del nodo conocido de la red Pastry que será utilizado para unirse a ella; y la ruta del almacén de claves
donde se encuentra el certificado a utilizar por el nodo ejecutado. Por simplicidad, se utiliza el mismo almacén
para ambos nodos. En la siguiente figura se muestra la salida de consola tras la ejecución del tutorial en la
101
máquina virtual y el tráfico capturado con Wireshark para demostrar que la comunicación se ha cifrado
correctamente. Puede apreciarse que el nodo se une a la red Pastry y envía con éxito los mensajes a su
conjunto de vecinos (el nodo ubicado en el PC desarrollo), además de recibir mensajes del otro nodo, donde
también se está ejecutando el tutorial.

Figura 110. Resultado de ejecución de tutorial FreePastry SSL (arriba) y captura de tráfico cifrado con
Wireshark (abajo)
Tras comprobar que es posible utilizar la propia librería de Freepastry para la securización del canal de
comunicaciones, se da paso a la adaptación del código de la aplicación del proyecto para dar cabida a esta
solución.

4.5.4.2 Establecer alternativa escogida

En la tarea anterior sólo se ha visto una alternativa y ha resultado válida para dar cobertura a la Historia de
Usuario incluida en la pila del Sprint. Por ello, en este Sprint, la tarea relativa a establecer la alternativa
escogida no consume tiempo del equipo de desarrollo, que puede pasar directamente a comenzar el desarrollo
sobre la aplicación del proyecto.

4.5.4.3 Desarrollar el back-end necesario para implantación de propuesta

En esta tarea se lleva a cabo la adaptación del código de la aplicación del proyecto para que se incluya la
securización de las comunicaciones mediante TLS. En primer lugar se realiza la adaptación del código relativo
a la versión de consola para comprobar el funcionamiento y trasladarlo después a la versión con interfaz
gráfica. Se realizan, por tanto los siguientes trabajos:
• Obtención por parámetros de ejecución de la ruta al fichero que contiene el almacén de claves a
utilizar en la clase que ejecuta la vista de consola (VistaConsola). Esta ruta, al igual que en el tutorial
SSL, sirve para crear un objeto java.io.File que se proporciona al controlador en el momento de
instanciarlo (ver código mostrado en la Tabla 22).
• En la clase relativa al controlador (ControladorConsolaImpl) se lleva a cabo la adaptación de código
para configurar el almacén de claves (ver código mostrado en la Tabla 23) y la sobreescritura de la
instancia que sirve como fábrica de nodos (SocketPastryNodeFactory) para que la capa de transporte
102
utilice la implementación de FreePastry de capa SSL/TLS (ver código mostrado en la Tabla 21).
Tras el trabajo de adaptación, se utiliza el escenario mostrado en la Figura 109 para probar el funcionamiento
de la aplicación cifrando las comunicaciones. El nodo anfitrión (que actúa como nodo conocido para que el
resto se una a la red Pastry) se ejecuta en el PC desarrollo sin problemas, algo que era de esperar teniendo en
cuenta que no hay interacciones con otros nodos todavía. Al ejecutar la aplicación en el nodo de la VM
Virtualbox y tratar de conectar a la red Pastry, se lanza una excepción que provoca el fin de ejecución de la
aplicación. A continuación se muestra la traza de la excepción.

Figura 111. Excepción java.nio.BufferOverflowException obtenida al ejecutar la aplicación con TLS


Tras indagar en el código, se detecta que el desbordamiento indicado en la excepción puede venir de un
método de la clase SSLSocketManager, que se utiliza en FreePastry para el manejo de las conexiones
SSL/TLS. En concreto, parece surgir el desbordamiento al tratar de escribir en un buffer sin comprobar
anteriormente si el array a escribir es de un tamaño igual o menor que el disponible. En la siguiente figura se
muestra el código en cuestión, resaltando el punto donde se escribe en buffer y no se comprueba si desbordará
el contenido a escribir.
Para afrontar este problema, se modifica el bloque de código para evitar el desborde de la misma forma que se
realiza en la primera parte del método read. En la siguiente figura se muestra el cambio realizado.

Figura 112. Fragmento de código de SSLSocketManager.java donde se aprecia un potencial desbordamiento


de buffer (izquierda) y cambio para evitarlo (derecha)
Tras realizar estos cambios, se procede al compilado del código y la ejecución de la aplicación de consola otra

103
vez. Se ejecuta en el nodo de PC Desarrollo como anfitrión y después en el nodo de VM Virtualbox utilizando
la IP y el puerto de PC Desarrollo para la unión a la red. En esta ocasión, se logra comunicar ambos nodos
cifrando el canal con SSL/TLS. Es importante hacer notar que la aplicación no responde de forma estable, y
los canales se cierran de forma inesperada en algunas ocasiones, teniendo que ejecutarla de nuevo para un
nuevo intento de conexión. A continuación, se muestra la ejecución de la aplicación en ambos nodos
comprobando cómo llega la comunicación entre ambos utilizando la funcionalidad de echo.

Figura 113. Ejecución de aplicación de mensajería de consola cifrando el canal con SSL/TLS

Para demostrar que la comunicación se realiza utilizando el cifrado SSL/TLS, se muestra a continuación la
captura de Wireshark donde se aprecian los paquetes intercambiados, con el protocolo TLS 1.3 y sin
posibilidad de interceptar la información.

Figura 114. Captura Wireshark de ejecución de aplicación de mensajería de consola cifrando el canal con TLS
1.3
Tras adaptar el código en la versión de consola, se lleva a cabo la adaptación del código en la versión con
interfaz gráfica desarrollada en este TFM. Este trabajo es similar al realizado anteriormente, pero trabajando
sobre las clases ControladorGUIImpl, VistaGUI y VistaConsolaPublic (descritas en el Sprint 1.
Implementación de una interfaz gráfica). Tras la adaptación, se ejecuta la aplicación gráfica sobre el mismo
escenario de la Figura 109. El resultado es correcto, aunque con los mismos problemas de inestabilidad que
hacen poco usable la solución. Aunque el objetivo de la Historia de Usuario se cumple, el equipo de desarrollo

104
determina que sería necesaria una nueva Historia de Usuario que permitiese analizar estos problemas de
inestabilidad para que la aplicación sea perfectamente usable utilizando la securización del canal.
Por último, debido a los problemas de estabilidad comentados, se decide hacer una pequeña refactorización en
la aplicación para que la securización de las comunicaciones sea opcional. De esta forma, sólo se tendrá en
cuenta la activación de la capa de transporte con SSL cuando se reciba un parámetro de ejecución con un
fichero de almacén de claves válido.

4.5.4.4 Realizar pruebas de validación de la propuesta

Para validar la solución desarrollada en este Sprint, se propone realizar un primer conjunto de pruebas que
permitan comprobar que el cifrado del canal de comunicación es factible. Para ello, se propone un conjunto de
pruebas a realizar utilizando el escenario mostrado en la Figura 109. A continuación, se muestra el circuito de
validación para la versión de consola:
1. Ejecución de aplicación en PC desarrollo:
a. java -cp “./lib/*” us.tfg.p2pmessenger.view.VistaConsola 9001 192.168.1.230 ./certs/nodo1.p12

2. Ejecución de aplicación en VM Virtualbox:


a. java -cp “./lib/*” us.tfg.p2pmessenger.view.VistaConsola 9002 192.168.1.133 ./certs/nodo1.p12

3. Introducir como IP de conexión a Pastry la del PC desarrollo en ambos casos (192.168.1.230).


4. Registrar un usuario en la red Pastry en ambos casos.
5. Iniciar sesión con el usuario creado.
6. Agregar el usuario creado en la otra ejecución como contacto.
7. Utilizar la funcionalidad de ping de la aplicación de consola, introduciendo como destino el contacto
agregado anteriormente. Realizar en ambos nodos.
Asimismo, se muestra el circuito de validación para la versión gráfica:
1. Ejecución de aplicación en PC desarrollo:
a. java -cp "../../lib/*" --module-path /usr/share/openjfx/lib --add-modules=javafx.controls,
javafx.web us.tfg.p2pmessenger.view.VistaGUI 9001 192.168.1.230 ./certs/nodo1.p12

2. Ejecución de aplicación en VM Virtualbox:


a. java -cp "../../lib/*" --module-path /usr/share/openjfx/lib --add-modules=javafx.controls,
javafx.web us.tfg.p2pmessenger.view.VistaGUI 9002 192.168.1.133 ./certs/nodo1.p12

3. Introducir como IP de conexión a Pastry la del PC desarrollo en ambos casos (192.168.1.230).


4. Registrar un usuario en la red Pastry en ambos casos.
5. Iniciar sesión con el usuario creado.
6. Agregar el usuario creado en la otra ejecución como contacto.
7. Abrir una conversación con el contacto creado y enviar un mensaje a la conversación. Realizar en
ambos nodos.
Para ambos circuitos, si todo funciona correctamente, deberían registrarse los usuarios en la red Pastry sin
problema y deberían llegar los mensajes enviados sin perder la conexión. Se debe comprobar mediante
Wireshark que los paquetes se cifran utilizando TLSv1.3.

4.5.5 Revisión del Sprint


Tras la finalización del periodo relativo al desarrollo del Sprint, se lleva a cabo la revisión del mismo. En esta
sección se debe comprobar el incremento entregado por parte del equipo de desarrollo, comparándolo con la
planificación realizada al inicio. De esta forma, se valoran las funcionalidades que pueden considerarse como
terminadas y que, por tanto, pasan a formar parte del producto en producción.
En este Sprint, se estableció como alcance la consecución de la Historia de Usuario mostrada en la Tabla 19.
En las secciones anteriores se ha mostrado el trabajo desarrollado para la consecución de esta Historia de
105
Usuario, donde se ha utilizado la propia librería de FreePastry para proporcionar seguridad mediante SSL/TLS
en la capa de transporte. Ha sido necesario realizar algunos cambios tanto en la librería como en el código de a
aplicación para conseguir la adaptación a las necesidades del proyecto. Además, se ha detectado gran
inestabilidad en la aplicación al utilizar el cifrado del canal y, por ello, se ha propuesto la siguiente Historia de
Usuario para que sea incluido en la pila del producto y pueda abordarse en un futuro.

𝐏𝐑𝐎𝐁𝐋𝐄𝐌𝐀𝐒 𝐃𝐄 𝐄𝐒𝐓𝐀𝐁𝐈𝐋𝐈𝐃𝐀𝐃 𝐂𝐎𝐍 𝐒𝐒𝐋/𝐓𝐋𝐒

“𝐂𝐨𝐦𝐨 𝑑𝑢𝑒ñ𝑜 𝑑𝑒𝑙 𝑝𝑟𝑜𝑑𝑢𝑐𝑡𝑜,


𝐪𝐮𝐢𝐞𝐫𝐨 conocer la causa de inestabilidad en la aplicación al cifrar las comunicaciones
𝐩𝐚𝐫𝐚 que no se detenga la ejecución continuamente"

Tabla 25. Definición de nueva Historia de Usuario detectada en Sprint 4


La Historia de Usuario puede darse por terminada. La funcionalidad se agrega como opcional por lo que la
rama creada sobre el repositorio del producto puede fusionarse para formar parte de la versión en producción
del producto sin que el problema de estabilidad afecte al funcionamiento de la aplicación.

106
5 CONCLUSIONES Y TRABAJO FUTURO

Everything that has a beginning has an end.


The Oracle. The Matrix Revolutions.

E
n este Trabajo Fin de Máster se ha llevado a cabo la evolución de una aplicación de mensajería P2P
utilizando el enfoque de desarrollo de software ágil, utilizando metodología SCRUM. Se ha partido de
un producto inicial, desarrollado con anterioridad en un TFG [9] dentro de la misma línea de
contribución. Este producto presentaba una serie de líneas de mejora que han sido transformadas en Historias
de Usuario y agregadas a la pila del producto, para abordarlas a lo largo de 4 Sprints. Al final de cada uno de
los Sprints, se ha hecho una revisión de las funcionalidades implementadas y del incremento de valor aportado
al producto con ellas. Las Historias de Usuario pretendían dar cobertura a las siguientes necesidades:
• Implementación de una interfaz gráfica. Para reemplazar la versión de aplicación de consola y
facilitar el acceso a las diversas funcionalidades de la aplicación. Esta necesidad fue resuelta con el
incremento obtenido tras el Sprint 1.
• Compartición de ficheros a través de la aplicación. Para permitir el envío de archivos además de
texto plano. Esta necesidad fue resuelta con el incremento obtenido tras el Sprint 2.
• Comunicación entre nodos ubicados tras redes NAT. Para dar cobertura a la mensajería entre
usuarios de distintas organizaciones o que se encuentran en redes privadas separadas (como las
domésticas) y que no tienen o no pueden intervenir en la configuración de red para tener visión directa
con los nodos de una red P2P. En el Sprint 3 se planteó una solución a este problema, mediante la
utilización de redes VPN para la comunicación entre estos nodos.
• Securización del canal de comunicaciones. Para garantizar la confidencialidad e integridad de los
datos transferidos a través de la aplicación y garantizar la autentificación entre pares en las
comunicaciones. En el Sprint 4 se implementa una solución que, si bien no funciona con estabilidad,
permite utilizar el protocolo TLSv1.3 para cifrar las comunicaciones.
Así mismo, con la realización del presente TFM, se han detectado nuevas líneas de evolución del producto.
Estas mejoras se proponen a continuación:
• Análisis de estabilidad de la aplicación. En general, se ha detectado que la aplicación no funciona
siempre de forma estable, sufriendo pérdidas de conexión que no son recuperables a menos que la
aplicación se ejecute de nuevo. Esta inestabilidad se ha visto acentuada en el Sprint 4, con la inclusión
de la securización del canal de comunicaciones, donde se necesitaban varios reintentos antes de
conseguir la correcta transmisión de la información cifrando las comunicaciones. Es importante
analizar el código para buscar las causas de esta inestabilidad, para refactorizarlo apropiadamente.
107
• Pruebas de rendimiento en escenarios de varias dimensiones. Sería conveniente probar la
aplicación en su estado actual en escenarios de distintas características, jugando con el número de
nodos conectados, su calidad de conexión, distribución geográfica, etc. Así, podrían sacarse
conclusiones acerca de su aplicación práctica en escenarios más o menos reales.
• Probar nuevas librerías P2P. La última versión de FreePastry fue liberada en 2009. Sería
conveniente realizar un estudio del estado del arte en el ámbito de librerías que puedan ser utilizadas
para aplicaciones como la desarrollada en este TFM. Es posible que actualmente haya librerías más
eficientes y manejables, que permitan mejorar el mantenimiento y la estabilidad de la aplicación.
• Agregar mensajes de voz. Como incremento funcional, sería conveniente ofrecer la posibilidad de
grabar mensajes de voz y enviarlos a través de la aplicación, para su reproducción dentro de la misma
aplicación.
• Integrar servicios de streaming de video/audio. Como incremento de funcionalidad, sería
interesante estudiar la posibilidad de incluir las funciones de llamada y/o videollamada en la
aplicación.

108
REFERENCIAS

[1] F. J. F. Jiménez, Apuntes Máster Ingeniería Telecomunicación. Asignatura: Procesamiento Ubicuo.


Tema: Redes P2P, Universidad de Sevilla.

[2] H. H. Y. E. K. L. John F. Koegel Buford, P2P networking and applications, Elsevier/Morgan Kaufmann,
2009.

[3] Napster, «Napster. Página oficial,» [En línea]. Available: https://es.napster.com/.

[4] D. Bravo, Copia este libro, Dmen S.L., 2005.

[5] Spotify, «Spotify. Web Oficial,» [En línea]. Available: https://www.spotify.com/es/.

[6] Apple, «Apple Music. Web oficial,» [En línea]. Available: https://www.apple.com/es/apple-music/.

[7] Bitcoin, «Bitcoin. Web Oficial,» [En línea]. Available: https://bitcoin.org/es/.

[8] Bitcoin, «White Paper. Bitcoin: un sistema de dinero en efectivo electrónico peer-to-peer,» [En línea].
Available: https://bitcoin.org/files/bitcoin-paper/bitcoin_es.pdf.

[9] D. F. Píriz, Aplicación P2P de comunicación y organización de grupos, Sevilla: Universidad de Sevilla,
2017.

[10] Oracle, «Java. Web Oficial,» [En línea]. Available: https://www.java.com/es/.

[11] G. E. Krasner y S. T. Pope, «A Description of the Model-View-Controller User Interface Paradigm in the
Smalltalk80 System,» 1988. [En línea]. Available:
https://www.researchgate.net/publication/239452280_A_Description_of_the_Model-View-
Controller_User_Interface_Paradigm_in_the_Smalltalk80_System.

[12] A. Rowstron y P. Druschel, «Pastry: Scalable, decentralized object location and routing for large-scale
peer-to-peer systems,» 2001. [En línea]. Available: http://www.freepastry.org/PAST/pastry.pdf.

[13] FreePastry, «FreePastry. Web Oficial,» [En línea]. Available: http://www.freepastry.org/.

[14] Universidad de Sevilla, «Trabajo Fin de Grado: material de apoyo,» [En línea]. Available:
http://bib.us.es/estudia_e_investiga/guias/tfg.

[15] Universidad de Sevilla, «FAMA. Catálogo de la Biblioteca de la Universidad de Sevilla,» [En línea].
Available: https://fama.us.es/.

[16] Google, «Google Académico,» [En línea]. Available: https://scholar.google.es/.

[17] Atlassian, «Trello. Herramienta de Gestión de proyectos,» [En línea]. Available: https://trello.com/es.

109
[18] Atlassian, «¿Qué es kanban?,» [En línea]. Available: https://www.atlassian.com/es/agile/kanban.

[19] SCRUM, «Metodología ágil SCRUM. Sitio web oficial,» [En línea]. Available: https://www.scrum.org/.

[20] Microsoft, «Visual Studio Code,» [En línea]. Available: https://code.visualstudio.com/.

[21] Git, «Git documentation,» [En línea]. Available: https://git-scm.com/doc.

[22] P. C. Vázquez, «Repositorio tfmteleco,» [En línea]. Available: https://github.com/lordcanete/tfmteleco.

[23] Github, «Github documentation,» [En línea]. Available: https://docs.github.com/es.

[24] Oracle, «VirtualBox,» [En línea]. Available: https://www.virtualbox.org/.

[25] A. Rowstron y P. Druschel, Pastry: Scalable, decentralized object location and routing for large-scale
peer-to-peer systems.

[26] S. Iyer, A. Rowstron y P. Druschel, Squirrel: A decentralized peer-to-peer web cache, 2002.

[27] UC Berkeley, «OceanStore. Sitio web oficial,» [En línea]. Available: https://oceanstore.cs.berkeley.edu/.

[28] MIT, «Ivy. Sitio web oficial,» [En línea]. Available: https://pdos.csail.mit.edu/archive/ivy/.

[29] A. N. Cadavid, J. D. F. Martínez y J. M. Vélez, «Revisión de metodologías ágiles para el desarrollo de


software,» [En línea]. Available: https://www.redalyc.org/pdf/4962/496250736004.pdf.

[30] Agile Alliance, «Acerca de Agile Alliance,» [En línea]. Available: https://www.agilealliance.org/the-
alliance/.

[31] Agile Manifesto, «Manifiesto por el Desarrollo Ágil de Software,» [En línea]. Available:
https://agilemanifesto.org/iso/es/manifesto.html.

[32] K. Schwaber y J. Sutherland, «The Scrum Guide,» [En línea]. Available:


https://www.scrumguides.org/scrum-guide.html.

[33] DIgital.AI, «14th Annual State of Agile Report,» [En línea]. Available: https://stateofagile.com/home.

[34] Scribe, «Scribe. A scalable group communication system,» [En línea]. Available:
http://www.freepastry.org/SCRIBE/default.htm.

[35] RIP Tutorial, «Communication between Java app and Javascript in the web page,» [En línea]. Available:
https://riptutorial.com/javafx/example/19313/communication-between-java-app-and-javascript-in-the-
web-page.

[36] FontAwesome, «FontAwesome Documentation,» [En línea]. Available: https://fontawesome.com/v4.7.0/.

[37] Bootstrap, «Bootstrap Documentation,» [En línea]. Available: https://getbootstrap.com/docs/4.5/getting-


started/introduction/.

[38] Google Developers, «Google Drive API v3,» [En línea]. Available:

110
https://developers.google.com/drive/api/v3/about-sdk.

[39] Gradle, «Gradle Documentation,» [En línea]. Available:


https://docs.gradle.org/current/userguide/userguide.html.

[40] A. Rowstron y P. Druschel, «Storage management and caching in PAST, a large-scale, persistent peer-to-
peer storage utility,» 2001.

[41] Google Developers, «Google API Client Library for Java,» [En línea]. Available:
https://developers.google.com/api-client-library/java.

[42] Google Developers, «Google Drive API - Java Quickstart,» [En línea]. Available:
https://developers.google.com/drive/api/v3/quickstart/java.

[43] DiNNgo, «Técnica de empatía: Customer Journey,» [En línea]. Available:


https://designthinking.es/inicio/herramienta.php?id=50&fase=empatiza.

[44] IETF, «RFC 791: Internet Protocol (IP),» [En línea]. Available: https://tools.ietf.org/html/rfc791.

[45] G. Davis, «2020: Life with 50 Billion Connected Devices,» [En línea]. Available:
https://ieeexplore.ieee.org/document/8326056.

[46] IETF, «RFC 2131: Dynamic Host Configuration Protocol,» [En línea]. Available:
https://tools.ietf.org/html/rfc2131.

[47] IETF, «RFC 2460: Internet Protocol, Version 6 (IPv6) Specification,» [En línea]. Available:
https://tools.ietf.org/html/rfc2460.

[48] Microsoft, «Virtual Private Networking: An Overview,» [En línea]. Available:


https://docs.microsoft.com/en-us/previous-versions/windows/it-pro/windows-2000-
server/bb742566(v=technet.10)?redirectedfrom=MSDN.

[49] Medium.com, «Setting up an OpenVPN Server on Google Compute Engine,» [En línea]. Available:
https://medium.com/teendevs/setting-up-an-openvpn-server-on-google-compute-engine-9ff760d775d9.

[50] IETF, «RFC 8446: The Transport Layer Security (TLS) Protocol Version 1.3,» [En línea]. Available:
https://tools.ietf.org/html/rfc8446.

[51] IETF, «RFC 6101: The Secure Sockets Layer (SSL) Protocol Version 3.0,» [En línea]. Available:
https://tools.ietf.org/html/rfc6101.

[52] IETF, «RFC 7292: PKCS #12: Personal Information Exchange Syntax v1.1,» [En línea]. Available:
https://tools.ietf.org/html/rfc7292.

[53] R. M. Reese, Learning Network Programming with Java, 2015.

[54] D. McGreal y R. Jocham, The Professional Product Owner, Pearson, 2018.

[55] M. T. Gallego, «Trabajo Fin de Carrera. Desarrollo detallado de la fase de aprobación de un proyecto
informático mediante el uso de metodologías ágiles,» [En línea]. Available:
http://openaccess.uoc.edu/webapps/o2/bitstream/10609/17885/1/mtrigasTFC0612memoria.pdf.

111
[56] J. H. Canós, P. Letelier y M. C. Penadés, «Métodologías Ágiles en el Desarrollo de Software,» [En línea].
Available: http://roa.ult.edu.cu/bitstream/123456789/476/1/TodoAgil.pdf.

[57] TOX chat, «TOX Chat Documentation,» [En línea]. Available: https://wiki.tox.chat/doku.php.

[58] AntiMath, «Prevent inner elements trigger an event on the parent,» [En línea]. Available:
https://www.antimath.info/jquery/prevent-inner-elements-trigger-an-event-on-the-parent/.

[59] StackOverflow, «Jquery empty() div except for matched elements,» [En línea]. Available:
https://stackoverflow.com/questions/1262930/jquery-empty-div-except-for-matched-elements.

[60] OpenVPN Support Forum, «Issue: openssl.cnf not found in easy-rsa/2.0,» [En línea]. Available:
https://forums.openvpn.net/viewtopic.php?t=8819.

[61] Experto.dev, «Instalar ANT en Windows,» [En línea]. Available: https://experto.dev/instalar-ant-en-


windows/.

[62] StackOverflow, «How to add JsonObjects to javax.json.JsonArray Using Loop (dynamically),» [En
línea]. Available: https://stackoverflow.com/questions/23871265/how-to-add-jsonobjects-to-javax-json-
jsonarray-using-loop-dynamically.

[63] EasyRSA, «EasyRSA Documentation,» [En línea]. Available: https://easy-rsa.readthedocs.io/en/latest/.

[64] Google Developers, «Drive API v3 Documentation,» [En línea]. Available:


https://developers.google.com/resources/api-libraries/documentation/drive/v3/java/latest/overview-
summary.html.

[65] Oracle, «Documentación JavaFX 8,» [En línea]. Available: https://docs.oracle.com/javase/8/javafx/api/.

112
ANEXO I. INSTALACIÓN, EJECUCIÓN Y
DEPENDENCIAS

Instalación del TFM


Para preparar el entorno y poder disponer de las herramientas necesarias para la ejecución del TFM, se deben
ejecutar los siguientes comandos (Ejecutados en Ubuntu 20.04):

#Actualización de repositorios
sudo apt-get update
#Instalación de GIT
sudo apt-get install -y git
#Instalación del SDK de Java
sudo apt-get install -y default-jdk
#Instalación de JavaFX
sudo apt-get install -y openjfx
#Instalación de Gradle
#Primero, se instala SDK (herramienta para gestionar versiones de SDKs)
curl -s "https://get.sdkman.io" | bash
source "$HOME/.sdkman/bin/sdkman-init.sh"
#Ahora, se instala Gradle
sdk install gradle 6.7.1
#Clonado del repositorio del TFM
git clone https://github.com/lordcanete/tfmteleco.git

Ejecución del TFM


Para ejecutar el proyecto, en primer lugar se debe compilar. Se dispone de un fichero build.gradle en la raíz del
proyecto que permite compilar y realizar los tests registrados mediante el comando:
gradle build

Si no se quieren ejecutar los tests, deberá ejecutarse el siguiente comando:


gradle build -x test

Tras la ejecución de cualquiera de los comandos anteriores, se creará un fichero “tfmteleco-1.0.jar” en la


carpeta lib de la raíz del proyecto. Para lanzar la aplicación, será necesario ejecutar el siguiente comando desde
la raíz del proyecto:
java -cp "lib/*" --module-path /usr/share/openjfx/lib --add-modules=javafx.controls,javafx.web
us.tfg.p2pmessenger.view.VistaGUI PUERTO_LOCAL IP_LOCAL RUTA_ALMACEN_CLAVES

En el comando anterior se puede observar que se agregan los módulos necesarios de JavaFX para la ejecución
de la interfaz gráfica. El directorio mostrado se corresponde con el directorio de instalación por defecto de
JavaFX mediante el comando de instalación explicado en la sección anterior. Los 3 parámetros que se utilizan
son: el puerto donde se ejecutará localmente la aplicación (por ejemplo, 9001); la IP a utilizar por la aplicación
(se puede obtener mediante el comando ifconfig); y la ruta al fichero almacén de claves (por ejemplo, el creado

113
para el proyecto: certs/nodo1.p12).

Dependencias de ejecución
A continuación, se muestran las librerías necesarias para la ejecución de la aplicación tras todos los
incrementos de este TFM:
bouncycastle.jar gson-2.8.6.jar grpc-context-1.32.1.jar
commons-jxpath-1.1.jar guava-29.0-jre.jar javax.servlet-api-
4.0.1.jar
commons-logging-1.1.1.jar httpclient-4.5.9.jar
jetty-6.1.5.jar
google-api-client-1.23.0.jar httpcore-4.4.11.jar
jetty-util-6.1.25.jar
google-api-client-1.30.4.jar jackson-core-2.9.5.jar
jsr305-3.0.2.jar
google-api-services-drive-v3-rev110- javafx.base.jar
1.23.0.jar objenesis-2.6.jar
javafx.controls.jar
google-cloud-storage-1.112.0.jar opencensus-api-0.27.0.jar
javafx.fxml.jar
google-http-client-1.32.1.jar protobuf-java-3.10.0.jar
javafx.graphics.jar
google-http-client-jackson2-1.32.1.jar sbbi-upnplib-1.0.4.jar
javafx.media.jar
google-oauth-client-1.30.3.jar sqlite-jdbc-3.16.1.jar
javafx.properties
google-oauth-client-1.30.4.jar tfmteleco-1.0.jar
javafx.swing.jar
google-oauth-client-java6-1.30.4.jar xmlpull_1_1_3_4a.jar
javafx.web.jar
google-oauth-client-jetty-1.23.0.jar xpp3-1.1.3.4d_b2.jar
javax.json-1.0.4.jar
opencensus-contrib-http-util-0.27.0.jar xpp3-1.1.4c.jar

Tabla 26. Dependencias necesarias para ejecución del proyecto

114
ANEXO II. CONFIGURACIONES DE SPRINT 2

Habilitar Google Drive API.


1. Acceder a la consola de APIs de Google54

2. Click en “Selecciona un proyecto” (arriba a la izquierda)


3. Crear un nuevo proyecto y asignarle un nombre

4. Ir a la biblioteca de APIs para habilitar la API de Google Drive

5. Buscar la API de Google Drive y hacer click en “Habilitar”

6. Una vez habilitada, entrar al menú de Credenciales dentro de la API

54 https://console.developers.google.com

115
7. Completar el asistente de Pantalla de consentimiento (sólo es obligatoria la primera sección)

8. Completar el resto de pasos (no es necesario modificar ningún campo más)


9. Seleccionar “Crear credenciales” -> ID de cliente de OAuth

10. Seleccionar un nombre para el ID y el tipo de aplicación. Después, pulsar en “Crear”.

11. Para descargar el fichero JSON con las credenciales necesarias para ubicar en el proyecto, pulsar en el
icono de descarga dentro de la lista de claves

116
ANEXO III. CONFIGURACIONES DE SPRINT 3

Creación de una red en Google Cloud Platform


1. Acceder a la consola de Google Cloud Platform: https://console.cloud.google.com/?hl=es
2. En el menú lateral, acceder a Red de VPC -> Redes de VPC

3. Seleccionar la opción CREAR RED VPC de la barra de opciones superior

4. Rellenar el formulario, dando un nombre a la red y creando las subredes con el rango de direcciones
que se desee.

5. Cuando se haya terminado de configurar la red, pulsar el botón de Crear ubicado al final del
formulario. Las instancias aparecerán en la consola de control de Google Cloud Platform

Creación de Máquina Virtual en Google Cloud Platform

117
1. Acceder a la consola de Google Cloud Platform: https://console.cloud.google.com/?hl=es
2. En el menú lateral, acceder a Compute Engine -> Instancias de VM

3. Seleccionar la opción Crear instancia de la barra de opciones superior

4. En el formulario de creación, será necesario escoger un nombre para la máquina y se podrá configurar
el tipo de máquina (más o menos recursos de computación), el Sistema Operativo, interfaces de red o
discos entre otras cosas.

5. En cuanto a la configuración de red, es interesante hacer notar que puede configurarse para ser visible
desde internet, o no (emulando una red doméstica).

6. Cuando se haya terminado de configurar la máquina, pulsar el botón de Crear ubicado al final del
118
formulario. Las instancias aparecerán en la consola de control de Google Cloud Platform.

Configuración de servidor OpenVPN


Para la configuración del servidor OpenVPN se ha seguido como base el tutorial de [49]. Las operaciones
mostradas a continuación se realizan sobre la máquina virtual de Google Cloud Platform llamada tfm-
ovpnserver.
1. Actualizar repositorios
sudo apt-get update

2. Instalar OpenVPN (software VPN) y EasyRSA (herramienta para manejar certificados)


sudo apt-get install openvpn easy-rsa

3. Configurar el CA (Certificate Authority) necesario en el servidor para crear y firmar el certificado del
servidor.
#Creación de directorio de trabajo
make-cadir ~/openvpn-ca
cd ~/openvpn-ca
#Abrir el fichero vars
nano vars
#Editar las lineas donde están las variables relativas al certificado (a gusto del
desarrollador)
#export KEY_COUNTRY="US"
#export KEY_PROVINCE="CA"
#export KEY_CITY="SanFrancisco"
#export KEY_ORG="Fort-Funston"
#export KEY_EMAIL="me@myhost.mydomain"
#export KEY_OU="MyOrganizationalUnit"
#export KEY_NAME="server"
#Guardar el fichero
#Dentro del directorio openvpn-ca, actualizar las variables editadas
source vars
#Debería aparecer el mensaje: “NOTE: If you run ./clean-all, I will be doing a rm -rf on
/home/username/openvpn-ca/keys”
#Ejecutar el comando recomendado para asegurar que tenemos un entorno totalmente limpio
./clean-all
#Crear el CA y el certificado de servidor (ojo, sustituir “server” por el nombre que se le
haya dado al servidor)
./build-ca
./build-key-server server
#Crear una clave de encriptación. Se utiliza Diffie-Hellman
./build-dh
#Crear una clave para firmar (HMAC55) los mensajes. Esto dará un extra de robustez a las
comunicaciones.
openvpn --genkey --secret keys/tfm.key

4. Instalar y configurar el servidor OpenVPN


#Copiar el certificado y las claves creadas en el paso anterior al directorio de
configuración de OpenVPN
cd ~/openvpn-ca/keys
sudo cp ca.crt server.crt server.key tiv.key dh2048.pem /etc/openvpn
#Extraer el fichero de configuración de ejemplo que trae por defecto OpenVPN
gunzip -c /usr/share/doc/openvpn/examples/sample-config-files/server.conf.gz | sudo tee
/etc/openvpn/server.conf
#Adaptar el fichero de configuración del servidor
sudo nano /etc/openvpn/server.conf
#A continuación se muestra el contenido del fichero utilizado para este TFM

55 https://www.ietf.org/rfc/rfc2104.txt

119
port 1194
proto udp
dev tun
ca ca.crt
cert server.crt
key server.key # This file should be kept secret
dh dh2048.pem
server 10.8.0.0 255.255.255.0
ifconfig-pool-persist /var/log/openvpn/ipp.txt
push "route 10.8.0.0 255.255.255.0"
keepalive 10 120
tls-auth tfm.key 0 # This file is secret
key-direction 0
cipher AES-128-CBC
auth SHA256
user nobody
group nogroup
persist-key
persist-tun
status /var/log/openvpn/openvpn-status.log
verb 3
explicit-exit-notify 1

5. Configurar el Sistema Operativo para permitir el encaminamiento del tráfico


#Para activar reenvío de paquetes, editar el fichero /etc/sysctl.conf
sudo nano /etc/sysctl.conf
#Buscar la directiva net.ipv4.ip_forward y fijar su valor a 1
net.ipv4.ip_forward=1
#Una vez guardados los cambios, actualizar las variables de sesión
sudo sysctl -p
#Buscar la interfaz donde está la ruta por defecto
ip route | grep default
#En el caso de la MV de este TFM es ens4

#Configurar las reglas de firewall acorde a esta interfaz


sudo nano /etc/ufw/before.rules
#Agregar las siguientes lineas al principio del fichero, y después guardar los cambios
# OPENVPN
# NAT Table
*nat
:POSTROUTING ACCEPT [0:0]
# OpenVPN client traffic
-A POSTROUTING -s 10.8.0.0/8 -o ens4 -j MASQUERADE
COMMIT
# OPENVPN
#Editar el fichero de reglas de reenvío
sudo nano /etc/default/ufw
#Cambiar el valor de la directiva DEFAULT_FORWARD_POLICY para aceptar el reenvío por defecto
y guardar los cambios
DEFAULT_FORWARD_POLICY="ACCEPT"

6. Ejecución del servidor OpenVPN


#Comando para arrancar el servicio OpenVPN
sudo systemctl start openvpn@server
#Comando para comprobar el estado del servicio OpenVPN
sudo systemctl status openvpn@server
#Comando para activar el servidor al arrancar la máquina virtual
sudo systemctl enable openvpn@server

Creación de configuración de cliente OpenVPN


Las siguientes operaciones se realizan en la máquina virtual del servidor OpenVPN
1. Crear un certificado de cliente firmado por el servidor
cd ~/openvpn-ca
source vars
./build-key client

2. Crear un directorio para los certificados de cliente


mkdir -p ~/clients/files
chmod 700 ~/clients/files

120
3. Copiar el fichero de configuración base que viene en la instalación de OpenVPN
cp /usr/share/doc/openvpn/examples/sample-config-files/client.conf ~/clients/base.conf

4. Editar el fichero de configuración. A continuación, se muestra cómo quedaría el fichero en este TFM.
client
dev tun
proto udp
remote 35.197.255.16 1194 #AQUI ES NECESARIO CAMBIAR LA IP POR LA DEL SERVIDOR
resolv-retry infinite
nobind
user nobody
group nogroup
persist-key
persist-tun
remote-cert-tls server
tls-auth ta.key 1
cipher AES-128-CBC
auth SHA256
key-direction 1
verb 3
script-security 2
up /etc/openvpn/update-resolv-conf
down /etc/openvpn/update-resolv-conf

5. Crear script para generación automática de ficheros de configuración de cliente.


nano ~/clients/gen_config.sh
#Contenido del script
#!/bin/bash
KEY_DIR=~/openvpn-ca/keys
OUTPUT_DIR=~/clients/files
BASE_CONFIG=~/clients/base.conf
cat ${BASE_CONFIG} \
<(echo -e '<ca>') \
${KEY_DIR}/ca.crt \
<(echo -e '</ca>\n<cert>') \
${KEY_DIR}/${1}.crt \
<(echo -e '</cert>\n<key>') \
${KEY_DIR}/${1}.key \
<(echo -e '</key>\n<tls-auth>') \
${KEY_DIR}/tfm.key \
<(echo -e '</tls-auth>') \
> ${OUTPUT_DIR}/${1}.ovpn
#Guardar cambios y, después, dar permisos de ejecución
chmod 700 ~/clients/gen_config.sh

6. Ejecutar script para crear las configuraciones de clientes necesarias. En este caso se muestra cómo
crear una. Ojo, es necesario realizar previamente el paso 1 para nuevas configuraciones de cliente.
cd ~/clients
./gen_config.sh client
#Al mostrar el contenido del directorio, debería aparecer el fichero de configuración
generado
ls ~/clients/files
➔ /home/username/clients/files/client.ovpn

Instalación de cliente OpenVPN y establecimiento de conexión con servidor


1. El fichero creado en la sección anterior debe copiarse en la máquina donde se vaya a ejecutar el
cliente OpenVPN.
2. Instalar OpenVPN
sudo apt-get update
sudo apt-get install openvpn

3. Ejecutar OpenVPN especificando el fichero de configuración


sudo openvpn — config /RUTA_HASTA_FICHERO_CONFI_CLIENTE/client.ovpn

121

También podría gustarte