]> git.llucax.com Git - z.facultad/75.74/practicos.git/commitdiff
Tags de entregas.
authorLeandro Lucarella <llucax@gmail.com>
Tue, 13 Jun 2006 03:38:59 +0000 (03:38 +0000)
committerLeandro Lucarella <llucax@gmail.com>
Tue, 13 Jun 2006 03:38:59 +0000 (03:38 +0000)
56 files changed:
practicas/pipi-1ra-entrega-corregida/ENUNCIADO [new file with mode: 0644]
practicas/pipi-1ra-entrega-corregida/README [new file with mode: 0644]
practicas/pipi-1ra-entrega-corregida/TODO [new file with mode: 0644]
practicas/pipi-1ra-entrega-corregida/rutas_ejemplo/route.txt [new file with mode: 0644]
practicas/pipi-1ra-entrega-corregida/rutas_ejemplo/route_10.10.10.1.txt [new file with mode: 0644]
practicas/pipi-1ra-entrega-corregida/rutas_ejemplo/route_10.10.10.2.txt [new file with mode: 0644]
practicas/pipi-1ra-entrega-corregida/rutas_ejemplo/route_10.10.10.3.txt [new file with mode: 0644]
practicas/pipi-1ra-entrega-corregida/rutas_ejemplo/route_10.10.10.4.txt [new file with mode: 0644]
practicas/pipi-1ra-entrega-corregida/rutas_ejemplo/route_10.10.10.5.txt [new file with mode: 0644]
practicas/pipi-1ra-entrega-corregida/src/Makefile [new file with mode: 0644]
practicas/pipi-1ra-entrega-corregida/src/dev.cpp [new file with mode: 0644]
practicas/pipi-1ra-entrega-corregida/src/dev.h [new file with mode: 0644]
practicas/pipi-1ra-entrega-corregida/src/ip.cpp [new file with mode: 0644]
practicas/pipi-1ra-entrega-corregida/src/ipaddr.cpp [new file with mode: 0644]
practicas/pipi-1ra-entrega-corregida/src/ipaddr.h [new file with mode: 0644]
practicas/pipi-1ra-entrega-corregida/src/ipheader.cpp [new file with mode: 0644]
practicas/pipi-1ra-entrega-corregida/src/ipheader.h [new file with mode: 0644]
practicas/pipi-1ra-entrega-corregida/src/ipin.cpp [new file with mode: 0644]
practicas/pipi-1ra-entrega-corregida/src/ipin.h [new file with mode: 0644]
practicas/pipi-1ra-entrega-corregida/src/ipout.cpp [new file with mode: 0644]
practicas/pipi-1ra-entrega-corregida/src/ipout.h [new file with mode: 0644]
practicas/pipi-1ra-entrega-corregida/src/routetable.cpp [new file with mode: 0644]
practicas/pipi-1ra-entrega-corregida/src/routetable.h [new file with mode: 0644]
practicas/pipi-1ra-entrega-corregida/src/test.sh [new file with mode: 0755]
practicas/pipi-1ra-entrega-corregida/src/test2.sh [new file with mode: 0755]
practicas/pipi-1ra-entrega-corregida/src/test_ipaddr.cpp [new file with mode: 0644]
practicas/pipi-1ra-entrega-corregida/src/test_ipin.cpp [new file with mode: 0644]
practicas/pipi-1ra-entrega-corregida/src/test_ipout.cpp [new file with mode: 0644]
practicas/pipi-1ra-entrega-corregida/src/test_recv.cpp [new file with mode: 0644]
practicas/pipi-1ra-entrega-corregida/src/test_send.cpp [new file with mode: 0644]
practicas/pipi-1ra-entrega/ENUNCIADO [new file with mode: 0644]
practicas/pipi-1ra-entrega/README [new file with mode: 0644]
practicas/pipi-1ra-entrega/rutas_ejemplo/route.txt [new file with mode: 0644]
practicas/pipi-1ra-entrega/rutas_ejemplo/route_10.10.10.1.txt [new file with mode: 0644]
practicas/pipi-1ra-entrega/rutas_ejemplo/route_10.10.10.2.txt [new file with mode: 0644]
practicas/pipi-1ra-entrega/rutas_ejemplo/route_10.10.10.3.txt [new file with mode: 0644]
practicas/pipi-1ra-entrega/rutas_ejemplo/route_10.10.10.5.txt [new file with mode: 0644]
practicas/pipi-1ra-entrega/src/Makefile [new file with mode: 0644]
practicas/pipi-1ra-entrega/src/dev.cpp [new file with mode: 0644]
practicas/pipi-1ra-entrega/src/dev.h [new file with mode: 0644]
practicas/pipi-1ra-entrega/src/ipaddr.cpp [new file with mode: 0644]
practicas/pipi-1ra-entrega/src/ipaddr.h [new file with mode: 0644]
practicas/pipi-1ra-entrega/src/ipheader.cpp [new file with mode: 0644]
practicas/pipi-1ra-entrega/src/ipheader.h [new file with mode: 0644]
practicas/pipi-1ra-entrega/src/ipin.cpp [new file with mode: 0644]
practicas/pipi-1ra-entrega/src/ipin.h [new file with mode: 0644]
practicas/pipi-1ra-entrega/src/ipout.cpp [new file with mode: 0644]
practicas/pipi-1ra-entrega/src/ipout.h [new file with mode: 0644]
practicas/pipi-1ra-entrega/src/routetable.cpp [new file with mode: 0644]
practicas/pipi-1ra-entrega/src/routetable.h [new file with mode: 0644]
practicas/pipi-1ra-entrega/src/test.sh [new file with mode: 0755]
practicas/pipi-1ra-entrega/src/test_ipaddr.cpp [new file with mode: 0644]
practicas/pipi-1ra-entrega/src/test_ipin.cpp [new file with mode: 0644]
practicas/pipi-1ra-entrega/src/test_ipout.cpp [new file with mode: 0644]
practicas/pipi-1ra-entrega/src/test_recv.cpp [new file with mode: 0644]
practicas/pipi-1ra-entrega/src/test_send.cpp [new file with mode: 0644]

