/* Ejemplo usando fsock dll
UDP (en este caso no hay que establecer conexión):
Envío de un mensaje y confirmación de llegada de dicho mensaje del destinatario al emisor

TCP:
Una vez se hayan conectados todos los clientes al servidor, éste les enviará a todos nº aleatorios hasta la finalización del mismo.
Los clientes verán el último nº aleatorio recibido, cuantos mensajes han recibido del servidor y el ping en relación al último mensaje recibido.
*/

//MENU
PROGRAM fsock;
import "fsock.dll";
const clients=2; // numero de clientes a conectar para TCP
global option;
begin

	full_screen=false;
	fsock_init(); // Inicializamos la librería fsock
	write(0,5,5,0,"1. Servidor TCP");
	write(0,5,15,0,"2. Cliente TCP");
	write(0,5,25,0,"3. Cliente UDP que envía");
	write(0,5,35,0,"4. Cliente UDP que recibe");
	write(0,5,45,0,"5. Salir");
	write(0,5,75,0,"Host: "+fsock_get_iphost(0)); // Mostramos Host de la máquina donde se ejecuta
	write(0,5,85,0,"IP: "+fsock_get_iphost(1)); // Mostramos IP de la máquina donde se ejecuta

	while (option==0)
	if (key(_1)) option=1;server();end
	if (key(_2)) option=1;client();end
	if (key(_3)) option=1;udpsend();end
	if (key(_4)) option=1;udprecv();end
	if (key(_5)) option=1;fsock_quit();end; // Cerramos la librería fsock
	frame;
	end;
end;


//UDP
process udpsend()
private
int socket, socket1;
int data;
int dataIn;
int ipOrigen;
int puertoOrigen;
begin
delete_text(0);
socket = udpsock_open(); //nuevo socket udp para envío
socket1 = udpsock_open(); //nuevo socket udp para recibir

fsock_bind(socket1,1200); //asociamos con el puerto 1200 el socket para poder recibir mensajes del receptor

fsock_socketset_free(0);// iniciamos el socketset 0 para comprobar actividad en el socket (esperar a que llegue confirmación)
fsock_socketset_add(0, socket1);

data = 1200; //enviamos puerto al que ha de confirmar el receptor, y al que tenemos asociado el socket1 para recbir

udpsock_send(socket, &data, sizeof(data), "127.0.0.1", 1300); //enviamos el mensaje a la dirección ip 127.0.0.1 y puerto 1300 (que hemos de conocer del receptor)

write (0,5,0,0, "Cliente UDP que envía al principio");
write (0,5,15,0, "Puerto en el que recibir confirmacion: " + data);
write (0,5,25,0, "Esperando confirmación del receptor...");

while (!key(_esc))

	//Vemos si hay actividad cada 100ms, si no, seguimos reenviando
	if (fsock_select(0,100)<=0)
		fsock_socketset_add(0, socket1); //en select debemos reincluir el socket cada vez que la usamos
		udpsock_send(socket, &data, sizeof(data), "127.0.0.1", 1300); //reenviamos el mensaje a la dirección ip 127.0.0.1 y puerto 1300 (que hemos de conocer)	
	else
		break;
	end

	frame;
end;

udpsock_recv(socket1, &dataIn, sizeof(dataIn), &ipOrigen, &puertoOrigen);

write (0,5,35,0, "Confirmación enviada desde " + fsock_get_ipstr(&ipOrigen)+ ":" + puertoOrigen);
write (0,5,45,0, "Mensaje obtenido - Número obtenido: ");
write_int(0,250,45,0,offset(dataIn));

write (0,5,65,0, "Fin transmisión");

//Fin de transmisión, no hay que cerrar conexiones porque en UDP no las hay, solo cerrar el socket y el socketset
fsock_close(socket);
fsock_close(socket1);
fsock_socketset_free(0);

fsock_quit(); //cerrar librería

//Hasta que no se pulse escape, no salimos
repeat

frame;
until (key(_esc))

end;

process udprecv()
private
int socket;
int data;
int dataOut;
int ipOrigen;
int puertoOrigen;
int actividad;
begin
delete_text(0);
socket = udpsock_open(); //nuevo socket udp (recibiremos y enviaremos mensaje)

fsock_bind(socket, 1300); //asociamos el socket con el puerto 1300 (para recibir mensajes)

fsock_socketset_free(0);// iniciamos el socketset 0 para comprobar actividad en el socket (esperar a que llegue mensaje)
fsock_socketset_add(0, socket);

write (0,5,0,0, "Cliente UDP que recibe puerto en el que confirmar");
write (0,5,15,0, "Esperando que el mensaje sea enviado...");

while (!key(_esc))

	//Vemos si hay actividad cada 100ms, para poder recibir
	if (fsock_select(0,100)>0)
		break;
	end

	//Reincluimos socket en el socketset, por usar select
	fsock_socketset_add(0, socket);

	frame;
end;

//Obtenemos ipOrigen y puertoOrigen desde donde llega el mensaje
udpsock_recv(socket, &data, sizeof(data), &ipOrigen, &puertoOrigen);

write (0,5,25,0, "Mensaje enviado desde " + fsock_get_ipstr(&ipOrigen)+":"+puertoOrigen);
write (0,5,35,0, "Puerto en el que confirmar: " + data);

dataOut = rand(32768,65536); //Generamos un número de confirmación aleatorio

