===== 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.