solo proceso usando poll.
CFLAGS += -ggdb -DDEBUG
# Para más verbose
-#CFLAGS += -DDEBUG2
+CFLAGS += -DDEBUG2
# Opciones para el compilador C++.
CXXFLAGS = $(CFLAGS) -fno-inline
# Programas
targets=ip
-tests=test_send test_recv test_ipaddr test_ipin test_ipout
+tests=test_send test_recv test_ipaddr test_ipin test_ipout test_devtcp
# Fuentes
-fuentes ?= $(wildcard *.cpp)
+fuentes ?= $(wildcard *.cpp) $(wildcard *.c)
# REGLAS
test_ipout: test_ipout.o ipout.o ipaddr.o ipheader.o devque.o routetable.o
+test_devtcp: test_devtcp.o devtcp.o libtcp.o ipaddr.o
+
ip: ip.o ipout.o ipin.o ipaddr.o ipheader.o devque.o routetable.o
depend:
devque.o: /usr/include/sys/ipc.h /usr/include/bits/ipctypes.h
devque.o: /usr/include/bits/ipc.h /usr/include/sys/msg.h
devque.o: /usr/include/bits/msq.h
+devtcp.o: devtcp.h dev.h /usr/include/stdint.h /usr/include/features.h
+devtcp.o: /usr/include/sys/cdefs.h /usr/include/gnu/stubs.h
+devtcp.o: /usr/include/bits/wchar.h /usr/include/bits/wordsize.h
+devtcp.o: /usr/include/sys/poll.h /usr/include/bits/poll.h ipaddr.h libtcp.h
+devtcp.o: /usr/include/stdio.h /usr/include/bits/types.h
+devtcp.o: /usr/include/bits/typesizes.h /usr/include/libio.h
+devtcp.o: /usr/include/_G_config.h /usr/include/wchar.h /usr/include/gconv.h
+devtcp.o: /usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h
+devtcp.o: /usr/include/stdlib.h /usr/include/sys/types.h /usr/include/time.h
+devtcp.o: /usr/include/endian.h /usr/include/bits/endian.h
+devtcp.o: /usr/include/sys/select.h /usr/include/bits/select.h
+devtcp.o: /usr/include/bits/sigset.h /usr/include/bits/time.h
+devtcp.o: /usr/include/sys/sysmacros.h /usr/include/bits/pthreadtypes.h
+devtcp.o: /usr/include/bits/sched.h /usr/include/alloca.h
+devtcp.o: /usr/include/unistd.h /usr/include/bits/posix_opt.h
+devtcp.o: /usr/include/bits/confname.h /usr/include/getopt.h
+devtcp.o: /usr/include/signal.h /usr/include/bits/signum.h
+devtcp.o: /usr/include/bits/siginfo.h /usr/include/bits/sigaction.h
+devtcp.o: /usr/include/bits/sigcontext.h /usr/include/asm/sigcontext.h
+devtcp.o: /usr/include/asm-i486/sigcontext.h /usr/include/linux/compiler.h
+devtcp.o: /usr/include/bits/sigstack.h /usr/include/bits/sigthread.h
+devtcp.o: /usr/include/sys/wait.h /usr/include/sys/resource.h
+devtcp.o: /usr/include/bits/resource.h /usr/include/bits/waitflags.h
+devtcp.o: /usr/include/bits/waitstatus.h /usr/include/string.h
+devtcp.o: /usr/include/sys/socket.h /usr/include/sys/uio.h
+devtcp.o: /usr/include/bits/uio.h /usr/include/bits/socket.h
+devtcp.o: /usr/include/limits.h /usr/include/bits/posix1_lim.h
+devtcp.o: /usr/include/bits/local_lim.h /usr/include/linux/limits.h
+devtcp.o: /usr/include/bits/posix2_lim.h /usr/include/bits/sockaddr.h
+devtcp.o: /usr/include/asm/socket.h /usr/include/asm-i486/socket.h
+devtcp.o: /usr/include/asm/sockios.h /usr/include/asm-i486/sockios.h
+devtcp.o: /usr/include/netinet/in.h /usr/include/bits/in.h
+devtcp.o: /usr/include/bits/byteswap.h /usr/include/arpa/inet.h
+devtcp.o: /usr/include/netdb.h /usr/include/rpc/netdb.h
+devtcp.o: /usr/include/bits/netdb.h /usr/include/fcntl.h
+devtcp.o: /usr/include/bits/fcntl.h /usr/include/sys/ipc.h
+devtcp.o: /usr/include/bits/ipctypes.h /usr/include/bits/ipc.h
+devtcp.o: /usr/include/sys/msg.h /usr/include/bits/msq.h
ip.o: ipout.h ipaddr.h ipheader.h /usr/include/stdint.h
ip.o: /usr/include/features.h /usr/include/sys/cdefs.h
ip.o: /usr/include/gnu/stubs.h /usr/include/bits/wchar.h
ipout.o: /usr/include/bits/ipc.h /usr/include/sys/msg.h
ipout.o: /usr/include/bits/msq.h
routetable.o: routetable.h dev.h ipaddr.h
+test_devtcp.o: ipaddr.h devtcp.h dev.h /usr/include/stdint.h
+test_devtcp.o: /usr/include/features.h /usr/include/sys/cdefs.h
+test_devtcp.o: /usr/include/gnu/stubs.h /usr/include/bits/wchar.h
+test_devtcp.o: /usr/include/bits/wordsize.h /usr/include/sys/poll.h
+test_devtcp.o: /usr/include/bits/poll.h /usr/include/unistd.h
+test_devtcp.o: /usr/include/bits/posix_opt.h /usr/include/bits/types.h
+test_devtcp.o: /usr/include/bits/typesizes.h /usr/include/bits/confname.h
+test_devtcp.o: /usr/include/getopt.h /usr/include/fcntl.h
+test_devtcp.o: /usr/include/bits/fcntl.h /usr/include/sys/types.h
+test_devtcp.o: /usr/include/time.h /usr/include/endian.h
+test_devtcp.o: /usr/include/bits/endian.h /usr/include/sys/select.h
+test_devtcp.o: /usr/include/bits/select.h /usr/include/bits/sigset.h
+test_devtcp.o: /usr/include/bits/time.h /usr/include/sys/sysmacros.h
+test_devtcp.o: /usr/include/bits/pthreadtypes.h /usr/include/bits/sched.h
+test_devtcp.o: /usr/include/sys/wait.h /usr/include/signal.h
+test_devtcp.o: /usr/include/bits/signum.h /usr/include/bits/siginfo.h
+test_devtcp.o: /usr/include/bits/sigaction.h /usr/include/bits/sigcontext.h
+test_devtcp.o: /usr/include/asm/sigcontext.h
+test_devtcp.o: /usr/include/asm-i486/sigcontext.h
+test_devtcp.o: /usr/include/linux/compiler.h /usr/include/bits/sigstack.h
+test_devtcp.o: /usr/include/bits/sigthread.h /usr/include/sys/resource.h
+test_devtcp.o: /usr/include/bits/resource.h /usr/include/bits/waitflags.h
+test_devtcp.o: /usr/include/bits/waitstatus.h /usr/include/sys/ipc.h
+test_devtcp.o: /usr/include/bits/ipctypes.h /usr/include/bits/ipc.h
+test_devtcp.o: /usr/include/sys/msg.h /usr/include/bits/msq.h
test_ipaddr.o: ipaddr.h ipheader.h /usr/include/stdint.h
test_ipaddr.o: /usr/include/features.h /usr/include/sys/cdefs.h
test_ipaddr.o: /usr/include/gnu/stubs.h /usr/include/bits/wchar.h
test_send.o: /usr/include/bits/sched.h /usr/include/sys/ipc.h
test_send.o: /usr/include/bits/ipctypes.h /usr/include/bits/ipc.h
test_send.o: /usr/include/sys/msg.h /usr/include/bits/msq.h
+libtcp.o: libtcp.h /usr/include/stdio.h /usr/include/features.h
+libtcp.o: /usr/include/sys/cdefs.h /usr/include/gnu/stubs.h
+libtcp.o: /usr/include/bits/types.h /usr/include/bits/wordsize.h
+libtcp.o: /usr/include/bits/typesizes.h /usr/include/libio.h
+libtcp.o: /usr/include/_G_config.h /usr/include/wchar.h
+libtcp.o: /usr/include/bits/wchar.h /usr/include/gconv.h
+libtcp.o: /usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h
+libtcp.o: /usr/include/stdlib.h /usr/include/sys/types.h /usr/include/time.h
+libtcp.o: /usr/include/endian.h /usr/include/bits/endian.h
+libtcp.o: /usr/include/sys/select.h /usr/include/bits/select.h
+libtcp.o: /usr/include/bits/sigset.h /usr/include/bits/time.h
+libtcp.o: /usr/include/sys/sysmacros.h /usr/include/bits/pthreadtypes.h
+libtcp.o: /usr/include/bits/sched.h /usr/include/alloca.h
+libtcp.o: /usr/include/unistd.h /usr/include/bits/posix_opt.h
+libtcp.o: /usr/include/bits/confname.h /usr/include/getopt.h
+libtcp.o: /usr/include/signal.h /usr/include/bits/signum.h
+libtcp.o: /usr/include/bits/siginfo.h /usr/include/bits/sigaction.h
+libtcp.o: /usr/include/bits/sigcontext.h /usr/include/asm/sigcontext.h
+libtcp.o: /usr/include/asm-i486/sigcontext.h /usr/include/linux/compiler.h
+libtcp.o: /usr/include/bits/sigstack.h /usr/include/bits/sigthread.h
+libtcp.o: /usr/include/sys/wait.h /usr/include/sys/resource.h
+libtcp.o: /usr/include/bits/resource.h /usr/include/bits/waitflags.h
+libtcp.o: /usr/include/bits/waitstatus.h /usr/include/string.h
+libtcp.o: /usr/include/sys/socket.h /usr/include/sys/uio.h
+libtcp.o: /usr/include/bits/uio.h /usr/include/bits/socket.h
+libtcp.o: /usr/include/limits.h /usr/include/bits/posix1_lim.h
+libtcp.o: /usr/include/bits/local_lim.h /usr/include/linux/limits.h
+libtcp.o: /usr/include/bits/posix2_lim.h /usr/include/bits/sockaddr.h
+libtcp.o: /usr/include/asm/socket.h /usr/include/asm-i486/socket.h
+libtcp.o: /usr/include/asm/sockios.h /usr/include/asm-i486/sockios.h
+libtcp.o: /usr/include/netinet/in.h /usr/include/stdint.h
+libtcp.o: /usr/include/bits/in.h /usr/include/bits/byteswap.h
+libtcp.o: /usr/include/arpa/inet.h /usr/include/netdb.h
+libtcp.o: /usr/include/rpc/netdb.h /usr/include/bits/netdb.h
--- /dev/null
+#include "devtcp.h"
+#include "ipaddr.h"
+#include "libtcp.h"
+#include <cstring>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/ipc.h>
+#include <sys/msg.h>
+#include <sys/poll.h>
+#ifdef DEBUG
+#include <iostream>
+#endif
+
+#define ISSET(var, flag) ((var & flag) == flag)
+
+DevTCP::DevTCP(mac_type mac, uint16_t port, size_t mtu)
+ throw (std::runtime_error, std::logic_error):
+ Dev(mac, mtu), port(port), pfds_size(1)
+{
+ if ((pfds[0].fd = libtcp_open_pasivo(port)) == -1)
+ throw std::runtime_error("No se pudo crear el socket que escucha");
+ pfds[0].events = POLLIN | POLLPRI;
+}
+
+void DevTCP::transmit(const std::string& data, const mac_type& mac)
+ throw (std::runtime_error, std::logic_error)
+{
+ if (data.size() > mtu)
+ throw std::logic_error("Tamaño de datos mayor al MTU");
+ if (tx_pool.find(mac) == tx_pool.end()) // No existe la conexión
+ {
+ std::string addr = IPAddr(mac);
+#ifdef DEBUG2
+ std::cout << "DevTCP::transmit: conectando a " << addr << ":" << port << "\n";
+#endif
+ tx_pool[mac] = libtcp_open_activo(addr.c_str(), port);
+ if (tx_pool[mac] == -1)
+ throw std::runtime_error("Error al conectar el socket");
+ }
+ size_t size = data.size();
+ if (libtcp_send(tx_pool[mac], &size, sizeof(size_t)) != sizeof(size_t))
+ throw std::runtime_error("Error al enviar por el socket");
+ if ((unsigned)libtcp_send(tx_pool[mac], data.c_str(), data.size()) != data.size())
+ throw std::runtime_error("Error al enviar por el socket");
+#ifdef DEBUG2
+ std::cout << "DevTCP::transmit(mac = " << mac << ", size = "
+ << data.size() << ")\n";
+#endif
+}
+
+std::string DevTCP::receive() throw (std::runtime_error)
+{
+ // Nos fijamos en todos los file descriptors si hay algo para nosotros.
+ while (true)
+ {
+ int res = poll(pfds, pfds_size, 5000);
+ if (res == -1)
+ throw std::runtime_error("Error al hacer poll");
+ if (!res)
+ continue;
+ // Si tengo conexiones esperando, las atiendo...
+ if (ISSET(pfds[0].revents, POLLIN)
+ || ISSET(pfds[0].revents, POLLPRI))
+ {
+ if (pfds_size == DEVTCP_MAX_CONN)
+ throw std::runtime_error("Demasiadas conexiones activas");
+ pfds[pfds_size].fd = accept(pfds[0].fd, NULL, NULL);
+ if (pfds[pfds_size].fd == -1)
+ throw std::runtime_error("Error al hacer accept");
+ pfds[pfds_size].events = POLLIN | POLLPRI;
+ ++pfds_size;
+ }
+ // Luego me fijo si tengo algún otro socket con cosas para recibir
+ for (size_t i = 1; i < pfds_size; ++i)
+ {
+ if (ISSET(pfds[i].revents, POLLIN)
+ || ISSET(pfds[i].revents, POLLPRI))
+ {
+ size_t size;
+ int r = libtcp_receive_bin(pfds[i].fd, &size, sizeof(size_t));
+ if (r != sizeof(size_t))
+ // TODO cerrar socket?
+ continue;
+ char* buf = (char*)malloc(size);
+ r = libtcp_receive_bin(pfds[i].fd, buf, size);
+ if ((unsigned)r != size)
+ // TODO cerrar socket?
+ continue;
+ std::string ret(buf, size);
+ free(buf);
+#ifdef DEBUG2
+ std::cout << "DevTCP::receive(msgtype/mac = " << mac << ", size = "
+ << ret.size() << ")\n";
+#endif
+ return ret;
+ }
+ }
+ }
+ return ""; // No deberíamos caer nunca acá.
+}
+
+// vim: set et sw=4 sts=4 :
--- /dev/null
+#ifndef _DEVTCP_H_
+#define _DEVTCP_H_
+
+#include "dev.h"
+#include <map>
+#include <stdint.h>
+#include <sys/poll.h>
+
+#define DEVTCP_DEFAULT_PORT 65000
+#define DEVTCP_MAX_CONN 16
+
+/// Dispositivo de red (capa de enlace) implementado con TCP
+struct DevTCP: Dev
+{
+
+ /// Puerto en el cual escucha por conexiones
+ uint16_t port;
+
+ /// Información para poll sobre los fds
+ pollfd pfds[DEVTCP_MAX_CONN];
+ size_t pfds_size;
+
+ /// Mapa con el fd que corresponde a la conexión saliente con cada host
+ std::map< mac_type, int > tx_pool;
+
+ /// Constructor
+ DevTCP(mac_type mac, uint16_t port = DEVTCP_DEFAULT_PORT,
+ size_t mtu = DEV_MAX_MTU)
+ throw (std::runtime_error, std::logic_error);
+
+ /// Envía un frame
+ void transmit(const std::string& data, const mac_type& mac)
+ throw (std::runtime_error, std::logic_error);
+
+ /// Recibe un frame
+ std::string receive()
+ throw (std::runtime_error);
+
+};
+
+#endif // _DEVTCP_H_
+
+// vim: set et sw=4 sts=4 :
--- /dev/null
+/* LibTcp - Released underOpen Software License v. 2.0
+ *
+ * This Open Software License (the "License") applies to any original work of authorship
+ * (the "Original Work") whose owner (the "Licensor") has placed the following notice
+ * immediately following the copyright notice for the Original Work:
+ *
+ * Licensed under the Open Software License version 2.0
+ *
+ * See http://www.opensource.org/licenses/osl-2.0.php or the LICENSE file for more
+ * details.
+ */
+
+#include "libtcp.h"
+
+/** Abre un socket en modo activo para establecer una conexión con un servidor.
+ *
+ * Esta función es utilizada por los clientes para establecer una conexión TCP
+ * con un servidor.
+ *
+ * \param servidor Nombre del host server
+ * \param port Número del puerto
+ * \return >0 El descriptor del socket, si se conecto al servidor.
+ * \return -2 Si no existe el nombre del servidor.
+ * \return -1 Si hubo error en la conexion y se debe consultar errno.
+ */
+int libtcp_open_activo (const char *server, int port)
+{
+ int sockfd; /* socket de la conexion */
+ struct sockaddr_in serv_addr;
+ struct hostent *ptr_server; /*puntero a dir del server(gethostbyname)*/
+
+ /* Borrar la estructura (poner en cero) */
+ bzero ((char *) &serv_addr, sizeof(serv_addr));
+
+ /* Inicializo familia de direcciones (protocolo IP) */
+ serv_addr.sin_family = AF_INET;
+
+ /* Cargar port en el socket: Convertir Host-TO-Network-Short integer */
+ serv_addr.sin_port = htons (port);
+
+ /* Cargo dirección del server en el socket. Convertir nombre del host en su direccion */
+ ptr_server = gethostbyname (server);
+ if (ptr_server == NULL) {
+ /* No existe nombre de host. Posible falla en resolución de nombre */
+ return -2;
+ }
+ memcpy (&serv_addr.sin_addr, ptr_server->h_addr, ptr_server->h_length);
+
+ /* Abro como un socket de TCP (Internet stream socket) */
+ if ((sockfd = socket (AF_INET, SOCK_STREAM, 0)) < 0) {
+ /* Error en la creacion del socket */
+ return -1;
+ }
+
+ if (connect (sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) {
+ /* TODO : Deberia ser un codigo de error diferente, asi puedo diferenciarlos */
+ return -1;
+ }
+
+ return sockfd;
+}
+
+/** Abre un socket en modo pasivo usando protocolo TCP.
+ *
+ * La función se encarga de inicializar y crear el socket, y
+ * luego enlazarla con el SO.
+ *
+ * \param port Puerto sobre el cual atiende este servidor
+ * \return >0 El socket, si la operacion fue exitosa
+ * \return <0 Si hubo un error (ver errno)
+ */
+int libtcp_open_pasivo (int port)
+{
+ char mostrar[80]; /* mensajes en la pantalla */
+ int sockfd; /* socket que sirve como template */
+ struct sockaddr_in serv_addr;
+
+ bzero ((char *)&serv_addr, sizeof (serv_addr));
+ serv_addr.sin_family = AF_INET; /* Familia protocolos TCP/IP */
+ serv_addr.sin_addr.s_addr = htonl (INADDR_ANY); /* Cualquier cliente */
+ serv_addr.sin_port = htons ((unsigned short)port); /* Port en formato red */
+
+ /* Crea un socket para TCP (un Internet stream socket) */
+ if ((sockfd = socket (AF_INET, SOCK_STREAM, 0)) < 0) {
+ return -1;
+ }
+
+ // Reusamos address
+ int yes = 1;
+ if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (char *) &yes,
+ sizeof(yes)) < 0)
+ {
+ perror ("setsockopt");
+ close (sockfd);
+ return -1;
+ }
+
+ sprintf (mostrar, "LibTcp::ServerPasivo: socket creado %d\n", sockfd);
+ write (fileno(stdout), mostrar, strlen (mostrar));
+
+ /* Vincular el socket con la direccion local */
+ if (bind (sockfd, (struct sockaddr *) &serv_addr, sizeof (serv_addr)) < 0) {
+ return -1;
+ }
+
+ sprintf (mostrar, "LibTcp::Server: se hizo el bind\n");
+ write(fileno(stdout), mostrar, strlen(mostrar));
+
+ /* Definir la cola de espera = hasta 5 clientes */
+ listen(sockfd, 5);
+
+ sprintf (mostrar, "LibTcp::Server: se hizo el listen con el socket %d\n", sockfd);
+ write(fileno(stdout), mostrar, strlen(mostrar));
+
+ return sockfd;
+}
+
+/** Lee de a un byte por vez a un buffer hasta encontrar un "\n".
+ *
+ * La cadena leída es terminada en "\0".
+ *
+ * \return El tamaño, en caracteres, de la cadena leida.
+ * \param fd Descriptor del socket
+ * \param ptr Puntero al buffer
+ * \param maxlong Tamaño del buffer (en bytes)
+ * \TODO Soporte de caracteres multibyte
+ */
+int libtcp_receive (int fd, char *ptr, unsigned int maxlong)
+{
+ unsigned n;
+ int car;
+ char c;
+
+ for (n = 0; n < maxlong; n++) {
+ if ((car = read (fd, &c, sizeof (char))) == 1) {
+ *ptr++ = c;
+ if (c == '\n')
+ break;
+ } else if (car == 0) {
+ if (n == 1)
+ /* EOF, sin datos leidos */
+ return 0;
+ else
+ break; /* EOF, se leyo algo */
+ } else
+ return -1;
+ }
+
+ *ptr = '\0';
+ return n;
+}
+
+/** Lee una informacion binaria */
+int libtcp_receive_bin (int fd, void *ptr, unsigned int n)
+{
+ int nfaltan, nrecibidos;
+ char *p = (char*) ptr;
+
+ nfaltan = n;
+ while (nfaltan > 0) {
+ nrecibidos = read (fd, p, nfaltan);
+ if (nrecibidos <= 0)
+ return nrecibidos;
+
+ nfaltan -= nrecibidos;
+ p += nrecibidos;
+ }
+
+ return n - nfaltan;
+}
+
+
+/** Escribe n bytes sobre un descriptor.
+ *
+ * Si no se escribieron n bytes, trata de repetir hasta que se hayan escrito
+ * los n bytes.
+ *
+ * Se debe usar esta funcion cuando el descriptor en un stream socket.
+ *
+ * \param fd Descriptor del socket
+ * \param ptr Puntero al mensaje
+ * \param n cantidad de bytes
+ */
+int libtcp_send (int fd, const void *ptr, unsigned int n)
+{
+ int nfaltan, nenviados;
+ const char *p = (const char *) ptr;
+
+ nfaltan = n;
+ while (nfaltan > 0) {
+ nenviados = write (fd, p, nfaltan);
+ if (nenviados <= 0)
+ return nenviados;
+
+ nfaltan -= nenviados;
+ p += nenviados;
+ }
+
+ return n - nfaltan;
+}
+
--- /dev/null
+/* LibTcp - Released underOpen Software License v. 2.0
+ *
+ * This Open Software License (the "License") applies to any original work of authorship
+ * (the "Original Work") whose owner (the "Licensor") has placed the following notice
+ * immediately following the copyright notice for the Original Work:
+ *
+ * Licensed under the Open Software License version 2.0
+ *
+ * See http://www.opensource.org/licenses/osl-2.0.php or the LICENSE file for more
+ * details.
+ */
+
+#ifndef _LIBTCP_COMMON_H_
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <signal.h>
+#include <sys/wait.h>
+#include <sys/resource.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+
+#define LIBTCP_DEFAULT_UDP_PORT 5000
+#define LIBTCP_DEFAULT_TCP_PORT 5000
+
+extern int errno;
+
+int libtcp_open_activo (const char *server, int port);
+int libtcp_open_pasivo (int port);
+int libtcp_receive (int fd, char *ptr, unsigned int maxlong);
+int libtcp_receive_bin (int fd, void *ptr, unsigned int maxlong);
+int libtcp_send (int fd, const void *ptr, unsigned int n);
+
+#endif // _LIBTCP_COMMON_H_
+
--- /dev/null
+
+#include "ipaddr.h"
+#include "devtcp.h"
+#include <iostream>
+#include <fstream>
+#include <sstream>
+#include <string>
+#include <cassert>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <sys/ipc.h>
+#include <sys/msg.h>
+#include <signal.h>
+
+// Uso: ./test_devtcp port
+
+void send_loop(Dev& dev);
+
+int main(int argc, char* argv[])
+{
+ if (argc < 3)
+ {
+ std::cerr << "Uso: " << argv[0] << " addr port\n";
+ return 1;
+ }
+ Dev::mac_type mac = atoi(argv[1]);
+ uint16_t port = atoi(argv[2]);
+ // Creo medio físico y cola para forwarding
+ DevTCP dev(mac, port);
+ // Creo procesos
+ pid_t pid_send = fork();
+ if (pid_send == -1)
+ {
+ perror("fork()");
+ return 2;
+ }
+ if (pid_send) // Padre, send
+ {
+ int ret;
+ send_loop(dev);
+ kill(pid_send, SIGTERM);
+ waitpid(pid_send, &ret, 0);
+ return 0;
+ }
+ else // Hijo receive
+ {
+ while (true)
+ {
+ std::string s = dev.receive();
+ std::cout << "Recibido '" << s << "' (len " << s.size() << ")\n";
+ }
+ return 0;
+ }
+ return 0;
+}
+
+void send_loop(Dev& dev)
+{
+ std::string dst;
+ std::string msg;
+ while (std::getline(std::cin, dst))
+ {
+ if (!std::getline(std::cin, msg))
+ break;
+ dev.transmit(msg, IPAddr(dst.c_str()));
+ std::cout << "Enviado '" << msg << "' a " << dst << "\n";
+ }
+}
+
+// vim: set et sw=4 sts=4 :