Get Firefox

Firefox 4.0

stopsoftwarepatents.eu petition banner Manifiesto por la liberación de la cultura 
No a la traza privada
Últimos cambios
Últimos Cambios
Vote for Public Maps - Reject INSPIRE! Geocaching
Mi estado actual en Jabber/XMPP: - jabberES - jabber.org

Desarrollo de una Herramienta Software para el Acceso a Redes TCP/IP a través de la Red Telefónica Conmutada

Última Actualización: 30 de Junio de 1.996 - Domingo

Capítulo 8:
El Módulo TCP

El módulo TCP (Transport Control Protocol) [RFC793] es el equivalente al nivel OSI de transporte orientado a conexión. Sus características principales son:

En cuanto a los servicios que utilizan este módulo, destacan:

El protocolo TCP se define en [RFC793], texto notable por el gran número de erratas y ambigedades que contiene. En [RFC813], [RFC879], [RFC876], [RFC944] y [RFC1122] se concretan algunos detalles oscuros y se eliminan diversos errores.


Interfaz

La interfaz de este módulo está constituida por procesos y por subrutinas ejecutadas en el contexto del llamante. Su utilización es muy simple.


PROC_TCP_BC

Este proceso es el encargado de inicializar este módulo. Debe ser invocado con un mensaje "MSG_INIT" o "MSG_QUIT". La inicialización de este módulo debe ser posterior a la del módulo IP.


PROC_TCP_SUP
Este es el proceso que recibe los mensajes de las capas superiores y los gestiona adecuadamente. Los mensajes definidos son:

PROC_TCP_INF

Este proceso recibe los segmentos TCP y los gestiona adecuadamente. Está diseñado para intercomunicarse con los procesos en los módulos IP e ICMP. Los mensajes que espera recibir son:

En cuanto a los mensajes que transmite, tenemos:

En cuanto a rutinas, tenemos:


uint16 tcp_puerto_libre(void);

Esta rutina devuelve un puerto TCP actualmente no utilizado. Por compatibilidad con protocolos superiores, el valor del puerto es igual o superior a 1024.


estado tcp_listen(uint16 puerto,proc_id proc_retorno,puint32 id);

Esta rutina activa un puerto y espera un intento de conexión remoto. "puerto" es el valor del puerto en el que nos ponemos a escuchar. "proc_retorno" contiene el identificador del proceso al cual hay que informar de cualquier evento. Por último "id" es un puntero al lugar donde hay que dejar el identificador de esta conexión. La rutina retorna "OK" si todo ha ido bien y "ERR_OVERFLOW" si hay demasiadas conexiones TCP. "id" contendrá el identificador que debemos utilizar para comunicarnos con dicha conexión.

Si el puerto especificado ya está en modo "LISTEN" devuelve "ERR_EN_USO". Si necesitamos aceptar varias conexiones a un mismo puerto tendremos que lanzar un nuevo "LISTEN" cuando se recibe una petición remota de conexión y se ocupa el anterior.

Cualquier intento de conexión genera un mensaje "MSG_TCP_OPEN" que puede ser aceptado con otro "MSG_TCP_OPEN" o denegado con un "MSG_TCP_CLOSE". Si se deniega, el puerto regresará al modo "LISTEN" y esperará un nuevo intento de conexión.


uint32 tcp_connect(uint16 puerto,uint32 ip,proc_id proc_retorno);

Esta rutina inicia una conexión al puerto "puerto" de la máquina "ip". "proc_retorno" es el proceso al cual hay que informar de cualquier eventualidad. La rutina retorna el identificador asociado a esa conexión. Si es cero indica que hay demasiadas conexiones abiertas. El puerto local utilizado en la conexión se elige de forma arbitraria.

Si la conexión es aceptada se produce un "MSG_TCP_OPEN", mientras que si se deniega se enviará un "MSG_TCP_CLOSE". Si se excede el número de reintentos se enviará "MSG_TCP_TIMEOUT".


tcp_estado tcp_status(uint32 id);

Esta rutina devuelve el estado de una conexión, a partir de su identificador. Los valores posibles son:


estado tcp_flujo(uint32 id,uint16 tamanho);

Esta rutina es la que implanta el mecanismo de control de flujo TCP. Cada vez que una capa superior desea enviar información a través de una conexión TCP "id", debe pedir permiso. La rutina devuelve "OK" si el flujo está abierto y "FLUJO_LLENO" si la conexión no se encuentra en el estado "ESTABLISHED" o "CLOSE_WAIT".

