Esta página fue actualizada por última vez el February 2017 y es precisa con la versión 0.9.29 del router I2P.

Vista general

La librería streaming técnicamente es parte de la capa de "aplicación", ya que no es una función central del router. En la práctica, sin embargo, proporciona una función vital para casi todas las aplicaciones I2P existentes, proveyéndolas de flujos (`streams`) tipo-TCP sobre I2P, y permitiendo que las aplicaciones existentes sean fácilmente portadas a I2P. La otra librería de transporte extremo-a-extremo para la comunicación de clientes, es la librería datagram.

La librería de streaming es una capa sobre el corazón de la API I2CP que permite que flujos (streams) de mensajes fiables, ordenados y autentificados, operen a través de una capa de mensaje no confiable, desordenada y no autentificada. Justo como la relación TCP hacia IP, esta funcionalidad streaming tiene un conjunto completo de equilibrios y optimizaciones disponibles, pero en lugar de integrar esta funcionalidad junto al código base de I2P, ha sido desgajado en su propia librería para mantener las complejidades propias de TCP aparte, y para permitir implementaciones optimizadas alternativas.

En consideración al relativamente alto coste de los mensajes, el protocolo de la librería streaming para programar y entregar esos mensajes ha sido optimizado para permitir que los mensajes individuales pasen a contener tanta información como esté disponible. Por ejemplo, una pequeña transacción HTTP proxificada a través de la librería streaming puede ser completada en un sólo viaje de ida y vuelta - los primeros mensajes empaquetan un SYN, FIN, y la pequeña carga de la petición HTTP, y la respuesta empaqueta el SYN, FIN, ACK, y la carga de la respuesta HTTP. Aunque un ACK adicional debe ser transmitido para decirle al servidor HTTP que el SYN/FIN/ACK ha sido recibido, el proxy HTTP local a menudo puede entregar la respuesta completa de forma inmediata al navegador.

La librería streaming presenta mucha semejanza a una abstracción de TCP, con sus ventanas (de protocolo) deslizantes, algoritmos de control de congestión (tanto de inicio lento como de elusión de congestión), y comportamiento general del paquete (ACK, SYN, FIN, RST, cálculo RTO, etc.).

La librería streaming es una librería robusta que está optimizada para operar sobre I2P. Tiene una instalación de fase-única, y contiene una implementación de ventanización (protocolo) completa.

API

La API de la librería streaming proporciona un paradigma de socket estándar a las aplicaciones Java. La API de nivel-inferior de I2CP está completamente escondida, exceptuando que esas aplicaciones pueden pasar parámetros I2CP a través de la librería streaming, para que sean interpretados por I2CP.

La interfaz estándar de la librería streaming es para que la aplicación use el I2PSocketManagerFactory para crear un I2PSocketManager. La aplicación pregunta entonces al administrador de socket por una I2PSession, que producirá una conexión al router vía I2CP. La aplicación puede entonces establecer conexiones con un I2PSocket o recibir conexiones con un I2PServerSocket.

Aquí están los Javadocs de la librería streaming completa.

Para ver un buen ejemplo de uso, vea el código de i2psnark.

Opciones y valores predeterminados

Las opciones y los actuales valores predeterminados están listados debajo. Las opciones diferencian mayúsculas/minúsculas y pueden ser establecidas para todo el router, para un cliente concreto, o para un socket individual en base a cada conexión. Muchos valores son ajustados para el rendimiento HTTP sobre las condiciones típicas de I2P. Otras aplicaciones tales como los servicios entre pares (`peer-to-peer`) son fuertemente animadas a que los modifiquen como sea necesario, configurando las opciones y pasándolas a través de la llamada a I2PSocketManagerFactory.createManager(_i2cpHost, _i2cpPort, opts). Los valores de los tiempos están en ms.

Observe que las APIs de capa-superior, tales como SAM, BOB, e I2PTunnel, pueden imponer sus propias configuraciones predeterminadas sobre estas configuraciones por defecto. Observe también que muchas opciones sólo se aplican a los servidores que están escuchando conexiones entrantes.

Desde la versión 0.9.1 la mayoría de las opciones, pero no todas, pueden ser cambiadas en un administrador de socket activo o sesión. Vea los Javadocs para más detalles.