diff --git a/practicas/pipi-1ra-entrega-corregida/ENUNCIADO b/practicas/pipi-1ra-entrega-corregida/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-1ra-entrega-corregida/README b/practicas/pipi-1ra-entrega-corregida/README
new file mode 100644 (file)
index 0000000..cca4337
--- /dev/null
@@ -0,0 +1,193 @@
+===============================
+Sistemas Distribuidos I (75.74)
+===============================
+
+----------------------------
+Trabajo práctico de stack IP
+----------------------------
+
+: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`.
+Dentro de este directorio hay también dos scripts de pruebas completas:
+`test.sh` (con 1 router) y `test2.sh` (con 2 routers).
+
+En el directorio `rutas_ejemplo` contiene algunos archivos con descripciones de
+rutas de ejemplo para correr los programas.
+
+
+Uso
+===
+
+El trabajo consta de un programa llamado `ip` (más algunas otras pruebas que no
+tiene relevancia). Este programa corre 3 procesos, 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 está 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.
+
+
+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. Utiliza 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.
+
+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
+
+
+Ejemplo de corrida
+==================
+
+Host 10.10.10.1
+---------------
+
+Rutas:
+
+* 10.10.10.1  0.0.0.0     35  0
+* 10.10.10.3  10.10.10.5  35  1
+* 10.10.10.5  0.0.0.0     35  0
+
+Envía "adios mundo cruel!!!" al host 10.10.10.3::
+
+  $ (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
+  IPOut::send (10.10.10.1): Fragmento 0 => IPHeader: version=4 total_len=40 id=44919 DF=0 MF=1 offset=0 TTL=64 proto=0 checksum=214 src=10.10.10.1 dst=10.10.10.3
+          data (15) = Adios mundo cru
+  IPOut::send (10.10.10.1): Fragmento 1 => IPHeader: version=4 total_len=25 id=44919 DF=0 MF=0 offset=15 TTL=64 proto=0 checksum=315 src=10.10.10.1 dst=10.10.10.3
+          data (5) = el!!!
+  Enviado 'Adios mundo cruel!!!' a 10.10.10.3
+
+
+Router 10.10.10.5
+-----------------
+
+Rutas:
+
+* 10.10.10.1  0.0.0.0   35  0
+* 10.10.10.3  0.0.0.0   32  0
+* 10.10.10.5  0.0.0.0   35  0
+
+Recibe el mensaje::
+
+  $ ./ip 10.10.10.5 1 1 ../rutas_ejemplo/route_10.10.10.5.txt
+  IPIn::recv (10.10.10.5): IPHeader: version=4 total_len=40 id=44919 DF=0 MF=1 offset=0 TTL=64 proto=0 checksum=214 src=10.10.10.1 dst=10.10.10.3
+    data (15) = Adios mundo cru
+  IPIn::recv (10.10.10.5): IPHeader: version=4 total_len=25 id=44919 DF=0 MF=0 offset=15 TTL=64 proto=0 checksum=315 src=10.10.10.1 dst=10.10.10.3
+    data (5) = el!!!
+  IPOut::forward_loop (10.10.10.5): A forwardear (id 44919)
+  IPOut::send (10.10.10.5): Fragmento 0 => IPHeader: version=4 total_len=40 id=44919 DF=0 MF=1 offset=0 TTL=64 proto=0 checksum=214 src=10.10.10.1 dst=10.10.10.3
+    data (12) = Adios mundo 
+  IPOut::send (10.10.10.5): Fragmento 1 => IPHeader: version=4 total_len=28 id=44919 DF=0 MF=1 offset=12 TTL=64 proto=0 checksum=298 src=10.10.10.1 dst=10.10.10.3
+    data (3) = cru
+  IPOut::forward_loop (10.10.10.5): A forwardear (id 44919)
+  IPOut::send (10.10.10.5): Fragmento 0 => IPHeader: version=4 total_len=25 id=44919 DF=0 MF=0 offset=15 TTL=64 proto=0 checksum=315 src=10.10.10.1 dst=10.10.10.3
+    data (5) = el!!!
+
+
+Host 10.10.10.3
+---------------
+
+Rutas:
+
+* 10.10.10.1  10.10.10.5  32  1
+* 10.10.10.3  0.0.0.0     32  0
+* 10.10.10.5  0.0.0.0     32  0
+
+Finalmente este host recibe todos los fragmentos, reensabla y pasa el
+ paquete completo a la capa superior::
+
+  $ ./ip 10.10.10.3 0 0 ../rutas_ejemplo/route_10.10.10.3.txt
+  IPIn::recv (10.10.10.3): IPHeader: version=4 total_len=40 id=44919 DF=0 MF=1 offset=0 TTL=64 proto=0 checksum=214 src=10.10.10.1 dst=10.10.10.3
+    data (12) = Adios mundo 
+  IPIn::recv (10.10.10.3): IPHeader: version=4 total_len=28 id=44919 DF=0 MF=1 offset=12 TTL=64 proto=0 checksum=298 src=10.10.10.1 dst=10.10.10.3
+    data (3) = cru
+  IPIn::recv (10.10.10.3): IPHeader: version=4 total_len=25 id=44919 DF=0 MF=0 offset=15 TTL=64 proto=0 checksum=315 src=10.10.10.1 dst=10.10.10.3
+    data (5) = el!!!
+  IPIn::recv (10.10.10.3): Paquete completo: data = 'Adios mundo cruel!!!'
+  Recibido 'Adios mundo cruel!!!' (len 20) de 10.10.10.1 para 10.10.10.3 (proto = 0)
+
+.. vim: filetype=rst :
diff --git a/practicas/pipi-1ra-entrega-corregida/TODO b/practicas/pipi-1ra-entrega-corregida/TODO
new file mode 100644 (file)
index 0000000..e2ebac8
--- /dev/null
@@ -0,0 +1,6 @@
+- Implementar metricas
+- Implementar rutas de redes completas
+- 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
diff --git a/practicas/pipi-1ra-entrega-corregida/rutas_ejemplo/route.txt b/practicas/pipi-1ra-entrega-corregida/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-1ra-entrega-corregida/rutas_ejemplo/route_10.10.10.1.txt b/practicas/pipi-1ra-entrega-corregida/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-1ra-entrega-corregida/rutas_ejemplo/route_10.10.10.2.txt b/practicas/pipi-1ra-entrega-corregida/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-1ra-entrega-corregida/rutas_ejemplo/route_10.10.10.3.txt b/practicas/pipi-1ra-entrega-corregida/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-1ra-entrega-corregida/rutas_ejemplo/route_10.10.10.4.txt b/practicas/pipi-1ra-entrega-corregida/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-1ra-entrega-corregida/rutas_ejemplo/route_10.10.10.5.txt b/practicas/pipi-1ra-entrega-corregida/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-1ra-entrega-corregida/src/Makefile b/practicas/pipi-1ra-entrega-corregida/src/Makefile
new file mode 100644 (file)
index 0000000..9980baf
--- /dev/null
@@ -0,0 +1,189 @@
+# 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
+
+# Opciones para el compilador C++.
+CXXFLAGS = $(CFLAGS) -fno-inline
+
+# Opciones del enlazador.
+#LDFLAGS=
+
+# Compilador.
+CC=g++
+
+# Programas
+targets=ip
+tests=test_send test_recv test_ipaddr test_ipin test_ipout
+
+# Fuentes
+fuentes ?= $(wildcard *.cpp)
+
+
+# REGLAS
+#########
+
+.PHONY: all clean
+
+all: depend $(targets)
+
+tests: depend $(tests)
+
+test_send: test_send.o dev.o
+
+test_recv: test_recv.o dev.o
+
+test_ipaddr: test_ipaddr.o ipaddr.o ipheader.o
+
+test_ipin: test_ipin.o ipin.o ipaddr.o ipheader.o dev.o
+
+test_ipout: test_ipout.o ipout.o ipaddr.o ipheader.o dev.o routetable.o
+
+ip: ip.o ipout.o ipin.o ipaddr.o ipheader.o dev.o routetable.o
+
+depend:
+       @makedepend $(fuentes) > /dev/null 2>&1
+
+clean:
+       @$(RM) -fv *.o Makefile.bak $(targets)
+
+# DO NOT DELETE
+
+dev.o: dev.h /usr/include/unistd.h /usr/include/features.h
+dev.o: /usr/include/sys/cdefs.h /usr/include/gnu/stubs.h
+dev.o: /usr/include/bits/posix_opt.h /usr/include/bits/types.h
+dev.o: /usr/include/bits/wordsize.h /usr/include/bits/typesizes.h
+dev.o: /usr/include/bits/confname.h /usr/include/getopt.h
+dev.o: /usr/include/fcntl.h /usr/include/bits/fcntl.h
+dev.o: /usr/include/sys/types.h /usr/include/time.h /usr/include/endian.h
+dev.o: /usr/include/bits/endian.h /usr/include/sys/select.h
+dev.o: /usr/include/bits/select.h /usr/include/bits/sigset.h
+dev.o: /usr/include/bits/time.h /usr/include/sys/sysmacros.h
+dev.o: /usr/include/bits/pthreadtypes.h /usr/include/bits/sched.h
+dev.o: /usr/include/sys/ipc.h /usr/include/bits/ipctypes.h
+dev.o: /usr/include/bits/ipc.h /usr/include/sys/msg.h /usr/include/bits/msq.h
+ip.o: ipout.h ipaddr.h ipheader.h /usr/include/stdint.h
+ip.o: /usr/include/features.h /usr/include/sys/cdefs.h
+ip.o: /usr/include/gnu/stubs.h /usr/include/bits/wchar.h
+ip.o: /usr/include/bits/wordsize.h routetable.h dev.h ipin.h
+ip.o: /usr/include/unistd.h /usr/include/bits/posix_opt.h
+ip.o: /usr/include/bits/types.h /usr/include/bits/typesizes.h
+ip.o: /usr/include/bits/confname.h /usr/include/getopt.h /usr/include/fcntl.h
+ip.o: /usr/include/bits/fcntl.h /usr/include/sys/types.h /usr/include/time.h
+ip.o: /usr/include/endian.h /usr/include/bits/endian.h
+ip.o: /usr/include/sys/select.h /usr/include/bits/select.h
+ip.o: /usr/include/bits/sigset.h /usr/include/bits/time.h
+ip.o: /usr/include/sys/sysmacros.h /usr/include/bits/pthreadtypes.h
+ip.o: /usr/include/bits/sched.h /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
+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 ipheader.h /usr/include/stdint.h
+ipin.o: /usr/include/features.h /usr/include/sys/cdefs.h
+ipin.o: /usr/include/gnu/stubs.h /usr/include/bits/wchar.h
+ipin.o: /usr/include/bits/wordsize.h dev.h
+ipout.o: ipout.h ipaddr.h ipheader.h /usr/include/stdint.h
+ipout.o: /usr/include/features.h /usr/include/sys/cdefs.h
+ipout.o: /usr/include/gnu/stubs.h /usr/include/bits/wchar.h
+ipout.o: /usr/include/bits/wordsize.h routetable.h dev.h
+ipout.o: /usr/include/unistd.h /usr/include/bits/posix_opt.h
+ipout.o: /usr/include/bits/types.h /usr/include/bits/typesizes.h
+ipout.o: /usr/include/bits/confname.h /usr/include/getopt.h
+ipout.o: /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
+routetable.o: routetable.h dev.h ipaddr.h
+test_ipaddr.o: ipaddr.h ipheader.h /usr/include/stdint.h
+test_ipaddr.o: /usr/include/features.h /usr/include/sys/cdefs.h
+test_ipaddr.o: /usr/include/gnu/stubs.h /usr/include/bits/wchar.h
+test_ipaddr.o: /usr/include/bits/wordsize.h
+test_ipin.o: ipin.h ipaddr.h ipheader.h /usr/include/stdint.h
+test_ipin.o: /usr/include/features.h /usr/include/sys/cdefs.h
+test_ipin.o: /usr/include/gnu/stubs.h /usr/include/bits/wchar.h
+test_ipin.o: /usr/include/bits/wordsize.h dev.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 ipheader.h /usr/include/stdint.h
+test_ipout.o: /usr/include/features.h /usr/include/sys/cdefs.h
+test_ipout.o: /usr/include/gnu/stubs.h /usr/include/bits/wchar.h
+test_ipout.o: /usr/include/bits/wordsize.h routetable.h dev.h
+test_ipout.o: /usr/include/unistd.h /usr/include/bits/posix_opt.h
+test_ipout.o: /usr/include/bits/types.h /usr/include/bits/typesizes.h
+test_ipout.o: /usr/include/bits/confname.h /usr/include/getopt.h
+test_ipout.o: /usr/include/fcntl.h /usr/include/bits/fcntl.h
+test_ipout.o: /usr/include/sys/types.h /usr/include/time.h
+test_ipout.o: /usr/include/endian.h /usr/include/bits/endian.h
+test_ipout.o: /usr/include/sys/select.h /usr/include/bits/select.h
+test_ipout.o: /usr/include/bits/sigset.h /usr/include/bits/time.h
+test_ipout.o: /usr/include/sys/sysmacros.h /usr/include/bits/pthreadtypes.h
+test_ipout.o: /usr/include/bits/sched.h /usr/include/sys/ipc.h
+test_ipout.o: /usr/include/bits/ipctypes.h /usr/include/bits/ipc.h
+test_ipout.o: /usr/include/sys/msg.h /usr/include/bits/msq.h
+test_recv.o: 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_send.o: 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
diff --git a/practicas/pipi-1ra-entrega-corregida/src/dev.cpp b/practicas/pipi-1ra-entrega-corregida/src/dev.cpp
new file mode 100644 (file)
index 0000000..57e1d3d
--- /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, key_t key, size_t 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");
+    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-1ra-entrega-corregida/src/dev.h b/practicas/pipi-1ra-entrega-corregida/src/dev.h
new file mode 100644 (file)
index 0000000..bae7e17
--- /dev/null
@@ -0,0 +1,46 @@
+#ifndef _DEV_H_
+#define _DEV_H_
+
+#include <stdexcept>
+
+#define DEV_DEFAULT_KEY 0x1abcdef1
+#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;
+
+    /// Identificador de la cola a usar
+    int que_id;
+
+    /// Constructor
+    Dev(mac_type mac, key_t key = DEV_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);
+
+    // 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-1ra-entrega-corregida/src/ip.cpp b/practicas/pipi-1ra-entrega-corregida/src/ip.cpp
new file mode 100644 (file)
index 0000000..dd38b9b
--- /dev/null
@@ -0,0 +1,139 @@
+
+#include "ipout.h"
+#include "ipin.h"
+#include "ipaddr.h"
+#include "routetable.h"
+#include "dev.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_ipout ip [router forward routes_file queue_id 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;
+    unsigned proto = 0;
+    key_t queue_id = DEV_DEFAULT_KEY;
+    std::string fname = "route.txt";
+    if (argc < 2)
+    {
+        std::cerr << "Uso: ./test_ipout ip [router forward routes_file "
+            "queue_id 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)
+        queue_id = atoi(argv[5]);
+    if (argc > 6)
+        proto = atoi(argv[6]);
+    // Creo colas
+    int que_id = msgget(queue_id, IPC_CREAT | 0666); assert(que_id != -1);
+    que_id = msgget(DEV_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
+    Dev dev(addr, queue_id);
+    Dev fwque(addr, DEV_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 = " << 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.c_str(), gw.c_str(), metric, mtu, dev);
+    }
+}
+
+// vim: set et sw=4 sts=4 :
diff --git a/practicas/pipi-1ra-entrega-corregida/src/ipaddr.cpp b/practicas/pipi-1ra-entrega-corregida/src/ipaddr.cpp
new file mode 100644 (file)
index 0000000..7b153b2
--- /dev/null
@@ -0,0 +1,71 @@
+
+#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(int ip)
+{
+    atoms[0] = ip >> 24;
+    atoms[1] = ip >> 16;
+    atoms[2] = ip >> 8;
+    atoms[3] = ip;
+}
+
+/// 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());
+    }
+}
+
+/// Constructor
+//IPAddr::IPAddr(const std::string& ip) throw (std::logic_error)
+//{
+//    IPAddr(ip.c_str());
+//}
+
+/// Operador de casteo a unsigned
+IPAddr::operator unsigned () 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-1ra-entrega-corregida/src/ipaddr.h b/practicas/pipi-1ra-entrega-corregida/src/ipaddr.h
new file mode 100644 (file)
index 0000000..0c0c549
--- /dev/null
@@ -0,0 +1,45 @@
+#ifndef _IPADDR_H_
+#define _IPADDR_H_
+
+#include <string>
+#include <cstdlib>
+#include <stdexcept>
+
+/// Dirección IP
+struct IPAddr
+{
+
+    /// Átomo de dirección IP
+    typedef unsigned char atom;
+
+    /// Representación interna
+    atom atoms[4];
+
+    /// Constructor
+    IPAddr();
+
+    /// Constructor
+    IPAddr(atom a1, atom a2, atom a3, atom a4);
+
+    /// Constructor
+    IPAddr(int 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 unsigned () 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-1ra-entrega-corregida/src/ipheader.cpp b/practicas/pipi-1ra-entrega-corregida/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-1ra-entrega-corregida/src/ipheader.h b/practicas/pipi-1ra-entrega-corregida/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-1ra-entrega-corregida/src/ipin.cpp b/practicas/pipi-1ra-entrega-corregida/src/ipin.cpp
new file mode 100644 (file)
index 0000000..c8ea64e
--- /dev/null
@@ -0,0 +1,113 @@
+
+#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 o es un protocolo distinto, sigo
+        if (iph.mf || (iph.proto != proto))
+            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;
+        return data;
+    }
+}
+
+// vim: set et sw=4 sts=4 :
diff --git a/practicas/pipi-1ra-entrega-corregida/src/ipin.h b/practicas/pipi-1ra-entrega-corregida/src/ipin.h
new file mode 100644 (file)
index 0000000..8620278
--- /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-1ra-entrega-corregida/src/ipout.cpp b/practicas/pipi-1ra-entrega-corregida/src/ipout.cpp
new file mode 100644 (file)
index 0000000..c98c4b5
--- /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 << ")\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-1ra-entrega-corregida/src/ipout.h b/practicas/pipi-1ra-entrega-corregida/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-1ra-entrega-corregida/src/routetable.cpp b/practicas/pipi-1ra-entrega-corregida/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-1ra-entrega-corregida/src/routetable.h b/practicas/pipi-1ra-entrega-corregida/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-1ra-entrega-corregida/src/test.sh b/practicas/pipi-1ra-entrega-corregida/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-1ra-entrega-corregida/src/test2.sh b/practicas/pipi-1ra-entrega-corregida/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-1ra-entrega-corregida/src/test_ipaddr.cpp b/practicas/pipi-1ra-entrega-corregida/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-1ra-entrega-corregida/src/test_ipin.cpp b/practicas/pipi-1ra-entrega-corregida/src/test_ipin.cpp
new file mode 100644 (file)
index 0000000..e170b38
--- /dev/null
@@ -0,0 +1,56 @@
+
+#include "ipin.h"
+#include "ipaddr.h"
+#include "dev.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;
+    unsigned proto = 0;
+    key_t queue_id = DEV_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);
+    Dev dev(addr, mtu, queue_id);
+    que_id = msgget(queue_id+1, IPC_CREAT | 0666);
+    assert(que_id != -1);
+    Dev 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-1ra-entrega-corregida/src/test_ipout.cpp b/practicas/pipi-1ra-entrega-corregida/src/test_ipout.cpp
new file mode 100644 (file)
index 0000000..b8e75c9
--- /dev/null
@@ -0,0 +1,76 @@
+
+#include "ipout.h"
+#include "ipaddr.h"
+#include "routetable.h"
+#include "dev.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, 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 = DEV_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);
+    Dev dev(addr, mtu, queue_id);
+    Dev fwque(addr, DEV_MAX_MTU, queue_id+1);
+    RouteTable table(dev);
+    add_routes(table, ifs, 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, 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.c_str(), gw.c_str(), metric, dev);
+    }
+}
+
+// vim: set et sw=4 sts=4 :
diff --git a/practicas/pipi-1ra-entrega-corregida/src/test_recv.cpp b/practicas/pipi-1ra-entrega-corregida/src/test_recv.cpp
new file mode 100644 (file)
index 0000000..2471b4a
--- /dev/null
@@ -0,0 +1,24 @@
+
+#include "dev.h"
+#include <iostream>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/ipc.h>
+#include <sys/msg.h>
+
+int main()
+{
+    Dev 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-1ra-entrega-corregida/src/test_send.cpp b/practicas/pipi-1ra-entrega-corregida/src/test_send.cpp
new file mode 100644 (file)
index 0000000..618b862
--- /dev/null
@@ -0,0 +1,21 @@
+
+#include "dev.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(DEV_DEFAULT_KEY, IPC_CREAT | 0666);
+    assert(que_id != -1);
+    Dev 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-1ra-entrega/ENUNCIADO b/practicas/pipi-1ra-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-1ra-entrega/README b/practicas/pipi-1ra-entrega/README
new file mode 100644 (file)
index 0000000..2243ff3
--- /dev/null
@@ -0,0 +1,307 @@
+===============================
+Sistemas Distribuidos I (75.74)
+===============================
+
+----------------------------
+Trabajo práctico de stack IP
+----------------------------
+
+: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.
+
+
+Uso
+===
+
+El trabajo tiene 2 programas de prueba principales: `test_ipin` y `test_ipout`,
+ambos generados en el directorio `src` luego de compilar el código.
+
+test_ipin
+---------
+
+Este programa es el proceso que recibe paquetes IP y los procesa.
+
+Uso::
+
+  ./test_ipin [ip] [mtu] [router] [forward] [proto] [queue_id]
+
+ip
+  IP que utiliza este proceso (default 10.10.10.1)
+
+mtu
+  MTU de la capa física de este proceso (default 25)
+
+router
+  0 si es router, 1 si no lo es (default 0)
+
+forward
+  0 si puede hacer forwarding, 1 si no (default 0)
+
+proto
+  Protocolo que transporta (default 0)
+
+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`)
+
+
+test_ipout
+----------
+
+Este programa es el proceso que envía paquetes IP y rutea.
+
+Uso::
+
+  ./test_ipout [ip] [dst] [mtu] [routes_file] [proto] [queue_id]
+
+ip
+  IP que utiliza este proceso (default 10.10.10.2)
+
+dst
+  IP del destino al cual mandar paquetes (default 10.10.10.1)
+
+mtu
+  MTU de la capa física de este proceso (default 25)
+
+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) y métrica (todavía no se usa), separados
+  por uno o más espacios o tabs (default `route.txt`)
+
+proto
+  Protocolo que transporta (default 0)
+
+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`)
+
+
+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. Utiliza 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.
+
+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, 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
+  * 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
+
+
+Ejemplo de corrida
+==================
+
+Host 10.10.10.1
+---------------
+
+Rutas:
+
+* 10.10.10.1   0.0.0.0         0
+* 10.10.10.3   10.10.10.5      0
+* 10.10.10.5   0.0.0.0         0
+
+Envía "adios mundo cruel!!!" al host 10.10.10.3::
+
+  $ ./test_ipout 10.10.10.1 10.10.10.3 25 ../rutas_ejemplo/route_10.10.10.1.txt 
+  Se agregó tabla para 10.10.10.1: gw = 0.0.0.0, metric = 0
+  Se agregó tabla para 10.10.10.2: gw = 0.0.0.0, metric = 0
+  Se agregó tabla para 10.10.10.3: gw = 10.10.10.5, metric = 0
+  Se agregó tabla para 10.10.10.5: gw = 0.0.0.0, metric = 0
+  adios mundo cruel!!!
+  IPOut::send: Fragmento 0 => IPHeader: version= total_len=40 id=56121 DF=0 MF=1 offset=0 TTL=64 proto=0 checksum=196 src=10.10.10.1 dst=10.10.10.3
+          data (5) = adios
+  Dev::transmit(msgtype/mac = 168430085, size = 25)
+  IPOut::send: Fragmento 0 => IPHeader: version= total_len=35 id=56121 DF=0 MF=1 offset=5 TTL=64 proto=0 checksum=231 src=10.10.10.1 dst=10.10.10.3
+          data (5) =  mund
+  Dev::transmit(msgtype/mac = 168430085, size = 25)
+  IPOut::send: Fragmento 0 => IPHeader: version= total_len=30 id=56121 DF=0 MF=1 offset=10 TTL=64 proto=0 checksum=266 src=10.10.10.1 dst=10.10.10.3
+          data (5) = o cru
+  Dev::transmit(msgtype/mac = 168430085, size = 25)
+  IPOut::send: Fragmento 0 => IPHeader: version= total_len=25 id=56121 DF=0 MF=0 offset=15 TTL=64 proto=0 checksum=297 src=10.10.10.1 dst=10.10.10.3
+          data (5) = el!!!
+  Dev::transmit(msgtype/mac = 168430085, size = 25)
+  Enviado 'adios mundo cruel!!!' a 10.10.10.3
+
+El proceso test_ipin de este host no tiene relevancia.
+
+Router 10.10.10.5
+-----------------
+
+Rutas:
+
+* 10.10.10.1   0.0.0.0         0
+* 10.10.10.3   0.0.0.0         0
+* 10.10.10.5   0.0.0.0         0
+
+Recibe el mensaje::
+
+  $ ./test_ipin 10.10.10.5 25 1 1
+  Quedan 4 mensajes en la cola
+  Dev::receive(msgtype/mac = 168430085, size = 25)
+  IPIn::recv: IPHeader: version= total_len=40 id=56121 DF=0 MF=1 offset=0 TTL=64 proto=0 checksum=196 src=10.10.10.1 dst=10.10.10.3
+    data (5) = adios
+  Dev::transmit(msgtype/mac = 168430085, size = 25)
+  Dev::receive(msgtype/mac = 168430085, size = 25)
+  IPIn::recv: IPHeader: version= total_len=35 id=56121 DF=0 MF=1 offset=5 TTL=64 proto=0 checksum=231 src=10.10.10.1 dst=10.10.10.3
+    data (5) =  mund
+  Dev::transmit(msgtype/mac = 168430085, size = 25)
+  Dev::receive(msgtype/mac = 168430085, size = 25)
+  IPIn::recv: IPHeader: version= total_len=30 id=56121 DF=0 MF=1 offset=10 TTL=64 proto=0 checksum=266 src=10.10.10.1 dst=10.10.10.3
+    data (5) = o cru
+  Dev::transmit(msgtype/mac = 168430085, size = 25)
+  Dev::receive(msgtype/mac = 168430085, size = 25)
+  IPIn::recv: IPHeader: version= total_len=25 id=56121 DF=0 MF=0 offset=15 TTL=64 proto=0 checksum=297 src=10.10.10.1 dst=10.10.10.3
+    data (5) = el!!!
+  Dev::transmit(msgtype/mac = 168430085, size = 25)
+
+Y lo forwardea (refragmentando porque tiene un MTU más pequeño)::
+
+  $ ./test_ipout 10.10.10.5 10.10.10.1 23 ../rutas_ejemplo/route_10.10.10.5.txt
+  Se agregó tabla para 10.10.10.1: gw = 0.0.0.0, metric = 0
+  Se agregó tabla para 10.10.10.2: gw = 0.0.0.0, metric = 0
+  Se agregó tabla para 10.10.10.3: gw = 0.0.0.0, metric = 0
+  Se agregó tabla para 10.10.10.5: gw = 0.0.0.0, metric = 0
+  a
+  IPOut::send: Fragmento 0 => IPHeader: version= total_len=21 id=56140 DF=0 MF=0 offset=0 TTL=64 proto=0 checksum=194 src=10.10.10.5 dst=10.10.10.1
+    data (1) = a
+  Dev::transmit(msgtype/mac = 168430081, size = 21)
+  Enviado 'a' a 10.10.10.1
+  a
+  Dev::receive(msgtype/mac = 168430085, size = 25)
+  IPOut::send: A forwardear
+  IPOut::send: Fragmento 0 => IPHeader: version= total_len=40 id=56121 DF=0 MF=1 offset=0 TTL=64 proto=0 checksum=196 src=10.10.10.1 dst=10.10.10.3
+    data (3) = adi
+  Dev::transmit(msgtype/mac = 168430083, size = 23)
+  IPOut::send: Fragmento 0 => IPHeader: version= total_len=37 id=56121 DF=0 MF=1 offset=3 TTL=64 proto=0 checksum=217 src=10.10.10.1 dst=10.10.10.3
+    data (2) = os
+  Dev::transmit(msgtype/mac = 168430083, size = 22)
+  Dev::receive(msgtype/mac = 168430085, size = 25)
+  IPOut::send: A forwardear
+  IPOut::send: Fragmento 0 => IPHeader: version= total_len=35 id=56121 DF=0 MF=1 offset=5 TTL=64 proto=0 checksum=231 src=10.10.10.1 dst=10.10.10.3
+    data (3) =  mu
+  Dev::transmit(msgtype/mac = 168430083, size = 23)
+  IPOut::send: Fragmento 0 => IPHeader: version= total_len=32 id=56121 DF=0 MF=1 offset=8 TTL=64 proto=0 checksum=252 src=10.10.10.1 dst=10.10.10.3
+    data (2) = nd
+  Dev::transmit(msgtype/mac = 168430083, size = 22)
+  Dev::receive(msgtype/mac = 168430085, size = 25)
+  IPOut::send: A forwardear
+  IPOut::send: Fragmento 0 => IPHeader: version= total_len=30 id=56121 DF=0 MF=1 offset=10 TTL=64 proto=0 checksum=266 src=10.10.10.1 dst=10.10.10.3
+    data (3) = o c
+  Dev::transmit(msgtype/mac = 168430083, size = 23)
+  IPOut::send: Fragmento 0 => IPHeader: version= total_len=27 id=56121 DF=0 MF=1 offset=13 TTL=64 proto=0 checksum=287 src=10.10.10.1 dst=10.10.10.3
+    data (2) = ru
+  Dev::transmit(msgtype/mac = 168430083, size = 22)
+  Dev::receive(msgtype/mac = 168430085, size = 25)
+  IPOut::send: A forwardear
+  IPOut::send: Fragmento 0 => IPHeader: version= total_len=25 id=56121 DF=0 MF=1 offset=15 TTL=64 proto=0 checksum=301 src=10.10.10.1 dst=10.10.10.3
+    data (3) = el!
+  Dev::transmit(msgtype/mac = 168430083, size = 23)
+  IPOut::send: Fragmento 0 => IPHeader: version= total_len=22 id=56121 DF=0 MF=0 offset=18 TTL=64 proto=0 checksum=62 src=10.10.10.1 dst=10.10.10.3
+    data (2) = !!
+  Dev::transmit(msgtype/mac = 168430083, size = 22)
+  IPOut::send: Fragmento 0 => IPHeader: version= total_len=21 id=56147 DF=0 MF=0 offset=0 TTL=64 proto=0 checksum=201 src=10.10.10.5 dst=10.10.10.1
+    data (1) = a
+  Dev::transmit(msgtype/mac = 168430081, size = 21)
+  Enviado 'a' a 10.10.10.1
+
+(notar que para que haga el forwarding se tuvo que enviar un paquete
+*dummy* para que busque en la cola de paquetes a forwardear (es un error
+de diseño que tendré que corregir de alguna forma)
+
+Host 10.10.10.3
+---------------
+
+Rutas:
+
+* 10.10.10.1   10.10.10.5      0
+* 10.10.10.3   0.0.0.0         0
+* 10.10.10.5   0.0.0.0         0
+
+Finalmente este host recibe todos los fragmentos, reensabla y pasa el
+ paquete completo a la capa superior::
+
+  $ ./test_ipin 10.10.10.3 23
+  Quedan 8 mensajes en la cola
+  Dev::receive(msgtype/mac = 168430083, size = 23)
+  IPIn::recv: IPHeader: version= total_len=40 id=56121 DF=0 MF=1 offset=0 TTL=64 proto=0 checksum=196 src=10.10.10.1 dst=10.10.10.3
+    data (3) = adi
+  Dev::receive(msgtype/mac = 168430083, size = 22)
+  IPIn::recv: IPHeader: version= total_len=37 id=56121 DF=0 MF=1 offset=3 TTL=64 proto=0 checksum=217 src=10.10.10.1 dst=10.10.10.3
+    data (2) = os
+  Dev::receive(msgtype/mac = 168430083, size = 23)
+  IPIn::recv: IPHeader: version= total_len=35 id=56121 DF=0 MF=1 offset=5 TTL=64 proto=0 checksum=231 src=10.10.10.1 dst=10.10.10.3
+    data (3) =  mu
+  Dev::receive(msgtype/mac = 168430083, size = 22)
+  IPIn::recv: IPHeader: version= total_len=32 id=56121 DF=0 MF=1 offset=8 TTL=64 proto=0 checksum=252 src=10.10.10.1 dst=10.10.10.3
+    data (2) = nd
+  Dev::receive(msgtype/mac = 168430083, size = 23)
+  IPIn::recv: IPHeader: version= total_len=30 id=56121 DF=0 MF=1 offset=10 TTL=64 proto=0 checksum=266 src=10.10.10.1 dst=10.10.10.3
+    data (3) = o c
+  Dev::receive(msgtype/mac = 168430083, size = 22)
+  IPIn::recv: IPHeader: version= total_len=27 id=56121 DF=0 MF=1 offset=13 TTL=64 proto=0 checksum=287 src=10.10.10.1 dst=10.10.10.3
+    data (2) = ru
+  Dev::receive(msgtype/mac = 168430083, size = 23)
+  IPIn::recv: IPHeader: version= total_len=25 id=56121 DF=0 MF=1 offset=15 TTL=64 proto=0 checksum=301 src=10.10.10.1 dst=10.10.10.3
+    data (3) = el!
+  Dev::receive(msgtype/mac = 168430083, size = 22)
+  IPIn::recv: IPHeader: version= total_len=22 id=56121 DF=0 MF=0 offset=18 TTL=64 proto=0 checksum=62 src=10.10.10.1 dst=10.10.10.3
+    data (2) = !!
+  IPIn::recv: Paquete completo: data = 'adios mundo cruel!!!'
+  Recibido 'adios mundo cruel!!!' (len 20) de 10.10.10.1 para 10.10.10.3 (proto = 0)
+
+El proceso test_ipout de este host no tiene relevancia.
+
+
+.. vim: filetype=rst :
diff --git a/practicas/pipi-1ra-entrega/rutas_ejemplo/route.txt b/practicas/pipi-1ra-entrega/rutas_ejemplo/route.txt
new file mode 100644 (file)
index 0000000..3aae5e1
--- /dev/null
@@ -0,0 +1,3 @@
+10.10.10.1     0.0.0.0         0
+10.10.10.2     0.0.0.0         0
+10.10.10.3     10.10.10.5      0
diff --git a/practicas/pipi-1ra-entrega/rutas_ejemplo/route_10.10.10.1.txt b/practicas/pipi-1ra-entrega/rutas_ejemplo/route_10.10.10.1.txt
new file mode 100644 (file)
index 0000000..cc877c8
--- /dev/null
@@ -0,0 +1,4 @@
+10.10.10.1     0.0.0.0         0
+10.10.10.2     0.0.0.0         0
+10.10.10.3     10.10.10.5      0
+10.10.10.5     0.0.0.0         0
diff --git a/practicas/pipi-1ra-entrega/rutas_ejemplo/route_10.10.10.2.txt b/practicas/pipi-1ra-entrega/rutas_ejemplo/route_10.10.10.2.txt
new file mode 100644 (file)
index 0000000..cc877c8
--- /dev/null
@@ -0,0 +1,4 @@
+10.10.10.1     0.0.0.0         0
+10.10.10.2     0.0.0.0         0
+10.10.10.3     10.10.10.5      0
+10.10.10.5     0.0.0.0         0
diff --git a/practicas/pipi-1ra-entrega/rutas_ejemplo/route_10.10.10.3.txt b/practicas/pipi-1ra-entrega/rutas_ejemplo/route_10.10.10.3.txt
new file mode 100644 (file)
index 0000000..11ff580
--- /dev/null
@@ -0,0 +1,4 @@
+10.10.10.1     10.10.10.5      0
+10.10.10.2     10.10.10.5      0
+10.10.10.3     0.0.0.0         0
+10.10.10.5     0.0.0.0         0
diff --git a/practicas/pipi-1ra-entrega/rutas_ejemplo/route_10.10.10.5.txt b/practicas/pipi-1ra-entrega/rutas_ejemplo/route_10.10.10.5.txt
new file mode 100644 (file)
index 0000000..d57116e
--- /dev/null
@@ -0,0 +1,4 @@
+10.10.10.1     0.0.0.0         0
+10.10.10.2     0.0.0.0         0
+10.10.10.3     0.0.0.0         0
+10.10.10.5     0.0.0.0         0
diff --git a/practicas/pipi-1ra-entrega/src/Makefile b/practicas/pipi-1ra-entrega/src/Makefile
new file mode 100644 (file)
index 0000000..58539ef
--- /dev/null
@@ -0,0 +1,162 @@
+# 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
+
+# Opciones para el compilador C++.
+CXXFLAGS = $(CFLAGS) -fno-inline
+
+# Opciones del enlazador.
+#LDFLAGS=
+
+# Compilador.
+CC=g++
+
+# Programas
+targets=test_send test_recv test_ipaddr test_ipin test_ipout
+
+# Fuentes
+fuentes ?= $(wildcard *.cpp)
+
+
+# REGLAS
+#########
+
+.PHONY: all clean
+
+all: depend $(targets)
+
+test_send: test_send.o dev.o
+
+test_recv: test_recv.o dev.o
+
+test_ipaddr: test_ipaddr.o ipaddr.o ipheader.o
+
+test_ipin: test_ipin.o ipin.o ipaddr.o ipheader.o dev.o
+
+test_ipout: test_ipout.o ipout.o ipaddr.o ipheader.o dev.o routetable.o
+
+depend:
+       @makedepend $(fuentes) > /dev/null 2>&1
+
+clean:
+       @$(RM) -fv *.o Makefile.bak $(targets)
+
+# DO NOT DELETE
+
+dev.o: dev.h /usr/include/unistd.h /usr/include/features.h
+dev.o: /usr/include/sys/cdefs.h /usr/include/gnu/stubs.h
+dev.o: /usr/include/bits/posix_opt.h /usr/include/bits/types.h
+dev.o: /usr/include/bits/wordsize.h /usr/include/bits/typesizes.h
+dev.o: /usr/include/bits/confname.h /usr/include/getopt.h
+dev.o: /usr/include/fcntl.h /usr/include/bits/fcntl.h
+dev.o: /usr/include/sys/types.h /usr/include/time.h /usr/include/endian.h
+dev.o: /usr/include/bits/endian.h /usr/include/sys/select.h
+dev.o: /usr/include/bits/select.h /usr/include/bits/sigset.h
+dev.o: /usr/include/bits/time.h /usr/include/sys/sysmacros.h
+dev.o: /usr/include/bits/pthreadtypes.h /usr/include/bits/sched.h
+dev.o: /usr/include/sys/ipc.h /usr/include/bits/ipctypes.h
+dev.o: /usr/include/bits/ipc.h /usr/include/sys/msg.h /usr/include/bits/msq.h
+ipaddr.o: ipaddr.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 ipheader.h /usr/include/stdint.h
+ipin.o: /usr/include/features.h /usr/include/sys/cdefs.h
+ipin.o: /usr/include/gnu/stubs.h /usr/include/bits/wchar.h
+ipin.o: /usr/include/bits/wordsize.h dev.h
+ipout.o: ipout.h ipaddr.h ipheader.h /usr/include/stdint.h
+ipout.o: /usr/include/features.h /usr/include/sys/cdefs.h
+ipout.o: /usr/include/gnu/stubs.h /usr/include/bits/wchar.h
+ipout.o: /usr/include/bits/wordsize.h routetable.h dev.h
+ipout.o: /usr/include/unistd.h /usr/include/bits/posix_opt.h
+ipout.o: /usr/include/bits/types.h /usr/include/bits/typesizes.h
+ipout.o: /usr/include/bits/confname.h /usr/include/getopt.h
+ipout.o: /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
+routetable.o: routetable.h dev.h ipaddr.h
+test_ipaddr.o: ipaddr.h ipheader.h /usr/include/stdint.h
+test_ipaddr.o: /usr/include/features.h /usr/include/sys/cdefs.h
+test_ipaddr.o: /usr/include/gnu/stubs.h /usr/include/bits/wchar.h
+test_ipaddr.o: /usr/include/bits/wordsize.h
+test_ipin.o: ipin.h ipaddr.h ipheader.h /usr/include/stdint.h
+test_ipin.o: /usr/include/features.h /usr/include/sys/cdefs.h
+test_ipin.o: /usr/include/gnu/stubs.h /usr/include/bits/wchar.h
+test_ipin.o: /usr/include/bits/wordsize.h dev.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 ipheader.h /usr/include/stdint.h
+test_ipout.o: /usr/include/features.h /usr/include/sys/cdefs.h
+test_ipout.o: /usr/include/gnu/stubs.h /usr/include/bits/wchar.h
+test_ipout.o: /usr/include/bits/wordsize.h routetable.h dev.h
+test_ipout.o: /usr/include/unistd.h /usr/include/bits/posix_opt.h
+test_ipout.o: /usr/include/bits/types.h /usr/include/bits/typesizes.h
+test_ipout.o: /usr/include/bits/confname.h /usr/include/getopt.h
+test_ipout.o: /usr/include/fcntl.h /usr/include/bits/fcntl.h
+test_ipout.o: /usr/include/sys/types.h /usr/include/time.h
+test_ipout.o: /usr/include/endian.h /usr/include/bits/endian.h
+test_ipout.o: /usr/include/sys/select.h /usr/include/bits/select.h
+test_ipout.o: /usr/include/bits/sigset.h /usr/include/bits/time.h
+test_ipout.o: /usr/include/sys/sysmacros.h /usr/include/bits/pthreadtypes.h
+test_ipout.o: /usr/include/bits/sched.h /usr/include/sys/ipc.h
+test_ipout.o: /usr/include/bits/ipctypes.h /usr/include/bits/ipc.h
+test_ipout.o: /usr/include/sys/msg.h /usr/include/bits/msq.h
+test_recv.o: 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_send.o: 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
diff --git a/practicas/pipi-1ra-entrega/src/dev.cpp b/practicas/pipi-1ra-entrega/src/dev.cpp
new file mode 100644 (file)
index 0000000..932df00
--- /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-1ra-entrega/src/dev.h b/practicas/pipi-1ra-entrega/src/dev.h
new file mode 100644 (file)
index 0000000..129f78f
--- /dev/null
@@ -0,0 +1,46 @@
+#ifndef _DEV_H_
+#define _DEV_H_
+
+#include <stdexcept>
+
+#define DEV_DEFAULT_KEY 0x1abcdef1
+#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;
+
+    /// Identificador de la cola a usar
+    int que_id;
+
+    /// Constructor
+    Dev(mac_type mac, size_t mtu = DEV_MAX_MTU, key_t key = DEV_DEFAULT_KEY)
+        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);
+
+    // 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-1ra-entrega/src/ipaddr.cpp b/practicas/pipi-1ra-entrega/src/ipaddr.cpp
new file mode 100644 (file)
index 0000000..7b153b2
--- /dev/null
@@ -0,0 +1,71 @@
+
+#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(int ip)
+{
+    atoms[0] = ip >> 24;
+    atoms[1] = ip >> 16;
+    atoms[2] = ip >> 8;
+    atoms[3] = ip;
+}
+
+/// 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());
+    }
+}
+
+/// Constructor
+//IPAddr::IPAddr(const std::string& ip) throw (std::logic_error)
+//{
+//    IPAddr(ip.c_str());
+//}
+
+/// Operador de casteo a unsigned
+IPAddr::operator unsigned () 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-1ra-entrega/src/ipaddr.h b/practicas/pipi-1ra-entrega/src/ipaddr.h
new file mode 100644 (file)
index 0000000..0c0c549
--- /dev/null
@@ -0,0 +1,45 @@
+#ifndef _IPADDR_H_
+#define _IPADDR_H_
+
+#include <string>
+#include <cstdlib>
+#include <stdexcept>
+
+/// Dirección IP
+struct IPAddr
+{
+
+    /// Átomo de dirección IP
+    typedef unsigned char atom;
+
+    /// Representación interna
+    atom atoms[4];
+
+    /// Constructor
+    IPAddr();
+
+    /// Constructor
+    IPAddr(atom a1, atom a2, atom a3, atom a4);
+
+    /// Constructor
+    IPAddr(int 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 unsigned () 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-1ra-entrega/src/ipheader.cpp b/practicas/pipi-1ra-entrega/src/ipheader.cpp
new file mode 100644 (file)
index 0000000..0fbfca2
--- /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=" << 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-1ra-entrega/src/ipheader.h b/practicas/pipi-1ra-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-1ra-entrega/src/ipin.cpp b/practicas/pipi-1ra-entrega/src/ipin.cpp
new file mode 100644 (file)
index 0000000..15e102c
--- /dev/null
@@ -0,0 +1,101 @@
+
+#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())
+        {
+            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)
+        {
+            drop("Versión IP incorrecta", iph);
+            continue;
+        }
+        if (!iph.check_checksum())
+        {
+            drop("Mal checksum", iph);
+            continue;
+        }
+        // No es para nosotros y no forwardeamos
+        if (iph.dst != ip && !forward)
+        {
+            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)
+        {
+            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 o es un protocolo distinto, sigo
+        if (iph.mf || (iph.proto != proto))
+            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;
+        return data;
+    }
+}
+
+// vim: set et sw=4 sts=4 :
diff --git a/practicas/pipi-1ra-entrega/src/ipin.h b/practicas/pipi-1ra-entrega/src/ipin.h
new file mode 100644 (file)
index 0000000..8620278
--- /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-1ra-entrega/src/ipout.cpp b/practicas/pipi-1ra-entrega/src/ipout.cpp
new file mode 100644 (file)
index 0000000..6829d2f
--- /dev/null
@@ -0,0 +1,114 @@
+
+#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)
+{
+    // Mando todo lo que tengo para forwardear
+    while (to_forward())
+    {
+        std::string buf = forward_que.receive();
+        IPHeader iph(buf);
+#ifdef DEBUG
+        std::cout << "IPOut::send (" << ip << "): A forwardear\n";
+#endif
+        send(iph, buf.substr(iph.header_len()));
+    }
+    // Mando el paquete en sí
+    // 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);
+    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)
+    {
+        drop("No existe una ruta para el destino", iph);
+        return false;
+    }
+    // No quieren fragmentar
+    if (iph.df && (IPHeader::header_len() + data.size() > r->iface->mtu))
+    {
+        drop("Tamaño de paquete más grande que MTU y DF=1", iph);
+        return false;
+    }
+    // Fragmenta (de ser necesario)
+    int max_payload = r->iface->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;
+}
+
+/// Obtiene un identificador para el paquete
+uint16_t IPOut::get_id() const
+{
+    return time(NULL);
+}
+
+/// Se fija si hay paquetes a forwardear (y devuelve cuantos hay)
+unsigned IPOut::to_forward()
+{
+    struct msqid_ds minfo;
+    msgctl(forward_que.que_id, IPC_STAT, &minfo);
+    return minfo.msg_qnum;
+}
+
+// vim: set et sw=4 sts=4 :
diff --git a/practicas/pipi-1ra-entrega/src/ipout.h b/practicas/pipi-1ra-entrega/src/ipout.h
new file mode 100644 (file)
index 0000000..effe150
--- /dev/null
@@ -0,0 +1,58 @@
+#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);
+
+    /// 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-1ra-entrega/src/routetable.cpp b/practicas/pipi-1ra-entrega/src/routetable.cpp
new file mode 100644 (file)
index 0000000..4a043cd
--- /dev/null
@@ -0,0 +1,32 @@
+#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 metric, Dev& iface)
+{
+    table[net] = Route(gw, metric, 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-1ra-entrega/src/routetable.h b/practicas/pipi-1ra-entrega/src/routetable.h
new file mode 100644 (file)
index 0000000..2fe1586
--- /dev/null
@@ -0,0 +1,45 @@
+#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 metric;
+        Dev* iface;
+        Route(): gateway(0), metric(0), iface(0) {}
+        Route(const IPAddr& gateway, unsigned metric, Dev& iface):
+            gateway(gateway), 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 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-1ra-entrega/src/test.sh b/practicas/pipi-1ra-entrega/src/test.sh
new file mode 100755 (executable)
index 0000000..4493a19
--- /dev/null
@@ -0,0 +1,22 @@
+#!/bin/sh
+
+# Host 10.10.10.1
+./test_ipin 10.10.10.5 25 1 1 &
+echo 'Adios mundo cruel!!!' | ./test_ipout 10.10.10.1 10.10.10.3 25 \
+       ../rutas_ejemplo/route_10.10.10.1.txt
+
+# Router 10.10.10.5
+./test_ipin 10.10.10.5 25 1 1 &
+echo | ./test_ipout 10.10.10.5 10.10.10.1 23 \
+       ../rutas_ejemplo/route_10.10.10.5.txt
+
+# Host 10.10.10.3
+./test_ipin 10.10.10.3 23 0 0 &
+echo | ./test_ipout 10.10.10.3 10.10.10.5 25 \
+       ../rutas_ejemplo/route_10.10.10.3.txt
+
+# Limpio
+sleep 1
+killall test_ipin
+ipcrm -Q 0x1abcdef1
+ipcrm -Q 0x1abcdef2
diff --git a/practicas/pipi-1ra-entrega/src/test_ipaddr.cpp b/practicas/pipi-1ra-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-1ra-entrega/src/test_ipin.cpp b/practicas/pipi-1ra-entrega/src/test_ipin.cpp
new file mode 100644 (file)
index 0000000..e170b38
--- /dev/null
@@ -0,0 +1,56 @@
+
+#include "ipin.h"
+#include "ipaddr.h"
+#include "dev.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;
+    unsigned proto = 0;
+    key_t queue_id = DEV_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);
+    Dev dev(addr, mtu, queue_id);
+    que_id = msgget(queue_id+1, IPC_CREAT | 0666);
+    assert(que_id != -1);
+    Dev 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-1ra-entrega/src/test_ipout.cpp b/practicas/pipi-1ra-entrega/src/test_ipout.cpp
new file mode 100644 (file)
index 0000000..b8e75c9
--- /dev/null
@@ -0,0 +1,76 @@
+
+#include "ipout.h"
+#include "ipaddr.h"
+#include "routetable.h"
+#include "dev.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, 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 = DEV_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);
+    Dev dev(addr, mtu, queue_id);
+    Dev fwque(addr, DEV_MAX_MTU, queue_id+1);
+    RouteTable table(dev);
+    add_routes(table, ifs, 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, 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.c_str(), gw.c_str(), metric, dev);
+    }
+}
+
+// vim: set et sw=4 sts=4 :
diff --git a/practicas/pipi-1ra-entrega/src/test_recv.cpp b/practicas/pipi-1ra-entrega/src/test_recv.cpp
new file mode 100644 (file)
index 0000000..2471b4a
--- /dev/null
@@ -0,0 +1,24 @@
+
+#include "dev.h"
+#include <iostream>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/ipc.h>
+#include <sys/msg.h>
+
+int main()
+{
+    Dev 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-1ra-entrega/src/test_send.cpp b/practicas/pipi-1ra-entrega/src/test_send.cpp
new file mode 100644 (file)
index 0000000..618b862
--- /dev/null
@@ -0,0 +1,21 @@
+
+#include "dev.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(DEV_DEFAULT_KEY, IPC_CREAT | 0666);
+    assert(que_id != -1);
+    Dev dev(1234);
+    dev.transmit("hola mundo", 4321);
+    std::cout << "Enviado 'hola mundo' a 4321\n";
+    return 0;
+}
+
+// vim: set et sw=4 sts=4 :