]> git.llucax.com Git - z.facultad/75.74/practicos.git/blob - practicas/pipi/src/ipout.cpp
3e8dadc899ae045a388d5f2d1f48c5ec522df62c
[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
11 /// Constructor
12 IPOut::IPOut(const IPAddr& ip, RouteTable& rtable, Dev& forward_que, std::ostream& log):
13     ip(ip), rtable(rtable), forward_que(forward_que), log(log)
14 {
15 }
16
17 void IPOut::drop(const std::string& msg, const std::string& buf)
18 {
19     log << "IPOut::drop: " << msg << "\n\tBuffer: " << buf << "\n";
20 }
21
22 void IPOut::drop(const std::string& msg, const IPHeader& iph)
23 {
24     log << "IPOut::drop: " << msg << "\n\tIPHeader: " << iph << "\n";
25 }
26
27 /// Envía un paquete IP
28 bool IPOut::send(const std::string& data, uint8_t proto, IPAddr dst, IPAddr src,
29         bool df, uint8_t ttl, uint16_t id)
30     throw (std::runtime_error)
31 {
32     // Mando todo lo que tengo para forwardear
33     while (to_forward())
34     {
35         std::string buf = forward_que.receive();
36         IPHeader iph(buf);
37 #ifdef DEBUG
38         log << "IPOut::send: A forwardear\n";
39 #endif
40         send(iph, buf.substr(iph.header_len()));
41     }
42     // Mando el paquete en sí
43     // Armamos cabecera
44     if (!src)
45         src = ip;
46     if (!id)
47         id = get_id();
48     IPHeader iph(4, IPHeader::header_len() + data.size(), id, df, 0, 0,
49             ttl, proto, src, dst);
50     return send(iph, data);
51 }
52
53 /// Envía un paquete IP
54 bool IPOut::send(IPHeader iph, std::string data) throw (std::runtime_error)
55 {
56     // Buscamos ruta
57     RouteTable::Route* r = rtable.get(iph.dst);
58     if (!r)
59     {
60         drop("No existe una ruta para el destino", iph);
61         return false;
62     }
63     // No quieren fragmentar
64     if (iph.df && (IPHeader::header_len() + data.size() > r->iface->mtu))
65     {
66         drop("Tamaño de paquete más grande que MTU y DF=1", iph);
67         return false;
68     }
69     // Fragmenta (de ser necesario)
70     int max_payload = r->iface->mtu - IPHeader::header_len();
71     int cant_frag = data.size() / max_payload;
72     if (data.size() % max_payload)
73         ++cant_frag;
74     for (int i = 0; i < cant_frag; ++i)
75     {
76         IPHeader iph2 = iph;
77         if (i != (cant_frag - 1))
78             iph2.mf = 1;
79         iph2.offset += i * max_payload;
80         iph2.total_len -= i * max_payload;
81         iph2.do_checksum();
82         std::string buf((char*) &iph2, sizeof(IPHeader));
83         buf += data.substr(i * max_payload, max_payload);
84 #ifdef DEBUG
85         log << "IPOut::send: Fragmento 0 => IPHeader: " << iph2 << "\n";
86         std::string tmp = data.substr(i * max_payload, max_payload);
87         log << "\tdata (" << tmp.size() << ") = " << tmp << "\n";
88 #endif
89         r->iface->transmit(buf, r->gateway ? r->gateway : IPAddr(iph.dst));
90     }
91     return true;
92 }
93
94 /// Obtiene un identificador para el paquete
95 uint16_t IPOut::get_id() const
96 {
97     return time(NULL);
98 }
99
100 /// Se fija si hay paquetes a forwardear (y devuelve cuantos hay)
101 unsigned IPOut::to_forward()
102 {
103     struct msqid_ds minfo;
104     msgctl(forward_que.que_id, IPC_STAT, &minfo);
105     return minfo.msg_qnum;
106 }
107
108 // vim: set et sw=4 sts=4 :