OpciónValor predeterminadoNotas
i2cp.accessListnullLista separada por comas - o espacios - de hashes de pares (`peers`) Base64 usada bien como lista de acceso, o como lista negra. Desde la versión 0.7.13.
i2cp.destination.sigTypeDSA_SHA1Usar la lista de acceso como lista blanca para conexiones entrantes. The name or number of the signature type for a transient destination. Desde la versión 0.9.12.
i2cp.enableAccessListfalseUsar la lista de acceso como lista blanca para conexiones entrantes. Desde la versión 0.7.13.
i2cp.enableBlackListfalseUsar la lista de acceso como lista negra para conexiones entrantes. Desde la versión 0.7.13.
i2p.streaming.answerPingstrueResponder o no a los pings entrantes.
i2p.streaming.blacklistnullLista separada por comas - o espacios - de hashes de pares (`peers`) Base64 que sera usada como lista negra para las conexiones entrantes a TODOS los destinos en el contexto. Esta opción debe ser configurada en las propiedades contextuales, NO en el argumento createManager() de las opciones. Observe que establecer esto en el contexto del router no afectará a clientes fuera del router en una JVM y contexto aparte. Desde la versión 0.9.3.
i2p.streaming.bufferSize64KCuántos datos de transmisión (en bytes) serán aceptados que no hayan sido emitidos aún.
i2p.streaming.congestionAvoidanceGrowthRateFactor1Cuando estamos evitando la congestión, aumentamos el tamaño de la ventana (protocolo) al ritmo de 1/(tamañodeventana*factor). En TCP estándar, los tamaños de ventana se miden en bytes, mientras que en I2P los tamaños de ventana se miden en mensajes. Un número más alto significa un crecimiento más lento.
i2p.streaming.connectDelay-1Cuánto esperar después de crear una instancia de nueva conexión antes de intentar conectar realmente. Si esto es <= 0 conecta inmediatamente sin datos inciales. Si es mayor que 0, espera hasta que la salida del flujo de datos (`stream`) sea evacuada, se llene el buffer, o que pasen muchos milisegundos, e incluye cualquier dato inicial con el SYN.
i2p.streaming.connectTimeout5*60*1000Durante cuánto bloquear al conectar, en milisegundos. Valores negativos significan indefinidamente. El valor predeterminado es 5 minutos.
i2p.streaming.disableRejectLoggingfalseDesactivar o no las advertencias en los registros (`logs`), cuando se rechaza una conexión entrante debido a los límites de la conexión. Desde la versión 0.9.4.
i2p.streaming.dsalistnullComma- or space-separated list of Base64 peer Hashes or host names to be contacted using an alternate DSA destination. Only applies if multisession is enabled and the primary session is non-DSA (generally for shared clients only). This option must be set in the context properties, NOT in the createManager() options argument. Note that setting this in the router context will not affect clients outside the router in a separate JVM and context. Desde la versión 0.9.21.
i2p.streaming.enforceProtocolfalseEscuchar o no sólo el protocolo streaming. Configurando a verdadero (`true`) prohibirá la comunicación con Destinos que usen una versión más temprana que la 0.7.1 (publicada en marzo de 2009). Configure a verdadero si ejecuta múltiples protocolos sobre este Destino. Desde la versión 0.9.1.
i2p.streaming.inactivityAction2 (send) (0=nada, 1=desconectar) Qúe hacer durante un periodo de inactividad - no hacer nada, desconectar, o enviar un ACK duplicado.
i2p.streaming.inactivityTimeout90*1000 Idle time before sending a keepalive
i2p.streaming.initialAckDelay750 Delay before sending an ack
i2p.streaming.initialResendDelay1000El valor incial del campo de demora del reenvío en la cabecera del paquete, marca 1000. No está implementado completamente; vea debajo.
i2p.streaming.initialRTO9000Tiempo límite inicial (si no hay datos compartidos disponibles). Desde la versión 0.9.8.
i2p.streaming.initialRTT8000 Estimación de (RTT/RTD) tiempo de viaje de ida y vuelta (si no hay datos compartidos disponibles). Deshabilitado desde la versión 0.9.8; usa el RTT real.
i2p.streaming.initialWindowSize6(si no hay datos compatidos disponibles) En TCP estándar, los tamaños de las ventanas se miden en bytes, mientras que en I2P los tamaños de las ventanas se miden en mensajes.
i2p.streaming.maxConcurrentStreams-1 (0 o valores negativos significan ilimitado) Esto es un límite total para la combinación entrante y saliente.
i2p.streaming.maxConnsPerMinute0 Límite de conexión entrante (por pares ('peer`); 0 significa deshabilitado) Desde la versión 0.7.14.
i2p.streaming.maxConnsPerHour0 (por pares (`peer`); 0 significa deshabilitado) Desde la versión 0.7.14.
i2p.streaming.maxConnsPerDay0 (por pares (`peer`); 0 significa deshabilitado) Desde la versión 0.7.14.
i2p.streaming.maxMessageSize1730La MTU en bytes.
i2p.streaming.maxResends8Número máximo de retransmisiones antes de fallo.
i2p.streaming.maxTotalConnsPerMinute0 Límite de conexión entrante (todos los pares (`peers`); 0 significa deshabilitado) Desde la versión 0.7.14.
i2p.streaming.maxTotalConnsPerHour0 (todos los pares (`peers`); 0 significa deshabilitado) Usar con precaución ya que exceder esto deshabilitará un servidor por un largo periodo. Desde la versión 0.7.14.
i2p.streaming.maxTotalConnsPerDay0 (todos los pares (`peers`); 0 significa deshabilitado) Usar con precaución ya que exceder esto deshabilitará un servidor por un largo periodo. Desde la versión 0.7.14.
i2p.streaming.maxWindowSize128
i2p.streaming.profile1 (bulk)(2=interactivo no soportado) Esto actualmente no hace nada, pero configurándolo a un valor distino de 1 causará un error.
i2p.streaming.readTimeout-1Durante cuánto bloquear al leer, en milisegundos. Valores negativos significan indefinidamente.
i2p.streaming.slowStartGrowthRateFactor1Cuando estemos en un inicio lento, elevaremos el tamaño de la ventana (del protocolo) a un ritmo de 1/(factor). En TCP estándar, los tamaños de ventana se miden en bytes, mientras que en I2P los tamaños de ventana se miden en mensajes. Un número más alto significa un crecimiento más lento.
i2p.streaming.tcbcache.rttDampening0.75Ref: RFC 2140. Valor del punto flotante. Puede ser establecido sólo mediante las propiedades contextuales, no las opciones de conexión Desde la versión 0.9.8.
i2p.streaming.tcbcache.rttdevDampening0.75Ref: RFC 2140. Valor del punto flotante. Puede ser establecido sólo mediante las propiedades contextuales, no las opciones de conexión Desde la versión 0.9.8.
i2p.streaming.tcbcache.wdwDampening0.75Ref: RFC 2140. Valor del punto flotante. Puede ser establecido sólo mediante las propiedades contextuales, no las opciones de conexión Desde la versión 0.9.8.
i2p.streaming.writeTimeout-1Durante cuánto bloquear al escribir/limpiar, en milisegundos. Los valores negativos significan indefinidamente.

Especificación del protocolo

Vea la página Especificación de la librería streaming.

Detalles de la implementación

Configuración

El iniciador envía un paquete con el distintitivo SYNCHRONIZE (sincronizar) establecido. Este paquete puede contener también los datos iniciales. El par (`peer`) responde con un paquete con el distintivo SYNCHRONIZE establecido. Este paquete puede contener también los datos de respuesta iniciales

El iniciador puede enviar paquetes de datos adicionales, hasta el tamaño de ventana inicial, antes de recibir la respuesta SYNCHRONIZE. Estos paquetes también tendrán el campo `envíar Identificador de Stream` establecido a 0. Los receptores deben guardar en el buffer los paquetes recibidos sobre flujos (`streams`) desconocidos durante un periodo corto de tiempo, ya que pueden llegar estropeados, adelantándose al paquete SYNCHRONIZE.

Selección y negociación MTU

El máximo tamaño de mensaje (también llamado MTU / MRU) es negociado al menor valor soportado por los dos pares (`peers`). Como los mensajes túnel están acotados a 1KB, una elección MTU pobre llevaría a una gran cantidad de tráfico de control. La MTU está especificada por la opción i2p.streaming.maxMessageSize. La MTU está especificada por la opción i2p.streaming.maxMessageSize. La MTU actual por defecto de 1720 fue elegida para encajar precisamente en dos mensajes túnel I2NP de 1K, incluyendo el tráfico de control para un caso típico.

El primer mensaje en una conexión incluye un Destino de 387 bytes (típico) añadido por la capa streaming, y usualmente un LeaseSet (todos los leases o túneles autorizados a recibir conexiones para un destino concreto) de 898 bytes (típico), y claves de Sesión, empaquetadas en un mensaje Ajo (`Garlic`) por el router (El LeaseSet y las Claves de Sesión no serán empaquetadas si se estableció previamente una Sesión ElGamal). Por lo tanto, la meta de encajar una petición HTTP completa en un sólo mensaje I2NP (I2P Network Protocol) de 1KB no siempre es alcanzable. Sin embargo, la elección de MTU, junto con una cuidadosa implementación de fragmentación y estrategias de elaboración de lotes en el procesador del túnel de la pasarela de salida (`gateway`), son factores importantes en el ancho de banda, latencia, fiabilidad y eficiencia de la red, especialmente para conexión de vida-larga.

Integridad de los datos

La integridad de los datos está asegurada por el checksum CRC-32 de gzip implementado en la capa I2CP. No hay un campo checksum en el protocolo streaming.

Encapsulado de paquetes

Cada paquete es enviado a través de I2P como un solo mensaje (o como un diente en un mensaje Garlic). La encapsulación de los mensajes es implementada en el I2CP subyacente, en el I2NP, y en las capas de los túneles de mensajes. No hay mecanismo delimitador o campo de tamaño del payload en el protocolo de streaming.

Optional Delay

Data packets may include an optional delay field specifying the requested delay, in ms, before the receiver should ack the packet. Valid values are 0 to 60000 inclusive. A value of 0 requests an immediate ack. This is advisory only, and receivers should delay slightly so that additional packets may be acknowledged with a single ack. Some implementations may include an advisory value of (measured RTT / 2) in this field. For nonzero optional delay values, receivers should limit the maximum delay before sending an ack to a few seconds at most. Optional delay values greater than 60000 indicate choking, see below.

Receive Window and Choking

TCP headers include the receive window in bytes. The streaming protocol does not contain a receive window, it uses only a simple choke/unchoke indication. Each endpoint must maintain its own estimate of the far-end receive window, in either bytes or packets. The recommended minimum buffer size for receiver implementations is 128 packets or 217 KB (approximately 128x1730). Because of I2P netowrk latency, packet drops, and the resulting congestion control, a buffer of this size is rarely filled. Overflow is, however, likely to occur on high-bandwidth "local loopback" (same-router) connections.

To quickly indicate and smoothly recover from overflow conditions, there is a simple mechanism for pushback in the streaming protocol. If a packet is received with an optional delay field of value of 60001 or higher, that indicates "choking" or a receive window of zero. A packet with an optional delay field of value of 60000 or less indicates "unchoking". Packets without an optional delay field do not affect the choke/unchoke state.

After being choked, no more packets with data should be sent until the transmitter is unchoked, except for occasional "probe" data packets to compensate for possible lost unchoke packets. The choked endpoint should start a "persist timer" to control the probing, as in TCP. The unchoking endpoint should send several packets with this field set, or continue sending them periodically until data packets are received again. Maximum time to wait for unchoking is implementation-dependent. Transmitter window size and congestion control strategy after being unchoked is implementation-dependent.

Congestion Control

La librería streaming utiliza fases estándar de inicio-lento (crecimiento exponencial de la ventana (del protocolo)) y de elusión de congestión (crecimiento lineal de la ventana), con retroceso exponencial. La ventanización y los acuses de recibo ('acknowledments') cuentan paquetes, no bytes.

Cerrar

Cualquier paquete, incluyendo uno con el distintivo SYNCHRONIZE establecido, puede haber enviado también el distintivo CLOSE. La conexión no está cerrada hasta que el par (`peer`) responde con el distintivo CLOSE. Los paquetes CLOSE también pueden contener datos.

Ping / Pong

There is no ping function at the I2CP layer (equivalent to ICMP echo) or in datagrams. This function is provided in streaming. Pings and pongs may not be combined with a standard streaming packet; if the ECHO option is set, then most other flags, options, ackThrough, sequenceNum, NACKs, etc. are ignored.

Un paquete de ping debe tener establecidos los indicadores ECHO (eco), SIGNATURE_INCLUDED (firma incluida), y FROM_INCLUDED (origen incluido). El sendStreamId (identificador de stream de envío) puede o no corresponder con una conexión existente.

A pong packet must have the ECHO flag set. The sendStreamId must be zero, and the receiveStreamId is the sendStreamId from the ping. Prior to release 0.9.18, the pong packet does not include any payload that was contained in the ping.

As of release 0.9.18, pings and pongs may contain a payload. The payload in the ping, up to a maximum of 32 bytes, is returned in the pong.

El protocolo de streaming puede ser configurado para deshabilitar el envío de pongs con la configuración i2p.streaming.answerPings=false .

Compartición del bloque de control

La librería streaming (de flujo) soporta compartición del Bloque de Control "TCP" (protocolo de control de transmisiones). Esto comparte tres importantes parámetros de la librería streaming (tamaño de la ventana, tiempo de viaje de ida y vuelta (RTT/RTD), variación del RTT) entre las conexiones al mismo par (`peer`) remoto. Esto se usa para la compartición "temporal" en el momento de apertura/cierre de la conexión, no para la compartición "coral" durante una conexión (Vea RFC 2140). Hay una compartición separada por ConnectionManager (administrador de conexión) (ej: por destino local), así que no hay información sobre filtraciones a otros destinos en el mismo router. Los datos compartidos para un par (`peer`) dado expiran después de unos pocos minutos. Los siguientes parámetros de Compartición del Bloque de Control pueden ser establecidos en cada router.

  • RTT_DAMPENING = 0.75
  • RTTDEV_DAMPENING = 0.75
  • WINDOW_DAMPENING = 0.75

Otros parámetros

Los siguientes parámetros son internos, pero pueden ser de interés para el análisis:

  • MIN_RESEND_DELAY = 100 ms (minimum RTO)
  • MAX_RESEND_DELAY = 45 sec (maximum RTO)
  • MIN_WINDOW_SIZE = 1
  • TREND_COUNT = 3
  • MIN_MESSAGE_SIZE = 512 (minimum MTU)
  • INBOUND_BUFFER_SIZE = maxMessageSize * (maxWindowSize + 2)
  • INITIAL_TIMEOUT (valid only before RTT is sampled) = 9 sec
  • "alpha" ( RTT dampening factor as per RFC 6298 ) = 0.125
  • "beta" ( RTTDEV dampening factor as per RFC 6298 ) = 0.25
  • "K" ( RTDEV multiplier as per RFC 6298 ) = 4
  • PASSIVE_FLUSH_DELAY = 175 ms
  • Maximum RTT estimate: 60 sec

Historia

La librería streaming ha crecido orgánicamente para I2P - primero mihi implementó la "librería mini streaming" como parte de I2PTunnel, que estaba limitada a un tamaño de ventana de 1 mensaje (requiriendo un ACK antes de enviar el siguiente), y entonces fue desgajado en una interfaz streaming genérica (a semejanza de los sockets TCP) y la implementación streaming completa fue desplegada con un protocolo de ventanas deslizantes y optimizaciones para tener en cuenta el alto valor del producto (ancho-de-banda x demora). Los flujos (`streams`) individuales pueden ajustar su tamaño máximo de paquete y otras opciones. El tamaño predeterminado del mensaje se selecciona para encajar de forma precisa en dos mensajes túnel I2NP (I2P Network Protocol) de 1KB, y es un compromiso de equilibrio razonable entre el coste en ancho de banda de retransmitir mensajes perdidos, y la latencia y tráfico de control de múltiples mensajes.

Trabajo futuro

El comportamiento de la librería streaming tiene un profundo impacto sobre el rendimiento en el nivel-aplicación, y como tal, es un área importante para análisis detallados.

  • Podrían ser necesarios ajustes adicionales de los parámetros de librería streaming.
  • Otro área de investigación es la interacción de la librería streaming con las capas de transporte NTCP (TCP basado en NIO) y SSU (UDP Seguro Semiconfiable). Para mayor detalle vea la página de discusión sobre NTCP.
  • La interacción de los algoritmos de enrutado con la librería streaming afecta fuertemente al rendimiento. En particular, la distribución aleatoria de mensajes a múltiples túneles entre los que están en depósito, lleva a un alto grado de entregas estropeadas que resultan en tamaños de ventana más pequeños de lo que serían en otro caso. Actualmente el router enruta mensajes para un único par desde/hacia el destino a través de un conjunto consistente de túneles, hasta la expiración del túnel o un fallo en la entrega. El fallo del router y los algoritmos de selección del túnel deben ser revisados en busca de posibles mejoras.
  • Los datos en el primer paquete SYN (sincronizar) pueden exceder la MTU (Unidad Máxima de Transporte) del receptor.
  • El campo DELAY_REQUESTED (demora requerida) podría ser usado más.
  • Los paquetes iniciales SYNCHRONIZE duplicados sobre streams de vida-corta pueden ser no reconocidos y eliminados.
  • No envía la MTU en una retransmisión.
  • Los datos se envían al recorrido a menos que la ventana de salida esté llena (es decir sin-Nagle o TCP_NODELAY). Probablemente debe haber una opción de configuración para esto.
  • zzz ha añadido código de depuración a la librería streaming para registrar (`log`) paquetes en un formato compatible-wireshark (pcap); utilice esto para analizar el rendimiento con mayor detalle. El formato puede requerir mejoras para mapear más parámetros de librería streaming en campos TCP.
  • Hay propuestas para reemplazar la librería streaming con TCP estándar (o quizá con una capa vacía junto con sockets crudos (`raw`)). Desafortunadamente esto sería incompatible con la librería streaming pero sería bueno para comparar el rendimiento de los dos.