]> git.llucax.com Git - z.facultad/75.74/practicos.git/commitdiff
Implementada y probada mínimamente la capa física usando TPC "doble vía" con un
authorLeandro Lucarella <llucax@gmail.com>
Wed, 14 Jun 2006 20:36:20 +0000 (20:36 +0000)
committerLeandro Lucarella <llucax@gmail.com>
Wed, 14 Jun 2006 20:36:20 +0000 (20:36 +0000)
solo proceso usando poll.

practicas/pipi/src/Makefile
practicas/pipi/src/devtcp.cpp [new file with mode: 0644]
practicas/pipi/src/devtcp.h [new file with mode: 0644]
practicas/pipi/src/libtcp.c [new file with mode: 0644]
practicas/pipi/src/libtcp.h [new file with mode: 0644]
practicas/pipi/src/test_devtcp.cpp [new file with mode: 0644]

index d312d83e9fcc5b1c99ef94a2aafcab337e3e0240..80e3177ec0e80070144126e244f4d765d7bc7d05 100644 (file)
@@ -18,7 +18,7 @@ CFLAGS = -Wall -ansi -pedantic-errors
 CFLAGS += -ggdb -DDEBUG
 
 # Para más verbose
-#CFLAGS += -DDEBUG2
+CFLAGS += -DDEBUG2
 
 # Opciones para el compilador C++.
 CXXFLAGS = $(CFLAGS) -fno-inline
@@ -31,10 +31,10 @@ CC=g++
 
 # 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
@@ -56,6 +56,8 @@ test_ipin: test_ipin.o ipin.o ipaddr.o ipheader.o devque.o
 
 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:
@@ -80,6 +82,44 @@ devque.o: /usr/include/bits/pthreadtypes.h /usr/include/bits/sched.h
 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
@@ -127,6 +167,31 @@ ipout.o: /usr/include/sys/ipc.h /usr/include/bits/ipctypes.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
@@ -191,3 +256,37 @@ test_send.o: /usr/include/sys/sysmacros.h /usr/include/bits/pthreadtypes.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
diff --git a/practicas/pipi/src/devtcp.cpp b/practicas/pipi/src/devtcp.cpp
new file mode 100644 (file)
index 0000000..828e0e6
--- /dev/null
@@ -0,0 +1,103 @@
+#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 :
diff --git a/practicas/pipi/src/devtcp.h b/practicas/pipi/src/devtcp.h
new file mode 100644 (file)
index 0000000..680561f
--- /dev/null
@@ -0,0 +1,43 @@
+#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 :
diff --git a/practicas/pipi/src/libtcp.c b/practicas/pipi/src/libtcp.c
new file mode 100644 (file)
index 0000000..a3aea62
--- /dev/null
@@ -0,0 +1,201 @@
+/* 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;
+}
+
diff --git a/practicas/pipi/src/libtcp.h b/practicas/pipi/src/libtcp.h
new file mode 100644 (file)
index 0000000..4964c0f
--- /dev/null
@@ -0,0 +1,40 @@
+/* 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_
+
diff --git a/practicas/pipi/src/test_devtcp.cpp b/practicas/pipi/src/test_devtcp.cpp
new file mode 100644 (file)
index 0000000..c588e62
--- /dev/null
@@ -0,0 +1,72 @@
+
+#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 :