Es posible, aunque no recomendable, enviar información a través de una conexión aunque su control de flujo esté cerrado. Con ello se pretende simplificar la implementación de algunos protocolos superiores. No debería abusarse de esta característica si no se está completamente seguro de sus implicaciones.

Si el control de flujo está cerrado hay que volver a intentarlo tras un tiempo prudencial (por ejemplo, una décima de segundo).


void tcp_cerrar_flujo_rx(uint32 id);

A través de esta llamada se informa a la máquina remota que la conexión "id" no admite más datos. La capa TCP enviará un segmento vacío con el fin de actualizar la información de ventana del otro extremo. Aún cuando se reciban más segmentos no se enviarán hacia la capa superior. No obstante se entregará cualquier segmento que ya hubiese sido enviado al dispatcher.

Esta acción sólo debe solicitarse en casos de necesidad. En [RFC1122] se especifica claramente que debe evitarse su uso en lo posible.


void tcp_abrir_flujo_rx(uint32 id);

Esta rutina complementa la anterior e informa al otro extremo que estamos dispuestos a aceptar nuevos datos. La capa TCP enviará un segmento para que la máquina remota pueda actualizar su información de ventana.


void tcp_trace(uint32 id,ttcp_trace POINTER trace);

Esta rutina facilita diversa información de depuración y análisis sobre una conexión dada. "id" contiene el identificador de la conexión en la que estamos interesados. "trace" es un puntero a una estructura definida como:


  typedef struct {
    tcp_estado estado;
    uint32     bytes_tx;
    uint32     bytes_rx;
    uint32     srtt;
    uint16     ventana_tx;
    uint16     bytes_cola_tx;
    uint16     mss;
  } ttcp_trace;

"estado" contiene el estado de la conexión, tal y como se vió con anterioridad. "bytes_tx" y "bytes_rx" indican el número de bytes transmitidos y recibidos, respectivamente. "srtt" es el tiempo ida y vuelta estimado de la conexión, en milisegundos. "ventana_tx" informa del tamaño de la ventana publicada por el otro extremo. "bytes_cola_tx" es el número de bytes que pendientes de confirmación. Por último "mss" es el tamaño máximo de segmento que admite la máquina remota.


Implementación

Este módulo sigue escrupulosamente todas las guías definidas en [RFC793], implantándolo completamente. Se trata de un protocolo complejo y ambiguo. El texto original contiene dos errores graves:

En [RFC1122] se indican más errores en la especificación original, y se concretan muchos detalles oscuros.

En la implementación actual los mensajes de control de flujo, "MSG_ICMP_SOURCE_QUENCH", son ignorados. La razón de ello es que este Proyecto ha sido diseñado para trabajar en redes de baja velocidad (modems) y con acceso final a redes rápidas, por lo que la congestión que provocamos es nula. Se mantiene en estudio el utilizar un esquema sencillo de control de flujo mediante, por ejemplo, la paralización de las transmisiones TCP durante un tiempo determinado (por ejemplo, cinco o diez segundos). Los posibles mensajes "MSG_ICMP_DEST_UNREACHABLE" también son ignorados, confiando en el mecanismo de reintentos para o bien solucionar el problema o bien cerrar la conexión.

A la hora de calcular el tiempo de tránsito de la red se cronometra el tiempo transcurrido entre el envío de un segmento y su confirmación, sujeto a una exponencial 2^-x. Suponemos que el retardo de la red es aproximadamente igual en ambas direcciones. El mecanismo de retransmisiones se dispara cuando transcurre un período superior al 25% del RTT estimado sin que llegue alguna confirmación. Cada vez que se realiza una retransmisión crece el RTT, y la conexión se aborta cuando éste supera un valor crítico (actualmente unos 75 segundos).

Todo este mecanismo está siendo estudiado con cuidado, intentando acomodarlo lo máximo posible a las características de este Proyecto. En [RFC1122] se mencionan dos esquemas alternativos que dejan obsoleto a éste, pero desgraciadamente no han sido publicados como RFCs. Uno de nuestros mayores problemas es el hecho de que la longitud de los datagramas influye considerablemente en el RTT, ya que nuestro enlace es de muy baja velocidad (comparativamente). El otro problema es que si nosotros no estamos transmitiendo nada no podemos recalcular el RTT. De todos modos la implementación efectuada ha dado unos resultados bastante aceptables y, además, todo esto no influye en la recepción de datos, acción mucho más habitual en nuestro contexto.

