===== Proxy genérico ===== Se trata de escribir un programa que haga de "proxy" de un servidor: se trata de instalar un intermediario que simula ser un servidor, pero que en realidad "representa" a otro servidor que ahora está en otra máquina. Es como un "forwarder" que sirve para instalarlo si movemos un servidor de una máquina a otra y queremos que los clientes antiguos sigan funcionando, o para instalar en un computador que es accesible desde Internet para representar un servidor que está en un computador sin acceso a Internet (una intranet por ejemplo). La invocación de este proxy es: % ./proxy port-in server port-out Escucha en la máquina local conexiones que llegan a port-in, luego se conecta a (server, port-out) y luego envía y recibe todos los datos de ambos lados. Haremos dos versiones, una que crea dos procesos hijos (uno que copia en una dirección del socket y otro que copia en la dirección opuesta) y otra con select que queda mejor. Solución con 2 hijos: #include #include #include #include #include "jsocket.h" /* * proxy: proxy multi-cliente usando procesos pesados * Hacer version con select? */ #define BUF_SIZE 200 /* * Esta es la forma mas simple de enterrar a los hijos sin complicarse l a vida */ void child() { int status; while(waitpid(-1, &status, WNOHANG)>0) ; } void die() { fprintf(stderr, "cliente desconectado\n"); exit(0); } /* * Este es el servidor y el codigo para un socket cliente ya conectado: */ void proxy(int s1, char *host, int portout) { int cnt, size = BUF_SIZE; char buf[BUF_SIZE]; int s2; int pid; signal(SIGUSR1, die); s2 = j_socket(); if(j_connect(s2, host, portout) < 0) { fprintf(stderr, "connection refused to %s/%d\n", host, portout); exit(1); } fprintf(stderr, "cliente conectado\n"); if((pid = fork()) < 0) { fprintf(stderr, "no pude fork\n"); exit(1); } if(pid == 0) { while((cnt=read(s1, buf, size)) > 0) if(write(s2, buf, cnt) < 0) break; kill(getppid(), SIGUSR1); exit(0); } else while((cnt=read(s2, buf, size)) > 0) if(write(s1, buf, cnt) < 0) break; kill(pid, SIGKILL); fprintf(stderr, "cliente desconectado\n"); } /* * Este es el principal: solo acepta conexiones y crea a los hijos servi dores */ main(int argc, char **argv) { int s, s2; int portin, portout; char *host; if(argc != 4) { fprintf(stderr, "Use: %s port-in host port-out\n", argv[0]); exit(1); } portin = atoi(argv[1]); host = argv[2]; portout = atoi(argv[3]); signal(SIGCHLD, child); s = j_socket(); if(j_bind(s, portin) < 0) { fprintf(stderr, "bind failed\n"); exit(1); } for(;;) { s2 = j_accept(s); if(fork() == 0) { /* Este es el hijo */ close(s); /* cerrar el socket que no voy a usar */ proxy(s2, host, portout); exit(0); } else close(s2); /* cerrar el socket que no voy a usar */ } } Y una mejor con select: #include #include #include #include #include "jsocket.h" /* * proxy: proxy multi-cliente usando procesos pesados * version con select */ #define BUF_SIZE 200 /* * Esta es la forma mas simple de enterrar a los hijos sin complicarse l a vida */ void child() { int status; while(waitpid(-1, &status, WNOHANG)>0) ; } /* * Este es el servidor y el codigo para un socket cliente ya conectado: s */ void proxy(int s1, char *host, int portout) { int cnt, size = BUF_SIZE; char buf[BUF_SIZE]; int s2; int pid; fd_set mask; s2 = j_socket(); if(j_connect(s2, host, portout) < 0) { fprintf(stderr, "connection refused to %s/%d\n", host, portout); exit(1); } fprintf(stderr, "cliente conectado\n"); /* int select(int numfds, fd_set *readfds, fd_set *writefds , fd_set *exceptfds, struct timeval * timeout); FD_CLR(int fd, fd_set *set); FD_ISSET(int fd, fd_set *set); FD_SET(int fd, fd_set *set); FD_ZERO(fd_set * set); */ for(;;) { FD_ZERO(&mask); FD_SET(s1, &mask); FD_SET(s2, &mask); select(getdtablesize(), &mask, NULL, NULL, NULL); if(FD_ISSET(s1, &mask)) { cnt=read(s1, buf, size); if(cnt <= 0) { fprintf(stderr, "cliente desconectado\n"); exit(0); } write(s2, buf, cnt); } if(FD_ISSET(s2, &mask)) { cnt=read(s2, buf, size); if(cnt <= 0) { fprintf(stderr, "cliente desconectado\n"); exit(0); } write(s1, buf, cnt); } } } /* * Este es el principal: solo acepta conexiones y crea a los hijos servi dores */ main(int argc, char **argv) { int s, s2; int portin, portout; char *host; if(argc != 4) { fprintf(stderr, "Use: %s port-in host port-out\n", argv[0]); exit(1); } portin = atoi(argv[1]); host = argv[2]; portout = atoi(argv[3]); signal(SIGCHLD, child); s = j_socket(); if(j_bind(s, portin) < 0) { fprintf(stderr, "bind failed\n"); exit(1); } for(;;) { s2 = j_accept(s); if(fork() == 0) { /* Este es el hijo */ close(s); /* cerrar el socket que no voy a usar */ proxy(s2, host, portout); exit(0); } else close(s2); /* cerrar el socket que no voy a usar */ } } === El super demonio inetd === Estudie [[http://users.dcc.uchile.cl/~lmateu/CC3301/apuntes/Sockets/|el super demonio inetd]] que aparece en los apuntes de Patricio Poblete.