--- /dev/null
+
+SUBDIRS=libtcp common parte1
+
+.PHONY: clean
+all clean:
+ @set fnord $(MAKEFLAGS); amf=$$2; target=$@ ; \
+ dot_seen=no; \
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ echo "Making $$target in $$subdir"; \
+ if test "$$subdir" = "."; then \
+ dot_seen=yes; \
+ local_target="$$target-am"; \
+ else \
+ local_target="$$target"; \
+ fi; \
+ (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+ || case "$$amf" in *=*) exit 1;; *k*) fail=yes;; *) exit 1;; esac; \
+ done;
+
--- /dev/null
+
+TARGET=common.a
+LIBS=
+CFLAGS=-O0 -g
+CC=g++
+
+all: $(TARGET)
+
+$(TARGET): common.o
+ $(AR) cru $(TARGET) common.o
+
+common.o: common.h common.c
+
+.PHONY: clean
+clean:
+ rm -f *.o $(TARGET)
--- /dev/null
+/* 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 "common.h"
+#include <string.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <unistd.h>
+
+void print_msg (FILE *fp, const char *fmt, ...)
+{
+ char linea[255];
+ va_list va;
+
+ va_start (va, fmt);
+ vsprintf(linea, fmt, va);
+ va_end (va);
+
+ write (fileno (fp), linea, strlen (linea));
+}
--- /dev/null
+/* 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 _ECHO_COMMON_H_
+#define _ECHO_COMMON_H_
+
+#include <stdio.h>
+
+void print_msg (FILE *fp, const char *fmt, ...);
+
+#endif // _ECHO_COMMON_H_
+
--- /dev/null
+# LibTcp - Internet stream version (TCP protocol)
+
+TARGET=libtcp.a
+LIBS=
+CFLAGS=-O0 -g
+CC=g++
+
+all: $(TARGET)
+
+$(TARGET): libtcp.o
+ $(AR) cru libtcp.a libtcp.o
+
+libtcp.o: libtcp.h libtcp.c
+
+.PHONY: clean
+clean:
+ rm -f *.o $(TARGET)
--- /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 ((u_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;
+ }
+
+ 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)
+{
+ int n, 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 maxlong)
+{
+ return read (fd, ptr, maxlong);
+}
+
+
+/** 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 char *ptr, unsigned int n)
+{
+ int nfaltan, nenviados;
+
+ nfaltan = n;
+ while (nfaltan > 0) {
+ nenviados = write (fd, ptr, nfaltan);
+ if (nenviados <= 0)
+ return nenviados;
+
+ nfaltan -= nenviados;
+ ptr += 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 char *ptr, unsigned int n);
+
+#endif // _LIBTCP_COMMON_H_
+
--- /dev/null
+
+CLIENTE=client
+SERVER_ITER=serverhandler
+SERVER_REAL=server
+LIBS=../libtcp/libtcp.a ../common/common.a
+CFLAGS=-g -Wall -I../libtcp -I../common
+CXXFLAGS=$(CFLAGS)
+TARGET=$(CLIENTE) $(SERVER_ITER) $(SERVER_REAL)
+CC=g++
+
+all: $(TARGET)
+
+$(CLIENTE): client.o $(LIBS)
+
+client.o: client.cpp
+
+$(SERVER_ITER): serverhandler.o $(LIBS)
+
+serverhandler.o: serverhandler.cpp
+
+$(SERVER_REAL): server.o $(LIBS)
+
+server.o: server.cpp
+
+.PHONY: clean
+clean:
+ rm -f *.o $(TARGET)
--- /dev/null
+/*
+ * Cliente que envía operaciones al hash del servidor.
+ */
+
+#include "libtcp.h"
+#include "common.h"
+#include "protocol.h"
+#include <string>
+#include <sstream>
+#include <iostream>
+
+int main(int argc, char *argv[])
+{
+ int sockfd;
+ int client_id;
+ char *server_name;
+ char *localhost = "localhost";
+ pid_t pid;
+ int port;
+ const char *pname = argv[0];
+
+ // mostrar el pid del cliente
+ pid = getpid();
+ print_msg(stdout, "%s Cliente con pid = %d\n", pname, pid);
+
+ // Verifico parametros de linea de comandos
+ if (argc > 2)
+ port = atoi (argv[2]);
+ else
+ port = LIBTCP_DEFAULT_TCP_PORT;
+
+ if (port <= 0)
+ {
+ // valor incorrecto: aviso y terminar
+ print_msg(stdout, "%s (%d): Nro. de port invalido %d\n", pname, pid, port);
+ exit(1);
+ }
+
+ if (argc > 1)
+ server_name = argv[1];
+ else
+ server_name = localhost;
+
+ // id del cliente, por default calculado en base al pid
+ if (argc > 3)
+ client_id = atoi(argv[3]);
+ else
+ client_id = pid % 32;
+
+ // Abro el socket
+ sockfd = libtcp_open_activo(server_name, port);
+ if (sockfd < 0)
+ {
+ // ERROR
+ if (sockfd == -2)
+ {
+ print_msg(stdout, "%s (%d): Nombre de server no existe %s\n", pname, pid, server_name);
+ exit(1);
+ }
+ else
+ {
+ perror("Error al llamar a libtcp_open_activo");
+ exit(1);
+ }
+ }
+
+ std::string line;
+ Protocol::Type type;
+ while (std::getline(std::cin, line))
+ {
+ std::istringstream iss(line);
+ std::string token;
+ if (!(iss >> token)) return 0;
+ if (token == "put")
+ {
+ type = Protocol::PUT;
+ }
+ else if (token == "find")
+ {
+ type = Protocol::FIND;
+ }
+ else if (token == "del")
+ {
+ type = Protocol::DEL;
+ }
+ else
+ {
+ print_msg(stderr, "%s (%d): Invalid token %s!\n", pname, pid, token.c_str());
+ exit(1);
+ }
+ while (iss >> token)
+ {
+ Protocol proto(type, 0, client_id, token.size());
+ print_msg(stdout, "%s (%d): escribiendo %s\n", pname, pid, token.c_str());
+ if (libtcp_send(sockfd, (char*) &proto, sizeof(Protocol)) != sizeof(Protocol)
+ || libtcp_send(sockfd, token.c_str(), token.size()) != token.size())
+ {
+ print_msg(stderr, "%s (%d): error en envio sobre el socket\n", pname, pid);
+ exit(1);
+ }
+ }
+ Protocol proto(type, 1, client_id, 0);
+ if (libtcp_send(sockfd, (char*) &proto, sizeof(Protocol)) != sizeof(Protocol))
+ {
+ print_msg(stderr, "%s (%d): error en envio sobre el socket\n", pname, pid);
+ exit(1);
+ }
+ // Esperando respuesta del servidor con el resultado
+ int response;
+ int n = libtcp_receive(sockfd, (char*) &response, sizeof(response));
+ if (n < 0)
+ {
+ print_msg(stderr, "%s (%d): error en recibir\n", pname, pid);
+ }
+ else
+ {
+ print_msg(stdout, "%s (%d): el server responde %d\n", pname, pid, response);
+ }
+ }
+
+ Protocol proto(Protocol::QUIT, 1, client_id, 0);
+ if (libtcp_send(sockfd, (char*) &proto, sizeof(Protocol)) != sizeof(Protocol))
+ {
+ print_msg(stderr, "%s (%d): error en envio sobre el socket\n", pname, pid);
+ exit(1);
+ }
+
+ /* Limpio y salgo */
+ close(sockfd);
+ return EXIT_SUCCESS;
+}
+
+// vim: set et sw=4 sts=4 :
--- /dev/null
+#ifndef _PROTOCOL_H_
+#define _PROTOCOL_H_
+
+struct Protocol
+{
+ enum Type { PUT, FIND, DEL, QUIT };
+ enum Result { OK, NOT_FOUND, EXISTS };
+
+ unsigned char type: 2; // 2 bits para tipo
+ unsigned char end: 1; // 1 bit para marca de FIN
+ unsigned char client_id: 5; // 5 bits para id de cliente
+ unsigned char len; // 255 máximo
+
+ Protocol() {}
+
+ Protocol(unsigned type, unsigned end, unsigned client_id, unsigned len):
+ type(type), end(end), client_id(client_id), len(len) {}
+
+};
+
+#endif // _PROTOCOL_H_
+
+// vim: set et sw=4 sts=4 :
--- /dev/null
+/*
+ * Server concurrente usando protocolo TCP para manipular un set.
+ */
+
+#include "libtcp.h"
+#include "common.h"
+#include <csignal>
+
+void fin_hijos(int);
+
+int main (int argc, char *argv[])
+{
+ static char el_socket[15]; /* string que contiene el socket para el servidor de eco */
+
+ int sockfd; /* socket que sirve como template */
+ int newsockfd; /* socket conectado al cliente */
+ int port;
+ unsigned int clilen; /* longitud dir. cliente */
+ unsigned int childpid; /* pid del hijo */
+ struct sockaddr_in cli_addr;
+
+ /* Verifico parametros de linea de comandos */
+ if (argc > 1)
+ port = atoi(argv[1]);
+ else
+ port = LIBTCP_DEFAULT_TCP_PORT;
+
+
+ /* Inicia Servidor - Open Pasivo */
+ if ((sockfd = libtcp_open_pasivo(port)) < 0)
+ {
+ perror("Server: no se puede abrir el stream socket");
+ exit(1);
+ }
+
+ print_msg(stdout, "server: se hizo el open pasivo, socket %d\n", sockfd);
+
+ signal(SIGCHLD, fin_hijos);
+
+ /* PROCESAMIENTO DEL SERVER */
+ while (1)
+ {
+ clilen = sizeof(cli_addr);
+ newsockfd = accept(sockfd, (struct sockaddr *) &cli_addr, &clilen);
+ if (newsockfd < 0)
+ {
+ perror("server: error en el accept");
+ exit(1);
+ }
+
+ if ((childpid = fork()) < 0)
+ {
+ perror("server: error en el fork");
+ exit(1);
+ }
+ else if (childpid == 0)
+ {
+ /* PROCESO HIJO (child) que atiende al cliente */
+ close(sockfd); /* cerramos socket original */
+
+ print_msg(stdout, "server: socket armado con un cliente %d\n", newsockfd);
+
+ /* pasarle el socket al hijo que atiende */
+ sprintf(el_socket, "%d\n", newsockfd);
+
+ /* Se lanza el proceso que atiende a ese cliente */
+ execlp("./serverhandler", "./serverhandler", el_socket, (char *)0);
+ perror("Server: error al lanzar el handler del servidor.");
+ exit(3);
+ }
+
+ /* PROCESO PADRE, se prepara para recibir otro cliente */
+ /* cerrar el socket pasado al hijo */
+ close(newsockfd);
+ }
+}
+
+/** Elimina Procesos-hijos que terminaron */
+void fin_hijos(int)
+{
+ union wait status;
+ while (wait3((int *)&status, WNOHANG, (struct rusage *)0) >= 0);
+}
+
+// vim: set et sw=4 sts=4 :
--- /dev/null
+/*
+ * Servidor de hash
+ */
+
+#include "libtcp.h"
+#include "common.h"
+#include "protocol.h"
+#include <set>
+#include <string>
+#include <cstdlib>
+
+int main(int argc, char *argv[])
+{
+ char *pname;
+ int sockfd;/* socket que sirve como template */
+ pid_t pid; /* pid del server iterativo */
+ char linea[256];
+ char fin = 0, fin_cmd = 0;
+ int result = 0;
+ std::set< std::string > set;
+
+ pname = argv[0];
+ pid = getpid();
+
+ /* Verifico parametros de linea de comando */
+ if (argc > 1)
+ sockfd = atoi(argv[1]);
+ else
+ {
+ perror("Falta parametro con fd");
+ exit (1);
+ }
+
+ print_msg(stdout, "%s (%d): atendiendo a cliente por socket %d\n", pname, pid, sockfd);
+
+ while (!fin)
+ {
+ std::string buffer;
+ while (!fin_cmd)
+ {
+ Protocol proto;
+ int n = libtcp_receive_bin(sockfd, (char*) &proto, sizeof(Protocol));
+ if (n < 0)
+ {
+ print_msg(stdout, "%s (%d): error en recibir\n", pname, pid);
+ exit(1);
+ }
+ print_msg(stdout, "%s (%d): cliente %d envio operacion (%d, %d, %d)\n",
+ pname, pid, proto.client_id, proto.type, proto.end, proto.len);
+
+ n = libtcp_receive_bin(sockfd, linea, proto.len);
+ if (n < 0)
+ {
+ print_msg(stdout, "%s (%d): error en recibir\n", pname, pid);
+ exit(1);
+ }
+ linea[proto.len] = '\0';
+ print_msg(stdout, "%s (%d): se recibieron %d bytes de payload (%s)\n",
+ pname, pid, proto.len, linea);
+ buffer += linea;
+ print_msg(stdout, "%s (%d): buffer: %s\n", pname, pid, buffer.c_str());
+
+ if (proto.end)
+ {
+ switch (proto.type)
+ {
+ case Protocol::PUT:
+ if (set.find(buffer) == set.end())
+ {
+ set.insert(buffer);
+ result = Protocol::OK;
+ }
+ else
+ result = Protocol::EXISTS;
+ break;
+ case Protocol::FIND:
+ if (set.find(buffer) == set.end())
+ result = Protocol::NOT_FOUND;
+ else
+ result = Protocol::OK;
+ break;
+ case Protocol::DEL:
+ if (set.erase(buffer))
+ result = Protocol::OK;
+ else
+ result = Protocol::NOT_FOUND;
+ break;
+ case Protocol::QUIT:
+ print_msg(stdout, "%s (%d): Say no more\n", pname, pid);
+ fin = 1;
+ fin_cmd = 1;
+ break;
+ default:
+ print_msg(stderr, "%s (%d): Operacion no soportada\n", pname, pid);
+ }
+ buffer.clear();
+ fin_cmd = 1;
+ }
+ }
+ fin_cmd = 0;
+
+ // Envío respuesta
+ libtcp_send(sockfd, (char*) &result, sizeof(int));
+ print_msg(stdout, "%s (%d) FIN (resultado = %d)\n", pname, pid, result);
+ }
+
+ close(sockfd);
+
+}
+
+// vim: set et sw=4 sts=4 :