X-Git-Url: https://git.llucax.com/z.facultad/75.74/practicos.git/blobdiff_plain/f3d349d8dd455a3c7ee639d2ad3152f4bfa49f13..093ef819f410add240cf97b72f9e7dcab5abd16c:/practicas/pipi/src/ipout.cpp diff --git a/practicas/pipi/src/ipout.cpp b/practicas/pipi/src/ipout.cpp index 48cbc30..cf5c28c 100644 --- a/practicas/pipi/src/ipout.cpp +++ b/practicas/pipi/src/ipout.cpp @@ -1,11 +1,18 @@ #include "ipout.h" #include "ipheader.h" +#include +#include +#include +#include +#include +#include /// 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) { @@ -18,26 +25,83 @@ void IPOut::drop(const std::string& msg, const IPHeader& iph) } /// Envía un paquete IP -bool IPOut::send(const std::string& data, IPAddr& src, IPAddr& dst, - uint8_t proto, bool df, uint8_t ttl, uint16_t id) +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 + log << "IPOut::send: A forwardear => IPHeader: " << iph << "\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"; + log << "IPOut::send: Fragmento 0 => IPHeader: " << iph2 << "\n"; + log << "\tbuf (" << buf.size() << ") = " << buf << "\n"; #endif - dev.transmit(buf, dst /*TODO rutear */); + 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 :