]> git.llucax.com Git - z.facultad/75.74/practicos.git/blobdiff - practicas/pipi/src/ipout.cpp
Se cambia el logueo de paquetes dropeados a std::cerr para diferenciar de
[z.facultad/75.74/practicos.git] / practicas / pipi / src / ipout.cpp
index fb60ffd02ba32907187b253e46e29c679b6612d8..6e0c80733914f6ddeaaf427e6d6513a02a680f8a 100644 (file)
@@ -2,11 +2,20 @@
 #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, Dev& dev, std::ostream& log):
-    ip(ip), dev(dev), log(log)
-{}
+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)
 {
@@ -23,25 +32,65 @@ 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)
 {
-    // TODO fragmentar
-    if (IPHeader::header_len() + data.size() > dev.mtu)
+    // Mando todo lo que tengo para forwardear
+    while (to_forward())
     {
-        drop("Tamaño de paquete más grande que MTU", data);
-        return false;
+        std::string buf = forward_que.receive();
+        IPHeader iph(buf);
+#ifdef DEBUG
+        std::cout << "IPOut::send: 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);
-    std::string buf((char*) &iph, sizeof(IPHeader));
-    buf += data;
+    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
-    log << "IPOut::send: IPHeader: " << iph << "\n";
-    log << "IPOut::send: buf = " << buf << "\n";
+        std::cout << "IPOut::send: Fragmento 0 => IPHeader: " << iph2 << "\n";
+        std::string tmp = data.substr(i * max_payload, max_payload);
+        std::cout << "\tdata (" << tmp.size() << ") = " << tmp << "\n";
 #endif
-    dev.transmit(buf, dst /*TODO rutear */);
+        r->iface->transmit(buf, r->gateway ? r->gateway : IPAddr(iph.dst));
+    }
     return true;
 }
 
@@ -51,4 +100,12 @@ 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 :