Herramientas de usuario

Herramientas del sitio


sockets-opt

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 <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <wait.h>
#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 <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <wait.h>
#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 el super demonio inetd que aparece en los apuntes de Patricio Poblete.

sockets-opt.txt · Última modificación: 2018/08/16 10:04 por lmateu