/* WifiServer PC: Application to connect the Wifiloader Client in the NDS
Copyright (C) 2006
Hermes (Spain)
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable31/08/2006 for any
damages arising from the use of this software.
Permission is granted to anyone to use this software for any
purpose, including commercial applications, and to alter it and
redistribute it freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you
must not claim that you wrote the original software. If you use
this software in a product, an acknowledgment in the product
documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and
must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source
distribution.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <errno.h>
//#include "winsock2.h"
//#include "windows.h"
//#include "commdlg.h"
//#define BIG_ENDIAN 1
#define CONECTION_CLOSED -2
#ifdef BIG_ENDIAN
unsigned int CPU_swap_u32(unsigned int value)
{
unsigned int byte1, byte2, byte3, byte4, swapped;
byte4 = (value >> 24) & 0xff;
byte3 = (value >> 16) & 0xff;
byte2 = (value >> 8) & 0xff;
byte1 = value & 0xff;
swapped = (byte1 << 24) | (byte2 << 16) | (byte3 << 8) | byte4;
return( swapped );
}
#endif
int send_com(int sck,char *comando,int dat,int dat2)
{
int i;
char packet[16];
memset(packet,0,16);
strcpy(packet,comando);
#ifdef BIG_ENDIAN
dat=CPU_swap_u32(dat);
dat2=CPU_swap_u32(dat2);
#endif
memcpy(packet+8, &dat,4);
memcpy(packet+12, &dat2,4);
if(send(sck, packet, 16, 0)!=16)
{
return -1;
}
return 0;
}
int get_com(int sck,char * comando,int *dat,int *dat2)
{
int r;
int i;
char tmp[4];
char tmp2[4];
char packet[16];
r=recv(sck, packet, 16, 0);
if(r<=0)
{
return -2;
}
if(r!=16)
{
return -1;
}
packet[7]=0;
memcpy(comando,packet,8);
memcpy(dat,packet+8,4);
memcpy(dat2,packet+12,4);
#ifdef BIG_ENDIAN
*dat = CPU_swap_u32((unsigned int)*dat);
*dat2 = CPU_swap_u32((unsigned int)*dat2);
#endif
return 0;
}
int get_data(int sck,char * datas,int len)
{
int r;
int b;
b=0;
while(len>0)
{
r=recv(sck, datas+b, len, 0);
if(r<=0) return -2; // conexion cerrada
b+=r; len-=r;
}
return b;
}
int send_int(int sck, int data)
{
int r;
#ifdef BIG_ENDIAN
data = CPU_swap_u32(data);
#endif
r = send_data(sck, (char *)&data, 4);
return r;
}
int send_data(int sck,char *datas,int len)
{
int i;
int r;
int b;
b=0;
while(len>0)
{
r=send(sck, datas+b, len, 0);
if(r<=0) return -1;
b+=r; len-=r;
}
return b;
}
// rutina simple de checksum
int my_checksum(char *p,int size)
{
int n,m;
m=0;
for(n=0;n<size;n++)
{
m+=*p ^85;
p++;
}
return m;
}
/***************************************************/
/* variables */
/***************************************************/
//WSADATA wsaData;
int port=9999;
char comando[16]; // :-> comando entrante
int uno,dos; // :-> uno, recibe el numero de paquete (que luego hay que reenviar en la respuesta), dos, recibe normalmente la longitud de los datos
// asociados a la respuestas (coger con pinzas esto, por que no tiene porque ser asi)
int datfseek[2]; // :-> aqui se reciben los datos para mover el puntero fseek
char filename[256]; //:-> aqui se recibe el nombre el fichero a abrir cuando la DS envia el comando 'OPENFIL'
unsigned char recvbuf[4096+8]; //:-> buffer de salida de datos del fichero
// IMPORTANTE: Tened en cuenta que los datos estan pensados para gestionar un unico cliente.
/********************************************************/
/* main() */
/********************************************************/
int main(int argc, char *argv[])
{
int n;
int yes = 1;
int filesize;
int my_socket,my_socket2; // sockets for the connection
struct sockaddr_in serve; // contains the details of the server
struct sockaddr_in client; // recieves the client data (through getpeername())
FILE *fp[16]; // holds 16 files
char szFileName[255] = "";
/* datos d ela venta de seleccion de archivos */
printf("Wifiloader Server, (c) 2006, Hermes (www.elotrolado.net) and Rattboi\n");
if(argc < 2)
{
printf("Error: Needs at least 1 argument\n");
return;
}
strcpy(szFileName, argv[1]);
if(argc>=3)
{
port=atoi(argv[2]);
}
for(n=0;n<16;n++) fp[n]=NULL; // inicializa los punteros de fichero
my_socket = socket( AF_INET, SOCK_STREAM, IPPROTO_TCP ); // obtiene un socket para protocolo TCP/IP
if (my_socket == -1 )
{
printf(" Error at socket(), INVALID_SOCKET\n");
return;
}
setsockopt(my_socket, SOL_SOCKET, SO_REUSEPORT, &yes, sizeof(int));
serve.sin_family = AF_INET;
serve.sin_addr.s_addr = INADDR_ANY; // :-> escucha todas las direcciones //inet_addr( "192.168.0.1" );
serve.sin_port = htons( port);
if ( bind( my_socket, (struct sockaddr *) &serve, sizeof(struct sockaddr)) == -1 )
{
printf( "bind() failed.\n" );
perror("server.c");
close(my_socket);
return;
}
if ( listen( my_socket, 1 ) == -1 )
{
printf( "Error listening on socket.\n");
}
printf( "\nWaiting for the Wifiloader Client on port %i ...\n",port );
my_socket2 = -1;
while ( my_socket2 == -1 )
{
my_socket2 = accept( my_socket, NULL, NULL );
}
printf( "Wifiloader Connected.\n");
getpeername(my_socket2, (struct sockaddr *)&client, (socklen_t *)sizeof(client)); //:-> averigua la IP del cliente
printf("Client IP %s \n",inet_ntoa(client.sin_addr));
// aqui se gestionan todos los comandos recibidos
while(1)
{
int r;
r=get_com(my_socket2,comando,&uno,&dos);
// printf("Command = %s, uno = %d, dos = %d\n", comando, uno, dos);
if(r==-2) break; // salir (conexion perdida u error)
if(r==0)
{
if(!strcmp(comando,"FIN"))
break; // libera la conexion (este server solo admite una conexion)
if(!strcmp(comando,"EXECFIL")) // comando de ejecutar fichero: abre la ventana de seleccion y abre el fichero
{
for(n=0;n<16;n++) // negocia en busca de un puntero de fichero libre
{
if(fp[n]==0)
break;
}
if(n==16)
n=-1; // todos los punteros en uso :S
if(n!=-1)
{
fp[n] = fopen(szFileName, "rb");
if(!fp[n])
{
printf("Error Opening Execution file\n");
n=-1;
}
}
if(n==-1)
printf("Command Open Failed!\n");
r=send_com(my_socket2,"ACKDATA",uno,4); // :-> envia el comando de respuesta con el numero de paquete asociado
r=send_int(my_socket2,n); // :-> envia el 'fd' del fichero (-1 si hubo error)
}
else
if(!strcmp(comando,"OPENFIL")) // comando de abrir fichero: lo mismo que EXECFIL pero aqui el nombre de fichero lo elige la NDS
{
r=get_data(my_socket2,filename,256); //:-> recibe la ruta del fichero a abrir
for(n=0;n<16;n++)
{
if(fp[n]==0) break;
}
if(n==16) n=-1; // todos los punteros en uso :S
if(n!=-1)
{
fp[n] = fopen(filename, "rb");
filesize = fsize(fp[n]);
if(!fp[n])
n=-1;
if(n==-1)
printf("Command Open Failed!\n");
}
r=send_com(my_socket2,"ACKDATA",uno,4); // :-> send the command of request with the packet number associated
r=send_int(my_socket2,n); // :-> send the file 'fd' (-1 if there's an error)
}
else
if(!strcmp(comando,"READDAT")) // :-> comando de lectura secuencial de ficheros: lee un bloque de 4KB y lo envia
{
r=fread(recvbuf+8, 1,1024*4, fp[dos]); // lee 4KB desde el fichero (recvbuf+8)
#ifdef BIG_ENDIAN
r=CPU_swap_u32(r);
#endif
memcpy(recvbuf,&r,4); // almacena el numero de bytes leidos (recvbuf+0)
#ifdef BIG_ENDIAN
r=CPU_swap_u32(r);
#endif
r=my_checksum((char *)recvbuf+8,r); // calcula el checksum para enviar (recvbuf+4)
#ifdef BIG_ENDIAN
r=CPU_swap_u32(r);
#endif
memcpy(recvbuf+4,&r,4);
r=send_com(my_socket2,"ACKDATA",uno,8+1024*4); // envia el comando 'ACKDATA' con la respuesta
r=send_data(my_socket2,(char *)recvbuf,8+1024*4);
}
else
if(!strcmp(comando,"READBYS")) //: este comando se recibe si el checksum de un comando READDAT, no coincide en el cliente
{ // con los datos recibidos. READBYS repite el envio de los datos anteriores
r=send_com(my_socket2,"ACKDATA",uno,8+1024*4); // envia de nuevo el buffer de datos
r=send_data(my_socket2,(char *)recvbuf,8+1024*4);
}
else
if(!strcmp(comando,"SEEKPOS")) // :-> comando de lectura secuencial de ficheros: lee un bloque de 4KB y lo envia
{
r=get_data(my_socket2,(char *)datfseek,8); //:-> recibe los parametros para fseek
n=-1;
if(dos>=0 && dos<16)
{
n=fseek( fp[dos],datfseek[0],datfseek[1]); // lee 4KB desde el fichero (recvbuf+8)
}
r=send_com(my_socket2,"ACKDATA",uno,4); // :-> envia el comando de respuesta con el numero de paquete asociado
r=send_int(my_socket2,n); // :-> envia la posicion del fichero
}
else
if(!strcmp(comando,"CLOSEFI")) //:-> cierra un fichero. 'dos' contiene el FD del fichero
{
if(dos>=0 && dos<16)
{
if(fp[dos])
fclose(fp[dos]);
fp[dos]=NULL;
}
else
printf("Command CLOSEFI with invalid FD\n");
r=send_com(my_socket2,"ACKDATA",uno,0);
}
else
if(!strcmp(comando,"CLOSEAL")) // cierra todos los ficheros
{
for(n=0;n<16;n++)
{
if(fp[n]!=NULL)
{
fclose(fp[n]);
fp[n]=NULL;
}
}
r=send_com(my_socket2,"ACKDATA",uno,0);
}
}
}////
close(my_socket2);
close(my_socket);
for(n=0;n<16;n++)
{
if(fp[n]!=NULL)
{
fclose(fp[n]);
fp[n]=NULL;
}
}
printf("Finished Sending\n");
return 0;
}