//Gracias a la ipOrigen y puertoOrigen, sabemos a donde tenemos que enviar la confirmación
//aunque debemos confirmar en el puerto que almacena data (hemos recibido) y la ipOrigen dada
udpsock_send(socket, &dataOut, sizeof(dataOut), fsock_get_ipstr(&ipOrigen), data);

write (0,5,45,0, "Confirmación enviada - Número enviado: ");
write_int(0,250,45,0,offset(dataOut));

write (0,5,65,0, "Fin transmisión");

//Fin de transmisión, no hay que cerrar conexiones porque en UDP no las hay, solo cerrar el socket y el socketset
fsock_close(socket);
fsock_socketset_free(0);

fsock_quit(); //cerrar librería


//Hasta que no se pulse escape, no salimos
repeat

frame;
until (key(_esc))

end;


//TCP
process server()
private
int socket_listen, socket[clients-1];// socket_listen para recoger peticiones, socket[clients-1] para manejar peticiones
int data;
int connection=0;
int i;
int informacion; // enviaremos a los clientes números aleatorios entre 0 y 32768
int ipaddr, portaddr;
int actividad;
begin
delete_text(0);
socket_listen=tcpsock_open(); // nuevo socket
fsock_bind(socket_listen,1200); // asociamos socket_listen con el puerto 1200
tcpsock_listen(socket_listen,clients); // numero de conexiones a escuchar igual a clients
	write(0,5,5,0,"Esperando conexion de cliente(s)...");
	frame;
	while (connection<clients) // Mientras no hayan conectado los clientes esperamos su conexión


		if ((socket[connection]=tcpsock_accept(socket_listen,&ipaddr,&portaddr))!=-1) // Si recibimos una petición de conexión distinta de -1, la aceptamos
		connection++;data++;
		tcpsock_send(socket[connection-1],&data, sizeof(data)); // Envía el número de jugador al nuevo cliente
		write (0, 5, connection*10+5, 0, "Cliente conectado: "+fsock_get_ipstr(&ipaddr)+":"+portaddr);
		end;

		if (key(_esc)) // Cerramos el programa aunque no hayan conectado todos los clientes
		fsock_close(socket_listen); // Cierra el socket
		for (i=0;i<clients;i++)
		fsock_close(socket[connection]);// Cierra el socket
		end;
		exit(0,0);
		fsock_quit(); // Cerramos la librería tcpsock
		end

	frame;
	end;

	delete_text(0);
	write(0,5,5,0,"Todos los clientes han conectado");
	write(0,5,25,0,"Enviando mensajes a todos ellos...");

loop
	for (i=0;i<connection;i++) // Nº aleatorio que enviamos a cada cliente
	informacion=rand(0,32768);
	tcpsock_send(socket[i],&informacion,sizeof(informacion));
	end;

if (key(_esc))
	fsock_close(socket_listen); // Cierra el socket
	for (i=0;i<clients;i++)
	fsock_close(socket[connection]);// Cierra el socket
	end;
	exit(0,0);
	fsock_quit(); // Cerramos la librería tcpsock
end

frame;
end;
end;

process client()
private
int socket;
int data;
int informacion=1; // recibe la información (nº aleatorio 0-32768) que envía en cada mensaje el servidor
int envios; // nº de mensajes recibidos desde la conexión
int ping[1];
begin
delete_text(0);
socket=tcpsock_open();// nuevo socket
write(0,5,5,0,"Conectando...");
fsock_socketset_free(0);// iniciamos el socketset 0
fsock_socketset_add(0,socket);// añadimos el socket al socketset 0
frame;

	if (tcpsock_connect(socket,"127.0.0.1",1200)==0) // Conectamos al servidor con ip 127.0.0.1 y puerto 1200
	delete_text(0);
	write(0,5,5,0,"Conectado");
	frame;

		if (fsock_socketset_check(0)>0) // si hay actividad en el socket recibimos el nº de jugador
		tcpsock_recv(socket,&data,sizeof(data)); // Recibimos el número de jugador
		write(0,135,35,0,data);
		end;
		write(0,5,35,0,"Soy el jugador: ");
		write(0,5,70,0,"Mensajes recibidos del servidor: ");
		write(0,5,105,0,"Ping:            ms");
		write(0,5,140,0,"Ultimo nº aleatorio recibido: ");
		write_int(0,250,70,0,offset(envios));
		write_int(0,60,105,0,offset(ping[0]));
		write_int(0,250,140,0,offset(informacion));
	else
	delete_text(0);
	write(0,5,5,0,"No se pudo conectar");
	end;

loop
	if (fsock_socketset_check(0)>0) // si hay actividad en el socket recibimos el mensaje
		if (tcpsock_recv(socket,&informacion,sizeof(informacion))>0); // Recibimos mensaje (nº aleatorio en información)
		envios++; // nuevo mensaje recibido
		ping[1]=timer[0]; // ha llegado un mensaje, hay transmisión fluida
		end;
	end;

if (timer[1]>100) ping[0]=timer[0]-ping[1];timer[1]=0;end // refrescamos el ping

// Se pulsó escape y cierra el programa
if (key(_esc)) fsock_socketset_free(0);fsock_close(socket);fsock_quit();exit(0,0);end // Cierra el socket y cerramos librería fsock
frame;
end;
end;
