]> git.llucax.com Git - z.facultad/75.74/practicos.git/commitdiff
Tag de 2da entrega.
authorLeandro Lucarella <llucax@gmail.com>
Sun, 25 Jun 2006 01:26:33 +0000 (01:26 +0000)
committerLeandro Lucarella <llucax@gmail.com>
Sun, 25 Jun 2006 01:26:33 +0000 (01:26 +0000)
57 files changed:
practicas/pipi-2da-entrega/ENUNCIADO [new file with mode: 0644]
practicas/pipi-2da-entrega/README [new file with mode: 0644]
practicas/pipi-2da-entrega/TODO [new file with mode: 0644]
practicas/pipi-2da-entrega/informe.rtf [new file with mode: 0644]
practicas/pipi-2da-entrega/rutas_ejemplo/mi_lan.txt [new file with mode: 0644]
practicas/pipi-2da-entrega/rutas_ejemplo/route.txt [new file with mode: 0644]
practicas/pipi-2da-entrega/rutas_ejemplo/route_10.10.10.1.txt [new file with mode: 0644]
practicas/pipi-2da-entrega/rutas_ejemplo/route_10.10.10.141_tcp.txt [new file with mode: 0644]
practicas/pipi-2da-entrega/rutas_ejemplo/route_10.10.10.2.txt [new file with mode: 0644]
practicas/pipi-2da-entrega/rutas_ejemplo/route_10.10.10.2_tcp.txt [new file with mode: 0644]
practicas/pipi-2da-entrega/rutas_ejemplo/route_10.10.10.3.txt [new file with mode: 0644]
practicas/pipi-2da-entrega/rutas_ejemplo/route_10.10.10.4.txt [new file with mode: 0644]
practicas/pipi-2da-entrega/rutas_ejemplo/route_10.10.10.5.txt [new file with mode: 0644]
practicas/pipi-2da-entrega/src/Makefile [new file with mode: 0644]
practicas/pipi-2da-entrega/src/dev.cpp [new file with mode: 0644]
practicas/pipi-2da-entrega/src/dev.h [new file with mode: 0644]
practicas/pipi-2da-entrega/src/devque.cpp [new file with mode: 0644]
practicas/pipi-2da-entrega/src/devque.h [new file with mode: 0644]
practicas/pipi-2da-entrega/src/devtcp.cpp [new file with mode: 0644]
practicas/pipi-2da-entrega/src/devtcp.h [new file with mode: 0644]
practicas/pipi-2da-entrega/src/dns.cpp [new file with mode: 0644]
practicas/pipi-2da-entrega/src/ip.cpp [new file with mode: 0644]
practicas/pipi-2da-entrega/src/ipaddr.cpp [new file with mode: 0644]
practicas/pipi-2da-entrega/src/ipaddr.h [new file with mode: 0644]
practicas/pipi-2da-entrega/src/ipheader.cpp [new file with mode: 0644]
practicas/pipi-2da-entrega/src/ipheader.h [new file with mode: 0644]
practicas/pipi-2da-entrega/src/ipin.cpp [new file with mode: 0644]
practicas/pipi-2da-entrega/src/ipin.h [new file with mode: 0644]
practicas/pipi-2da-entrega/src/ipout.cpp [new file with mode: 0644]
practicas/pipi-2da-entrega/src/ipout.h [new file with mode: 0644]
practicas/pipi-2da-entrega/src/libtcp.c [new file with mode: 0644]
practicas/pipi-2da-entrega/src/libtcp.h [new file with mode: 0644]
practicas/pipi-2da-entrega/src/nameserver.cpp [new file with mode: 0644]
practicas/pipi-2da-entrega/src/nameserver.h [new file with mode: 0644]
practicas/pipi-2da-entrega/src/resolvproto.cpp [new file with mode: 0644]
practicas/pipi-2da-entrega/src/resolvproto.h [new file with mode: 0644]
practicas/pipi-2da-entrega/src/routetable.cpp [new file with mode: 0644]
practicas/pipi-2da-entrega/src/routetable.h [new file with mode: 0644]
practicas/pipi-2da-entrega/src/test.sh [new file with mode: 0755]
practicas/pipi-2da-entrega/src/test2.sh [new file with mode: 0755]
practicas/pipi-2da-entrega/src/test_devtcp.cpp [new file with mode: 0644]
practicas/pipi-2da-entrega/src/test_ipaddr.cpp [new file with mode: 0644]
practicas/pipi-2da-entrega/src/test_ipin.cpp [new file with mode: 0644]
practicas/pipi-2da-entrega/src/test_ipout.cpp [new file with mode: 0644]
practicas/pipi-2da-entrega/src/test_nameserver_file.cpp [new file with mode: 0644]
practicas/pipi-2da-entrega/src/test_nameserver_resolvnext.cpp [new file with mode: 0644]
practicas/pipi-2da-entrega/src/test_nameserver_zones.txt [new file with mode: 0644]
practicas/pipi-2da-entrega/src/test_poll.c [new file with mode: 0644]
practicas/pipi-2da-entrega/src/test_recv.cpp [new file with mode: 0644]
practicas/pipi-2da-entrega/src/test_resolvproto.cpp [new file with mode: 0644]
practicas/pipi-2da-entrega/src/test_resolvprotoc.cpp [new file with mode: 0644]
practicas/pipi-2da-entrega/src/test_resolvprotos.cpp [new file with mode: 0644]
practicas/pipi-2da-entrega/src/test_send.cpp [new file with mode: 0644]
practicas/pipi-2da-entrega/zonas_ejemplo/10.10.10.1.txt [new file with mode: 0644]
practicas/pipi-2da-entrega/zonas_ejemplo/10.10.10.141.txt [new file with mode: 0644]
practicas/pipi-2da-entrega/zonas_ejemplo/10.10.10.2.txt [new file with mode: 0644]
practicas/pipi-2da-entrega/zonas_ejemplo/10.10.10.3.txt [new file with mode: 0644]