No es necesario que los "MSG_MBUF" que se transmitan midan lo mismo que el MSS de la conexión. La capa TCP se encarga de realizar las correcciones necesarias. Lo que sí es imprescindible es que nunca se supere el valor "MEM_BLOQUE" declarado en el módulo de gestión de memoria. En la negociación del MSS se tiene en cuenta el MTU del canal asociado a nuestra dirección IP, con el fin de evitar la fragmentación de los segmentos.

El estado "TIME_WAIT" se emplea para conservar ciertas estructuras internas asociadas a una conexión que ya ha sido cerrada, en previsión de que la red pueda duplicar y/o desordenar datagramas. Según [RFC793] este estado debe mantenerse durante un tiempo mínimo que garantice que cualquier datagrama en tránsito agote su tiempo de vida. En la implementación actual se ha fijado una temporización de dos minutos. No obstante las estructuras asociadas a una conexión son grandes y, por consiguiente, ocupan una considerable cantidad de memoria. Por ello, si se intenta abrir una conexión y no hay suficiente sitio en las tablas internas para ello, se busca la conexión en estado "TIME_WAIT" más antigua y se elimina para acomodar los nuevos datos. Si no hay ninguna conexión en "TIME_WAIT" no se podrá crear el nuevo enlace.

Aún cuando el protocolo permite enlaces unidireccionales, cuando uno de los extremos cierra la conexión pero el otro no, la filosofía general de las aplicaciones que hacen uso de esta capa consiste en cerrar la conexión en cuanto el otro extremo lo hace.

Se han considerado algunas extensiones:

En el documento [RFC1263] se hace un análisis detallado del impacto, a nivel de compatibilidad y ampliaciones futuras, de las extensiones propuestas. No se ha incluido ninguna de ellas por tratarse de modificaciones experimentales poco difundidas.


Bibliografía


[HTTP1.1]   "HyperText Transfer Protocol"
            http://www.w3.org

[RFC793]    RFC793: "Transport Control Protocol"
            Jon Postel
            Septiembre 1.981

[RFC813]    RFC813: "WINDOW AND ACKNOWLEDGEMENT STRATEGY IN TCP"
            David D. Clark
            Julio 1.982

[RFC821]    RFC821: "SIMPLE MAIL TRANSFER PROTOCOL"
            Jonathan B. Postel
            Agosto 1.982

[RFC854]    RFC854: "Telnet Protocol specification"
            Jon Postel
            Joyce Reynolds
            Mayo 1.983

[RFC862]    RFC862: "Echo Protocol"
            Jon Postel
            Mayo 1.983

[RFC863]    RFC863: "Discard Protocol"
            Jon Postel
            Mayo 1.983

[RFC879]    RFC879: "The TCP Maximum Segment Size and Related
            Topics"
            Jon Postel
            Noviembre 1.983

[RFC896]    RFC896: "Congestion Control in IP/TCP Internetworks"
            John Nagle
            Enero 1.984

[RFC944]    RFC944: "Official ARPA-Internet protocols"
            Joyce Reynolds
            Jon Postel
            Abril 1.985

[RFC959]    RFC959: "FILE TRANSFER PROTOCOL (FTP)"
            Joyce Reynolds
            Jon Postel
            Octubre 1.985

[RFC1072]   RFC1072: "TCP Extensions for Long-Delay Paths"
            Van Jacobson
            R. Braden
            Octubre 1.988

[RFC1122]   RFC1122: "Requirements for Internet Hosts --
            Communication Layers"
            Robert Braden
            Octubre 1.989

[RFC1146]   RFC1146: "TCP Alternate Checksum Options"
            Johnny Zweig
            Craig Partridge
            Marzo 1.990

[RFC1191]   RFC1191: "Path MTU Discovery"
            Jeffrey Mogul
            Steve Deering
            Noviembre 1.990

[RFC1263]   RFC1263: "TCP EXTENSIONS CONSIDERED HARMFUL"
            Larry L. Peterson
            Sean O'Malley
            Octubre 1.991

[RFC1323]   RFC1323: "TCP Extensions for High Performance"
            Van Jacobson
            Bob Braden
            Dave Borman
            Mayo 1.992

[RFC1435]   RFC1435: "IESG Advice from Experience with Path MTU
            Discovery"
            Stev Knowles
            Marzo 1.993

[RFC1693]   RFC1693: "An Extension to TCP : Partial Order Service"
            Phill Conrad
            Paul D. Amer
            Tom Connolly
            Noviembre 1.994

[RFC1866]   RFC1866: "Hypertext Markup Language - 2.0"
            T. Berners-Lee
            D. Connolly
            Noviembre 1.995



Firefox 4.0 Python Zope ©1996 jcea@jcea.es