]> git.llucax.com Git - z.facultad/75.74/practicos.git/blobdiff - practicas/pipi/src/ipin.cpp
Se agrega opción para recibir paquetes de un host específico y se mejora el
[z.facultad/75.74/practicos.git] / practicas / pipi / src / ipin.cpp
index 45e340e90bd285632496c0e9870015460571487e..73913abda23f59f33e1fbae858efacb309263a4a 100644 (file)
 
 #include "ipin.h"
 #include "ipheader.h"
+#ifdef DEBUG
+#include <iostream>
+#endif
 
 /// Constructor
-IPIn::IPIn(const IPAddr& ip, Dev& dev, std::ostream& log):
-    ip(ip), dev(dev), log(log)
-{}
+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: " << msg << "\n\tBuffer: " << buf << "\n";
+    log << "IPIn::drop (" << ip << "): " << msg << "\n\tBuffer: " << buf
+            << "\n";
 }
 
 void IPIn::drop(const std::string& msg, const IPHeader& iph)
 {
-    log << "IPIn::drop: " << msg << "\n\tIPHeader: " << iph << "\n";
+    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)
+std::string IPIn::recv(uint8_t proto, IPAddr& src, IPAddr& dst, bool filter)
+    throw (std::runtime_error)
 {
     while (true)
     {
+        // Reviso buffers completos a ver si puedo sacar algo
+        buffer_complete_type::iterator f = buffer_complete.find(proto);
+        if (f != buffer_complete.end()) // Hay algo
+        {
+            srcmap_type& srcmap = f->second;
+            srcmap_type::iterator b;
+            if (filter)
+                b = srcmap.find(src); // Si filtro, busco el que me interesa
+            else
+                b = srcmap.begin(); // Si no filtro, agarro el primero
+            if (b != srcmap.end())
+            {
+                src = b->first;
+                dst = (b->second).dst;
+                std::string data = b->second.data;
+                // Limpio buffers
+                srcmap.erase(src);
+                if (srcmap.empty())
+                    buffer_complete.erase(proto);
+                return data;
+            }
+        }
+        // Si no pude sacar nada, recibo
         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
-        log << iph << "\n";
+        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;
         }
-        // TODO forwarding (ponerlo en una cola para el proceso que manda)
-        if (iph.dst != ip)
+        // 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;
         }
-        //TODO a un buffer
-        if (iph.proto != proto)
+        // No es para nosotros pero forwardeamos
+        else if (iph.dst != ip)
+        {
+            forward_que.transmit(buf, ip);
+            continue;
+        }
+        // Es para nosotros pero somos router
+        else if (router)
+        {
+            // Silencioso
+            drop("Es para nosotros pero somos un router", iph);
+            continue;
+        }
+        // Es para nosotros y somos un host
+        // Guarda en buffer
+        buffer[iph][iph.offset] = buf.substr(iph.header_len());
+        // Si tiene más fragmentos, sigo
+        if (iph.mf)
+            continue;
+        // No hay más fragmentos, reensamblamos (de ser necesario)
+        std::string data;
+        for (offsetmap_type::iterator i = buffer[iph].begin();
+                i != buffer[iph].end(); ++i)
+        {
+            //TODO chequear que los fragmentos estén todos
+            data += i->second;
+        }
+#ifdef DEBUG
+        std::cout << "IPIn::recv (" << ip << "): Paquete completo: data = '"
+                << data << "'\n";
+#endif
+        buffer.erase(iph);
+        // Si es un protocolo distinto o no es de quien quiero, rearmo paquete
+        // (ya sé que no hay más fragmentos) y guardo en buffer nomás
+        if ((iph.proto != proto) || (filter == true && src != iph.src))
         {
-            drop("No es el protocolo pedido", iph);
+            buffer_complete[proto][iph.src] = BufferPkt(iph.dst, data);
             continue;
         }
+        //TODO faltaría limpiar fragmentos viejos cada tanto (timer?)
         src = iph.src;
         dst = iph.dst;
-        std::string data = buf.substr(iph.total_len - iph.header_len());
         return data;
     }
 }