]> git.llucax.com Git - z.facultad/75.74/practicos.git/blob - practicas/pipi/src/ipout.cpp
Primera aproximación al cache y a la resolución de nombres.
[z.facultad/75.74/practicos.git] / practicas / pipi / src / ipout.cpp
1
2 #include "ipout.h"
3 #include "ipheader.h"
4 #include <ctime>
5 #include <unistd.h>
6 #include <fcntl.h>
7 #include <sys/types.h>
8 #include <sys/ipc.h>
9 #include <sys/msg.h>
10 #ifdef DEBUG
11 #include <iostream>
12 #endif
13
14 /// Constructor
15 IPOut::IPOut(const IPAddr& ip, RouteTable& rtable, Dev& forward_que, std::ostream& log):
16     ip(ip), rtable(rtable), forward_que(forward_que), log(log)
17 {
18 }
19
20 void IPOut::drop(const std::string& msg, const std::string& buf)
21 {
22     log << "IPOut::drop (" << ip << "): " << msg << "\n\tBuffer: " << buf
23             << "\n";
24 }
25
26 void IPOut::drop(const std::string& msg, const IPHeader& iph)
27 {
28     log << "IPOut::drop (" << ip << "): " << msg << "\n\tIPHeader: " << iph
29             << "\n";
30 }
31
32 /// Envía un paquete IP
33 bool IPOut::send(const std::string& data, uint8_t proto, IPAddr dst, IPAddr src,
34         bool df, uint8_t ttl, uint16_t id)
35     throw (std::runtime_error)
36 {
37     // Armamos cabecera
38     if (!src)
39         src = ip;
40     if (!id)
41         id = get_id();
42     IPHeader iph(4, IPHeader::header_len() + data.size(), id, df, 0, 0,
43             ttl, proto, src, dst);
44     // Enviamos
45     return send(iph, data);
46 }
47
48 /// Envía un paquete IP
49 bool IPOut::send(IPHeader iph, std::string data) throw (std::runtime_error)
50 {
51     // Buscamos ruta
52     RouteTable::Route* r = rtable.get(iph.dst);
53     if (!r)
54     {
55         // ICMP
56         drop("No existe una ruta para el destino -> ICMP", iph);
57         return false;
58     }
59     // No quieren fragmentar
60     if (iph.df && (IPHeader::header_len() + data.size() > r->mtu))
61     {
62         // Silencioso
63         drop("Tamaño de paquete más grande que MTU y DF=1", iph);
64         return false;
65     }
66     // Fragmenta (de ser necesario)
67     int max_payload = r->mtu - IPHeader::header_len();
68     int cant_frag = data.size() / max_payload;
69     if (data.size() % max_payload)
70         ++cant_frag;
71     for (int i = 0; i < cant_frag; ++i)
72     {
73         IPHeader iph2 = iph;
74         if (i != (cant_frag - 1))
75             iph2.mf = 1;
76         iph2.offset += i * max_payload;
77         iph2.total_len -= i * max_payload;
78         iph2.do_checksum();
79         std::string buf((char*) &iph2, sizeof(IPHeader));
80         buf += data.substr(i * max_payload, max_payload);
81 #ifdef DEBUG
82         std::cout << "IPOut::send (" << ip << "): Fragmento " << i
83                 << " => IPHeader: " << iph2 << "\n";
84         std::string tmp = data.substr(i * max_payload, max_payload);
85         std::cout << "\tdata (" << tmp.size() << ") = " << tmp << "\n";
86 #endif
87         r->iface->transmit(buf, r->gateway ? r->gateway : IPAddr(iph.dst));
88     }
89     return true;
90 }
91
92 /// Realiza el forwarding de paquetes (en un loop infinito)
93 void IPOut::forward_loop()
94     throw (std::runtime_error)
95 {
96     while (true)
97     {
98         std::string buf = forward_que.receive();
99         IPHeader iph(buf);
100 #ifdef DEBUG
101         std::cout << "IPOut::forward_loop (" << ip << "): A forwardear (id "
102                 << iph.id << ", offset " << iph.offset << ")\n";
103 #endif
104         send(iph, buf.substr(iph.header_len()));
105     }
106 }
107
108 /// Obtiene un identificador para el paquete
109 uint16_t IPOut::get_id() const
110 {
111     static uint16_t st = time(NULL);
112     uint16_t tt = time(NULL);
113     return (tt == st) ? ++st : tt;
114 }
115
116 // vim: set et sw=4 sts=4 :