]> git.llucax.com Git - z.facultad/75.74/practicos.git/blob - practicas/pipi/src/devtcp.cpp
Se generaliza el devque para seguir (ab)usándolo como cola y poder pedir de
[z.facultad/75.74/practicos.git] / practicas / pipi / src / devtcp.cpp
1 #include "devtcp.h"
2 #include "ipaddr.h"
3 #include "libtcp.h"
4 #include <cstring>
5 #include <unistd.h>
6 #include <fcntl.h>
7 #include <sys/types.h>
8 #include <sys/ipc.h>
9 #include <sys/msg.h>
10 #include <sys/poll.h>
11 #ifdef DEBUG
12 #include <iostream>
13 #endif
14
15 #define ISSET(var, flag) ((var & flag) == flag)
16
17 DevTCP::DevTCP(mac_type mac, uint16_t port, size_t mtu)
18     throw (std::runtime_error, std::logic_error):
19         Dev(mac, mtu), port(port), pfds_size(1)
20 {
21     if ((pfds[0].fd = libtcp_open_pasivo(port)) == -1)
22         throw std::runtime_error("No se pudo crear el socket que escucha");
23     pfds[0].events = POLLIN | POLLPRI;
24 }
25
26 void DevTCP::transmit(const std::string& data, const mac_type& mac)
27     throw (std::runtime_error, std::logic_error)
28 {
29     if (data.size() > mtu)
30         throw std::logic_error("Tamaño de datos mayor al MTU");
31     if (tx_pool.find(mac) == tx_pool.end()) // No existe la conexión
32     {
33         std::string addr = IPAddr(mac);
34 #ifdef DEBUG2
35         std::cout << "DevTCP::transmit: conectando a " << addr << ":" << port << "\n";
36 #endif
37         tx_pool[mac] = libtcp_open_activo(addr.c_str(), port);
38         if (tx_pool[mac] == -1)
39             throw std::runtime_error("Error al conectar el socket");
40     }
41     size_t size = data.size();
42     if (libtcp_send(tx_pool[mac], &size, sizeof(size_t)) != sizeof(size_t))
43         throw std::runtime_error("Error al enviar por el socket");
44     if ((unsigned)libtcp_send(tx_pool[mac], data.c_str(), data.size()) != data.size())
45         throw std::runtime_error("Error al enviar por el socket");
46 #ifdef DEBUG2
47     std::cout << "DevTCP::transmit(mac = " << mac << ", size = "
48         << data.size() << ")\n";
49 #endif
50 }
51
52 std::string DevTCP::receive() throw (std::runtime_error)
53 {
54     // Nos fijamos en todos los file descriptors si hay algo para nosotros.
55     while (true)
56     {
57         int res = poll(pfds, pfds_size, 5000);
58         if (res == -1)
59             throw std::runtime_error("Error al hacer poll");
60         if (!res)
61             continue;
62         // Si tengo conexiones esperando, las atiendo...
63         if (ISSET(pfds[0].revents, POLLIN)
64                 || ISSET(pfds[0].revents, POLLPRI))
65         {
66             if (pfds_size == DEVTCP_MAX_CONN)
67                 throw std::runtime_error("Demasiadas conexiones activas");
68             pfds[pfds_size].fd = accept(pfds[0].fd, NULL, NULL);
69             if (pfds[pfds_size].fd == -1)
70                 throw std::runtime_error("Error al hacer accept");
71             pfds[pfds_size].events = POLLIN | POLLPRI;
72             ++pfds_size;
73         }
74         // Luego me fijo si tengo algún otro socket con cosas para recibir
75         for (size_t i = 1; i < pfds_size; ++i)
76         {
77             if (ISSET(pfds[i].revents, POLLIN)
78                     || ISSET(pfds[i].revents, POLLPRI))
79             {
80                 size_t size;
81                 int r = libtcp_receive_bin(pfds[i].fd, &size, sizeof(size_t));
82                 if (r != sizeof(size_t))
83                     // TODO cerrar socket?
84                     continue;
85                 char* buf = (char*)malloc(size);
86                 r = libtcp_receive_bin(pfds[i].fd, buf, size);
87                 if ((unsigned)r != size)
88                     // TODO cerrar socket?
89                     continue;
90                 std::string ret(buf, size);
91                 free(buf);
92 #ifdef DEBUG2
93                 std::cout << "DevTCP::receive(msgtype/mac = " << mac << ", size = "
94                     << ret.size() << ")\n";
95 #endif
96                 return ret;
97             }
98         }
99     }
100     return ""; // No deberíamos caer nunca acá.
101 }
102
103 // vim: set et sw=4 sts=4 :