diff --git a/practicas/pipi-2da-entrega/ENUNCIADO b/practicas/pipi-2da-entrega/ENUNCIADO
new file mode 100644 (file)
index 0000000..cfd611c
--- /dev/null
@@ -0,0 +1,41 @@
+Enunciado extraoficial
+
+Hay que hacer 2 procesos, uno que manda y otro que recibe IP, por cada
+host/router. Todos los procesos que envian, ponen las cosas en una cola, todos
+los que reciben, sacan de esa cola. Se usa como MAC la IP, y como ID del mensaje
+de la cola (de esta manera cada proceso saca solo los "paquetes" con el ID/MAC
+que le corresponda).
+
+1) Campos en IP
+        id de paquete
+        ip origen
+        ip destino
+        checksum (0/1, de juguete)
+        tamaño del paquete completo
+        ToS
+        Don't Fragment (0/1)
+        End (0/1)
+        offset
+        TTL
+        tamaño de este fragmento
+        tipo de payload (IP / ICMP)
+        (se que faltan algunos, si tienen algo mas,
+          completen)
+
+2) Casos de descarte de paquetes
+        Error de checksum (silencioso)
+        No hay buffer para fragmento (silencioso)
+        Un host que no rutea recibe un paquete para otro host
+          (silencioso)
+        No hay ruta (icmp)
+        DF == 1 y MTU < size (icmp)
+        TTL == 0 (icmp)
+
+3) Comportamiento del protocolo
+        Debe rutear (si es un router)
+        Debe fragmentar y reensamblar
+        Debe contemplar todos los casos de descarte de
+          paquetes anteriores escribiendo en un archivo
+          los paquetes descartados según corresponda
+          (silecioso, icmp).
+
diff --git a/practicas/pipi-2da-entrega/README b/practicas/pipi-2da-entrega/README
new file mode 100644 (file)
index 0000000..cc25153
--- /dev/null
@@ -0,0 +1,351 @@
+===============================
+Sistemas Distribuidos I (75.74)
+===============================
+
+------------------------------------------------------------------
+TP 2: Sistema de resolución de nombres sobre IP adaptado a sockets
+------------------------------------------------------------------
+
+:Author: Leandro Lucarella (77891)
+
+
+Organización
+============
+
+En el directorio `src` se encuentra el código fuente del trabajo, con su
+correspondiente `Makefile` para compilarlo tan solo ejecutando `make`.
+
+En el directorio `rutas_ejemplo` contiene algunos archivos con descripciones de
+rutas de ejemplo para correr los programas. En el directorio `zonas_ejemplo` se
+encuentran archivos de configuración de zonas de dominios de nombre para
+realizar pruebas.
+
+
+Uso
+===
+
+El trabajo consta de dos programas, uno llamado `ip` y otro `dns` (más algunas
+otras pruebas que no tienen relevancia).
+
+ip
+--
+
+El programa `ip` corre 3 procesos (fork(2)eados), uno que recibe paquetes IP
+otro que recibe entrada del usuario y envía paquetes IP y otro que redirecciona
+(forward) paquetes IP en caso de ser pertinente.
+
+Uso::
+
+  ./ip ip [router [forward [route_file [queue_id [proto]]]]]
+
+ip
+  IP que utiliza este proceso
+
+router
+  0 si es router, 1 si no lo es (default 0)
+
+forward
+  0 si puede hacer forwarding, 1 si no (default 0)
+
+route_file
+  Archivo con las rutas. El formato del archivo es una ruta por línea, cada
+  línea se compone de red (por ahora sólo soporta IPs puntuales), gateway (si es
+  cero es que están en la misma red), MTU y métrica (todavía no se usa),
+  separados por uno o más espacios o tabs (default `route.txt`)
+
+queue_id
+  Identificador de la cola a usar como medio físico, también establece el
+  identificador de la cola a usar para comunicarse con el otro proceso
+  (`test_ipout`) para hacer forwarding, que será queue_id + 1 (default
+  `DEV_DEFAULT_KEY` obtenido de `dev.h`)
+
+proto
+  Protocolo que transporta (default 0)
+
+
+El programa se queda esperando la entrada del usuario, y sale cuando esta se
+termina (Ctrl-D). El formato de entrada es::
+
+  IP DESTINO
+  MENSAJE
+
+Es decir, en una línea se pone la IP de destino y en la línea siguiente el
+mensaje. Para enviar otro mensaje, nuevamente se pone IP de destino en una línea
+y el mensaje en la siguiente.
+
+dns
+---
+
+El programa `dns` corre también 3 procesos (fork(2)eados), uno que recibe
+peticiones de nombres, otro que recibe entrada del usuario y envía peticiones
+(o mejor dicho encola peticiones para ser enviadas) y otro que realiza el envío
+de las peticiones realmente.
+
+Uso::
+
+  ./dns ip [route_file [zone_file [port]]]
+
+ip
+  IP que utiliza este proceso (ídem programa `ip`)
+
+route_file
+  Archivo con las rutas (ídem programa `ip`)
+
+zone_file
+  Archivo con la descripción de las zonas. El formato es muy simple. Cada zona
+  está separada por un renglón en blanco y empieza con una línea con 3 campos
+  separados por espacios o tab: nombre de la zona, TTL y nodo padre. Luego le
+  sigue la lista de registros de esa zona, también con 3 campos por renglón:
+  nombre, tipo de registro (A para indicar una IP, NS para indicar donde buscar
+  registros de una zona con ese nombre) e IP (ya sea la IP definitiva si es A o
+  la IP del nameserver al cual recurrir si es NS). Se pueden ver ejemplos de
+  estos archivos en el disco entregado.
+
+port
+  Puerto en el cual escuchará la abstracción de capa física sobre TCP.
+
+
+El programa es muy similar a `ip`, se queda esperando la entrada del usuario,
+y sale cuando esta se termina (Ctrl-D). El formato de entrada es::
+
+  HOSTNAME_A_BUSCAR
+
+Es decir, se escribe en una línea el nombre del host del cual se quiera obtener
+la IP y se presiona ENTER.
+
+
+Diseño del trabajo
+==================
+
+El trabajo fue desarrollado en C++, orientado a objetos. Se compone de las
+siguientes clases:
+
+Dev
+  Encapsula la capa física y el dispositivo de red. Es una interfaz abstracta.
+
+DevQue
+  Implementación de Dev utilizando una cola como medio físico y el id
+  representaría el cable (si 2 dispositivos tienen cola con id distinto serían
+  como si no compartieran el mismo cable). Por simplicidad a la cola siempre
+  se envía el tamaño del MTU completo pero se agrega una cabecera con el
+  tamaño real del frame.
+
+DevTCP
+  Implementación de Dev utilizando conexiones TCP. Por cada frame saliente a un
+  destino en particular se crea una conexión TCP (a menos que ya esté creada, en
+  cuyo caso se reutiliza) y se escucha por conexiones entrantes para recibir
+  frames (también guardándolas para reutilizarlas). A diferencia del DevQue se
+  envía el tamaño del frame exacto (en realidad se agrega una pequeña cabecera).
+
+IPAddr
+  Clase auxiliar que encapsula una dirección IP.
+
+IPHeader
+  Encapsula una cabecera IP. El cálculo de checksum se simplificó (haciendo una
+  suma byte a byte de toda la cabecera) porque cumple con el objetivo didactico
+  de todas maneras.
+
+RouteTable
+  Encapsula una tabla de ruteo. Por falta de tiempo y simplicidad por ahora sólo
+  soporta rutas a un sólo host (no a una red) pero es muy fácilmente extensible
+  y transparente para el resto de las clases que la usan. Las rutas se componen
+  de red (en realidad por ahora host), geteway, MTU, metrica y dispositivo de
+  red por el cual salir (Dev).
+  
+IPIn
+  Es la clase encargada de recibir paquetes IP. Hace chequeos varios y descarta
+  paquetes según los siguientes criterios:
+
+  * Cabecera incompleta o no es IP
+  * Versión IP incorrecta
+  * Mal checksum
+  * TTL=0
+  * No es para nosotros y no hacemos forward
+  * Es para nosotros pero somos un router
+
+  Si hace forwarding le pasa a IPOut el paquete por una cola y reensabla de ser
+  necesario.
+
+IPOut
+  Es la clase encargada de enviar paquetes IP. Tiene una RouteTable para hacer
+  el ruteo y verifica si hay paquetes a forwardear antes de enviar lo que le
+  piden. También fragmenta y puede "descartar" paquetes según estos criterios:
+
+  * No existe una ruta para el destino
+  * Tamaño de paquete más grande que MTU y DF=1
+
+libtcp
+  Es el único componente del TP que no es orientado a objetos ya que se
+  reutilizó de trabajos anteriores. Es una pequeña abstracción sobre la API de
+  sockets de BSD para mayor simplicidad.
+
+ResolvProtoRequest
+  Clase que encapsula una petición de resolución de nombre a enviar via IP.
+
+ResolvProtoResponse
+  Clase que encapsula una respuesta de resolución de nombre a enviar via IP.
+
+NameServer
+  Clase encargada de resolver los nombres. Escucha por peticiones y puede
+  resolverlas recursiva o directamente (según venga de otro NameServer o de un
+  Resolver la petición). Esta clase se compone de varias otras clases auxiliares
+  para almacenar las zonas y el cache.
+
+
+Ejemplo de corrida
+==================
+
+Archivo de configuración de zonas de 10.10.10.2::
+
+  homero.casa  600     10.10.10.1
+  tito A       10.10.100.1
+  juan A       10.10.100.2
+  juan A       10.10.100.3
+  pepe A       10.10.100.4
+  juan A       10.10.100.5
+  pepe A       10.10.100.6
+  marge        NS      10.10.10.3
+  todos        NS      10.10.10.1
+  todos        NS      10.10.10.3
+  todos        NS      10.10.10.141
+
+Línea de comandos::
+
+  ./dns 10.10.10.2 ../rutas_ejemplo/mi_lan.txt ../zonas_ejemplo/10.10.10.2.txt
+
+Resolución de un nombre local con una sola IP
+---------------------------------------------
+
+Línea de comandos::
+
+  ./dns 10.10.10.2 ../rutas_ejemplo/mi_lan.txt ../zonas_ejemplo/10.10.10.2.txt
+
+Salida::
+
+  tito.homero.casa
+  Resolviendo tito.homero.casa...
+  resolv_direct -> tratando de resolver: tito.homero.casa
+  resolv_direct found (local/hijo): ResolvProtoResponse(ret=2, ttl=600, 10.10.100.1)
+  resolv_recursive -> gotcha! ResolvProtoResponse(ret=2, ttl=600, 10.10.100.1)
+  Resultado: ResolvProtoResponse(ret=2, ttl=600, 10.10.100.1)
+
+Resolución de un nombre local con múltiples IP
+----------------------------------------------
+
+Salida::
+
+  juan.homero.casa
+  Resolviendo juan.homero.casa...
+  resolv_direct -> tratando de resolver: juan.homero.casa
+  resolv_direct found (local/hijo): ResolvProtoResponse(ret=2, ttl=600, 10.10.100.2, 10.10.100.3, 10.10.100.5)
+  resolv_recursive -> gotcha! ResolvProtoResponse(ret=2, ttl=600, 10.10.100.2, 10.10.100.3, 10.10.100.5)
+  Resultado: ResolvProtoResponse(ret=2, ttl=600, 10.10.100.2, 10.10.100.3, 10.10.100.5)
+
+Resolución de un nombre local no existente
+------------------------------------------
+
+Salida::
+
+  none.homero.casa
+  Resolviendo none.homero.casa...
+  resolv_direct -> tratando de resolver: none.homero.casa
+  resolv_direct NOT FOUND (es local pero no existe)
+  Resultado: ResolvProtoResponse(ret=4, ttl=0)
+
+Resolución de un nombre remoto con múltiples IP y 2 niveles de indirección
+--------------------------------------------------------------------------
+
+Archivo de configuración de zonas de 10.10.10.1::
+
+  casa  600 0.0.0.0
+  burns A 10.10.10.1
+  homero  A 10.10.10.2
+  marge A 10.10.10.3
+  manuk A 10.10.10.141
+  juan  A 100.10.100.5
+  pepe  A 100.10.100.6
+  homero  NS  10.10.10.2
+  marge NS  10.10.10.3
+  manuk NS  10.10.10.141
+
+  burns.casa  600 0.0.0.0
+  tito  A 100.10.100.1
+  juan  A 100.10.100.2
+  juan  A 100.10.100.3
+  pepe  A 100.10.100.4
+  juan  A 100.10.100.5
+  pepe  A 100.10.100.6
+
+  todos.homero.casa 9500  0.0.0.0
+  tito  A 10.1.100.1
+  juan  A 10.1.100.2
+  juan  A 10.1.100.3
+  pepe  A 10.1.100.4
+  juan  A 10.1.100.5
+  pepe  A 10.1.100.6
+
+Archivo de configuración de zonas de 10.10.10.3::
+
+  marge.casa  600 10.10.10.1
+  tito  A 30.10.100.1
+  juan  A 30.10.100.2
+  juan  A 30.10.100.3
+  pepe  A 30.10.100.4
+  juan  A 30.10.100.5
+  pepe  A 30.10.100.6
+  manuk NS  10.10.10.141
+  todos NS  10.10.10.1
+  todos NS  10.10.10.3
+  todos NS  10.10.10.141
+
+  todos.homero.casa 9500  10.10.10.2
+  tito  A 10.1.100.1
+  juan  A 10.1.100.2
+  juan  A 10.1.100.3
+  pepe  A 10.1.100.4
+  juan  A 10.1.100.5
+  pepe  A 10.1.100.6
+
+  marge.homero.casa 9500  10.10.10.2
+  tito  A 10.3.100.1
+  juan  A 10.3.100.2
+  juan  A 10.3.100.3
+  pepe  A 10.3.100.4
+  juan  A 10.3.100.5
+  pepe  A 10.3.100.6
+
+
+La petición se realiza desde 10.10.10.2, quien debe recurir a su nodo padre
+(10.10.10.1) que indica que el encargado de resolver esa zona es 10.10.10.3.
+
+Salida de 10.10.10.2::
+
+  pepe.marge.casa
+  Resolviendo pepe.marge.casa...
+  resolv_direct -> tratando de resolver: pepe.marge.casa
+  resolv_direct -> evaluando padre 10.10.10.1
+  resolv_direct found (al padre): 10.10.10.1
+  resolv_recursive -> redirect a ResolvProtoResponse(ret=3, ttl=600, 10.10.10.1)
+  query -> pidiendo ResolvProtoRequest(query_type=0, name=pepe.marge.casa) a 10.10.10.1
+  query -> recibido ResolvProtoResponse(ret=3, ttl=600, 10.10.10.3) de 10.10.10.1
+  resolv_recursive_r -> redirect a ResolvProtoResponse(ret=3, ttl=600, 10.10.10.3)
+  query -> pidiendo ResolvProtoRequest(query_type=0, name=pepe.marge.casa) a 10.10.10.3
+  query -> recibido ResolvProtoResponse(ret=2, ttl=600, 30.10.100.4, 30.10.100.6) de 10.10.10.3
+  resolv_recursive_r -> gotcha! ResolvProtoResponse(ret=2, ttl=600, 30.10.100.4, 30.10.100.6)
+  Resultado: ResolvProtoResponse(ret=2, ttl=600, 30.10.100.4, 30.10.100.6)
+
+Salida de 10.10.10.1::
+
+  NameServer::send_loop() -> recibido ResolvProtoRequest(query_type=0, name=pepe.marge.casa)
+  resolv_direct -> tratando de resolver: pepe.marge.casa
+  resolv_direct found (local/hijo): ResolvProtoResponse(ret=3, ttl=600, 10.10.10.3)
+  NameServer::send_loop() -> respondo ResolvProtoResponse(ret=3, ttl=600, 10.10.10.3)
+
+Salida de 10.10.10.3::
+
+  NameServer::send_loop() -> recibido ResolvProtoRequest(query_type=0, name=pepe.marge.casa)
+  resolv_direct -> tratando de resolver: pepe.marge.casa
+  resolv_direct found (local/hijo): ResolvProtoResponse(ret=2, ttl=600, 30.10.100.4, 30.10.100.6)
+  NameServer::send_loop() -> respondo ResolvProtoResponse(ret=2, ttl=600, 30.10.100.4, 30.10.100.6)
+
+.. vim: filetype=rst sw=2 sts=2 et :
diff --git a/practicas/pipi-2da-entrega/TODO b/practicas/pipi-2da-entrega/TODO
new file mode 100644 (file)
index 0000000..62cecf1
--- /dev/null
@@ -0,0 +1,24 @@
+IP:
+===
+- Implementar metricas
+- Implementar rutas de redes completas (no sólo ruta a un host)
+- Arreglar cola de forwarding para que no dependa del medio fisico/dispositivo
+- Tener en cuenta el TTL para limpiar buffers
+- Ver que hayan llegado todos los fragmentos antes de subir a capa superior
+- Separar descartes de ICMP de silenciosos (parcialmente hecho)
+- Manejar envíos a través de una cola para que no se rompa (como creo que
+  debería romperse, por ser 2 procesos distintos los que mandan y no comparten
+  el pool de conexiones TCP) el forwarding.
+
+DevTCP:
+=======
+- Controlar pérdidas de conexiones.
+
+DNS:
+====
+- Agregar entradas al cache y revisar la edad del cache antes de usarlo (y
+  limpiarlo si es viejo).
+- Resolver el problema de requests/responses simultáneos de distintos lugares
+  (probablemente haya que agregar un ID al protocolo para identificar distintas
+  respuestas).
+- Resolver (!)
diff --git a/practicas/pipi-2da-entrega/informe.rtf b/practicas/pipi-2da-entrega/informe.rtf
new file mode 100644 (file)
index 0000000..eebe262
--- /dev/null
@@ -0,0 +1,113 @@
+{\rtf1\ansi\ansicpg1252\deff0
+{\fonttbl
+{\f0\fnil\fcharset0\fprq0\fttruetype Arial;}
+{\f1\fnil\fcharset0\fprq0\fttruetype Times New Roman;}
+{\f2\fnil\fcharset0\fprq0\fttruetype Courier New;}
+{\f3\fnil\fcharset0\fprq0\fttruetype Dingbats;}
+{\f4\fnil\fcharset0\fprq0\fttruetype Symbol;}}
+{\colortbl
+\red0\green0\blue0;
+\red255\green255\blue255;}
+{\stylesheet
+{\s1\fi-431\li720\sbasedon28\snext28Contents 1;}
+{\s2\fi-431\li1440\sbasedon28\snext28Contents 2;}
+{\s3\fi-431\li2160\sbasedon28\snext28Contents 3;}
+{\s8\fi-431\li720\sbasedon28Lower Roman List;}
+{\s5\tx431\sbasedon24\snext28Numbered Heading 1;}
+{\s6\tx431\sbasedon25\snext28Numbered Heading 2;}
+{\s7\fi-431\li720Square List;}
+{\*\cs11\sbasedon28Endnote Text;}
+{\s4\fi-431\li2880\sbasedon28\snext28Contents 4;}
+{\s9\fi-431\li720Diamond List;}
+{\s10\fi-431\li720Numbered List;}
+{\*\cs12\fs20\superEndnote Reference;}
+{\s13\fi-431\li720Triangle List;}
+{\s14\tx431\sbasedon26\snext28Numbered Heading 3;}
+{\s15\fi-431\li720Dashed List;}
+{\s16\fi-431\li720\sbasedon10Upper Roman List;}
+{\s17\sb440\sa60\f0\fs24\b\sbasedon28\snext28Heading 4;}
+{\s18\fi-431\li720Heart List;}
+{\s34\fi-431\li720Box List;}
+{\s20\fi-431\li720\sbasedon10Upper Case List;}
+{\s21\fi-431\li720Bullet List;}
+{\s22\fi-431\li720Hand List;}
+{\*\cs23\fs20\sbasedon28Footnote Text;}
+{\s24\sb440\sa60\f0\fs34\b\sbasedon28\snext28Heading 1;}
+{\s25\sb440\sa60\f0\fs28\b\sbasedon28\snext28Heading 2;}
+{\s19\qc\sb240\sa120\f0\fs32\b\sbasedon28\snext28Contents Header;}
+{\s27\fi-431\li720Tick List;}
+{\s26\sb440\sa60\f0\fs24\b\sbasedon28\snext28Heading 3;}
+{\s29\fi-431\li720\sbasedon10Lower Case List;}
+{\s30\li1440\ri1440\sa120\sbasedon28Block Text;}
+{\s36\f2\sbasedon28Plain Text;}
+{\s32\tx1584\sbasedon5\snext28Section Heading;}
+{\s33\fi-431\li720Implies List;}
+{\s28\f1\fs24\lang1034Normal;}
+{\s35\fi-431\li720Star List;}
+{\*\cs31\fs20\superFootnote Reference;}
+{\s37\tx1584\sbasedon5\snext28Chapter Heading;}}
+\kerning0\cf0\ftnbj\fet2\ftnstart1\ftnnar\aftnnar\ftnstart1\aftnstart1\aenddoc\revprop3{\info\uc1}\deftab720\viewkind1\paperw11905\paperh16837\margl1440\margr1440\widowctl
+\sectd\sbknone\colsx360\pgncont\ltrsect
+\pard\plain\ltrpar\qc\s28\itap0{\s28\f0\fs52\b\lang1034{\*\listtag0}\abinodiroverride\ltrch Sistemas Distribuidos I (75.74)}{\s28\f1\fs24\lang1034{\*\listtag1003}\par}
+\pard\plain\ltrpar\qc\s28\itap0{\s28\f0\fs28\lang1034{\*\listtag0}\abinodiroverride\ltrch TP 2: Sistema de resoluci\'f3n de nombres sobre IP adaptado a sockets}{\s28\f0\fs28\lang1034{\*\listtag0}\par}
+\pard\plain\ltrpar\qc\s28\itap0{\field\fdledit{\*\fldinst {\ TOC }}}
+\pard\plain\ltrpar\ql\s28\itap0{\s28\f1\fs24\lang1034{\*\listtag0}\par}
+\pard\plain\ltrpar\ql\sb440\sa60\s24\itap0{\s24\f0\fs34\b\lang1034{\*\listtag0}\abinodiroverride\ltrch DNS}{\s24\f0\fs34\b\lang1034{\*\listtag0}\par}
+\pard\plain\ltrpar\ql\sb440\sa60\s25\itap0{\s25\f0\fs28\b\lang1034{\*\listtag0}\abinodiroverride\ltrch Diagrama de secuencia}{\s25\f0\fs28\b\lang1034{\*\listtag0}\par}
+\pard\plain\ltrpar\ql\s28\itap0{\s28\f1\fs24\lang1034{\*\listtag0}\abinodiroverride\ltrch \page }{\s28\f1\fs24\lang1034{\*\listtag0}\par}
+\pard\plain\ltrpar\ql\sb440\sa60\s25\itap0{\s25\f0\fs28\b\lang1034{\*\listtag0}\abinodiroverride\ltrch Dise\'f1o de mensajes de intercambio de DNS.}{\s25\f0\fs28\b\lang1034{\*\listtag0}\par}
+\pard\plain\ltrpar\ql\s28\itap0{\s28\f1\fs24\lang1034{\*\listtag0}\abinodiroverride\ltrch Petici\'f3n de un nameserver}{\s28\f1\fs24\lang1034{\*\listtag0}\par}
+\pard\plain\ltrpar\ql\s28\itap0{\s28\f2\fs22\lang1034{\*\listtag0}\abinodiroverride\ltrch +------------+------------+------------+}{\s28\f2\fs22\lang1034{\*\listtag0}\par}
+\pard\plain\ltrpar\ql\s28\itap0{\s28\f2\fs22\lang1034{\*\listtag0}\abinodiroverride\ltrch | QUERY_TYPE |    SIZE    |    NAME    |}{\s28\f2\fs22\lang1034{\*\listtag0}\par}
+\pard\plain\ltrpar\ql\s28\itap0{\s28\f2\fs22\lang1034{\*\listtag0}\abinodiroverride\ltrch +------------+------------+------------+}{\s28\f2\fs22\lang1034{\*\listtag0}\par}
+\pard\plain\ltrpar\ql\s28\itap0{\s28\f2\fs22\lang1034{\*\listtag0}\abinodiroverride\ltrch /-- 1 byte --/- 2 bytes --/- variable -/}{\s28\f2\fs22\lang1034{\*\listtag0}\par}
+\pard\plain\ltrpar\ql\s28\itap0{\s28\f1\fs24\lang1034{\*\listtag0}\par}
+\pard\plain\ltrpar\ql\s28\itap0{\s28\f1\fs24\lang1034{\*\listtag0}\abinodiroverride\ltrch QUERY_TYPE en realidad es una cabecera com\'fan a las peticiones y respuestas, cuyos c\'f3digos pueden ser los siguientes:}{\s28\f1\fs24\lang1034{\*\listtag0}\par}
+\pard\plain\ltrpar\ql\s28\itap0{\s28\f2\fs22\b\lang1034{\*\listtag0}\abinodiroverride\ltrch Requests}{\s28\f2\fs22\b\lang1034{\*\listtag0}\par}
+\pard\plain\ltrpar\ql\s28\itap0{\s28\f2\fs22\lang1034{\*\listtag0}\abinodiroverride\ltrch RP_REQ_DIRECT   -> B\'fasqueda directa (inter nameservers)}{\s28\f2\fs22\lang1034{\*\listtag0}\par}
+\pard\plain\ltrpar\ql\s28\itap0{\s28\f2\fs22\lang1034{\*\listtag0}\abinodiroverride\ltrch RP_REQ_RECURSIVE-> B\'fasqueda recursiva (para resolvers)}{\s28\f2\fs22\lang1034{\*\listtag0}\par}
+\pard\plain\ltrpar\ql\s28\itap0{\s28\f2\fs22\b\lang1034{\*\listtag0}\abinodiroverride\ltrch Responses}{\s28\f2\fs22\b\lang1034{\*\listtag0}\par}
+\pard\plain\ltrpar\ql\s28\itap0{\s28\f2\fs22\lang1034{\*\listtag0}\abinodiroverride\ltrch RP_RES_A        -> OK, se devolvi\'f3 un registro A}{\s28\f2\fs22\lang1034{\*\listtag0}\par}
+\pard\plain\ltrpar\ql\s28\itap0{\s28\f2\fs22\lang1034{\*\listtag0}\abinodiroverride\ltrch RP_RES_NS       -> OK, se devolvi\'f3 un registro NS (s\'f3lo en directo)}{\s28\f2\fs22\lang1034{\*\listtag0}\par}
+\pard\plain\ltrpar\ql\s28\itap0{\s28\f2\fs22\lang1034{\*\listtag0}\abinodiroverride\ltrch RP_RES_NOTFOUND -> No se encontr\'f3}{\s28\f2\fs22\lang1034{\*\listtag0}\par}
+\pard\plain\ltrpar\ql\s28\itap0{\s28\f2\fs22\lang1034{\*\listtag0}\abinodiroverride\ltrch RP_RES_TIMEOUT  -> Tard\'f3 demasiado la consulta}{\s28\f2\fs22\lang1034{\*\listtag0}\par}
+\pard\plain\ltrpar\ql\s28\itap0{\s28\f1\fs24\lang1034{\*\listtag0}\par}
+\pard\plain\ltrpar\ql\s28\itap0{\s28\f1\fs24\lang1034{\*\listtag0}\abinodiroverride\ltrch SIZE es el tama\'f1o del string con el nombre a buscar, NAME es el string (de longitud variable). Faltar\'eda agregar un campo con un ID para evitar que se confundan unas respuestas o peticiones con otras.}{\s28\f1\fs24\lang1034{\*\listtag0}\par}
+\pard\plain\ltrpar\ql\s28\itap0{\s28\f1\fs24\lang1034{\*\listtag0}\par}
+\pard\plain\ltrpar\ql\s28\itap0{\s28\f1\fs24\lang1034{\*\listtag0}\abinodiroverride\ltrch Respuesta de un nameserver}{\s28\f1\fs24\lang1034{\*\listtag0}\par}
+\pard\plain\ltrpar\ql\s28\itap0{\s28\f2\fs20\lang1034{\*\listtag0}\abinodiroverride\ltrch +-----------+-----------+-----------+-----------+-----------+-----------+}{\s28\f2\fs20\lang1034{\*\listtag0}\par}
+\pard\plain\ltrpar\ql\s28\itap0{\s28\f2\fs20\lang1034{\*\listtag0}\abinodiroverride\ltrch |    RET    |    TTL    |   COUNT   |    IP 1   |    ...    |    IP N   |}{\s28\f2\fs20\lang1034{\*\listtag0}\par}
+\pard\plain\ltrpar\ql\s28\itap0{\s28\f2\fs20\lang1034{\*\listtag0}\abinodiroverride\ltrch +-----------+-----------+-----------+-----------+-----------+-----------+}{\s28\f2\fs20\lang1034{\*\listtag0}\par}
+\pard\plain\ltrpar\ql\s28\itap0{\s28\f2\fs20\lang1034{\*\listtag0}\abinodiroverride\ltrch /-- 1 byte -/- 4 bytes -/-- 1 byte -/- 4 bytes -/- 4 bytes -/- 4 bytes -/}{\s28\f2\fs20\lang1034{\*\listtag0}\par}
+\pard\plain\ltrpar\ql\s28\itap0{\s28\f1\fs24\lang1034{\*\listtag0}\par}
+\pard\plain\ltrpar\ql\s28\itap0{\s28\f1\fs24\lang1034{\*\listtag0}\abinodiroverride\ltrch RET es del mismo tipo que QUERY_TYPE y se hizo as\'ed para poder reconocer si un paquete es un request o un response con s\'f3lo leer el 1er byte. TTL es el tiempo que puede vivir en el cache (en segundos), COUNT es la cantidad de IPs encontradas para ese registro e IP1 a IPN son las IP en s\'ed (cantidad variable).}{\s28\f1\fs24\lang1034{\*\listtag0}\par}
+\pard\plain\ltrpar\ql\sb440\sa60\s25\itap0{\s25\f0\fs28\b\lang1034{\*\listtag0}\abinodiroverride\ltrch Par\'e1metros y resultados de la funci\'f3n gethostbyname()}{\s25\f0\fs28\b\lang1034{\*\listtag0}\par}
+\pard\plain\ltrpar\ql\s28\itap0{\s28\f2\fs20\lang1034{\*\listtag0}\par}
+\pard\plain\ltrpar\ql\s28\itap0{\s28\f2\fs20\lang1034{\*\listtag0}\abinodiroverride\ltrch std::vector< IPAddr > gethostbyname(std::string name, int& result);}{\s28\f2\fs20\lang1034{\*\listtag0}\par}
+\pard\plain\ltrpar\ql\s28\itap0{\s28\f2\fs20\lang1034{\*\listtag0}\par}
+\pard\plain\ltrpar\ql\s28\itap0{\s28\f1\fs24\lang1034{\*\listtag0}\abinodiroverride\ltrch Esta funci\'f3n toma como par\'e1metro un string con el nombre de dominio a buscar (por ejemplo "mi.dominio.casa") y retorna un vector de IPs. Si hay un error o no encuentra ninguna el vector se devuelve vac\'edo y se pone el c\'f3digo de error en la variable result. El trabajo de la funci\'f3n es conectarse a todos los nameservers que conozca y env\'ede un pedido de resoluci\'f3n de nombre RECURSIVO, hasta que tenga \'e9xito o se acabe la lista de nameservers disponibles. Por falta de tiempo esta funci\'f3n no est\'e1 implementada del lado del resolver pero s\'ed del nameserver, y es muy muy similar (hace exactamente lo mismo).}{\s28\f1\fs24\lang1034{\*\listtag0}\par}
+\pard\plain\ltrpar\ql\sb440\sa60\s24\itap0{\s24\f0\fs34\b\lang1034{\*\listtag0}\abinodiroverride\ltrch IP}{\s24\f0\fs34\b\lang1034{\*\listtag0}\par}
+\pard\plain\ltrpar\ql\sb440\sa60\s25\itap0{\s25\f0\fs28\b\lang1034{\*\listtag0}\abinodiroverride\ltrch Dise\'f1o del paquete IP}{\s25\f0\fs28\b\lang1034{\*\listtag0}\par}
+\pard\plain\ltrpar\ql\s28\itap0{\s28\f1\fs24\lang1034{\*\listtag0}\abinodiroverride\ltrch \page }{\s28\f1\fs24\lang1034{\*\listtag0}\par}
+\pard\plain\ltrpar\ql\s28\itap0{\s28\f2\fs24\lang1034{\*\listtag0}\abinodiroverride\ltrch     // Campos}{\s28\f2\fs24\lang1034{\*\listtag0}\par}
+\pard\plain\ltrpar\ql\s28\itap0{\s28\f2\fs24\lang1034{\*\listtag0}\abinodiroverride\ltrch     uint8_t version;}{\s28\f2\fs24\lang1034{\*\listtag0}\par}
+\pard\plain\ltrpar\ql\s28\itap0{\s28\f2\fs24\lang1034{\*\listtag0}\abinodiroverride\ltrch     uint16_t total_len;}{\s28\f2\fs24\lang1034{\*\listtag0}\par}
+\pard\plain\ltrpar\ql\s28\itap0{\s28\f2\fs24\lang1034{\*\listtag0}\abinodiroverride\ltrch     uint16_t id;}{\s28\f2\fs24\lang1034{\*\listtag0}\par}
+\pard\plain\ltrpar\ql\s28\itap0{\s28\f2\fs24\lang1034{\*\listtag0}\abinodiroverride\ltrch     uint16_t reserved_flag: 1;}{\s28\f2\fs24\lang1034{\*\listtag0}\par}
+\pard\plain\ltrpar\ql\s28\itap0{\s28\f2\fs24\lang1034{\*\listtag0}\abinodiroverride\ltrch     uint16_t df: 1;}{\s28\f2\fs24\lang1034{\*\listtag0}\par}
+\pard\plain\ltrpar\ql\s28\itap0{\s28\f2\fs24\lang1034{\*\listtag0}\abinodiroverride\ltrch     uint16_t mf: 1;}{\s28\f2\fs24\lang1034{\*\listtag0}\par}
+\pard\plain\ltrpar\ql\s28\itap0{\s28\f2\fs24\lang1034{\*\listtag0}\abinodiroverride\ltrch     uint16_t offset: 13;}{\s28\f2\fs24\lang1034{\*\listtag0}\par}
+\pard\plain\ltrpar\ql\s28\itap0{\s28\f2\fs24\lang1034{\*\listtag0}\abinodiroverride\ltrch     uint8_t ttl;}{\s28\f2\fs24\lang1034{\*\listtag0}\par}
+\pard\plain\ltrpar\ql\s28\itap0{\s28\f2\fs24\lang1034{\*\listtag0}\abinodiroverride\ltrch     uint8_t proto;}{\s28\f2\fs24\lang1034{\*\listtag0}\par}
+\pard\plain\ltrpar\ql\s28\itap0{\s28\f2\fs24\lang1034{\*\listtag0}\abinodiroverride\ltrch     uint16_t checksum;}{\s28\f2\fs24\lang1034{\*\listtag0}\par}
+\pard\plain\ltrpar\ql\s28\itap0{\s28\f2\fs24\lang1034{\*\listtag0}\abinodiroverride\ltrch     uint32_t src;}{\s28\f2\fs24\lang1034{\*\listtag0}\par}
+\pard\plain\ltrpar\ql\s28\itap0{\s28\f2\fs24\lang1034{\*\listtag0}\abinodiroverride\ltrch     uint32_t dst;}{\s28\f2\fs24\lang1034{\*\listtag0}\par}
+\pard\plain\ltrpar\ql\s28\itap0{\s28\f1\fs24\lang1034{\*\listtag0}\abinodiroverride\ltrch \page }{\s28\f1\fs24\lang1034{\*\listtag0}\par}
+\pard\plain\ltrpar\ql\sb440\sa60\s25\itap0{\s25\f0\fs28\b\lang1034{\*\listtag0}\abinodiroverride\ltrch Diagrama de secuencia}{\s25\f0\fs28\b\lang1034{\*\listtag0}\par}
+\pard\plain\ltrpar\ql\s28\itap0{\s28\f1\fs24\lang1034{\*\listtag0}\abinodiroverride\ltrch \page }{\s28\f1\fs24\lang1034{\*\listtag0}\par}
+\pard\plain\ltrpar\ql\sb440\sa60\s25\itap0{\s25\f0\fs28\b\lang1034{\*\listtag0}\abinodiroverride\ltrch Cambios}{\s25\f0\fs28\b\lang1034{\*\listtag0}\par}
+\pard\plain\ltrpar\ql\s28\itap0{\s28\f1\fs24\lang1034{\*\listtag0}\abinodiroverride\ltrch Se agreg\'f3 principalmente la clase DevTCP que implementa la capa f\'edsica a trav\'e9s de TCP.  Por cada frame saliente a un destino en particular se crea una conexi\'f3n TCP (a menos que ya est\'e9 creada, en cuyo caso se reutiliza) y se escucha por conexiones entrantes para recibir frames (tambi\'e9n guard\'e1ndolas para reutilizarlas). A diferencia del DevQue se env\'eda el tama\'f1o del frame exacto (en realidad se agrega una peque\'f1a cabecera).}{\s28\f1\fs24\lang1034{\*\listtag0}\par}
+\pard\plain\ltrpar\ql\sb440\sa60\s24\itap0{\s24\f0\fs34\b\lang1034{\*\listtag0}\abinodiroverride\ltrch Lista de fuentes de informaci\'f3n}{\s24\f0\fs34\b\lang1034{\*\listtag0}\par}
+\pard\plain\ltrpar\ql\s28\itap0{\s28\f1\fs24\lang1034{\*\listtag0}\abinodiroverride\ltrch RFC 1034 - Domain names - concepts and facilities:}{\s28\f1\fs24\lang1034{\*\listtag0}\par}
+\pard\plain\ltrpar\ql\s28\itap0{\s28\f1\fs24\lang1034{\*\listtag0}\abinodiroverride\ltrch \tab http://www.faqs.org/rfcs/rfc1034.html}{\s28\f1\fs24\lang1034{\*\listtag0}\par}
+\pard\plain\ltrpar\ql\s28\itap0{\s28\f1\fs24\lang1034{\*\listtag0}\abinodiroverride\ltrch \tab Conceptos y desiciones de dise\'f1o del DNS.}{\s28\f1\fs24\lang1034{\*\listtag0}\par}}
\ No newline at end of file
diff --git a/practicas/pipi-2da-entrega/rutas_ejemplo/mi_lan.txt b/practicas/pipi-2da-entrega/rutas_ejemplo/mi_lan.txt
new file mode 100644 (file)
index 0000000..aa77b5c
--- /dev/null
@@ -0,0 +1,4 @@
+10.10.10.1     0.0.0.0         30      0
+10.10.10.2     0.0.0.0         30      0
+10.10.10.3     0.0.0.0         30      0
+10.10.10.141   0.0.0.0         30      0
diff --git a/practicas/pipi-2da-entrega/rutas_ejemplo/route.txt b/practicas/pipi-2da-entrega/rutas_ejemplo/route.txt
new file mode 100644 (file)
index 0000000..5efe7da
--- /dev/null
@@ -0,0 +1,3 @@
+10.10.10.1     0.0.0.0         25      0
+10.10.10.2     0.0.0.0         25      0
+10.10.10.3     10.10.10.5      25      0
diff --git a/practicas/pipi-2da-entrega/rutas_ejemplo/route_10.10.10.1.txt b/practicas/pipi-2da-entrega/rutas_ejemplo/route_10.10.10.1.txt
new file mode 100644 (file)
index 0000000..e74908d
--- /dev/null
@@ -0,0 +1,5 @@
+10.10.10.1     0.0.0.0         35      0
+10.10.10.2     10.10.10.5      35      2
+10.10.10.3     10.10.10.5      35      1
+10.10.10.4     10.10.10.5      35      1
+10.10.10.5     0.0.0.0         35      0
diff --git a/practicas/pipi-2da-entrega/rutas_ejemplo/route_10.10.10.141_tcp.txt b/practicas/pipi-2da-entrega/rutas_ejemplo/route_10.10.10.141_tcp.txt
new file mode 100644 (file)
index 0000000..98cf91e
--- /dev/null
@@ -0,0 +1,2 @@
+10.10.10.2     0.0.0.0         25      0
+10.10.10.141   0.0.0.0         25      0
diff --git a/practicas/pipi-2da-entrega/rutas_ejemplo/route_10.10.10.2.txt b/practicas/pipi-2da-entrega/rutas_ejemplo/route_10.10.10.2.txt
new file mode 100644 (file)
index 0000000..cff2d1b
--- /dev/null
@@ -0,0 +1,5 @@
+10.10.10.1     10.10.10.4      25      2
+10.10.10.2     0.0.0.0         25      0
+10.10.10.3     10.10.10.4      25      2
+10.10.10.4     0.0.0.0         25      0
+10.10.10.5     10.10.10.4      25      1
diff --git a/practicas/pipi-2da-entrega/rutas_ejemplo/route_10.10.10.2_tcp.txt b/practicas/pipi-2da-entrega/rutas_ejemplo/route_10.10.10.2_tcp.txt
new file mode 100644 (file)
index 0000000..98cf91e
--- /dev/null
@@ -0,0 +1,2 @@
+10.10.10.2     0.0.0.0         25      0
+10.10.10.141   0.0.0.0         25      0
diff --git a/practicas/pipi-2da-entrega/rutas_ejemplo/route_10.10.10.3.txt b/practicas/pipi-2da-entrega/rutas_ejemplo/route_10.10.10.3.txt
new file mode 100644 (file)
index 0000000..a4e4cfb
--- /dev/null
@@ -0,0 +1,5 @@
+10.10.10.1     10.10.10.5      32      1
+10.10.10.2     10.10.10.5      32      2
+10.10.10.3     0.0.0.0         32      0
+10.10.10.4     10.10.10.5      32      1
+10.10.10.5     0.0.0.0         32      0
diff --git a/practicas/pipi-2da-entrega/rutas_ejemplo/route_10.10.10.4.txt b/practicas/pipi-2da-entrega/rutas_ejemplo/route_10.10.10.4.txt
new file mode 100644 (file)
index 0000000..54c7650
--- /dev/null
@@ -0,0 +1,5 @@
+10.10.10.1     10.10.10.5      28      1
+10.10.10.2     0.0.0.0         25      0
+10.10.10.3     10.10.10.5      28      1
+10.10.10.4     0.0.0.0         28      0
+10.10.10.5     0.0.0.0         28      0
diff --git a/practicas/pipi-2da-entrega/rutas_ejemplo/route_10.10.10.5.txt b/practicas/pipi-2da-entrega/rutas_ejemplo/route_10.10.10.5.txt
new file mode 100644 (file)
index 0000000..c19729c
--- /dev/null
@@ -0,0 +1,5 @@
+10.10.10.1     0.0.0.0         35      0
+10.10.10.2     10.10.10.4      28      1
+10.10.10.3     0.0.0.0         32      0
+10.10.10.4     0.0.0.0         28      0
+10.10.10.5     0.0.0.0         35      0
diff --git a/practicas/pipi-2da-entrega/src/Makefile b/practicas/pipi-2da-entrega/src/Makefile
new file mode 100644 (file)
index 0000000..d116c96
--- /dev/null
@@ -0,0 +1,437 @@
+# Makefile de ejemplo para C++
+# 
+# Creado: jue abr 15 15:34:19 ART 2004
+#
+# Copyleft 2004 - Leandro Lucarella, Bajo licencia GPL [http://www.gnu.org/]
+#
+
+# CONFIGURACION 
+################
+
+# Opciones para el compilador C/C++ en modo ansi.
+CFLAGS = -Wall -ansi -pedantic-errors
+
+# Para que explote lo mas posible
+#CFLAGS += -O3 -DNDEBUG
+
+# Para valgrind o debug
+CFLAGS += -ggdb -DDEBUG
+
+# Para más verbose
+CFLAGS += -DDEBUG2
+
+# Opciones para el compilador C++.
+CXXFLAGS = $(CFLAGS) -fno-inline
+
+# Opciones del enlazador.
+#LDFLAGS=
+
+# Compilador.
+CC=g++
+
+# Programas
+targets=ip dns
+tests=test_send test_recv test_ipaddr test_ipin test_ipout test_devtcp \
+      test_poll test_resolvproto test_nameserver_file \
+      test_nameserver_resolvnext
+
+# Fuentes
+fuentes ?= $(wildcard *.cpp) $(wildcard *.c)
+
+ip_objs=ipout.o ipin.o ipaddr.o ipheader.o devque.o devtcp.o routetable.o \
+       libtcp.o
+dns_objs=nameserver.o resolvproto.o
+
+# REGLAS
+#########
+
+.PHONY: all clean
+
+all: depend $(targets)
+
+tests: depend $(tests)
+
+test_send: test_send.o devque.o
+
+test_recv: test_recv.o devque.o
+
+test_ipaddr: test_ipaddr.o ipaddr.o ipheader.o
+
+test_ipin: test_ipin.o ipin.o ipaddr.o ipheader.o devque.o
+
+test_ipout: test_ipout.o ipout.o ipaddr.o ipheader.o devque.o routetable.o
+
+test_devtcp: test_devtcp.o devtcp.o libtcp.o ipaddr.o
+
+test_poll: test_poll.o libtcp.o
+
+test_resolvproto: test_resolvproto.o resolvproto.o ipaddr.o
+
+test_nameserver_file: test_nameserver_file.o $(dns_objs) $(ip_objs)
+
+#FIXME no va libtcp.o, debe ir sobre mi implementación de ip.
+test_nameserver_resolvnext: test_nameserver_resolvnext.o $(dns_objs) $(ip_objs)
+
+ip: ip.o $(ip_objs)
+
+dns: dns.o $(ip_objs) $(dns_objs)
+
+depend:
+       @makedepend $(fuentes) > /dev/null 2>&1
+
+clean:
+       @$(RM) -fv *.o Makefile.bak $(targets) $(tests)
+
+# DO NOT DELETE
+
+devque.o: devque.h dev.h /usr/include/unistd.h /usr/include/features.h
+devque.o: /usr/include/sys/cdefs.h /usr/include/gnu/stubs.h
+devque.o: /usr/include/bits/posix_opt.h /usr/include/bits/types.h
+devque.o: /usr/include/bits/wordsize.h /usr/include/bits/typesizes.h
+devque.o: /usr/include/bits/confname.h /usr/include/getopt.h
+devque.o: /usr/include/fcntl.h /usr/include/bits/fcntl.h
+devque.o: /usr/include/sys/types.h /usr/include/time.h /usr/include/endian.h
+devque.o: /usr/include/bits/endian.h /usr/include/sys/select.h
+devque.o: /usr/include/bits/select.h /usr/include/bits/sigset.h
+devque.o: /usr/include/bits/time.h /usr/include/sys/sysmacros.h
+devque.o: /usr/include/bits/pthreadtypes.h /usr/include/bits/sched.h
+devque.o: /usr/include/sys/ipc.h /usr/include/bits/ipctypes.h
+devque.o: /usr/include/bits/ipc.h /usr/include/sys/msg.h
+devque.o: /usr/include/bits/msq.h
+devtcp.o: devtcp.h dev.h /usr/include/stdint.h /usr/include/features.h
+devtcp.o: /usr/include/sys/cdefs.h /usr/include/gnu/stubs.h
+devtcp.o: /usr/include/bits/wchar.h /usr/include/bits/wordsize.h
+devtcp.o: /usr/include/sys/poll.h /usr/include/bits/poll.h ipaddr.h libtcp.h
+devtcp.o: /usr/include/stdio.h /usr/include/bits/types.h
+devtcp.o: /usr/include/bits/typesizes.h /usr/include/libio.h
+devtcp.o: /usr/include/_G_config.h /usr/include/wchar.h /usr/include/gconv.h
+devtcp.o: /usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h
+devtcp.o: /usr/include/stdlib.h /usr/include/sys/types.h /usr/include/time.h
+devtcp.o: /usr/include/endian.h /usr/include/bits/endian.h
+devtcp.o: /usr/include/sys/select.h /usr/include/bits/select.h
+devtcp.o: /usr/include/bits/sigset.h /usr/include/bits/time.h
+devtcp.o: /usr/include/sys/sysmacros.h /usr/include/bits/pthreadtypes.h
+devtcp.o: /usr/include/bits/sched.h /usr/include/alloca.h
+devtcp.o: /usr/include/unistd.h /usr/include/bits/posix_opt.h
+devtcp.o: /usr/include/bits/confname.h /usr/include/getopt.h
+devtcp.o: /usr/include/signal.h /usr/include/bits/signum.h
+devtcp.o: /usr/include/bits/siginfo.h /usr/include/bits/sigaction.h
+devtcp.o: /usr/include/bits/sigcontext.h /usr/include/asm/sigcontext.h
+devtcp.o: /usr/include/asm-i486/sigcontext.h /usr/include/linux/compiler.h
+devtcp.o: /usr/include/bits/sigstack.h /usr/include/bits/sigthread.h
+devtcp.o: /usr/include/sys/wait.h /usr/include/sys/resource.h
+devtcp.o: /usr/include/bits/resource.h /usr/include/bits/waitflags.h
+devtcp.o: /usr/include/bits/waitstatus.h /usr/include/string.h
+devtcp.o: /usr/include/sys/socket.h /usr/include/sys/uio.h
+devtcp.o: /usr/include/bits/uio.h /usr/include/bits/socket.h
+devtcp.o: /usr/include/limits.h /usr/include/bits/posix1_lim.h
+devtcp.o: /usr/include/bits/local_lim.h /usr/include/linux/limits.h
+devtcp.o: /usr/include/bits/posix2_lim.h /usr/include/bits/sockaddr.h
+devtcp.o: /usr/include/asm/socket.h /usr/include/asm-i486/socket.h
+devtcp.o: /usr/include/asm/sockios.h /usr/include/asm-i486/sockios.h
+devtcp.o: /usr/include/netinet/in.h /usr/include/bits/in.h
+devtcp.o: /usr/include/bits/byteswap.h /usr/include/arpa/inet.h
+devtcp.o: /usr/include/netdb.h /usr/include/rpc/netdb.h
+devtcp.o: /usr/include/bits/netdb.h /usr/include/fcntl.h
+devtcp.o: /usr/include/bits/fcntl.h /usr/include/sys/ipc.h
+devtcp.o: /usr/include/bits/ipctypes.h /usr/include/bits/ipc.h
+devtcp.o: /usr/include/sys/msg.h /usr/include/bits/msq.h
+dns.o: ipout.h ipaddr.h /usr/include/stdint.h /usr/include/features.h
+dns.o: /usr/include/sys/cdefs.h /usr/include/gnu/stubs.h
+dns.o: /usr/include/bits/wchar.h /usr/include/bits/wordsize.h ipheader.h
+dns.o: routetable.h dev.h ipin.h devtcp.h /usr/include/sys/poll.h
+dns.o: /usr/include/bits/poll.h devque.h nameserver.h resolvproto.h
+dns.o: /usr/include/unistd.h /usr/include/bits/posix_opt.h
+dns.o: /usr/include/bits/types.h /usr/include/bits/typesizes.h
+dns.o: /usr/include/bits/confname.h /usr/include/getopt.h
+dns.o: /usr/include/fcntl.h /usr/include/bits/fcntl.h
+dns.o: /usr/include/sys/types.h /usr/include/time.h /usr/include/endian.h
+dns.o: /usr/include/bits/endian.h /usr/include/sys/select.h
+dns.o: /usr/include/bits/select.h /usr/include/bits/sigset.h
+dns.o: /usr/include/bits/time.h /usr/include/sys/sysmacros.h
+dns.o: /usr/include/bits/pthreadtypes.h /usr/include/bits/sched.h
+dns.o: /usr/include/sys/wait.h /usr/include/signal.h
+dns.o: /usr/include/bits/signum.h /usr/include/bits/siginfo.h
+dns.o: /usr/include/bits/sigaction.h /usr/include/bits/sigcontext.h
+dns.o: /usr/include/asm/sigcontext.h /usr/include/asm-i486/sigcontext.h
+dns.o: /usr/include/linux/compiler.h /usr/include/bits/sigstack.h
+dns.o: /usr/include/bits/sigthread.h /usr/include/sys/resource.h
+dns.o: /usr/include/bits/resource.h /usr/include/bits/waitflags.h
+dns.o: /usr/include/bits/waitstatus.h /usr/include/sys/ipc.h
+dns.o: /usr/include/bits/ipctypes.h /usr/include/bits/ipc.h
+dns.o: /usr/include/sys/msg.h /usr/include/bits/msq.h
+ip.o: ipout.h ipaddr.h /usr/include/stdint.h /usr/include/features.h
+ip.o: /usr/include/sys/cdefs.h /usr/include/gnu/stubs.h
+ip.o: /usr/include/bits/wchar.h /usr/include/bits/wordsize.h ipheader.h
+ip.o: routetable.h dev.h ipin.h devtcp.h /usr/include/sys/poll.h
+ip.o: /usr/include/bits/poll.h devque.h /usr/include/unistd.h
+ip.o: /usr/include/bits/posix_opt.h /usr/include/bits/types.h
+ip.o: /usr/include/bits/typesizes.h /usr/include/bits/confname.h
+ip.o: /usr/include/getopt.h /usr/include/fcntl.h /usr/include/bits/fcntl.h
+ip.o: /usr/include/sys/types.h /usr/include/time.h /usr/include/endian.h
+ip.o: /usr/include/bits/endian.h /usr/include/sys/select.h
+ip.o: /usr/include/bits/select.h /usr/include/bits/sigset.h
+ip.o: /usr/include/bits/time.h /usr/include/sys/sysmacros.h
+ip.o: /usr/include/bits/pthreadtypes.h /usr/include/bits/sched.h
+ip.o: /usr/include/sys/wait.h /usr/include/signal.h
+ip.o: /usr/include/bits/signum.h /usr/include/bits/siginfo.h
+ip.o: /usr/include/bits/sigaction.h /usr/include/bits/sigcontext.h
+ip.o: /usr/include/asm/sigcontext.h /usr/include/asm-i486/sigcontext.h
+ip.o: /usr/include/linux/compiler.h /usr/include/bits/sigstack.h
+ip.o: /usr/include/bits/sigthread.h /usr/include/sys/resource.h
+ip.o: /usr/include/bits/resource.h /usr/include/bits/waitflags.h
+ip.o: /usr/include/bits/waitstatus.h /usr/include/sys/ipc.h
+ip.o: /usr/include/bits/ipctypes.h /usr/include/bits/ipc.h
+ip.o: /usr/include/sys/msg.h /usr/include/bits/msq.h
+ipaddr.o: ipaddr.h /usr/include/stdint.h /usr/include/features.h
+ipaddr.o: /usr/include/sys/cdefs.h /usr/include/gnu/stubs.h
+ipaddr.o: /usr/include/bits/wchar.h /usr/include/bits/wordsize.h
+ipheader.o: ipheader.h ipaddr.h /usr/include/stdint.h /usr/include/features.h
+ipheader.o: /usr/include/sys/cdefs.h /usr/include/gnu/stubs.h
+ipheader.o: /usr/include/bits/wchar.h /usr/include/bits/wordsize.h
+ipin.o: ipin.h ipaddr.h /usr/include/stdint.h /usr/include/features.h
+ipin.o: /usr/include/sys/cdefs.h /usr/include/gnu/stubs.h
+ipin.o: /usr/include/bits/wchar.h /usr/include/bits/wordsize.h ipheader.h
+ipin.o: dev.h
+ipout.o: ipout.h ipaddr.h /usr/include/stdint.h /usr/include/features.h
+ipout.o: /usr/include/sys/cdefs.h /usr/include/gnu/stubs.h
+ipout.o: /usr/include/bits/wchar.h /usr/include/bits/wordsize.h ipheader.h
+ipout.o: routetable.h dev.h /usr/include/unistd.h
+ipout.o: /usr/include/bits/posix_opt.h /usr/include/bits/types.h
+ipout.o: /usr/include/bits/typesizes.h /usr/include/bits/confname.h
+ipout.o: /usr/include/getopt.h /usr/include/fcntl.h /usr/include/bits/fcntl.h
+ipout.o: /usr/include/sys/types.h /usr/include/time.h /usr/include/endian.h
+ipout.o: /usr/include/bits/endian.h /usr/include/sys/select.h
+ipout.o: /usr/include/bits/select.h /usr/include/bits/sigset.h
+ipout.o: /usr/include/bits/time.h /usr/include/sys/sysmacros.h
+ipout.o: /usr/include/bits/pthreadtypes.h /usr/include/bits/sched.h
+ipout.o: /usr/include/sys/ipc.h /usr/include/bits/ipctypes.h
+ipout.o: /usr/include/bits/ipc.h /usr/include/sys/msg.h
+ipout.o: /usr/include/bits/msq.h
+nameserver.o: nameserver.h devque.h dev.h ipaddr.h /usr/include/stdint.h
+nameserver.o: /usr/include/features.h /usr/include/sys/cdefs.h
+nameserver.o: /usr/include/gnu/stubs.h /usr/include/bits/wchar.h
+nameserver.o: /usr/include/bits/wordsize.h resolvproto.h ipin.h ipheader.h
+nameserver.o: ipout.h routetable.h
+resolvproto.o: resolvproto.h ipaddr.h /usr/include/stdint.h
+resolvproto.o: /usr/include/features.h /usr/include/sys/cdefs.h
+resolvproto.o: /usr/include/gnu/stubs.h /usr/include/bits/wchar.h
+resolvproto.o: /usr/include/bits/wordsize.h ipin.h ipheader.h dev.h ipout.h
+resolvproto.o: routetable.h
+routetable.o: routetable.h dev.h ipaddr.h /usr/include/stdint.h
+routetable.o: /usr/include/features.h /usr/include/sys/cdefs.h
+routetable.o: /usr/include/gnu/stubs.h /usr/include/bits/wchar.h
+routetable.o: /usr/include/bits/wordsize.h
+test_devtcp.o: ipaddr.h /usr/include/stdint.h /usr/include/features.h
+test_devtcp.o: /usr/include/sys/cdefs.h /usr/include/gnu/stubs.h
+test_devtcp.o: /usr/include/bits/wchar.h /usr/include/bits/wordsize.h
+test_devtcp.o: devtcp.h dev.h /usr/include/sys/poll.h
+test_devtcp.o: /usr/include/bits/poll.h /usr/include/unistd.h
+test_devtcp.o: /usr/include/bits/posix_opt.h /usr/include/bits/types.h
+test_devtcp.o: /usr/include/bits/typesizes.h /usr/include/bits/confname.h
+test_devtcp.o: /usr/include/getopt.h /usr/include/fcntl.h
+test_devtcp.o: /usr/include/bits/fcntl.h /usr/include/sys/types.h
+test_devtcp.o: /usr/include/time.h /usr/include/endian.h
+test_devtcp.o: /usr/include/bits/endian.h /usr/include/sys/select.h
+test_devtcp.o: /usr/include/bits/select.h /usr/include/bits/sigset.h
+test_devtcp.o: /usr/include/bits/time.h /usr/include/sys/sysmacros.h
+test_devtcp.o: /usr/include/bits/pthreadtypes.h /usr/include/bits/sched.h
+test_devtcp.o: /usr/include/sys/wait.h /usr/include/signal.h
+test_devtcp.o: /usr/include/bits/signum.h /usr/include/bits/siginfo.h
+test_devtcp.o: /usr/include/bits/sigaction.h /usr/include/bits/sigcontext.h
+test_devtcp.o: /usr/include/asm/sigcontext.h
+test_devtcp.o: /usr/include/asm-i486/sigcontext.h
+test_devtcp.o: /usr/include/linux/compiler.h /usr/include/bits/sigstack.h
+test_devtcp.o: /usr/include/bits/sigthread.h /usr/include/sys/resource.h
+test_devtcp.o: /usr/include/bits/resource.h /usr/include/bits/waitflags.h
+test_devtcp.o: /usr/include/bits/waitstatus.h /usr/include/sys/ipc.h
+test_devtcp.o: /usr/include/bits/ipctypes.h /usr/include/bits/ipc.h
+test_devtcp.o: /usr/include/sys/msg.h /usr/include/bits/msq.h
+test_ipaddr.o: ipaddr.h /usr/include/stdint.h /usr/include/features.h
+test_ipaddr.o: /usr/include/sys/cdefs.h /usr/include/gnu/stubs.h
+test_ipaddr.o: /usr/include/bits/wchar.h /usr/include/bits/wordsize.h
+test_ipaddr.o: ipheader.h
+test_ipin.o: ipin.h ipaddr.h /usr/include/stdint.h /usr/include/features.h
+test_ipin.o: /usr/include/sys/cdefs.h /usr/include/gnu/stubs.h
+test_ipin.o: /usr/include/bits/wchar.h /usr/include/bits/wordsize.h
+test_ipin.o: ipheader.h dev.h devque.h /usr/include/unistd.h
+test_ipin.o: /usr/include/bits/posix_opt.h /usr/include/bits/types.h
+test_ipin.o: /usr/include/bits/typesizes.h /usr/include/bits/confname.h
+test_ipin.o: /usr/include/getopt.h /usr/include/fcntl.h
+test_ipin.o: /usr/include/bits/fcntl.h /usr/include/sys/types.h
+test_ipin.o: /usr/include/time.h /usr/include/endian.h
+test_ipin.o: /usr/include/bits/endian.h /usr/include/sys/select.h
+test_ipin.o: /usr/include/bits/select.h /usr/include/bits/sigset.h
+test_ipin.o: /usr/include/bits/time.h /usr/include/sys/sysmacros.h
+test_ipin.o: /usr/include/bits/pthreadtypes.h /usr/include/bits/sched.h
+test_ipin.o: /usr/include/sys/ipc.h /usr/include/bits/ipctypes.h
+test_ipin.o: /usr/include/bits/ipc.h /usr/include/sys/msg.h
+test_ipin.o: /usr/include/bits/msq.h
+test_ipout.o: ipout.h ipaddr.h /usr/include/stdint.h /usr/include/features.h
+test_ipout.o: /usr/include/sys/cdefs.h /usr/include/gnu/stubs.h
+test_ipout.o: /usr/include/bits/wchar.h /usr/include/bits/wordsize.h
+test_ipout.o: ipheader.h routetable.h dev.h devque.h /usr/include/unistd.h
+test_ipout.o: /usr/include/bits/posix_opt.h /usr/include/bits/types.h
+test_ipout.o: /usr/include/bits/typesizes.h /usr/include/bits/confname.h
+test_ipout.o: /usr/include/getopt.h /usr/include/fcntl.h
+test_ipout.o: /usr/include/bits/fcntl.h /usr/include/sys/types.h
+test_ipout.o: /usr/include/time.h /usr/include/endian.h
+test_ipout.o: /usr/include/bits/endian.h /usr/include/sys/select.h
+test_ipout.o: /usr/include/bits/select.h /usr/include/bits/sigset.h
+test_ipout.o: /usr/include/bits/time.h /usr/include/sys/sysmacros.h
+test_ipout.o: /usr/include/bits/pthreadtypes.h /usr/include/bits/sched.h
+test_ipout.o: /usr/include/sys/ipc.h /usr/include/bits/ipctypes.h
+test_ipout.o: /usr/include/bits/ipc.h /usr/include/sys/msg.h
+test_ipout.o: /usr/include/bits/msq.h
+test_nameserver_file.o: nameserver.h devque.h dev.h ipaddr.h
+test_nameserver_file.o: /usr/include/stdint.h /usr/include/features.h
+test_nameserver_file.o: /usr/include/sys/cdefs.h /usr/include/gnu/stubs.h
+test_nameserver_file.o: /usr/include/bits/wchar.h
+test_nameserver_file.o: /usr/include/bits/wordsize.h resolvproto.h ipin.h
+test_nameserver_file.o: ipheader.h ipout.h routetable.h
+test_nameserver_resolvnext.o: nameserver.h devque.h dev.h ipaddr.h
+test_nameserver_resolvnext.o: /usr/include/stdint.h /usr/include/features.h
+test_nameserver_resolvnext.o: /usr/include/sys/cdefs.h
+test_nameserver_resolvnext.o: /usr/include/gnu/stubs.h
+test_nameserver_resolvnext.o: /usr/include/bits/wchar.h
+test_nameserver_resolvnext.o: /usr/include/bits/wordsize.h resolvproto.h
+test_nameserver_resolvnext.o: ipin.h ipheader.h ipout.h routetable.h
+test_recv.o: devque.h dev.h /usr/include/unistd.h /usr/include/features.h
+test_recv.o: /usr/include/sys/cdefs.h /usr/include/gnu/stubs.h
+test_recv.o: /usr/include/bits/posix_opt.h /usr/include/bits/types.h
+test_recv.o: /usr/include/bits/wordsize.h /usr/include/bits/typesizes.h
+test_recv.o: /usr/include/bits/confname.h /usr/include/getopt.h
+test_recv.o: /usr/include/fcntl.h /usr/include/bits/fcntl.h
+test_recv.o: /usr/include/sys/types.h /usr/include/time.h
+test_recv.o: /usr/include/endian.h /usr/include/bits/endian.h
+test_recv.o: /usr/include/sys/select.h /usr/include/bits/select.h
+test_recv.o: /usr/include/bits/sigset.h /usr/include/bits/time.h
+test_recv.o: /usr/include/sys/sysmacros.h /usr/include/bits/pthreadtypes.h
+test_recv.o: /usr/include/bits/sched.h /usr/include/sys/ipc.h
+test_recv.o: /usr/include/bits/ipctypes.h /usr/include/bits/ipc.h
+test_recv.o: /usr/include/sys/msg.h /usr/include/bits/msq.h
+test_resolvproto.o: resolvproto.h ipaddr.h /usr/include/stdint.h
+test_resolvproto.o: /usr/include/features.h /usr/include/sys/cdefs.h
+test_resolvproto.o: /usr/include/gnu/stubs.h /usr/include/bits/wchar.h
+test_resolvproto.o: /usr/include/bits/wordsize.h ipin.h ipheader.h dev.h
+test_resolvproto.o: ipout.h routetable.h libtcp.h /usr/include/stdio.h
+test_resolvproto.o: /usr/include/bits/types.h /usr/include/bits/typesizes.h
+test_resolvproto.o: /usr/include/libio.h /usr/include/_G_config.h
+test_resolvproto.o: /usr/include/wchar.h /usr/include/gconv.h
+test_resolvproto.o: /usr/include/bits/stdio_lim.h
+test_resolvproto.o: /usr/include/bits/sys_errlist.h /usr/include/stdlib.h
+test_resolvproto.o: /usr/include/sys/types.h /usr/include/time.h
+test_resolvproto.o: /usr/include/endian.h /usr/include/bits/endian.h
+test_resolvproto.o: /usr/include/sys/select.h /usr/include/bits/select.h
+test_resolvproto.o: /usr/include/bits/sigset.h /usr/include/bits/time.h
+test_resolvproto.o: /usr/include/sys/sysmacros.h
+test_resolvproto.o: /usr/include/bits/pthreadtypes.h
+test_resolvproto.o: /usr/include/bits/sched.h /usr/include/alloca.h
+test_resolvproto.o: /usr/include/unistd.h /usr/include/bits/posix_opt.h
+test_resolvproto.o: /usr/include/bits/confname.h /usr/include/getopt.h
+test_resolvproto.o: /usr/include/signal.h /usr/include/bits/signum.h
+test_resolvproto.o: /usr/include/bits/siginfo.h /usr/include/bits/sigaction.h
+test_resolvproto.o: /usr/include/bits/sigcontext.h
+test_resolvproto.o: /usr/include/asm/sigcontext.h
+test_resolvproto.o: /usr/include/asm-i486/sigcontext.h
+test_resolvproto.o: /usr/include/linux/compiler.h
+test_resolvproto.o: /usr/include/bits/sigstack.h
+test_resolvproto.o: /usr/include/bits/sigthread.h /usr/include/sys/wait.h
+test_resolvproto.o: /usr/include/sys/resource.h /usr/include/bits/resource.h
+test_resolvproto.o: /usr/include/bits/waitflags.h
+test_resolvproto.o: /usr/include/bits/waitstatus.h /usr/include/string.h
+test_resolvproto.o: /usr/include/sys/socket.h /usr/include/sys/uio.h
+test_resolvproto.o: /usr/include/bits/uio.h /usr/include/bits/socket.h
+test_resolvproto.o: /usr/include/limits.h /usr/include/bits/posix1_lim.h
+test_resolvproto.o: /usr/include/bits/local_lim.h /usr/include/linux/limits.h
+test_resolvproto.o: /usr/include/bits/posix2_lim.h
+test_resolvproto.o: /usr/include/bits/sockaddr.h /usr/include/asm/socket.h
+test_resolvproto.o: /usr/include/asm-i486/socket.h /usr/include/asm/sockios.h
+test_resolvproto.o: /usr/include/asm-i486/sockios.h /usr/include/netinet/in.h
+test_resolvproto.o: /usr/include/bits/in.h /usr/include/bits/byteswap.h
+test_resolvproto.o: /usr/include/arpa/inet.h /usr/include/netdb.h
+test_resolvproto.o: /usr/include/rpc/netdb.h /usr/include/bits/netdb.h
+test_send.o: devque.h dev.h /usr/include/unistd.h /usr/include/features.h
+test_send.o: /usr/include/sys/cdefs.h /usr/include/gnu/stubs.h
+test_send.o: /usr/include/bits/posix_opt.h /usr/include/bits/types.h
+test_send.o: /usr/include/bits/wordsize.h /usr/include/bits/typesizes.h
+test_send.o: /usr/include/bits/confname.h /usr/include/getopt.h
+test_send.o: /usr/include/fcntl.h /usr/include/bits/fcntl.h
+test_send.o: /usr/include/sys/types.h /usr/include/time.h
+test_send.o: /usr/include/endian.h /usr/include/bits/endian.h
+test_send.o: /usr/include/sys/select.h /usr/include/bits/select.h
+test_send.o: /usr/include/bits/sigset.h /usr/include/bits/time.h
+test_send.o: /usr/include/sys/sysmacros.h /usr/include/bits/pthreadtypes.h
+test_send.o: /usr/include/bits/sched.h /usr/include/sys/ipc.h
+test_send.o: /usr/include/bits/ipctypes.h /usr/include/bits/ipc.h
+test_send.o: /usr/include/sys/msg.h /usr/include/bits/msq.h
+libtcp.o: libtcp.h /usr/include/stdio.h /usr/include/features.h
+libtcp.o: /usr/include/sys/cdefs.h /usr/include/gnu/stubs.h
+libtcp.o: /usr/include/bits/types.h /usr/include/bits/wordsize.h
+libtcp.o: /usr/include/bits/typesizes.h /usr/include/libio.h
+libtcp.o: /usr/include/_G_config.h /usr/include/wchar.h
+libtcp.o: /usr/include/bits/wchar.h /usr/include/gconv.h
+libtcp.o: /usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h
+libtcp.o: /usr/include/stdlib.h /usr/include/sys/types.h /usr/include/time.h
+libtcp.o: /usr/include/endian.h /usr/include/bits/endian.h
+libtcp.o: /usr/include/sys/select.h /usr/include/bits/select.h
+libtcp.o: /usr/include/bits/sigset.h /usr/include/bits/time.h
+libtcp.o: /usr/include/sys/sysmacros.h /usr/include/bits/pthreadtypes.h
+libtcp.o: /usr/include/bits/sched.h /usr/include/alloca.h
+libtcp.o: /usr/include/unistd.h /usr/include/bits/posix_opt.h
+libtcp.o: /usr/include/bits/confname.h /usr/include/getopt.h
+libtcp.o: /usr/include/signal.h /usr/include/bits/signum.h
+libtcp.o: /usr/include/bits/siginfo.h /usr/include/bits/sigaction.h
+libtcp.o: /usr/include/bits/sigcontext.h /usr/include/asm/sigcontext.h
+libtcp.o: /usr/include/asm-i486/sigcontext.h /usr/include/linux/compiler.h
+libtcp.o: /usr/include/bits/sigstack.h /usr/include/bits/sigthread.h
+libtcp.o: /usr/include/sys/wait.h /usr/include/sys/resource.h
+libtcp.o: /usr/include/bits/resource.h /usr/include/bits/waitflags.h
+libtcp.o: /usr/include/bits/waitstatus.h /usr/include/string.h
+libtcp.o: /usr/include/sys/socket.h /usr/include/sys/uio.h
+libtcp.o: /usr/include/bits/uio.h /usr/include/bits/socket.h
+libtcp.o: /usr/include/limits.h /usr/include/bits/posix1_lim.h
+libtcp.o: /usr/include/bits/local_lim.h /usr/include/linux/limits.h
+libtcp.o: /usr/include/bits/posix2_lim.h /usr/include/bits/sockaddr.h
+libtcp.o: /usr/include/asm/socket.h /usr/include/asm-i486/socket.h
+libtcp.o: /usr/include/asm/sockios.h /usr/include/asm-i486/sockios.h
+libtcp.o: /usr/include/netinet/in.h /usr/include/stdint.h
+libtcp.o: /usr/include/bits/in.h /usr/include/bits/byteswap.h
+libtcp.o: /usr/include/arpa/inet.h /usr/include/netdb.h
+libtcp.o: /usr/include/rpc/netdb.h /usr/include/bits/netdb.h
+test_poll.o: libtcp.h /usr/include/stdio.h /usr/include/features.h
+test_poll.o: /usr/include/sys/cdefs.h /usr/include/gnu/stubs.h
+test_poll.o: /usr/include/bits/types.h /usr/include/bits/wordsize.h
+test_poll.o: /usr/include/bits/typesizes.h /usr/include/libio.h
+test_poll.o: /usr/include/_G_config.h /usr/include/wchar.h
+test_poll.o: /usr/include/bits/wchar.h /usr/include/gconv.h
+test_poll.o: /usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h
+test_poll.o: /usr/include/stdlib.h /usr/include/sys/types.h
+test_poll.o: /usr/include/time.h /usr/include/endian.h
+test_poll.o: /usr/include/bits/endian.h /usr/include/sys/select.h
+test_poll.o: /usr/include/bits/select.h /usr/include/bits/sigset.h
+test_poll.o: /usr/include/bits/time.h /usr/include/sys/sysmacros.h
+test_poll.o: /usr/include/bits/pthreadtypes.h /usr/include/bits/sched.h
+test_poll.o: /usr/include/alloca.h /usr/include/unistd.h
+test_poll.o: /usr/include/bits/posix_opt.h /usr/include/bits/confname.h
+test_poll.o: /usr/include/getopt.h /usr/include/signal.h
+test_poll.o: /usr/include/bits/signum.h /usr/include/bits/siginfo.h
+test_poll.o: /usr/include/bits/sigaction.h /usr/include/bits/sigcontext.h
+test_poll.o: /usr/include/asm/sigcontext.h /usr/include/asm-i486/sigcontext.h
+test_poll.o: /usr/include/linux/compiler.h /usr/include/bits/sigstack.h
+test_poll.o: /usr/include/bits/sigthread.h /usr/include/sys/wait.h
+test_poll.o: /usr/include/sys/resource.h /usr/include/bits/resource.h
+test_poll.o: /usr/include/bits/waitflags.h /usr/include/bits/waitstatus.h
+test_poll.o: /usr/include/string.h /usr/include/sys/socket.h
+test_poll.o: /usr/include/sys/uio.h /usr/include/bits/uio.h
+test_poll.o: /usr/include/bits/socket.h /usr/include/limits.h
+test_poll.o: /usr/include/bits/posix1_lim.h /usr/include/bits/local_lim.h
+test_poll.o: /usr/include/linux/limits.h /usr/include/bits/posix2_lim.h
+test_poll.o: /usr/include/bits/sockaddr.h /usr/include/asm/socket.h
+test_poll.o: /usr/include/asm-i486/socket.h /usr/include/asm/sockios.h
+test_poll.o: /usr/include/asm-i486/sockios.h /usr/include/netinet/in.h
+test_poll.o: /usr/include/stdint.h /usr/include/bits/in.h
+test_poll.o: /usr/include/bits/byteswap.h /usr/include/arpa/inet.h
+test_poll.o: /usr/include/netdb.h /usr/include/rpc/netdb.h
+test_poll.o: /usr/include/bits/netdb.h /usr/include/assert.h
+test_poll.o: /usr/include/sys/poll.h /usr/include/bits/poll.h
diff --git a/practicas/pipi-2da-entrega/src/dev.cpp b/practicas/pipi-2da-entrega/src/dev.cpp
new file mode 100644 (file)
index 0000000..d9465a6
--- /dev/null
@@ -0,0 +1,71 @@
+#include "dev.h"
+#include <cstring>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/ipc.h>
+#include <sys/msg.h>
+#ifdef DEBUG
+#include <iostream>
+#endif
+
+struct Frame
+{
+    Dev::mac_type mac;
+    size_t size;
+    char frame[1];
+};
+
+Dev::Dev(mac_type mac, size_t mtu, key_t key)
+    throw (std::runtime_error, std::logic_error):
+    mac(mac), mtu(mtu)
+{
+    if (mtu > DEV_MAX_MTU)
+        throw std::logic_error("MTU más grande que DEV_MAX_MTU");
+    que_id = msgget(key, 0666); // Debe estar previamente creada
+    if (que_id == -1)
+        throw std::runtime_error("No se pudo crear la cola");
+}
+
+void Dev::transmit(const std::string& data, const mac_type& mac)
+    throw (std::runtime_error, std::logic_error)
+{
+    if (data.size() > mtu)
+        throw std::logic_error("Tamaño de datos mayor al MTU");
+    Frame* f = (Frame*) malloc(sizeof(Frame) + mtu);
+    if (!f)
+        throw std::runtime_error("No se puede reservar memoria");
+    f->mac = mac;
+    f->size = data.size();
+    memcpy(f->frame, data.c_str(), data.size());
+    int res = msgsnd(que_id, f, mtu + sizeof(size_t), 0);
+#ifdef DEBUG
+    //std::cout << "Dev::transmit(msgtype/mac = " << f->mac << ", size = "
+    //    << f->size << ")\n";
+#endif
+    free(f);
+    if (res == -1)
+        throw std::runtime_error("Error al poner en la cola");
+}
+
+std::string Dev::receive() throw (std::runtime_error)
+{
+    Frame* f = (Frame*) malloc(sizeof(Frame) + mtu);
+    if (!f)
+        throw std::runtime_error("No se puede reservar memoria");
+    int res = msgrcv(que_id, f, mtu + sizeof(size_t), mac, 0);
+    if (res == -1)
+    {
+        free(f);
+        throw std::runtime_error("Error al sacar de la cola");
+    }
+    std::string s((char*) f->frame, f->size);
+    free(f);
+#ifdef DEBUG
+    //std::cout << "Dev::receive(msgtype/mac = " << mac << ", size = "
+    //    << s.size() << ")\n";
+#endif
+    return s;
+}
+
+// vim: set et sw=4 sts=4 :
diff --git a/practicas/pipi-2da-entrega/src/dev.h b/practicas/pipi-2da-entrega/src/dev.h
new file mode 100644 (file)
index 0000000..f06e8b1
--- /dev/null
@@ -0,0 +1,50 @@
+#ifndef _DEV_H_
+#define _DEV_H_
+
+#include <stdexcept>
+
+#define DEV_MAX_MTU 1500
+
+/// Dispositivo de red (capa de enlace)
+struct Dev
+{
+
+    /// Tipo de la mac
+    typedef long mac_type;
+
+    /// Dirección MAC
+    mac_type mac;
+
+    /// MTU
+    size_t mtu;
+
+    /// Constructor
+    Dev(mac_type mac, size_t mtu = DEV_MAX_MTU)
+        throw (std::runtime_error, std::logic_error):
+            mac(mac), mtu(mtu)
+    {
+        if (mtu > DEV_MAX_MTU)
+            throw std::logic_error("MTU más grande que DEV_MAX_MTU");
+    }
+
+    /// Envía un frame
+    virtual void transmit(const std::string& data, const mac_type& mac)
+        throw (std::runtime_error, std::logic_error) = 0;
+
+    /// Recibe un frame
+    virtual std::string receive()
+        throw (std::runtime_error) = 0;
+
+    /// Destructor virtual por si las moscas
+    virtual ~Dev() {}
+
+    // Nada de andar copiando placas...
+    private:
+    Dev(const Dev&);
+    Dev& operator=(const Dev&);
+
+};
+
+#endif // _DEV_H_
+
+// vim: set et sw=4 sts=4 :
diff --git a/practicas/pipi-2da-entrega/src/devque.cpp b/practicas/pipi-2da-entrega/src/devque.cpp
new file mode 100644 (file)
index 0000000..0791354
--- /dev/null
@@ -0,0 +1,90 @@
+#include "devque.h"
+#include <cstring>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/ipc.h>
+#include <sys/msg.h>
+#ifdef DEBUG
+#include <iostream>
+#endif
+
+struct Frame
+{
+    Dev::mac_type mac;
+    size_t size;
+    char frame[1];
+};
+
+DevQue::DevQue(mac_type mac, key_t key, size_t mtu)
+    throw (std::runtime_error, std::logic_error):
+        Dev(mac, mtu)
+{
+    que_id = msgget(key, IPC_CREAT | 0666);
+    if (que_id == -1)
+        throw std::runtime_error("No se pudo crear la cola");
+}
+
+void DevQue::transmit(const std::string& data, const mac_type& mac)
+    throw (std::runtime_error, std::logic_error)
+{
+    if (data.size() > mtu)
+        throw std::logic_error("Tamaño de datos mayor al MTU");
+    Frame* f = (Frame*) malloc(sizeof(Frame) + mtu);
+    if (!f)
+        throw std::runtime_error("No se puede reservar memoria");
+    f->mac = mac;
+    f->size = data.size();
+    memcpy(f->frame, data.c_str(), data.size());
+    int res = msgsnd(que_id, f, mtu + sizeof(size_t), 0);
+#ifdef DEBUG2
+    std::cout << "DevQue::transmit(msgtype/mac = " << f->mac << ", size = "
+        << f->size << ")\n";
+#endif
+    free(f);
+    if (res == -1)
+        throw std::runtime_error("Error al poner en la cola");
+}
+
+std::string DevQue::receive() throw (std::runtime_error)
+{
+    return receive(mac);
+}
+
+std::string DevQue::receive(mac_type& mac) throw (std::runtime_error)
+{
+    Frame* f = (Frame*) malloc(sizeof(Frame) + mtu);
+    if (!f)
+        throw std::runtime_error("No se puede reservar memoria");
+    int res = msgrcv(que_id, f, mtu + sizeof(size_t), mac, 0);
+    if (res == -1)
+    {
+        free(f);
+        throw std::runtime_error("Error al sacar de la cola");
+    }
+    std::string s((char*) f->frame, f->size);
+    if (mac == 0)
+        mac = f->mac;
+    free(f);
+#ifdef DEBUG2
+    std::cout << "DevQue::receive(msgtype/mac = " << mac << ", size = "
+        << s.size() << ")\n";
+#endif
+    return s;
+}
+
+/// Indica cuantos elementos hay en la cola
+size_t DevQue::size() const
+{
+    struct msqid_ds minfo;
+    msgctl(que_id, IPC_STAT, &minfo);
+    return minfo.msg_qnum;
+}
+
+/// Indica si está vacía la cola
+bool DevQue::empty() const
+{
+    return size() == 0;
+}
+
+// vim: set et sw=4 sts=4 :
diff --git a/practicas/pipi-2da-entrega/src/devque.h b/practicas/pipi-2da-entrega/src/devque.h
new file mode 100644 (file)
index 0000000..70ddb36
--- /dev/null
@@ -0,0 +1,43 @@
+#ifndef _DEVQUE_H_
+#define _DEVQUE_H_
+
+#include "dev.h"
+
+#define DEVQUE_DEFAULT_KEY 0x1abcdef1
+
+/// Dispositivo de red (capa de enlace) implementado con una cola
+struct DevQue: Dev
+{
+
+    /// Identificador de la cola a usar
+    int que_id;
+
+    /// Constructor
+    DevQue(mac_type mac, key_t key = DEVQUE_DEFAULT_KEY,
+            size_t mtu = DEV_MAX_MTU)
+        throw (std::runtime_error, std::logic_error);
+
+    /// Envía un frame
+    void transmit(const std::string& data, const mac_type& mac)
+        throw (std::runtime_error, std::logic_error);
+
+    /// Recibe un frame
+    std::string receive()
+        throw (std::runtime_error);
+
+    /// Recibe un frame para el tipo de mac especificado, si es 0 recibe
+    /// cualquier y guarda en esa mac la dirección.
+    std::string receive(mac_type& mac)
+        throw (std::runtime_error);
+
+    /// Indica cuantos elementos hay en la cola
+    size_t size() const;
+
+    /// Indica si está vacía la cola
+    bool empty() const;
+
+};
+
+#endif // _DEVQUE_H_
+
+// vim: set et sw=4 sts=4 :
diff --git a/practicas/pipi-2da-entrega/src/devtcp.cpp b/practicas/pipi-2da-entrega/src/devtcp.cpp
new file mode 100644 (file)
index 0000000..828e0e6
--- /dev/null
@@ -0,0 +1,103 @@
+#include "devtcp.h"
+#include "ipaddr.h"
+#include "libtcp.h"
+#include <cstring>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/ipc.h>
+#include <sys/msg.h>
+#include <sys/poll.h>
+#ifdef DEBUG
+#include <iostream>
+#endif
+
+#define ISSET(var, flag) ((var & flag) == flag)
+
+DevTCP::DevTCP(mac_type mac, uint16_t port, size_t mtu)
+    throw (std::runtime_error, std::logic_error):
+        Dev(mac, mtu), port(port), pfds_size(1)
+{
+    if ((pfds[0].fd = libtcp_open_pasivo(port)) == -1)
+        throw std::runtime_error("No se pudo crear el socket que escucha");
+    pfds[0].events = POLLIN | POLLPRI;
+}
+
+void DevTCP::transmit(const std::string& data, const mac_type& mac)
+    throw (std::runtime_error, std::logic_error)
+{
+    if (data.size() > mtu)
+        throw std::logic_error("Tamaño de datos mayor al MTU");
+    if (tx_pool.find(mac) == tx_pool.end()) // No existe la conexión
+    {
+        std::string addr = IPAddr(mac);
+#ifdef DEBUG2
+        std::cout << "DevTCP::transmit: conectando a " << addr << ":" << port << "\n";
+#endif
+        tx_pool[mac] = libtcp_open_activo(addr.c_str(), port);
+        if (tx_pool[mac] == -1)
+            throw std::runtime_error("Error al conectar el socket");
+    }
+    size_t size = data.size();
+    if (libtcp_send(tx_pool[mac], &size, sizeof(size_t)) != sizeof(size_t))
+        throw std::runtime_error("Error al enviar por el socket");
+    if ((unsigned)libtcp_send(tx_pool[mac], data.c_str(), data.size()) != data.size())
+        throw std::runtime_error("Error al enviar por el socket");
+#ifdef DEBUG2
+    std::cout << "DevTCP::transmit(mac = " << mac << ", size = "
+        << data.size() << ")\n";
+#endif
+}
+
+std::string DevTCP::receive() throw (std::runtime_error)
+{
+    // Nos fijamos en todos los file descriptors si hay algo para nosotros.
+    while (true)
+    {
+        int res = poll(pfds, pfds_size, 5000);
+        if (res == -1)
+            throw std::runtime_error("Error al hacer poll");
+        if (!res)
+            continue;
+        // Si tengo conexiones esperando, las atiendo...
+        if (ISSET(pfds[0].revents, POLLIN)
+                || ISSET(pfds[0].revents, POLLPRI))
+        {
+            if (pfds_size == DEVTCP_MAX_CONN)
+                throw std::runtime_error("Demasiadas conexiones activas");
+            pfds[pfds_size].fd = accept(pfds[0].fd, NULL, NULL);
+            if (pfds[pfds_size].fd == -1)
+                throw std::runtime_error("Error al hacer accept");
+            pfds[pfds_size].events = POLLIN | POLLPRI;
+            ++pfds_size;
+        }
+        // Luego me fijo si tengo algún otro socket con cosas para recibir
+        for (size_t i = 1; i < pfds_size; ++i)
+        {
+            if (ISSET(pfds[i].revents, POLLIN)
+                    || ISSET(pfds[i].revents, POLLPRI))
+            {
+                size_t size;
+                int r = libtcp_receive_bin(pfds[i].fd, &size, sizeof(size_t));
+                if (r != sizeof(size_t))
+                    // TODO cerrar socket?
+                    continue;
+                char* buf = (char*)malloc(size);
+                r = libtcp_receive_bin(pfds[i].fd, buf, size);
+                if ((unsigned)r != size)
+                    // TODO cerrar socket?
+                    continue;
+                std::string ret(buf, size);
+                free(buf);
+#ifdef DEBUG2
+                std::cout << "DevTCP::receive(msgtype/mac = " << mac << ", size = "
+                    << ret.size() << ")\n";
+#endif
+                return ret;
+            }
+        }
+    }
+    return ""; // No deberíamos caer nunca acá.
+}
+
+// vim: set et sw=4 sts=4 :
diff --git a/practicas/pipi-2da-entrega/src/devtcp.h b/practicas/pipi-2da-entrega/src/devtcp.h
new file mode 100644 (file)
index 0000000..680561f
--- /dev/null
@@ -0,0 +1,43 @@
+#ifndef _DEVTCP_H_
+#define _DEVTCP_H_
+
+#include "dev.h"
+#include <map>
+#include <stdint.h>
+#include <sys/poll.h>
+
+#define DEVTCP_DEFAULT_PORT 65000
+#define DEVTCP_MAX_CONN 16
+
+/// Dispositivo de red (capa de enlace) implementado con TCP
+struct DevTCP: Dev
+{
+
+    /// Puerto en el cual escucha por conexiones
+    uint16_t port;
+
+    /// Información para poll sobre los fds
+    pollfd pfds[DEVTCP_MAX_CONN];
+    size_t pfds_size;
+
+    /// Mapa con el fd que corresponde a la conexión saliente con cada host
+    std::map< mac_type, int > tx_pool;
+
+    /// Constructor
+    DevTCP(mac_type mac, uint16_t port = DEVTCP_DEFAULT_PORT,
+            size_t mtu = DEV_MAX_MTU)
+        throw (std::runtime_error, std::logic_error);
+
+    /// Envía un frame
+    void transmit(const std::string& data, const mac_type& mac)
+        throw (std::runtime_error, std::logic_error);
+
+    /// Recibe un frame
+    std::string receive()
+        throw (std::runtime_error);
+
+};
+
+#endif // _DEVTCP_H_
+
+// vim: set et sw=4 sts=4 :
diff --git a/practicas/pipi-2da-entrega/src/dns.cpp b/practicas/pipi-2da-entrega/src/dns.cpp
new file mode 100644 (file)
index 0000000..5b3c66c
--- /dev/null
@@ -0,0 +1,128 @@
+
+#include "ipout.h"
+#include "ipin.h"
+#include "ipaddr.h"
+#include "routetable.h"
+#include "devtcp.h"
+#include "devque.h"
+#include "nameserver.h"
+#include <iostream>
+#include <fstream>
+#include <sstream>
+#include <string>
+#include <cassert>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <sys/ipc.h>
+#include <sys/msg.h>
+#include <signal.h>
+
+// Uso: ./dns ip [routes_file zones_file forward port]
+
+void send_loop(NameServer& ns);
+
+void add_routes(RouteTable& rt, std::istream& is, Dev& dev);
+
+int main(int argc, char* argv[])
+{
+    uint16_t port = DEVTCP_DEFAULT_PORT;
+    std::string rfile = "route.txt";
+    std::string zfile = "zones.txt";
+    if (argc < 2)
+    {
+        std::cerr << "Uso: " << argv[0] << " ip [route_file zone_file port]\n";
+        return 1;
+    }
+    IPAddr addr(argv[1]);
+    if (argc > 2)
+        rfile = argv[2];
+    if (argc > 3)
+        zfile = argv[3];
+    if (argc > 4)
+        port = atoi(argv[4]);
+    // Abro archivo con rutas
+    std::ifstream rifs(rfile.c_str()); assert(rifs);
+    // Abro archivo con zonas
+    std::ifstream zifs(zfile.c_str()); assert(zifs);
+    // Creo medio físico y colas para forwarding y NameServer
+    DevTCP dev(addr, port);
+    DevQue fwque(addr, DEVQUE_DEFAULT_KEY-1);
+    DevQue nsreqque(addr, DEVQUE_DEFAULT_KEY-2);
+    DevQue nsresque(addr, DEVQUE_DEFAULT_KEY-3);
+    DevQue nssndque(addr, DEVQUE_DEFAULT_KEY-4);
+    // Creo Rutas, IPOut, IPIn
+    RouteTable table(dev);
+    add_routes(table, rifs, dev);
+    IPOut ipout(addr, table, fwque, std::cerr);
+    IPIn ipin(addr, dev, fwque, false, false, std::cerr);
+    NameServer ns(zifs, ipin, ipout, nsreqque, nsresque, nssndque);
+    // Creo procesos
+    pid_t pid_send = fork();
+    if (pid_send == -1)
+    {
+        perror("fork() send");
+        return 2;
+    }
+    if (pid_send) // IPOut
+    {
+        pid_t pid_fw = fork();
+        if (pid_fw == -1)
+        {
+            perror("fork() forward");
+            return 3;
+        }
+        if (pid_fw) // Padre (Entrada por teclado)
+        {
+            int ret;
+            send_loop(ns);
+            kill(pid_send, SIGTERM);
+            waitpid(pid_send, &ret, 0);
+            kill(pid_fw, SIGTERM);
+            waitpid(pid_fw, &ret, 0);
+            return 0;
+        }
+        else // Hijo 1 (envío del DNS)
+        {
+            ns.send_loop();
+            return 0;
+        }
+    }
+    else // Hijo 2 (recepción del DNS)
+    {
+        ns.recv_loop();
+        return 0;
+    }
+    return 0;
+}
+
+void send_loop(NameServer& ns)
+{
+    std::string name;
+    while (std::getline(std::cin, name))
+    {
+        std::cout << "Resolviendo " << name << "...\n";
+        ResolvProtoResponse res = ns.resolv_recursive(name);
+        std::cout << "Resultado: " << res << "\n";
+    }
+}
+
+void add_routes(RouteTable& rt, std::istream& is, Dev& dev)
+{
+    std::string line;
+    while (std::getline(is, line))
+    {
+        std::istringstream iss(line);
+        std::string net;
+        std::string gw;
+        unsigned mtu;
+        unsigned metric;
+        iss >> net >> gw >> mtu >> metric;
+        if (net == "0") net = "0.0.0.0";
+        if (gw == "0") gw = "0.0.0.0";
+        rt.add(net, gw, metric, mtu, dev);
+    }
+}
+
+// vim: set et sw=4 sts=4 :
diff --git a/practicas/pipi-2da-entrega/src/ip.cpp b/practicas/pipi-2da-entrega/src/ip.cpp
new file mode 100644 (file)
index 0000000..6988169
--- /dev/null
@@ -0,0 +1,140 @@
+
+#include "ipout.h"
+#include "ipin.h"
+#include "ipaddr.h"
+#include "routetable.h"
+#include "devtcp.h"
+#include "devque.h"
+#include <iostream>
+#include <fstream>
+#include <sstream>
+#include <string>
+#include <cassert>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <sys/ipc.h>
+#include <sys/msg.h>
+#include <signal.h>
+
+// Uso: ./ip ip [router forward routes_file port proto]
+
+void send_loop(IPOut& ipout, unsigned proto);
+
+void add_routes(RouteTable& rt, std::istream& is, Dev& dev);
+
+int main(int argc, char* argv[])
+{
+    bool router = false;
+    bool forward = false;
+    uint8_t proto = 0;
+    uint16_t port = DEVTCP_DEFAULT_PORT;
+    std::string fname = "route.txt";
+    if (argc < 2)
+    {
+        std::cerr << "Uso: " << argv[0] << " ip [router forward routes_file "
+            "port proto]\n";
+        return 1;
+    }
+    IPAddr addr(argv[1]);
+    if (argc > 2)
+        router = atoi(argv[2]);
+    if (argc > 3)
+        forward = atoi(argv[3]);
+    if (argc > 4)
+        fname = argv[4];
+    if (argc > 5)
+        port = atoi(argv[5]);
+    if (argc > 6)
+        proto = atoi(argv[6]);
+    // Creo cola para comunicar el IPIn con IPOut
+    int que_id = msgget(DEVQUE_DEFAULT_KEY-1, IPC_CREAT | 0666); assert(que_id != -1);
+    // Abro archivo con rutas
+    std::ifstream ifs(fname.c_str()); assert(ifs);
+    // Creo medio físico y cola para forwarding
+    DevTCP dev(addr, port);
+    DevQue fwque(addr, DEVQUE_DEFAULT_KEY-1);
+    // Creo procesos
+    pid_t pid_send = fork();
+    if (pid_send == -1)
+    {
+        perror("fork() send");
+        return 2;
+    }
+    if (pid_send) // IPOut
+    {
+        RouteTable table(dev);
+        add_routes(table, ifs, dev);
+        IPOut ipout(addr, table, fwque, std::cerr);
+        pid_t pid_fw = fork();
+        if (pid_fw == -1)
+        {
+            perror("fork() forward");
+            return 3;
+        }
+        if (pid_fw) // Padre (IPOut send)
+        {
+            int ret;
+            send_loop(ipout, proto);
+            kill(pid_send, SIGTERM);
+            waitpid(pid_send, &ret, 0);
+            kill(pid_fw, SIGTERM);
+            waitpid(pid_fw, &ret, 0);
+            return 0;
+        }
+        else // Hijo 1 (IPOut forward)
+        {
+            ipout.forward_loop();
+            return 0;
+        }
+    }
+    else // Hijo 2 (IPIn)
+    {
+        IPIn ipin(addr, dev, fwque, router, forward, std::cerr);
+        while (true)
+        {
+            IPAddr src, dst;
+            std::string s = ipin.recv(proto, src, dst);
+            std::cout << "Recibido '" << s << "' (len " << s.size() << ") de "
+                << src << " para " << dst << " (proto = " << unsigned(proto)
+                << ")\n";
+        }
+        return 0;
+    }
+    return 0;
+}
+
+void send_loop(IPOut& ipout, unsigned proto)
+{
+    std::string dst;
+    std::string msg;
+    while (std::getline(std::cin, dst))
+    {
+        if (!std::getline(std::cin, msg))
+            break;
+        if (ipout.send(msg, proto, IPAddr(dst.c_str())))
+            std::cout << "Enviado '" << msg << "' a " << dst << "\n";
+        else
+            std::cout << "NO SE PUDO ENVIAR '" << msg << "' a " << dst << "\n";
+    }
+}
+
+void add_routes(RouteTable& rt, std::istream& is, Dev& dev)
+{
+    std::string line;
+    while (std::getline(is, line))
+    {
+        std::istringstream iss(line);
+        std::string net;
+        std::string gw;
+        unsigned mtu;
+        unsigned metric;
+        iss >> net >> gw >> mtu >> metric;
+        if (net == "0") net = "0.0.0.0";
+        if (gw == "0") gw = "0.0.0.0";
+        rt.add(net, gw, metric, mtu, dev);
+    }
+}
+
+// vim: set et sw=4 sts=4 :
diff --git a/practicas/pipi-2da-entrega/src/ipaddr.cpp b/practicas/pipi-2da-entrega/src/ipaddr.cpp
new file mode 100644 (file)
index 0000000..5d9bfdf
--- /dev/null
@@ -0,0 +1,80 @@
+
+#include "ipaddr.h"
+#include <sstream>
+
+/// Constructor
+IPAddr::IPAddr()
+{
+    atoms[0] = 0;
+    atoms[1] = 0;
+    atoms[2] = 0;
+    atoms[3] = 0;
+}
+
+/// Constructor
+IPAddr::IPAddr(atom a1, atom a2, atom a3, atom a4)
+{
+    atoms[0] = a1;
+    atoms[1] = a2;
+    atoms[2] = a3;
+    atoms[3] = a4;
+}
+
+/// Constructor
+IPAddr::IPAddr(uint32_t ip)
+{
+    atoms[0] = ip >> 24;
+    atoms[1] = ip >> 16;
+    atoms[2] = ip >> 8;
+    atoms[3] = ip;
+}
+
+#if 0
+/// Constructor
+IPAddr::IPAddr(const char* ip) throw (std::logic_error)
+{
+    std::istringstream iss(ip);
+    std::string ips;
+    for (int i = 0; i < 4; ++i)
+    {
+        if (!std::getline(iss, ips, '.'))
+            throw std::logic_error("Dirección IP inválida");
+        atoms[i] = std::atoi(ips.c_str());
+    }
+}
+#endif
+
+/// Constructor
+IPAddr::IPAddr(const std::string& ip) throw (std::logic_error)
+{
+    std::istringstream iss(ip);
+    std::string ips;
+    for (int i = 0; i < 4; ++i)
+    {
+        if (!std::getline(iss, ips, '.'))
+            throw std::logic_error("Dirección IP inválida");
+        atoms[i] = std::atoi(ips.c_str());
+    }
+}
+
+/// Operador de casteo a unsigned
+IPAddr::operator uint32_t () const
+{
+    return (atoms[0] << 24) + (atoms[1] << 16) + (atoms[2] << 8) + atoms[3];
+}
+
+/// Operador de casteo a std::string
+IPAddr::operator std::string () const
+{
+    std::ostringstream oss;
+    oss << unsigned(atoms[0]) << "." << unsigned(atoms[1]) << "."
+        << unsigned(atoms[2]) << "." << unsigned(atoms[3]);
+    return oss.str();
+}
+
+std::ostream& operator<< (std::ostream& os, const IPAddr& ip)
+{
+    return os << std::string(ip);
+}
+
+// vim: set et sw=4 sts=4 :
diff --git a/practicas/pipi-2da-entrega/src/ipaddr.h b/practicas/pipi-2da-entrega/src/ipaddr.h
new file mode 100644 (file)
index 0000000..b5c9cea
--- /dev/null
@@ -0,0 +1,46 @@
+#ifndef _IPADDR_H_
+#define _IPADDR_H_
+
+#include <string>
+#include <cstdlib>
+#include <stdexcept>
+#include <stdint.h>
+
+/// Dirección IP
+struct IPAddr
+{
+
+    /// Átomo de dirección IP
+    typedef uint8_t atom;
+
+    /// Representación interna
+    atom atoms[4];
+
+    /// Constructor
+    IPAddr();
+
+    /// Constructor
+    IPAddr(atom a1, atom a2, atom a3, atom a4);
+
+    /// Constructor
+    IPAddr(uint32_t ip);
+
+    /// Constructor
+    //IPAddr(const char* ip) throw (std::logic_error);
+
+    /// Constructor
+    IPAddr(const std::string& ip) throw (std::logic_error);
+
+    /// Operador de casteo a unsigned
+    operator uint32_t () const;
+
+    /// Operador de casteo a std::string
+    operator std::string () const;
+
+};
+
+std::ostream& operator<< (std::ostream& os, const IPAddr& ip);
+
+#endif // _IPADDR_H_
+
+// vim: set et sw=4 sts=4 :
diff --git a/practicas/pipi-2da-entrega/src/ipheader.cpp b/practicas/pipi-2da-entrega/src/ipheader.cpp
new file mode 100644 (file)
index 0000000..facc22b
--- /dev/null
@@ -0,0 +1,60 @@
+#include "ipheader.h"
+
+IPHeader::IPHeader(uint8_t version, uint16_t total_len, uint16_t id, bool df,
+        bool mf, uint16_t offset, uint8_t ttl, uint8_t proto,
+        const IPAddr& src, const IPAddr& dst):
+    version(version), total_len(total_len), id(id), reserved_flag(0),
+    df(df), mf(mf), offset(offset), ttl(ttl), proto(proto), checksum(0),
+    src(src), dst(dst)
+{
+    do_checksum();
+}
+
+IPHeader::IPHeader(const std::string& s)
+{
+    *this = *((IPHeader*)s.c_str());
+}
+
+size_t IPHeader::header_len()
+{
+    return sizeof(IPHeader);
+}
+
+bool IPHeader::check_checksum() const
+{
+    IPHeader iph = *this;
+    iph.checksum = 0;
+    char* raw = (char*) &iph;
+    uint16_t sum = 0;
+    for (unsigned i = 0; i < sizeof(IPHeader); ++i)
+        sum += raw[i];
+    return sum == checksum;
+}
+
+void IPHeader::do_checksum()
+{
+    checksum = 0;
+    char* raw = (char*) this;
+    uint16_t sum = 0;
+    for (unsigned i = 0; i < sizeof(IPHeader); ++i)
+        sum += raw[i];
+    checksum = sum;
+}
+
+std::ostream& operator<<(std::ostream& os, const IPHeader& iph)
+{
+    return os
+        << "version=" << unsigned(iph.version)
+        << " total_len=" << iph.total_len
+        << " id=" << iph.id
+        << " DF=" << bool(iph.df)
+        << " MF=" << bool(iph.mf)
+        << " offset=" << unsigned(iph.offset)
+        << " TTL=" << unsigned(iph.ttl)
+        << " proto=" << unsigned(iph.proto)
+        << " checksum=" << iph.checksum
+        << " src=" << IPAddr(iph.src)
+        << " dst=" << IPAddr(iph.dst);
+}
+
+// vim: set et sw=4 sts=4 :
diff --git a/practicas/pipi-2da-entrega/src/ipheader.h b/practicas/pipi-2da-entrega/src/ipheader.h
new file mode 100644 (file)
index 0000000..f22c703
--- /dev/null
@@ -0,0 +1,47 @@
+#ifndef _IPHEADER_H_
+#define _IPHEADER_H_
+
+#include "ipaddr.h"
+#include <string>
+#include <ostream>
+#include <stdint.h>
+
+/// Dispositivo de red (capa de enlace)
+struct IPHeader
+{
+
+    // Campos
+    uint8_t version;
+    //TODO IHL
+    //TODO TOS
+    uint16_t total_len;
+    uint16_t id;
+    uint16_t reserved_flag: 1;
+    uint16_t df: 1;
+    uint16_t mf: 1;
+    uint16_t offset: 13;
+    uint8_t ttl;
+    uint8_t proto;
+    uint16_t checksum;
+    uint32_t src;
+    uint32_t dst;
+
+    IPHeader(uint8_t version, uint16_t total_len, uint16_t id, bool df,
+            bool mf, uint16_t offset, uint8_t ttl, uint8_t proto,
+            const IPAddr& src, const IPAddr& dst);
+
+    IPHeader(const std::string& s);
+
+    static size_t header_len();
+
+    bool check_checksum() const;
+
+    void do_checksum();
+
+};
+
+std::ostream& operator<<(std::ostream& os, const IPHeader& iph);
+
+#endif // _IPHEADER_H_
+
+// vim: set et sw=4 sts=4 :
diff --git a/practicas/pipi-2da-entrega/src/ipin.cpp b/practicas/pipi-2da-entrega/src/ipin.cpp
new file mode 100644 (file)
index 0000000..1ff0560
--- /dev/null
@@ -0,0 +1,115 @@
+
+#include "ipin.h"
+#include "ipheader.h"
+#ifdef DEBUG
+#include <iostream>
+#endif
+
+/// Constructor
+IPIn::IPIn(const IPAddr& ip, Dev& dev, Dev& forward_que, bool router,
+        bool forward, std::ostream& log):
+    ip(ip), dev(dev), forward_que(forward_que), router(router),
+    forward(forward), log(log)
+{
+    if (router) forward = true;
+}
+
+void IPIn::drop(const std::string& msg, const std::string& buf)
+{
+    log << "IPIn::drop (" << ip << "): " << msg << "\n\tBuffer: " << buf
+            << "\n";
+}
+
+void IPIn::drop(const std::string& msg, const IPHeader& iph)
+{
+    log << "IPIn::drop (" << ip << "): " << msg << "\n\tIPHeader: " << iph
+            << "\n";
+}
+
+/// Recibe un paquete IP
+std::string IPIn::recv(uint8_t& proto, IPAddr& src, IPAddr& dst)
+    throw (std::runtime_error)
+{
+    while (true)
+    {
+        std::string buf = dev.receive();
+        // No es siquiera IP
+        if (buf.size() < IPHeader::header_len())
+        {
+            // Silencioso
+            drop("Cabecera incompleta o no es IP", buf);
+            continue;
+        }
+        IPHeader iph(buf);
+#ifdef DEBUG
+        std::cout << "IPIn::recv (" << ip << "): IPHeader: " << iph << "\n";
+        std::string tmp = buf.substr(iph.header_len());
+        std::cout << "\tdata (" << tmp.size() << ") = " << tmp << "\n";
+#endif
+        if (iph.version != 4)
+        {
+            // Silencioso
+            drop("Versión IP incorrecta", iph);
+            continue;
+        }
+        if (!iph.check_checksum())
+        {
+            // Silencioso
+            drop("Mal checksum", iph);
+            continue;
+        }
+        // Si el TTL se va a 0
+        if (!--iph.ttl)
+        {
+            // ICMP
+            drop("TTL == 0 -> ICMP", iph);
+            continue;
+        }
+        // No es para nosotros y no forwardeamos
+        if (iph.dst != ip && !forward)
+        {
+            // Silencioso
+            drop("No es para nosotros y no hacemos forward", iph);
+            continue;
+        }
+        // No es para nosotros pero forwardeamos
+        else if (iph.dst != ip)
+        {
+            forward_que.transmit(buf, ip);
+            continue;
+        }
+        // Es para nosotros pero somos router
+        else if (router)
+        {
+            // Silencioso
+            drop("Es para nosotros pero somos un router", iph);
+            continue;
+        }
+        // Es para nosotros y somos un host
+        // Guarda en buffer
+        buffer[iph][iph.offset] = buf.substr(iph.header_len());
+        // Si tiene más fragmentos, sigo
+        if (iph.mf)
+            continue;
+        // No hay más fragmentos, reensamblamos (de ser necesario)
+        std::string data;
+        for (offsetmap_type::iterator i = buffer[iph].begin();
+                i != buffer[iph].end(); ++i)
+        {
+            //TODO chequear que los fragmentos estén todos
+            data += i->second;
+        }
+#ifdef DEBUG
+        std::cout << "IPIn::recv (" << ip << "): Paquete completo: data = '"
+                << data << "'\n";
+#endif
+        buffer.erase(iph);
+        //TODO faltaría limpiar fragmentos viejos cada tanto (timer?)
+        src = iph.src;
+        dst = iph.dst;
+        proto = iph.proto;
+        return data;
+    }
+}
+
+// vim: set et sw=4 sts=4 :
diff --git a/practicas/pipi-2da-entrega/src/ipin.h b/practicas/pipi-2da-entrega/src/ipin.h
new file mode 100644 (file)
index 0000000..8a452b2
--- /dev/null
@@ -0,0 +1,71 @@
+#ifndef _IPIN_H_
+#define _IPIN_H_
+
+#include "ipaddr.h"
+#include "ipheader.h"
+#include "dev.h"
+#include <map>
+#include <string>
+#include <iostream>
+#include <stdexcept>
+
+/// IP de recepción
+struct IPIn
+{
+
+    /// Dirección IP
+    IPAddr ip;
+
+    /// Dispositivo de red
+    Dev& dev;
+
+    /// Cola para forwardear paquetes
+    Dev& forward_que;
+
+    /// Indica si es un router
+    bool router;
+
+    /// Indica si hace forwarding
+    bool forward;
+
+    /// Dispositivo de logging
+    std::ostream& log;
+
+    /// Buffers de recepción
+    struct BufferKey
+    {
+        uint16_t id;
+        uint32_t src, dst;
+        uint8_t proto;
+        BufferKey(const IPHeader& h):
+            id(h.id), src(h.src), dst(h.dst), proto(h.proto)
+        {}
+        bool operator< (const BufferKey& b) const
+        { return id < b.id && src < b.src && dst < b.dst && proto < b.proto; }
+    };
+    typedef std::map< uint16_t, std::string > offsetmap_type;
+    typedef std::map< BufferKey, offsetmap_type > buffer_type;
+    buffer_type buffer;
+
+    /// Constructor
+    IPIn(const IPAddr& ip, Dev& dev, Dev& forward_que, bool router = false,
+        bool forward = false, std::ostream& log = std::cout);
+
+    /// Descarta un paquete
+    void drop(const std::string& msg, const std::string& buf);
+    void drop(const std::string& msg, const IPHeader& iph);
+
+    /// Recibe un paquete IP
+    std::string recv(uint8_t& proto, IPAddr& src, IPAddr& dst)
+        throw (std::runtime_error);
+
+    // Nada de andar copiando placas...
+    private:
+    IPIn(const IPIn&);
+    IPIn& operator=(const IPIn&);
+
+};
+
+#endif // _IPIN_H_
+
+// vim: set et sw=4 sts=4 :
diff --git a/practicas/pipi-2da-entrega/src/ipout.cpp b/practicas/pipi-2da-entrega/src/ipout.cpp
new file mode 100644 (file)
index 0000000..84a3733
--- /dev/null
@@ -0,0 +1,116 @@
+
+#include "ipout.h"
+#include "ipheader.h"
+#include <ctime>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/ipc.h>
+#include <sys/msg.h>
+#ifdef DEBUG
+#include <iostream>
+#endif
+
+/// Constructor
+IPOut::IPOut(const IPAddr& ip, RouteTable& rtable, Dev& forward_que, std::ostream& log):
+    ip(ip), rtable(rtable), forward_que(forward_que), log(log)
+{
+}
+
+void IPOut::drop(const std::string& msg, const std::string& buf)
+{
+    log << "IPOut::drop (" << ip << "): " << msg << "\n\tBuffer: " << buf
+            << "\n";
+}
+
+void IPOut::drop(const std::string& msg, const IPHeader& iph)
+{
+    log << "IPOut::drop (" << ip << "): " << msg << "\n\tIPHeader: " << iph
+            << "\n";
+}
+
+/// Envía un paquete IP
+bool IPOut::send(const std::string& data, uint8_t proto, IPAddr dst, IPAddr src,
+        bool df, uint8_t ttl, uint16_t id)
+    throw (std::runtime_error)
+{
+    // Armamos cabecera
+    if (!src)
+        src = ip;
+    if (!id)
+        id = get_id();
+    IPHeader iph(4, IPHeader::header_len() + data.size(), id, df, 0, 0,
+            ttl, proto, src, dst);
+    // Enviamos
+    return send(iph, data);
+}
+
+/// Envía un paquete IP
+bool IPOut::send(IPHeader iph, std::string data) throw (std::runtime_error)
+{
+    // Buscamos ruta
+    RouteTable::Route* r = rtable.get(iph.dst);
+    if (!r)
+    {
+        // ICMP
+        drop("No existe una ruta para el destino -> ICMP", iph);
+        return false;
+    }
+    // No quieren fragmentar
+    if (iph.df && (IPHeader::header_len() + data.size() > r->mtu))
+    {
+        // Silencioso
+        drop("Tamaño de paquete más grande que MTU y DF=1", iph);
+        return false;
+    }
+    // Fragmenta (de ser necesario)
+    int max_payload = r->mtu - IPHeader::header_len();
+    int cant_frag = data.size() / max_payload;
+    if (data.size() % max_payload)
+        ++cant_frag;
+    for (int i = 0; i < cant_frag; ++i)
+    {
+        IPHeader iph2 = iph;
+        if (i != (cant_frag - 1))
+            iph2.mf = 1;
+        iph2.offset += i * max_payload;
+        iph2.total_len -= i * max_payload;
+        iph2.do_checksum();
+        std::string buf((char*) &iph2, sizeof(IPHeader));
+        buf += data.substr(i * max_payload, max_payload);
+#ifdef DEBUG
+        std::cout << "IPOut::send (" << ip << "): Fragmento " << i
+                << " => IPHeader: " << iph2 << "\n";
+        std::string tmp = data.substr(i * max_payload, max_payload);
+        std::cout << "\tdata (" << tmp.size() << ") = " << tmp << "\n";
+#endif
+        r->iface->transmit(buf, r->gateway ? r->gateway : IPAddr(iph.dst));
+    }
+    return true;
+}
+
+/// Realiza el forwarding de paquetes (en un loop infinito)
+void IPOut::forward_loop()
+    throw (std::runtime_error)
+{
+    while (true)
+    {
+        std::string buf = forward_que.receive();
+        IPHeader iph(buf);
+#ifdef DEBUG
+        std::cout << "IPOut::forward_loop (" << ip << "): A forwardear (id "
+                << iph.id << ", offset " << iph.offset << ")\n";
+#endif
+        send(iph, buf.substr(iph.header_len()));
+    }
+}
+
+/// Obtiene un identificador para el paquete
+uint16_t IPOut::get_id() const
+{
+    static uint16_t st = time(NULL);
+    uint16_t tt = time(NULL);
+    return (tt == st) ? ++st : tt;
+}
+
+// vim: set et sw=4 sts=4 :
diff --git a/practicas/pipi-2da-entrega/src/ipout.h b/practicas/pipi-2da-entrega/src/ipout.h
new file mode 100644 (file)
index 0000000..96cbbb6
--- /dev/null
@@ -0,0 +1,61 @@
+#ifndef _IPOUT_H_
+#define _IPOUT_H_
+
+#include "ipaddr.h"
+#include "ipheader.h"
+#include "routetable.h"
+#include <iostream>
+#include <string>
+#include <stdexcept>
+
+/// IP de envío
+struct IPOut
+{
+
+    /// Dirección MAC
+    IPAddr ip;
+
+    /// Dispositivo de logging
+    RouteTable& rtable;
+
+    /// Cola para forwardear paquetes
+    Dev& forward_que;
+
+    /// Dispositivo de logging
+    std::ostream& log;
+
+    /// Constructor
+    IPOut(const IPAddr& ip, RouteTable& rtable, Dev& forward_que,
+            std::ostream& log = std::cout);
+
+    /// Descarta un paquete
+    void drop(const std::string& msg, const std::string& buf);
+    void drop(const std::string& msg, const IPHeader& iph);
+
+    /// Envía un paquete IP a armar (y forwardea los encolados, de haber)
+    bool send(const std::string& data, uint8_t proto, IPAddr dst,
+            IPAddr src = 0, bool df = 0, uint8_t ttl = 64, uint16_t id = 0)
+        throw (std::runtime_error);
+
+    /// Envía un paquete IP ya armado
+    bool send(IPHeader iph, std::string data) throw (std::runtime_error);
+
+    /// Realiza el forwarding de paquetes (en un loop infinito)
+    void forward_loop() throw (std::runtime_error);
+
+    /// Obtiene un identificador para el paquete
+    uint16_t get_id() const;
+
+    /// Se fija si hay paquetes a forwardear (y devuelve cuantos hay)
+    unsigned to_forward();
+
+    // Nada de andar copiando...
+    private:
+    IPOut(const IPOut&);
+    IPOut& operator=(const IPOut&);
+
+};
+
+#endif // _IPOUT_H_
+
+// vim: set et sw=4 sts=4 :
diff --git a/practicas/pipi-2da-entrega/src/libtcp.c b/practicas/pipi-2da-entrega/src/libtcp.c
new file mode 100644 (file)
index 0000000..68a6d2c
--- /dev/null
@@ -0,0 +1,207 @@
+/* LibTcp - Released underOpen Software License v. 2.0
+ *
+ * This Open Software License (the "License") applies to any original work of authorship 
+ * (the "Original Work") whose owner (the "Licensor") has placed the following notice 
+ * immediately following the copyright notice for the Original Work:
+ *
+ *     Licensed under the Open Software License version 2.0
+ *
+ * See http://www.opensource.org/licenses/osl-2.0.php or the LICENSE file for more
+ * details.
+ */
+
+#include "libtcp.h"
+
+/** Abre un socket en modo activo para establecer una conexión con un servidor.
+ *
+ * Esta función es utilizada por los clientes para establecer una conexión TCP
+ * con un servidor. 
+ *
+ * \param servidor Nombre del host server
+ * \param port Número del puerto
+ * \return >0 El descriptor del socket, si se conecto al servidor.
+ * \return -2 Si no existe el nombre del servidor.
+ * \return -1 Si hubo error en la conexion y se debe consultar errno.
+ */
+int libtcp_open_activo (const char *server, int port)
+{
+       int sockfd; /* socket de la conexion */
+       struct sockaddr_in serv_addr;
+       struct hostent *ptr_server; /*puntero a dir del server(gethostbyname)*/
+
+       /* Borrar la estructura (poner en cero) */ 
+       bzero ((char *) &serv_addr, sizeof(serv_addr));
+       
+       /*      Inicializo familia de direcciones (protocolo IP) */
+       serv_addr.sin_family = AF_INET;
+
+       /* Cargar port en el socket: Convertir Host-TO-Network-Short integer */
+       serv_addr.sin_port = htons (port);
+
+       /* Cargo dirección del server en el socket. Convertir nombre del host en su direccion */
+       ptr_server = gethostbyname (server); 
+       if (ptr_server == NULL) {
+               /* No existe nombre de host. Posible falla en resolución de nombre */
+               return -2;
+       }
+       memcpy (&serv_addr.sin_addr, ptr_server->h_addr, ptr_server->h_length);
+
+       /* Abro como un socket de TCP (Internet stream socket) */
+       if ((sockfd = socket (AF_INET, SOCK_STREAM, 0)) < 0) {
+               /* Error en la creacion del socket */
+               return -1;
+       }
+
+       if (connect (sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) {
+               /* TODO : Deberia ser un codigo de error diferente, asi puedo diferenciarlos */
+               return -1;
+       }
+
+  return sockfd;
+}
+
+/** Abre un socket en modo pasivo usando protocolo TCP.
+ *
+ * La función se encarga de inicializar y crear el socket, y
+ * luego enlazarla con el SO.
+ * 
+ * \param port Puerto sobre el cual atiende este servidor
+ * \return >0 El socket, si la operacion fue exitosa
+ * \return <0 Si hubo un error (ver errno)
+ */
+int libtcp_open_pasivo (int port)
+{
+       char mostrar[80]; /* mensajes en la pantalla */ 
+       int     sockfd; /* socket que sirve como template */ 
+       struct sockaddr_in      serv_addr;
+
+       bzero ((char *)&serv_addr, sizeof (serv_addr));
+       serv_addr.sin_family = AF_INET; /* Familia protocolos TCP/IP */
+       serv_addr.sin_addr.s_addr = htonl (INADDR_ANY); /* Cualquier cliente */ 
+       serv_addr.sin_port = htons ((unsigned short)port); /* Port en formato red */
+
+       /* Crea un socket para TCP (un Internet stream socket) */
+       if ((sockfd = socket (AF_INET, SOCK_STREAM, 0)) < 0) {
+               return -1;
+       }
+
+       // Reusamos address
+       int yes = 1;
+       if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (char *) &yes,
+                       sizeof(yes)) < 0)
+       {
+               perror ("setsockopt");
+               close (sockfd);
+               return -1;
+       }
+
+#ifdef DEBUG2
+       sprintf (mostrar, "LibTcp::ServerPasivo: socket creado %d\n", sockfd);
+       write (fileno(stdout), mostrar, strlen (mostrar));
+#endif
+
+       /* Vincular el socket con la direccion local */
+       if (bind (sockfd, (struct sockaddr *) &serv_addr, sizeof (serv_addr)) < 0) {
+               return -1;
+       }
+
+#ifdef DEBUG2
+       sprintf (mostrar, "LibTcp::Server: se hizo el bind\n");
+       write(fileno(stdout), mostrar, strlen(mostrar));
+#endif
+
+  /* Definir la cola de espera = hasta 5 clientes */
+       listen(sockfd, 5);
+
+#ifdef DEBUG2
+       sprintf (mostrar, "LibTcp::Server: se hizo el listen con el socket %d\n", sockfd);
+       write(fileno(stdout), mostrar, strlen(mostrar));
+#endif
+
+       return sockfd;
+}
+
+/** Lee de a un byte por vez a un buffer hasta encontrar un "\n".
+ * 
+ *  La cadena leída es terminada en "\0".
+ *
+ *  \return El tamaño, en caracteres, de la cadena leida.
+ *     \param fd       Descriptor del socket
+ *     \param ptr Puntero al buffer 
+ *     \param maxlong Tamaño del buffer (en bytes)
+ *     \TODO Soporte de caracteres multibyte
+ */
+int libtcp_receive (int fd, char *ptr, unsigned int maxlong)
+{
+       unsigned n;
+       int     car;
+       char    c;
+
+       for (n = 0; n < maxlong; n++) {
+               if ((car = read (fd, &c, sizeof (char))) == 1) {
+                       *ptr++ = c;
+                       if (c == '\n')
+                               break;
+                       } else if (car == 0) {
+                               if (n == 1)
+                                       /* EOF, sin datos leidos */
+                                       return 0;
+                               else
+                                       break;          /* EOF, se leyo algo */
+               } else
+                       return -1;
+       }
+
+       *ptr = '\0';
+       return n;
+}
+
+/** Lee una informacion binaria */
+int libtcp_receive_bin (int fd, void *ptr, unsigned int n)
+{
+       int     nfaltan, nrecibidos;
+       char *p = (char*) ptr;
+
+       nfaltan = n;
+       while (nfaltan > 0) {
+               nrecibidos = read (fd, p, nfaltan);
+               if (nrecibidos <= 0)
+                       return nrecibidos;
+
+               nfaltan -= nrecibidos;
+               p       += nrecibidos;
+       }
+
+       return n - nfaltan;
+}
+
+
+/** Escribe n bytes sobre un descriptor.
+ *
+ *  Si no se escribieron n bytes, trata de repetir hasta que se hayan escrito
+ *  los n bytes.
+ *
+ *  Se debe usar esta funcion cuando el descriptor en un stream socket.
+ *  
+ *     \param fd Descriptor del socket
+ *     \param ptr Puntero al mensaje
+ *     \param n cantidad de bytes
+ */
+int libtcp_send (int fd, const void *ptr, unsigned int n)
+{
+       int     nfaltan, nenviados;
+       const char *p = (const char *) ptr;
+
+       nfaltan = n;
+       while (nfaltan > 0) {
+               nenviados = write (fd, p, nfaltan);
+               if (nenviados <= 0)
+                       return nenviados;
+
+               nfaltan -= nenviados;
+               p       += nenviados;
+       }
+
+       return n - nfaltan;
+}
+
diff --git a/practicas/pipi-2da-entrega/src/libtcp.h b/practicas/pipi-2da-entrega/src/libtcp.h
new file mode 100644 (file)
index 0000000..4964c0f
--- /dev/null
@@ -0,0 +1,40 @@
+/* LibTcp - Released underOpen Software License v. 2.0
+ *
+ * This Open Software License (the "License") applies to any original work of authorship 
+ * (the "Original Work") whose owner (the "Licensor") has placed the following notice 
+ * immediately following the copyright notice for the Original Work:
+ *
+ *     Licensed under the Open Software License version 2.0
+ *
+ * See http://www.opensource.org/licenses/osl-2.0.php or the LICENSE file for more
+ * details.
+ */
+
+#ifndef _LIBTCP_COMMON_H_
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <signal.h>
+#include <sys/wait.h>
+#include <sys/resource.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+
+#define        LIBTCP_DEFAULT_UDP_PORT 5000
+#define        LIBTCP_DEFAULT_TCP_PORT 5000
+
+extern int errno;
+
+int libtcp_open_activo (const char *server, int port);
+int libtcp_open_pasivo (int port);
+int libtcp_receive (int fd, char *ptr, unsigned int maxlong);
+int libtcp_receive_bin (int fd, void *ptr, unsigned int maxlong);
+int libtcp_send (int fd, const void *ptr, unsigned int n);
+
+#endif // _LIBTCP_COMMON_H_
+
diff --git a/practicas/pipi-2da-entrega/src/nameserver.cpp b/practicas/pipi-2da-entrega/src/nameserver.cpp
new file mode 100644 (file)
index 0000000..86f18e8
--- /dev/null
@@ -0,0 +1,472 @@
+#include "nameserver.h"
+#include <sstream>
+#include <algorithm>
+#include <iterator>
+#include <sstream>
+#include <functional>
+#ifdef DEBUG
+#include <iostream>
+#endif
+
+#define DEBUG_RESOLV
+
+NameServer::Name::Name(const std::string& s)
+{
+    std::istringstream iss(s);
+    std::string tok;
+    while (std::getline(iss, tok, '.'))
+        push_back(tok);
+}
+
+std::ostream& operator<< (std::ostream& os, const NameServer::Name& name)
+{
+    if (name.empty())
+        return os;
+    std::copy(name.begin(), name.end() - 1,
+            std::ostream_iterator< std::string >(os, "."));
+    return os << name.back();
+}
+
+NameServer::Name::operator std::string () const
+{
+    std::stringstream ss;
+    ss << *this;
+    return ss.str();
+}
+
+/// Parsea una zona
+static std::istream& parsezone(std::istream& is, NameServer::Zone& z)
+    throw (std::runtime_error)
+{
+    std::string line, sname, ip;
+    // [dominio] [ttl] [parent ip]
+    while (std::getline(is, line) && (line == "")); // Salteo líneas en blanco
+    if (!is)
+        return is;
+    std::istringstream iss(line);
+    if (!(iss >> sname >> z.ttl >> ip))
+        throw std::runtime_error("Error al parsear");
+    z.name = sname;
+#ifdef DEBUG_PARSER
+    std::cerr << "parsezone: IP = " << ip << "\n\n";
+#endif
+    z.parent = IPAddr(ip);
+    // un record por linea, sin líneas vacías
+    // [name] [type] [ip]
+    while (std::getline(is, line) && (line != ""))
+    {
+        iss.clear();
+        iss.str(line);
+        std::string key, type;
+        if (!(iss >> key >> type >> ip))
+            throw std::runtime_error("Error al parsear");
+        typedef NameServer::Record Rec;
+#ifdef DEBUG_PARSER
+        std::cerr << "parsezone: IP = " << ip << "\n\n";
+#endif
+        Rec r((type == "NS") ? Rec::NS : Rec::A, IPAddr(ip));
+        z.records.insert(NameServer::Zone::records_t::value_type(key, r));
+    }
+#ifdef DEBUG_PARSER
+    std::cerr << "parsezone: " << z << "\n\n";
+#endif
+    return is;
+}
+
+/// Constructor
+NameServer::Zone::Zone(std::string sname, size_t ttl, const IPAddr& parent):
+    name(sname), ttl(ttl), parent(parent)
+{
+}
+
+/// Constructor
+NameServer::Zone::Zone(std::istream& is)
+    throw (std::runtime_error)
+{
+    // Parsea la zona
+    if (!parsezone(is, *this))
+        throw std::runtime_error("Error de parser, no hay zona");
+}
+
+/// Limpia una zona
+void NameServer::Zone::clear()
+{
+    name.clear();
+    records.clear();
+}
+
+/// Constructor
+NameServer::NameServer(std::istream& is, IPIn& ipin, IPOut& ipout,
+        DevQue& req_que, DevQue& res_que, DevQue& snd_que)
+    throw (std::runtime_error):
+    ipin(ipin), ipout(ipout), req_que(req_que), res_que(res_que),
+        snd_que(snd_que)
+{
+    Zone z;
+    while (parsezone(is, z))
+    {
+        zones.push_back(z);
+        z.clear();
+#ifdef DEBUG_PARSER
+        std::cerr << "NameServer: " << z << "\n\n";
+#endif
+    }
+}
+
+/// Devuelve la parte izquierda de n, si la parte derecha coincide exactamente
+/// con m, si no devuelve un vector vacío.
+/// Elemplo: name_split("mi.domi.nio", "domi.nio") == ["mi"]
+///          name_split("dos.mi.domi.nio", "domi.nio") == ["dos", "mi"]
+///          name_split("domi.nio", "domi.nio") == []
+///          name_split("papeli.nio", "domi.nio") == []
+static NameServer::Name
+name_split(NameServer::Name n, NameServer::Name m)
+{
+    NameServer::Name r;
+    std::reverse(n.begin(), n.end());
+    std::reverse(m.begin(), m.end());
+    // Si m es más grande o igual que n, no hay nada que hacer
+    if (n.size() <= m.size())
+        return r;
+    // Si no coincide la parte derecha, no hay nada que hacer
+    NameServer::Name::size_type i;
+    for (i = 0; i < m.size(); ++i)
+        if (n[i] != m[i])
+            return r;
+    // Si era todo igual y sobran cosas, devolvemos lo que "sobra"
+    while (i < n.size())
+        r.push_back(n[i++]);
+    std::reverse(r.begin(), r.end());
+#ifdef DEBUG_NAME
+    std::cerr << "name_split(" << n << ", " << m << ") -> " << r << "\n";
+#endif
+    return r;
+}
+
+/// Devuelve -1 si es un nombre "hijo" (la parte derecha de n está contenida
+/// completamente en m, pero m y n no son iguales), 0 si m == n y 1 si es
+/// "padre" (m no coincide con la parte derecha de n).
+/// Elemplo: namecmp("mi.domi.nio", "domi.nio") == -1
+///          namecmp("otra.cosa", "domi.nio") == 1
+///          namecmp("papeli.nio", "domi.nio") == 1
+///          namecmp("domi.nio", "domi.nio") == 0
+/*enum name_cmp_t
+{
+    NC_DIRECT_CHILD,  ///> Hijo directo, es decir, está en la zona m
+    NC_CHILD,         ///> Hijo indirecto, está en una zona que cuelga de m
+    NC_EQUAL,         ///> Es el host de la zona m
+    NC_DIRECT_PARENT, ///> Padre directo, es decir, coincide en parte con m
+    NC_PARENT         ///> Padre indirecto, es completamente distinto a m
+};*/
+#if 0
+static int name_cmp(const NameServer::Name& n, const NameServer::Name& m)
+{
+    // Si m es más grande que n, seguro es padre
+    if (n.size() < m.size())
+        return 1;
+    // Si no coincide la parte derecha, seguro es padre
+    NameServer::Name::size_type i;
+    for (i = m.size(); i > 0; --i)
+        if (n[i-1] != m[i-1])
+            return 1;
+    // Si era todo igual y sobran cosas, es hijo
+    if (i)
+        return -1;
+    // Si no, son iguales.
+    return 0;
+}
+#endif
+
+struct search_zone: std::unary_function< NameServer::Zone, bool >
+{
+    bool local;
+    ResolvProtoResponse resp;
+    const NameServer::Name& name;
+    search_zone(const NameServer::Name& n): local(false), name(n) {}
+    bool operator() (const NameServer::Zone& z)
+    {
+        bool found = false;
+        NameServer::Name local_part = name_split(name, z.name);
+        if (!local_part.empty()) // Está en esta zona
+        {
+            local = true;
+            std::string n = local_part.back(); // Obtengo última parte
+            // busco
+            typedef NameServer::Zone::records_t::const_iterator itt;
+            std::pair<itt, itt> p = z.records.equal_range(n);
+            for (; p.first != p.second; ++p.first)
+            {
+                const NameServer::Record& r = (*p.first).second;
+                // Tiene que buscar solo A porque era un nombre
+                if ((local_part.size() == 1) && (r.type != NameServer::Record::A))
+                    continue;
+                // Tiene que seguir para abajo, solo busca NS
+                if ((local_part.size() > 1) && r.type != NameServer::Record::NS)
+                    continue;
+                found = true;
+                resp.ret = (r.type == NameServer::Record::NS) ? RP_RES_NS
+                    : RP_RES_A;
+                resp.ttl = z.ttl;
+                resp.ips.push_back(r.ip);
+            }
+        }
+        return found;
+    }
+};
+
+/// Resuelve un nombre de forma directa (no recursiva)
+ResolvProtoResponse NameServer::resolv_direct(const Name& n)
+{
+#ifdef DEBUG_RESOLV
+    std::cerr << "resolv_direct -> tratando de resolver: " << n << "\n";
+#endif
+    search_zone zs(n);
+    bool found;
+    for (zones_t::const_iterator i = zones.begin(); i!= zones.end(); ++i)
+        if ((found = zs(*i)))
+            break;
+    if (found)
+    {
+#ifdef DEBUG_RESOLV
+        std::cerr << "resolv_direct found (local/hijo): " << zs.resp << "\n";
+#endif
+        return zs.resp;
+    }
+    if (zs.local)
+    {
+#ifdef DEBUG_RESOLV
+        std::cerr << "resolv_direct NOT FOUND (es local pero no existe)\n";
+#endif
+        return ResolvProtoResponse(RP_RES_NOTFOUND);
+    }
+    cache_t::const_iterator i = cache.find(n);
+    // TODO TTL!?!
+    if (i != cache.end())
+    {
+#ifdef DEBUG_RESOLV
+        std::cerr << "resolv_direct found (en cache): " << i->second << "\n";
+#endif
+        const CacheRecord& cr = i->second;
+        return ResolvProtoResponse(RP_RES_A, cr.ttl, cr.ips);
+    }
+    if (zones.size())
+    {
+        // Busco una zona con padre para ver si puedo "trepar"
+        for (zones_t::const_iterator i = zones.begin(); i != zones.end(); ++i)
+        {
+#ifdef DEBUG_RESOLV
+            std::cerr << "resolv_direct -> evaluando padre " << i->parent
+                << "\n";
+#endif
+            if (i->parent != IPAddr(0))
+            {
+#ifdef DEBUG_RESOLV
+                std::cerr << "resolv_direct found (al padre): "
+                    << i->parent << "\n";
+#endif
+                ResolvProtoResponse rpr(RP_RES_NS, i->ttl);
+                rpr.ips.push_back(i->parent);
+                return rpr;
+            }
+        }
+    }
+#ifdef DEBUG_RESOLV
+    std::cerr << "resolv_direct NOT FOUND (no hay padre)\n";
+#endif
+    // No hay padre, no puedo hacer nada más
+    return ResolvProtoResponse(RP_RES_NOTFOUND);
+}
+
+/// Resuelve un nombre de forma recursiva
+ResolvProtoResponse NameServer::resolv_recursive(const Name& n)
+{
+    ResolvProtoResponse rpr = resolv_direct(n);
+    switch (rpr.ret)
+    {
+        case RP_RES_NS:
+#ifdef DEBUG_RESOLV
+            std::cerr << "resolv_recursive -> redirect a " << rpr << "\n";
+#endif
+            return resolv_recursive_r(n, rpr); // Sigo "bajando"
+        case RP_RES_A:
+#ifdef DEBUG_RESOLV
+            std::cerr << "resolv_recursive -> gotcha! " << rpr << "\n";
+#endif
+            // TODO agregar a cache
+            break;
+    }
+    return rpr; // Devuelvo el A o NOTFOUND
+}
+
+/// Resuelve un nombre de forma recursiva entrando a otros ns
+ResolvProtoResponse NameServer::resolv_recursive_r(const Name& n,
+        ResolvProtoResponse rpr)
+{
+    ResolvProtoResponse r;
+    for (ResolvProtoResponse::ipvec_t::const_iterator ip = rpr.ips.begin();
+            ip != rpr.ips.end(); ++ip)
+    {
+        r = query(n, *ip);
+        switch (r.ret)
+        {
+            case RP_RES_NS:
+#ifdef DEBUG_RESOLV
+                std::cerr << "resolv_recursive_r -> redirect a " << r << "\n";
+#endif
+                return resolv_recursive_r(n, r); // Sigo "bajando"
+            case RP_RES_NOTFOUND:
+#ifdef DEBUG_RESOLV
+                std::cerr << "resolv_recursive_r -> NOT FOUND en " << *ip
+                    << ", sigo probando\n";
+#endif
+                break; // Sigo probando del mismo nivel
+            case RP_RES_A:
+#ifdef DEBUG_RESOLV
+                std::cerr << "resolv_recursive_r -> gotcha! " << r << "\n";
+#endif
+                // TODO agregar a cache
+                return r; // Gotcha!
+        }
+    }
+#ifdef DEBUG_RESOLV
+    std::cerr << "resolv_recursive_r -> NOT FOUND, no hay más por hacer\n";
+#endif
+    return r; // NOTFOUND
+}
+
+/// Consulta a otro name server sobre un nombre
+ResolvProtoResponse NameServer::query(const Name& n, const IPAddr& ip)
+{
+    ResolvProtoRequest r(std::string(n), RP_REQ_DIRECT);
+#ifdef DEBUG_RESOLV
+    std::cerr << "query -> pidiendo " << r << " a " << ip << "\n";
+#endif
+    // Envía a través de la cola de envío
+    snd_que.transmit(std::string(r), ip);
+    Dev::mac_type mac = ip;
+    std::string buf = res_que.receive(mac);
+    ResolvProtoResponse resp(buf);
+#ifdef DEBUG_RESOLV
+    std::cerr << "query -> recibido " << resp << " de " << ip << "\n";
+#endif
+    return resp;
+}
+
+void NameServer::recv_loop()
+{
+    while (true)
+    {
+        IPAddr src, dst;
+        uint8_t proto;
+        std::string s = ipin.recv(proto, src, dst);
+#ifdef DEBUG_RESOLV
+            std::cout << "NameServer::recv_loop() -> recibido len=" << s.size()
+                << " de " << src << " para " << dst << " (proto = "
+                << unsigned(proto) << ")\n";
+#endif
+        if (proto == NAMESERVER_PROTO) // Si es para nosotros
+        {
+            rp_pkt_type_t type;
+            memcpy(&type, s.c_str(), sizeof(uint8_t));
+            switch (type)
+            {
+                // Request
+                case RP_REQ_DIRECT:
+                case RP_REQ_RECURSIVE:
+#ifdef DEBUG_RESOLV
+                    std::cout << "---> " << ResolvProtoRequest(s) << "\n";
+#endif
+                    req_que.transmit(s, src); // Encolo
+                    break;
+                // Response
+                default:
+#ifdef DEBUG_RESOLV
+                    std::cout << "---> " << ResolvProtoResponse(s) << "\n";
+#endif
+                    res_que.transmit(s, src); // Encolo
+            }
+        }
+    }
+}
+
+void NameServer::send_loop()
+{
+    while (true)
+    {
+        if (!req_que.empty())
+        {
+            Dev::mac_type mac = 0;
+            ResolvProtoRequest req(req_que.receive(mac));
+#ifdef DEBUG_RESOLV
+            std::cout << "NameServer::send_loop() -> recibido " << req << "\n";
+#endif
+            ResolvProtoResponse res
+                = (req.query_type == RP_REQ_DIRECT)
+                ? resolv_direct(req.name)
+                : resolv_recursive(req.name);
+#ifdef DEBUG_RESOLV
+            std::cout << "NameServer::send_loop() -> respondo " << res << "\n";
+#endif
+            ipout.send(res, NAMESERVER_PROTO, IPAddr(mac));
+        }
+        else if (!snd_que.empty()) // Hay un request para enviar
+        {
+            Dev::mac_type mac = 0;
+            std::string buf = snd_que.receive(mac);
+#ifdef DEBUG_RESOLV
+            std::cout << "NameServer::send_loop() -> envío request "
+                << ResolvProtoRequest(buf) << "\n";
+#endif
+            ipout.send(buf, NAMESERVER_PROTO, IPAddr(mac));
+        }
+        else // No hay nada, esperamos un rato
+        {
+            usleep(10000);
+        }
+    }
+}
+
+std::ostream& operator<< (std::ostream& os, const NameServer::Record::type_t& t)
+{
+    if (t == NameServer::Record::NS)
+        return os << "NS";
+    else
+        return os << "A";
+}
+
+std::ostream& operator<< (std::ostream& os, const NameServer::Record& r)
+{
+    return os << r.type << " " << r.ip;
+}
+
+std::ostream& operator<< (std::ostream& os,
+        const NameServer::Zone::records_t::value_type& p)
+{
+    return os << p.first << ": " << p.second;
+}
+
+std::ostream& operator<< (std::ostream& os, const NameServer::Zone& z)
+{
+    os << "Zone " << z.name << " " << z.ttl << " " << z.parent << "\n";
+    std::copy(z.records.begin(), z.records.end(), std::ostream_iterator<
+            NameServer::Zone::records_t::value_type >(os, "\n"));
+    return os;
+}
+
+std::ostream& operator<< (std::ostream& os, const NameServer::CacheRecord& cr)
+{
+    os << "CacheRecord(ttl=" << cr.ttl << ", records=";
+    std::copy(cr.ips.begin(), cr.ips.end(),
+            std::ostream_iterator< IPAddr >(os, ","));
+    return os << ")";
+}
+
+std::ostream& operator<< (std::ostream& os, const NameServer& ns)
+{
+    os << "NameServer: zones[" << ns.zones.size() << "] (\n\n";
+    std::copy(ns.zones.begin(), ns.zones.end(),
+            std::ostream_iterator< NameServer::Zone >(os, "\n"));
+    return os << ")";
+}
+
+// vim: set et sw=4 sts=4 :
diff --git a/practicas/pipi-2da-entrega/src/nameserver.h b/practicas/pipi-2da-entrega/src/nameserver.h
new file mode 100644 (file)
index 0000000..d9b8a4f
--- /dev/null
@@ -0,0 +1,129 @@
+#ifndef _NAMESERVER_H_
+#define _NAMESERVER_H_
+
+#include "devque.h"
+#include "ipaddr.h"
+#include "resolvproto.h"
+#include <string>
+#include <vector>
+#include <map>
+#include <istream>
+#include <ostream>
+#include <stdexcept>
+
+#define NAMESERVER_PROTO 59
+
+/// Petición del resolver a un nameserver
+struct NameServer
+{
+
+    /// Nombre de un dominio dividido en tokens
+    struct Name: std::vector< std::string >
+    {
+        /// Constructor
+        Name() {}
+        Name(const std::string& name);
+        operator std::string () const;
+    };
+
+    /// Registro de una zona
+    struct Record
+    {
+        /// Tipo de registro
+        enum type_t { A, NS };
+        type_t type;
+        /// Dirección IP del registro
+        IPAddr ip;
+        /// Constructor
+        Record(type_t t, const IPAddr& i): type(t), ip(i) {}
+    };
+
+    /// Zona
+    struct Zone
+    {
+        /// Nombre
+        Name name;
+        /// Time to live
+        size_t ttl;
+        /// Nodo padre
+        IPAddr parent;
+        /// Registros
+        typedef std::multimap< std::string, Record > records_t;
+        records_t records;
+        /// Constructores
+        Zone() {}
+        Zone(std::string sname, size_t ttl, const IPAddr& parent);
+        Zone(std::istream& is) throw (std::runtime_error);
+        /// Limpia una zona
+        void clear();
+    };
+
+    /// Zonas para las que este servidor de nombres es autoridad
+    typedef std::vector< Zone > zones_t;
+    zones_t zones;
+
+    /// Cache de un registro
+    struct CacheRecord
+    {
+        /// Time to live
+        size_t ttl;
+        /// Dirección IP del registro
+        typedef ResolvProtoResponse::ipvec_t ipvec_t;
+        ipvec_t ips;
+        /// Constructor
+        CacheRecord(): ttl(0) {}
+        CacheRecord(size_t ttl, const ipvec_t& ips):
+            ttl(ttl), ips(ips) {}
+    };
+
+    /// Cache de records
+    typedef std::map< Name, CacheRecord > cache_t;
+    cache_t cache;
+
+    /// IP
+    IPIn& ipin;
+    IPOut& ipout;
+
+    /// Colas de recepción
+    DevQue& req_que; // De requests
+    DevQue& res_que; // De responses
+
+    /// Cola de envío
+    DevQue& snd_que;
+
+    /// Constructor
+    NameServer(std::istream& is, IPIn& ipin, IPOut& ipout, DevQue& req_que,
+            DevQue& res_que, DevQue& snd_que) throw (std::runtime_error);
+
+    /// Resuelve un nombre de forma directa (no recursiva)
+    ResolvProtoResponse resolv_direct(const Name& n);
+
+    /// Resuelve un nombre de forma recursiva
+    ResolvProtoResponse resolv_recursive(const Name& n);
+
+    /// Consulta a otro name server sobre un nombre
+    ResolvProtoResponse query(const Name&n, const IPAddr& ip);
+
+    /// Loop que recibe y carga los paquetes en las colas para ser procesados
+    void recv_loop();
+
+    /// Loop que envía los paquetes de la cola de envío
+    void send_loop();
+
+    private:
+    /// Resuelve un nombre de forma recursiva entrando a otros ns
+    ResolvProtoResponse resolv_recursive_r(const Name& n,
+            ResolvProtoResponse rpr);
+
+};
+
+/// Impresión (para debug)
+std::ostream& operator<< (std::ostream& os, const NameServer& ns);
+std::ostream& operator<< (std::ostream& os, const NameServer::Name& name);
+std::ostream& operator<< (std::ostream& os, const NameServer::Record& r);
+std::ostream& operator<< (std::ostream& os, const NameServer::Zone& z);
+std::ostream& operator<< (std::ostream& os, const NameServer::CacheRecord& cr);
+
+#endif // _NAMESERVER_H_
+
+// vim: set et sw=4 sts=4 :
diff --git a/practicas/pipi-2da-entrega/src/resolvproto.cpp b/practicas/pipi-2da-entrega/src/resolvproto.cpp
new file mode 100644 (file)
index 0000000..f55bbf2
--- /dev/null
@@ -0,0 +1,104 @@
+#include "resolvproto.h"
+#include <cstdlib>
+#include <algorithm>
+#include <iterator>
+
+/// Constructor
+ResolvProtoRequest::ResolvProtoRequest(std::string name, rp_pkt_type_t query_type):
+    query_type(query_type), name(name)
+{}
+
+/// Constructor a partir de un buffer
+ResolvProtoRequest::ResolvProtoRequest(std::string buf)
+{
+    memcpy(&query_type, buf.c_str(), sizeof(uint8_t));
+    uint16_t size;
+    memcpy(&size, buf.c_str() + sizeof(uint8_t), sizeof(uint16_t));
+    name.assign(buf.c_str() + sizeof(uint8_t) + sizeof(uint16_t), size);
+}
+
+/// Convierte a un buffer
+ResolvProtoRequest::operator std::string () const
+{
+    std::string buf((char*)&query_type, sizeof(uint8_t));
+    uint16_t size = name.size();
+    buf.append((char*)&size, sizeof(uint16_t));
+    buf.append(name);
+    return buf;
+}
+
+size_t ResolvProtoRequest::packet_size() const
+{
+    return sizeof(uint8_t) + sizeof(uint16_t) + name.size();
+}
+
+/// Impresión de request
+std::ostream& operator<< (std::ostream& os, const ResolvProtoRequest& rpr)
+{
+    return os << "ResolvProtoRequest(query_type=" << unsigned(rpr.query_type)
+        << ", name=" << rpr.name << ")";
+}
+
+/// Constructor
+ResolvProtoResponse::ResolvProtoResponse(): ret(RP_RES_NOTFOUND), ttl(0)
+{
+}
+
+/// Constructor
+ResolvProtoResponse::ResolvProtoResponse(std::string buf)
+{
+    memcpy(&ret, buf.c_str(), sizeof(uint8_t));
+    memcpy(&ttl, buf.c_str() + sizeof(uint8_t), sizeof(uint32_t));
+    uint8_t count;
+    memcpy(&count, buf.c_str() + sizeof(uint8_t) + sizeof(uint32_t),
+            sizeof(uint8_t));
+    ips.reserve(count);
+    for (uint8_t i = 0; i < count; ++i)
+    {
+        uint32_t ip;
+        memcpy(&ip, buf.c_str() + 2 * sizeof(uint8_t)
+                + sizeof(uint32_t) * (i + 1), sizeof(uint32_t));
+        ips.push_back(ip);
+    }
+}
+
+/// Constructor
+ResolvProtoResponse::ResolvProtoResponse(rp_pkt_type_t ret, uint32_t ttl,
+        const ipvec_t& ips):
+    ret(ret), ttl(ttl), ips(ips)
+{}
+
+/// Convierte a buffer
+ResolvProtoResponse::operator std::string () const
+{
+    std::string buf((char*)&ret, sizeof(uint8_t));
+    buf.append((char*)&ttl, sizeof(uint32_t));
+    uint8_t count = ips.size();
+    buf.append((char*)&count, sizeof(uint8_t));
+    for (ipvec_t::const_iterator i = ips.begin(); i != ips.end(); ++i)
+    {
+        uint32_t ip = *i;
+        buf.append((char*)&ip, sizeof(uint32_t));
+    }
+    return buf;
+}
+
+size_t ResolvProtoResponse::packet_size() const
+{
+    return 2 * sizeof(uint8_t) + (ips.size() + 1) * sizeof(uint32_t);
+}
+
+/// Impresión de response
+std::ostream& operator<< (std::ostream& os, const ResolvProtoResponse& rpr)
+{
+    os << "ResolvProtoResponse(ret=" << unsigned(rpr.ret)
+        << ", ttl=" << rpr.ttl;
+    if (rpr.ips.empty())
+        return os << ")";
+    os << ", ";
+    std::copy(rpr.ips.begin(), rpr.ips.end() - 1,
+            std::ostream_iterator< IPAddr >(os, ", "));
+    return os << rpr.ips.back() << ")";
+}
+
+// vim: set et sw=4 sts=4 :
diff --git a/practicas/pipi-2da-entrega/src/resolvproto.h b/practicas/pipi-2da-entrega/src/resolvproto.h
new file mode 100644 (file)
index 0000000..2100771
--- /dev/null
@@ -0,0 +1,104 @@
+#ifndef _RESOLVPROTO_H_
+#define _RESOLVPROTO_H_
+
+#include "ipaddr.h"
+#include "ipin.h"
+#include "ipout.h"
+#include <string>
+#include <vector>
+#include <stdexcept>
+#include <stdint.h>
+
+/// Tipo de petición
+enum rp_pkt_type_t
+{
+    // requests
+    RP_REQ_DIRECT,     ///> Búsqueda directa (inter nameservers)
+    RP_REQ_RECURSIVE,  ///> Búsqueda recursiva (para resolvers)
+    // responses
+    RP_RES_A,          ///> OK, se devolvió un registro A
+    RP_RES_NS,         ///> OK, se devolvió un registro NS (sólo en directo)
+    RP_RES_NOTFOUND,   ///> No se encontró
+    RP_RES_TIMEOUT     ///> Tardó demasiado la consulta
+};
+
+/// Petición de un nameserver
+/// +------------+------------+------------+
+/// | QUERY_TYPE |    SIZE    |    NAME    |
+/// +------------+------------+------------+
+/// /-- 1 byte --/- 2 bytes --/- variable -/
+struct ResolvProtoRequest
+{
+
+    /// Tipo de petición (de tipo rp_pkt_type_t)
+    uint8_t query_type;
+
+    /// Nombre a buscar
+    std::string name;
+
+    /// Constructores
+    ResolvProtoRequest(std::string name, rp_pkt_type_t query_type);
+    ResolvProtoRequest(std::string buf);
+
+    /// Envía por socket
+    void send(IPOut& ipo) const throw (std::runtime_error);
+
+    /// Recibe por socket
+    void recv(IPIn& ipi) throw (std::runtime_error);
+
+    /// Obtiene tamaño del paquete
+    size_t packet_size() const;
+
+    /// Convierte a un string
+    operator std::string () const;
+
+};
+
+/// Impresión de request
+std::ostream& operator<< (std::ostream& os, const ResolvProtoRequest& rpr);
+
+
+/// Respuesta de un nameserver
+/// +-----------+-----------+-----------+-----------+-----------+-----------+
+/// |    RET    |    TTL    |   COUNT   |    IP 1   |    ...    |    IP N   |
+/// +-----------+-----------+-----------+-----------+-----------+-----------+
+/// /-- 1 byte -/- 4 bytes -/-- 1 byte -/- 4 bytes -/- 4 bytes -/- 4 bytes -/
+struct ResolvProtoResponse
+{
+
+    /// Resultado de la respuesta (de tipo rp_pkt_type_t)
+    uint8_t ret;
+
+    /// TTL (sólo útil para búsquedas (inter nameserver)
+    uint32_t ttl;
+
+    /// IPs devueltas
+    typedef std::vector< IPAddr > ipvec_t;
+    ipvec_t ips;
+
+    /// Constructores
+    ResolvProtoResponse();
+    ResolvProtoResponse(rp_pkt_type_t ret, uint32_t ttl = 0,
+            const ipvec_t& ips = ipvec_t());
+    ResolvProtoResponse(std::string buf);
+
+    /// Envía por socket
+    void send(IPOut& ipo) const throw (std::runtime_error);
+
+    /// Recibe por socket
+    void recv(IPIn& ipi) throw (std::runtime_error);
+
+    /// Obtiene tamaño del paquete
+    size_t packet_size() const;
+
+    /// Convierte a un string
+    operator std::string () const;
+
+};
+
+/// Impresión de response
+std::ostream& operator<< (std::ostream& os, const ResolvProtoResponse& rpr);
+
+#endif // _RESOLVPROTO_H_
+
+// vim: set et sw=4 sts=4 :
diff --git a/practicas/pipi-2da-entrega/src/routetable.cpp b/practicas/pipi-2da-entrega/src/routetable.cpp
new file mode 100644 (file)
index 0000000..40de2d3
--- /dev/null
@@ -0,0 +1,33 @@
+#include "routetable.h"
+#ifdef DEBUG
+#include <iostream>
+#endif
+
+RouteTable::RouteTable(Dev& default_iface): default_iface(default_iface)
+{
+}
+
+void RouteTable::add(const IPAddr& net, const IPAddr& gw, unsigned mtu,
+        unsigned metric, Dev& iface)
+{
+    table[net] = Route(gw, metric, mtu, iface);
+#ifdef DEBUG
+    //std::cout << "Se agregó tabla para " << net << ": gw = " << gw
+    //    << ", metric = " << metric << "\n";
+#endif
+}
+
+void RouteTable::del(const IPAddr& net)
+{
+    table.erase(net);
+}
+
+RouteTable::Route* RouteTable::get(const IPAddr& dst)
+{
+    // No existe
+    if (table.find(dst) == table.end())
+        return 0;
+    return &table[dst];
+}
+
+// vim: set et sw=4 sts=4 :
diff --git a/practicas/pipi-2da-entrega/src/routetable.h b/practicas/pipi-2da-entrega/src/routetable.h
new file mode 100644 (file)
index 0000000..20f62e8
--- /dev/null
@@ -0,0 +1,46 @@
+#ifndef _ROUTETABLE_H_
+#define _ROUTETABLE_H_
+
+#include "dev.h"
+#include "ipaddr.h"
+#include <map>
+
+/// Tabla de ruteo
+struct RouteTable
+{
+
+    /// Ruta
+    struct Route
+    {
+        IPAddr gateway;
+        unsigned mtu;
+        unsigned metric;
+        Dev* iface;
+        Route(): gateway(0), mtu(0), metric(0), iface(0) {}
+        Route(const IPAddr& gateway, unsigned mtu, unsigned metric, Dev& iface):
+            gateway(gateway), mtu(mtu), metric(metric), iface(&iface) {}
+    };
+
+    /// Tabla
+    std::map< IPAddr, Route > table;
+
+    /// Interfaz por default
+    Dev& default_iface;
+
+    /// Constructor
+    RouteTable(Dev& default_iface);
+
+    /// Agrega ruta
+    void add(const IPAddr& net, const IPAddr& gw, unsigned mtu, unsigned metric, Dev& iface);
+
+    /// Borra ruta
+    void del(const IPAddr& net);
+
+    /// Obtiene dirección e interfaz por la cual salir para un destino
+    Route* get(const IPAddr& dst);
+
+};
+
+#endif // _ROUTETABLE_H_
+
+// vim: set et sw=4 sts=4 :
diff --git a/practicas/pipi-2da-entrega/src/test.sh b/practicas/pipi-2da-entrega/src/test.sh
new file mode 100755 (executable)
index 0000000..c97dddd
--- /dev/null
@@ -0,0 +1,25 @@
+#!/bin/bash
+#              35                28                25
+# 10.10.10.1 ------ 10.10.10.5 ------ 10.10.10.4 ------ 10.10.10.2
+#                       |
+#                       | 32
+#                       |
+#                  10.10.10.3
+#
+
+# Host 10.10.10.1
+(echo -e '10.10.10.3\nAdios mundo cruel!!!'; sleep 1) \
+       | ./ip 10.10.10.1 0 0 ../rutas_ejemplo/route_10.10.10.1.txt &
+
+# Host 10.10.10.5
+(echo ; sleep 2) \
+       | ./ip 10.10.10.5 1 1 ../rutas_ejemplo/route_10.10.10.5.txt &
+
+# Host 10.10.10.3
+(echo ; sleep 3) \
+       | ./ip 10.10.10.3 0 0 ../rutas_ejemplo/route_10.10.10.3.txt &
+
+# Limpio
+sleep 4
+ipcrm -Q 0x1abcdef1
+ipcrm -Q 0x1abcdef0
diff --git a/practicas/pipi-2da-entrega/src/test2.sh b/practicas/pipi-2da-entrega/src/test2.sh
new file mode 100755 (executable)
index 0000000..cd60ac2
--- /dev/null
@@ -0,0 +1,30 @@
+#!/bin/bash
+#              35                28                25
+# 10.10.10.1 ------ 10.10.10.5 ------ 10.10.10.4 ------ 10.10.10.2
+#                       |
+#                       | 32
+#                       |
+#                  10.10.10.3
+#
+
+# Host 10.10.10.1
+(echo -e '10.10.10.2\nAdios mundo cruel!!!'; sleep 1) \
+       | ./ip 10.10.10.1 0 0 ../rutas_ejemplo/route_10.10.10.1.txt &
+
+# Host 10.10.10.5
+(echo ; sleep 2) \
+       | ./ip 10.10.10.5 1 1 ../rutas_ejemplo/route_10.10.10.5.txt &
+
+# Host 10.10.10.4
+(echo ; sleep 3) \
+       | ./ip 10.10.10.4 1 1 ../rutas_ejemplo/route_10.10.10.4.txt &
+
+# Host 10.10.10.2
+(echo ; sleep 4) \
+       | ./ip 10.10.10.2 0 0 ../rutas_ejemplo/route_10.10.10.2.txt &
+
+# Limpio
+sleep 5
+ipcrm -Q 0x1abcdef1
+ipcrm -Q 0x1abcdef0
+
diff --git a/practicas/pipi-2da-entrega/src/test_devtcp.cpp b/practicas/pipi-2da-entrega/src/test_devtcp.cpp
new file mode 100644 (file)
index 0000000..c588e62
--- /dev/null
@@ -0,0 +1,72 @@
+
+#include "ipaddr.h"
+#include "devtcp.h"
+#include <iostream>
+#include <fstream>
+#include <sstream>
+#include <string>
+#include <cassert>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <sys/ipc.h>
+#include <sys/msg.h>
+#include <signal.h>
+
+// Uso: ./test_devtcp port
+
+void send_loop(Dev& dev);
+
+int main(int argc, char* argv[])
+{
+    if (argc < 3)
+    {
+        std::cerr << "Uso: " << argv[0] << " addr port\n";
+        return 1;
+    }
+    Dev::mac_type mac = atoi(argv[1]);
+    uint16_t port = atoi(argv[2]);
+    // Creo medio físico y cola para forwarding
+    DevTCP dev(mac, port);
+    // Creo procesos
+    pid_t pid_send = fork();
+    if (pid_send == -1)
+    {
+        perror("fork()");
+        return 2;
+    }
+    if (pid_send) // Padre, send
+    {
+        int ret;
+        send_loop(dev);
+        kill(pid_send, SIGTERM);
+        waitpid(pid_send, &ret, 0);
+        return 0;
+    }
+    else // Hijo receive
+    {
+        while (true)
+        {
+            std::string s = dev.receive();
+            std::cout << "Recibido '" << s << "' (len " << s.size() << ")\n";
+        }
+        return 0;
+    }
+    return 0;
+}
+
+void send_loop(Dev& dev)
+{
+    std::string dst;
+    std::string msg;
+    while (std::getline(std::cin, dst))
+    {
+        if (!std::getline(std::cin, msg))
+            break;
+        dev.transmit(msg, IPAddr(dst.c_str()));
+        std::cout << "Enviado '" << msg << "' a " << dst << "\n";
+    }
+}
+
+// vim: set et sw=4 sts=4 :
diff --git a/practicas/pipi-2da-entrega/src/test_ipaddr.cpp b/practicas/pipi-2da-entrega/src/test_ipaddr.cpp
new file mode 100644 (file)
index 0000000..a34cb28
--- /dev/null
@@ -0,0 +1,29 @@
+#include "ipaddr.h"
+#include "ipheader.h"
+#include <iostream>
+
+int main()
+{
+    // Addr
+    IPAddr ip1(0x0a0a0a05);
+    IPAddr ip2("10.10.10.1");
+    IPAddr ip3(10, 10, 10, 2);
+    std::cout << "IP1 = " << ip1 << "\n";
+    std::cout << "IP2 = " << ip2 << "\n";
+    std::cout << "IP3 = " << ip3 << "\n";
+    // Header
+    IPHeader h1(4, 20, 1, 1, 0, 0, 64, 0x11, ip1, ip2);
+    std::cout << "Header1 = " << h1 << "\n";
+    if (h1.check_checksum())
+        std::cout << "Checksum OK\n";
+    else
+        std::cout << "Checksum MAL!\n";
+    h1.checksum = 1;
+    if (h1.check_checksum())
+        std::cout << "Checksum OK\n";
+    else
+        std::cout << "Checksum MAL!\n";
+    return 0;
+}
+
+// vim: set et sw=4 sts=4 :
diff --git a/practicas/pipi-2da-entrega/src/test_ipin.cpp b/practicas/pipi-2da-entrega/src/test_ipin.cpp
new file mode 100644 (file)
index 0000000..767db77
--- /dev/null
@@ -0,0 +1,56 @@
+
+#include "ipin.h"
+#include "ipaddr.h"
+#include "devque.h"
+#include <iostream>
+#include <cstdlib>
+#include <cassert>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/ipc.h>
+#include <sys/msg.h>
+
+// Uso: ./test_ipin ip mtu router forward proto queue_id
+
+int main(int argc, char* argv[])
+{
+    IPAddr addr("10.10.10.1");
+    unsigned mtu = 25;
+    bool router = false;
+    bool forward = false;
+    uint8_t proto = 0;
+    key_t queue_id = DEVQUE_DEFAULT_KEY;
+    if (argc > 1)
+        addr = IPAddr(argv[1]);
+    if (argc > 2)
+        mtu = atoi(argv[2]);
+    if (argc > 3)
+        router = atoi(argv[3]);
+    if (argc > 4)
+        forward = atoi(argv[4]);
+    if (argc > 5)
+        proto = atoi(argv[5]);
+    if (argc > 6)
+        queue_id = atoi(argv[6]);
+    int que_id = msgget(queue_id, IPC_CREAT | 0666);
+    assert(que_id != -1);
+    DevQue dev(addr, mtu, queue_id);
+    que_id = msgget(queue_id+1, IPC_CREAT | 0666);
+    assert(que_id != -1);
+    DevQue fwque(addr, DEV_MAX_MTU, queue_id+1);
+    IPIn ipin(addr, dev, fwque, router, forward, std::cerr);
+    struct msqid_ds minfo;
+    for (msgctl(dev.que_id, IPC_STAT, &minfo); minfo.msg_qnum;
+            msgctl(dev.que_id, IPC_STAT, &minfo))
+    {
+        IPAddr src, dst;
+        std::cout << "Quedan " << minfo.msg_qnum << " mensajes en la cola\n";
+        std::string s = ipin.recv(proto, src, dst);
+        std::cout << "Recibido '" << s << "' (len " << s.size() << ") de "
+            << src << " para " << dst << " (proto = " << proto << ")\n";
+    }
+    return 0;
+}
+
+// vim: set et sw=4 sts=4 :
diff --git a/practicas/pipi-2da-entrega/src/test_ipout.cpp b/practicas/pipi-2da-entrega/src/test_ipout.cpp
new file mode 100644 (file)
index 0000000..1f11fc1
--- /dev/null
@@ -0,0 +1,76 @@
+
+#include "ipout.h"
+#include "ipaddr.h"
+#include "routetable.h"
+#include "devque.h"
+#include <iostream>
+#include <fstream>
+#include <sstream>
+#include <string>
+#include <cassert>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/ipc.h>
+#include <sys/msg.h>
+
+// Uso: ./test_ipout ip dst mtu routes_file proto queue_id
+
+void add_routes(RouteTable& rt, std::istream& is, size_t mtu, Dev& dev);
+
+int main(int argc, char* argv[])
+{
+    IPAddr addr("10.10.10.2");
+    IPAddr dst("10.10.10.1");
+    unsigned mtu = 25;
+    unsigned proto = 0;
+    key_t queue_id = DEVQUE_DEFAULT_KEY;
+    std::string fname = "route.txt";
+    if (argc > 1)
+        addr = IPAddr(argv[1]);
+    if (argc > 2)
+        dst = IPAddr(argv[2]);
+    if (argc > 3)
+        mtu = atoi(argv[3]);
+    if (argc > 4)
+        fname = argv[4];
+    if (argc > 5)
+        proto = atoi(argv[5]);
+    if (argc > 6)
+        queue_id = atoi(argv[6]);
+    int que_id = msgget(queue_id, IPC_CREAT | 0666); assert(que_id != -1);
+    que_id = msgget(queue_id+1, IPC_CREAT | 0666); assert(que_id != -1);
+    std::ifstream ifs(fname.c_str()); assert(ifs);
+    DevQue dev(addr, mtu, queue_id);
+    DevQue fwque(addr, DEV_MAX_MTU, queue_id+1);
+    RouteTable table(dev);
+    add_routes(table, ifs, mtu, dev);
+    IPOut ipout(addr, table, fwque, std::cerr);
+    std::string msg;
+    while (std::getline(std::cin, msg))
+    {
+        if (ipout.send(msg, proto, dst))
+            std::cout << "Enviado '" << msg << "' a " << dst << "\n";
+        else
+            std::cout << "NO SE PUDO ENVIAR '" << msg << "' a " << dst << "\n";
+    }
+    return 0;
+}
+
+void add_routes(RouteTable& rt, std::istream& is, size_t mtu, Dev& dev)
+{
+    std::string line;
+    while (std::getline(is, line))
+    {
+        std::istringstream iss(line);
+        std::string net;
+        std::string gw;
+        unsigned metric;
+        iss >> net >> gw >> metric;
+        if (net == "0") net = "0.0.0.0";
+        if (gw == "0") gw = "0.0.0.0";
+        rt.add(net, gw, mtu, metric, dev);
+    }
+}
+
+// vim: set et sw=4 sts=4 :
diff --git a/practicas/pipi-2da-entrega/src/test_nameserver_file.cpp b/practicas/pipi-2da-entrega/src/test_nameserver_file.cpp
new file mode 100644 (file)
index 0000000..b6f158d
--- /dev/null
@@ -0,0 +1,16 @@
+
+#include "nameserver.h"
+#include <iostream>
+#include <fstream>
+#include <string>
+#include <cassert>
+
+int main(int argc, char* argv[])
+{
+    std::ifstream ifs("test_nameserver_zones.txt");
+    //FIXME NameServer ns(ifs);
+    //FIXME std::cout << ns << "\n";
+    return 0;
+}
+
+// vim: set et sw=4 sts=4 :
diff --git a/practicas/pipi-2da-entrega/src/test_nameserver_resolvnext.cpp b/practicas/pipi-2da-entrega/src/test_nameserver_resolvnext.cpp
new file mode 100644 (file)
index 0000000..1ebf385
--- /dev/null
@@ -0,0 +1,25 @@
+
+#include "nameserver.h"
+#include <iostream>
+#include <fstream>
+#include <string>
+#include <cassert>
+
+int main(int argc, char* argv[])
+{
+    typedef NameServer::Name N;
+    std::ifstream ifs("test_nameserver_zones.txt");
+    /* XXX NameServer ns(ifs);
+    std::cout << ns << "\n";
+    std::cout << ns.resolv_direct(N("tito.mi.super.nombre")) << "\n";
+    std::cout << ns.resolv_direct(N("juan.mi.super.nombre")) << "\n";
+    std::cout << ns.resolv_direct(N("pepe.otro.mi.super.nombre")) << "\n";
+    std::cout << ns.resolv_direct(N("pepe.mas.mi.super.nombre")) << "\n";
+    std::cout << ns.resolv_direct(N("super.nombre")) << "\n";
+    std::cout << ns.resolv_direct(N("nada.que.ver")) << "\n";
+    std::cout << ns.resolv_direct(N("tito.mas.super.nombres")) << "\n";
+    std::cout << ns.resolv_recursive(N("nada.que.ver")) << "\n";*/
+    return 0;
+}
+
+// vim: set et sw=4 sts=4 :
diff --git a/practicas/pipi-2da-entrega/src/test_nameserver_zones.txt b/practicas/pipi-2da-entrega/src/test_nameserver_zones.txt
new file mode 100644 (file)
index 0000000..655bd40
--- /dev/null
@@ -0,0 +1,24 @@
+mi.super.nombre        600     0.0.0.0
+tito   A       10.10.100.1
+juan   A       10.10.100.2
+juan   A       10.10.100.3
+pepe   A       10.10.100.4
+juan   A       10.10.100.5
+pepe   A       10.10.100.6
+otro   NS      10.10.100.100
+otro   NS      10.10.100.101
+mas    NS      10.10.200.1
+otro   NS      10.10.200.2
+
+mas.super.nombres      9500    10.10.10.1
+tito   A       10.1.100.1
+juan   A       10.1.100.2
+juan   A       10.1.100.3
+pepe   A       10.1.100.4
+juan   A       10.1.100.5
+pepe   A       10.1.100.6
+otro   NS      10.1.100.100
+otro   NS      10.1.100.101
+mas    NS      10.1.200.1
+otro   NS      10.1.200.2
+
diff --git a/practicas/pipi-2da-entrega/src/test_poll.c b/practicas/pipi-2da-entrega/src/test_poll.c
new file mode 100644 (file)
index 0000000..31fa213
--- /dev/null
@@ -0,0 +1,52 @@
+
+#include "libtcp.h"
+#include <assert.h>
+#include <sys/poll.h>
+
+#define MAX 10
+#define PORT 5000
+
+#define ISSET(var, flag) ((var & flag) == flag)
+
+int main()
+{
+       int ssock = libtcp_open_pasivo(PORT); assert(ssock != -1);
+       struct pollfd pfds[MAX];
+       pfds[0].fd = ssock;
+       pfds[0].events = POLLIN | POLLPRI;
+       int pfds_size = 1;
+       while (1)
+       {
+               int res;
+               res = poll(pfds, pfds_size, 5000); assert(res != -1);
+               if (!res)
+                       continue;
+               if (ISSET(pfds[0].revents, POLLIN)
+                               || ISSET(pfds[0].revents, POLLPRI))
+               {
+                       if (pfds_size == MAX)
+                       {
+                               printf("Demasiadas conexiones, ignorando...\n");
+                               continue;
+                       }
+                       pfds[pfds_size].fd = accept(ssock, NULL, NULL);
+                       assert(pfds[pfds_size].fd != -1);
+                       printf("Nueva conexión...\n");
+                       pfds[pfds_size].events = POLLIN | POLLPRI;
+                       ++pfds_size;
+               }
+               for (int i = 1; i < pfds_size; ++i)
+               {
+                       if (ISSET(pfds[i].revents, POLLIN)
+                                       || ISSET(pfds[i].revents, POLLPRI))
+                       {
+                               char buf[10];
+                               int recibidos = libtcp_receive_bin(pfds[i].fd, buf, 10);
+                               //assert(recibidos == 10);
+                               if (recibidos)
+                                       printf("recibido %s\n", buf);
+                       }
+               }
+       }
+}
+
diff --git a/practicas/pipi-2da-entrega/src/test_recv.cpp b/practicas/pipi-2da-entrega/src/test_recv.cpp
new file mode 100644 (file)
index 0000000..fb8be43
--- /dev/null
@@ -0,0 +1,24 @@
+
+#include "devque.h"
+#include <iostream>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/ipc.h>
+#include <sys/msg.h>
+
+int main()
+{
+    DevQue dev(4321);
+    struct msqid_ds minfo;
+    for (msgctl(dev.que_id, IPC_STAT, &minfo); minfo.msg_qnum;
+            msgctl(dev.que_id, IPC_STAT, &minfo))
+    {
+        std::cout << "Quedan " << minfo.msg_qnum << " mensajes en la cola\n";
+        std::string s = dev.receive();
+        std::cout << "Recibido '" << s << "' (len " << s.size() << ")\n";
+    }
+    return 0;
+}
+
+// vim: set et sw=4 sts=4 :
diff --git a/practicas/pipi-2da-entrega/src/test_resolvproto.cpp b/practicas/pipi-2da-entrega/src/test_resolvproto.cpp
new file mode 100644 (file)
index 0000000..964240b
--- /dev/null
@@ -0,0 +1,23 @@
+
+#include "resolvproto.h"
+#include "libtcp.h"
+#include <iostream>
+#include <cassert>
+
+int main()
+{
+    ResolvProtoRequest req("hola.tito", RP_REQ_RECURSIVE);
+    std::cout << "Request Original: " << req << "\n";
+    ResolvProtoRequest req2 = std::string(req);
+    std::cout << "Request Reconstruido: " << req2 << "\n";
+    ResolvProtoResponse res(RP_RES_A, 600);
+    res.ips.push_back(IPAddr("10.10.10.2"));
+    res.ips.push_back(IPAddr("100.20.45.21"));
+    res.ips.push_back(IPAddr("230.23.62.189"));
+    std::cout << "Response Original: " << res << "\n";
+    ResolvProtoResponse res2 = std::string(res);
+    std::cout << "Response Reconstruido: " << res2 << "\n";
+    return 0;
+}
+
+// vim: set et sw=4 sts=4 :
diff --git a/practicas/pipi-2da-entrega/src/test_resolvprotoc.cpp b/practicas/pipi-2da-entrega/src/test_resolvprotoc.cpp
new file mode 100644 (file)
index 0000000..4f04686
--- /dev/null
@@ -0,0 +1,19 @@
+
+#include "resolvproto.h"
+#include "libtcp.h"
+#include <iostream>
+#include <cassert>
+
+int main()
+{
+    int fd = libtcp_open_activo("localhost", 5050); assert(fd != -1);
+    ResolvProtoRequest rpr("hola.mundo.cruel");
+    std::cout << "Vamos a enviar: " << rpr << "\n";
+    rpr.send(fd);
+    ResolvProtoResponse rps(fd);
+    std::cout << "Recibimos: " << rps << "\n";
+    close(fd);
+    return 0;
+}
+
+// vim: set et sw=4 sts=4 :
diff --git a/practicas/pipi-2da-entrega/src/test_resolvprotos.cpp b/practicas/pipi-2da-entrega/src/test_resolvprotos.cpp
new file mode 100644 (file)
index 0000000..7286ab3
--- /dev/null
@@ -0,0 +1,24 @@
+
+#include "resolvproto.h"
+#include "libtcp.h"
+#include <iostream>
+#include <cassert>
+
+int main()
+{
+    int sfd = libtcp_open_pasivo(5050); assert(sfd != -1);
+    int cfd = accept(sfd, NULL, NULL); assert(cfd != -1);
+    close(sfd);
+    ResolvProtoRequest rpr(cfd);
+    std::cout << "Recibimos: " << rpr << "\n";
+    ResolvProtoResponse rps(ResolvProtoResponse::RET_OK);
+    rps.ips.push_back(IPAddr("10.10.10.2"));
+    rps.ips.push_back(IPAddr("100.20.45.21"));
+    rps.ips.push_back(IPAddr("230.23.62.189"));
+    std::cout << "Contestamos: " << rps << "\n";
+    rps.send(cfd);
+    close(cfd);
+    return 0;
+}
+
+// vim: set et sw=4 sts=4 :
diff --git a/practicas/pipi-2da-entrega/src/test_send.cpp b/practicas/pipi-2da-entrega/src/test_send.cpp
new file mode 100644 (file)
index 0000000..5b78b2c
--- /dev/null
@@ -0,0 +1,21 @@
+
+#include "devque.h"
+#include <iostream>
+#include <cassert>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/ipc.h>
+#include <sys/msg.h>
+
+int main()
+{
+    int que_id = msgget(DEVQUE_DEFAULT_KEY, IPC_CREAT | 0666);
+    assert(que_id != -1);
+    DevQue dev(1234);
+    dev.transmit("hola mundo", 4321);
+    std::cout << "Enviado 'hola mundo' a 4321\n";
+    return 0;
+}
+
+// vim: set et sw=4 sts=4 :
diff --git a/practicas/pipi-2da-entrega/zonas_ejemplo/10.10.10.1.txt b/practicas/pipi-2da-entrega/zonas_ejemplo/10.10.10.1.txt
new file mode 100644 (file)
index 0000000..5381f9d
--- /dev/null
@@ -0,0 +1,27 @@
+casa   600     0.0.0.0
+burns  A       10.10.10.1
+homero A       10.10.10.2
+marge  A       10.10.10.3
+manuk  A       10.10.10.141
+juan   A       100.10.100.5
+pepe   A       100.10.100.6
+homero NS      10.10.10.2
+marge  NS      10.10.10.3
+manuk  NS      10.10.10.141
+
+burns.casa     600     0.0.0.0
+tito   A       100.10.100.1
+juan   A       100.10.100.2
+juan   A       100.10.100.3
+pepe   A       100.10.100.4
+juan   A       100.10.100.5
+pepe   A       100.10.100.6
+
+todos.homero.casa      9500    0.0.0.0
+tito   A       10.1.100.1
+juan   A       10.1.100.2
+juan   A       10.1.100.3
+pepe   A       10.1.100.4
+juan   A       10.1.100.5
+pepe   A       10.1.100.6
+
diff --git a/practicas/pipi-2da-entrega/zonas_ejemplo/10.10.10.141.txt b/practicas/pipi-2da-entrega/zonas_ejemplo/10.10.10.141.txt
new file mode 100644 (file)
index 0000000..d75a5d8
--- /dev/null
@@ -0,0 +1,16 @@
+manuk.marge.casa       600     10.10.10.3
+tito   A       40.10.100.1
+juan   A       40.10.100.2
+juan   A       40.10.100.3
+pepe   A       40.10.100.4
+juan   A       40.10.100.5
+pepe   A       40.10.100.6
+
+todos.homero.casa      9500    10.10.10.2
+tito   A       10.1.100.1
+juan   A       10.1.100.2
+juan   A       10.1.100.3
+pepe   A       10.1.100.4
+juan   A       10.1.100.5
+pepe   A       10.1.100.6
+
diff --git a/practicas/pipi-2da-entrega/zonas_ejemplo/10.10.10.2.txt b/practicas/pipi-2da-entrega/zonas_ejemplo/10.10.10.2.txt
new file mode 100644 (file)
index 0000000..4cd1503
--- /dev/null
@@ -0,0 +1,12 @@
+homero.casa    600     10.10.10.1
+tito   A       10.10.100.1
+juan   A       10.10.100.2
+juan   A       10.10.100.3
+pepe   A       10.10.100.4
+juan   A       10.10.100.5
+pepe   A       10.10.100.6
+marge  NS      10.10.10.3
+todos  NS      10.10.10.1
+todos  NS      10.10.10.3
+todos  NS      10.10.10.141
+
diff --git a/practicas/pipi-2da-entrega/zonas_ejemplo/10.10.10.3.txt b/practicas/pipi-2da-entrega/zonas_ejemplo/10.10.10.3.txt
new file mode 100644 (file)
index 0000000..dc45182
--- /dev/null
@@ -0,0 +1,28 @@
+marge.casa     600     10.10.10.1
+tito   A       30.10.100.1
+juan   A       30.10.100.2
+juan   A       30.10.100.3
+pepe   A       30.10.100.4
+juan   A       30.10.100.5
+pepe   A       30.10.100.6
+manuk  NS      10.10.10.141
+todos  NS      10.10.10.1
+todos  NS      10.10.10.3
+todos  NS      10.10.10.141
+
+todos.homero.casa      9500    10.10.10.2
+tito   A       10.1.100.1
+juan   A       10.1.100.2
+juan   A       10.1.100.3
+pepe   A       10.1.100.4
+juan   A       10.1.100.5
+pepe   A       10.1.100.6
+
+marge.homero.casa      9500    10.10.10.2
+tito   A       10.3.100.1
+juan   A       10.3.100.2
+juan   A       10.3.100.3
+pepe   A       10.3.100.4
+juan   A       10.3.100.5
+pepe   A       10.3.100.6
+