/* Gigor RedneckHTTP Server Versuch */
#include <sys/types.h>
#include <sys\socket.h>
#include <netinet/tcp.h>
#include <errno.h>
#include <arpa/inet.h>
#include <pspkernel.h>
#include <pspdebug.h>
#include <pspdisplay.h>
#include <pspctrl.h>
#include <pspsdk.h>
#include <string.h>
#include <math.h>
#include <psputility.h>
#include <pspgu.h>
#include <pspgum.h>
#include <pspnet.h>
#include <pspnet_inet.h>
#include <pspnet_apctl.h>
#include "wurzelBumsNetDiag.c" /*Danke an Wurzelbums aus dem PSPKing Forum*/
#include <sys/fcntl.h>
#include <stdio.h>
#include <stdlib.h>
PSP_MODULE_INFO("RedneckHTTP", 0, 1, 1);
//Tippersparnis
#define printf pspDebugScreenPrintf
#define setPos pspDebugScreenSetXY
#define CRLF \r\n
//Request Typen
#define HTTP_GET 1
#define HTTP_POST 2
#define HTTP_HEAD 3
#define HTTP_UNKNOWN -1
//MAX etc
#define MAX_CLIENTS 2
#define MAX_VERBINDUNGEN 2
//Typen
typedef struct{
int typ;
char* text; //nullterminiert
} _httpHeader;
/*Bis jetzt nicht benutzt*/
typedef struct{
_httpHeader head;
size_t dataLength;
char* daten; //NULL wenn keine Daten (GET,HEAD etc.)
} _httpAnfrage;
//Funktionen Prototypen
_httpHeader *anfrageEmpfangen(int);
void headerFreigeben(_httpHeader*);
int httpTypBestimmen(char*);
int headerFertig(char*);
char *dateiRausfiltern(_httpHeader*);
void klientBedienen(int);
void dateiAusliefern(char*, int);
_httpHeader *antwortHeaderErstellen(int,int);
void klientThreadStarten(int);
void beendenFunktion();
//Variablen
int inSocket;
struct sockaddr_in serverAdresse;
int check;
int serverRennt = 1;
int gesamtAnfragen = 0;
int aktuelleVerbindungen = 0;
int main(){
SetupCallbacks();
pspDebugScreenInit();
gesamtNetDialogStart(); /*Danke an wurzelbums*/
/*Der Thread zum Beenden*/
SceUID bTh= sceKernelCreateThread("BEENDEN",beendenFunktion,0x18,0x4000,0,NULL);
sceKernelStartThread(bTh,0,NULL);
printf("BeendenThread eingerichet \n");
inSocket = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
if(inSocket<0){printf("Fehler!");}
memset(&serverAdresse,0,sizeof(serverAdresse));
serverAdresse.sin_family = AF_INET;
serverAdresse.sin_port = htons(80);
inet_aton(INADDR_ANY,(struct sockaddr*)&serverAdresse);
check = bind(inSocket,(struct sockaddr*)&serverAdresse,sizeof(serverAdresse));
if(check<0){printf("Fehler bei bind \n");}
check = listen(inSocket,MAX_CLIENTS);
if(check<0){printf("Fehler bei listen \n");}
//struct sockaddr_in clientAdresse;
socklen_t len = sizeof(struct sockaddr);
/*Server Hauptschleife
Nimmt eine Verbindung an und startet dafür einen neuen Thread
Leider geht bis jetzt nur einer gleichzeitig
Wenn die Maximale Anzahl von Verbindungen erreicht wurde, wird eine kleine Puase eingelegt, bis sie nichtmehr erriecht ist.
*/
while(serverRennt){
if(aktuelleVerbindungen>=MAX_VERBINDUNGEN){
printf("#");
sceKernelDelayThread(10000);
continue;
}
printf("Wartet auf eine neue Anfrage\n");
/*Achtung memory leak - wird nicht freigegeben - nur zu testzwecken erstmal*/
struct sockaddr *adressenZeiger = malloc(len);
int testSock = accept(inSocket,adressenZeiger,&len);
gesamtAnfragen++;
if(testSock<0){sceKernelExitGame();}
printf("Neue Anfrage erhalten.\n");
klientThreadStarten(testSock);
aktuelleVerbindungen++;
}
/*Hier kommt es normal garnicht hin*/
printf("Ende");
sceKernelExitGame();
return 0;
}
_httpHeader *anfrageEmpfangen(int socket){
/*Empfängt solange daten, bis ein doppeltes CRLF kommt
Problem: Wenn noch andre Daten mitgesendet werden!
Rückgabewert: Ein Zeiger auf eine _httpHeader struktur, die alloziert wird.
Die muss dann irgendwann später wieder freigegeben werden!
*/
/*Todo:
TimeOut Einbauen
*/
_httpHeader *rueckgabe = malloc(sizeof(_httpHeader));
int requestTyp;
char puffer[1024];
char *anfrageText = NULL;
int gesamtEmpf = 0;
int fertig = -1;
anfrageText = malloc(1);
while(fertig<0){
int empf = recv(socket,puffer,1024,0);
anfrageText = realloc(anfrageText,gesamtEmpf+empf+2);
if(anfrageText == NULL){printf("Fehler bei Speicheralloziierung");return NULL;}
memcpy(&anfrageText[gesamtEmpf],puffer,empf); /*Kopiert den Puffer in den Speicher von Header*/
gesamtEmpf = gesamtEmpf + empf;
anfrageText[gesamtEmpf] = '\0'; //Nullterminieren;
/*Überprüfen ob header schon fertig empfangen ist*/
fertig = headerFertig(anfrageText);
}
requestTyp = httpTypBestimmen(anfrageText);
rueckgabe->typ = requestTyp;
rueckgabe->text = anfrageText;
return rueckgabe;
}
void headerFreigeben(_httpHeader *frei){
free(frei->text);
free(frei);
}
int httpTypBestimmen(char* adresse){
int check;
check = memcmp(adresse,"GET",3);
if(check==0){return HTTP_GET;}
check = memcmp(adresse,"POST",4);
if(check==0){return HTTP_POST;}
check = memcmp(adresse,"HEAD",4);
if(check==0){return HTTP_HEAD;}
return HTTP_UNKNOWN;
}
int headerFertig(char* adresse){
/*Header ist Fertig, wenn zwei \r\n kommen*/
char* erg = strstr(adresse,"\r\n\r\n");
if(erg==NULL){
//Nicht gefunden, also nicht fertig
return -1; //normal -1 nur zu test
}
else{
//Gefunden, also fertig
return 1;
}
/*Problem: Wenn nach dem Header noch daten kommen*/
}
char *dateiRausfiltern(_httpHeader *head){
/* Bekommt als Argument ein Zeiger auf eine _httpHeader Struktur.
Filtert die Zeichenkette für den Dateinamen heraus, alloziert dafür Speicher und gibt die Adresse zurück
Muss auch wieder freigegeben werden! Wird in der klientBedienen freigegebn
*/
char buffer[1024];
int pruef = sscanf(head->text,"%*s %s",buffer);
if(pruef!=1){printf("SscanfFehler %d",pruef);return NULL;}
printf("Anfrage erhalten nach Datei: %s \n",buffer);
int laeng = strlen(buffer);
if((laeng==1)&&(buffer[0]=='/')){strcpy(buffer,"index.html"); laeng = strlen(buffer);}
char *rueck = malloc(laeng+2);
rueck[laeng+1] = '\0'; //dass es sicher terminiert ist
if(rueck == NULL){printf("Malloc Fehler\n");return NULL;}
/*Wenn das erste zechen ein / ist solls weg */
if(buffer[0]=='/'){strcpy(rueck,&buffer[1]);}
else{strcpy(rueck,buffer);}
return rueck;
}
void klientBedienen(int sock){
_httpHeader *head = anfrageEmpfangen(sock);
char *pfad = dateiRausfiltern(head);
if(pfad==NULL){
printf("Fehlerhaften Request Empfangen!\n");
dateiAusliefern(NULL,sock);
}
dateiAusliefern(pfad,sock);
/*Speicher wieder freigeben*/
headerFreigeben(head);
free(pfad);
//evtl loggen();
printf("Anfrage komplett bearbeitet.\n\n");
aktuelleVerbindungen--;
sceKernelExitDeleteThread(0);
}
void dateiAusliefern(char* pfad, int sock){
char puffer[2048];
FILE *datei = fopen(pfad,"r");
printf("Suchte nach datei: %s\n",pfad);
if(datei==NULL){
/*Fehler, 404 Page ausgeben */
_httpHeader *antwHead = antwortHeaderErstellen(13,404);
printf("->Datei %s nicht gefunden, 404\n",pfad);
send(sock,antwHead->text,strlen(antwHead->text),0);
send(sock,"404 not found",13,0);
close(sock);
headerFreigeben(antwHead);
return;
}
/*Größe der Datei Bestimmen*/
fseek(datei,0,SEEK_END);
long gr = ftell(datei);
fseek(datei,0,SEEK_SET);
_httpHeader *antwHead = antwortHeaderErstellen((int)gr,200);
send(sock,antwHead->text,strlen(antwHead->text),0);
//Daten senden,
while(!feof(datei)){
size_t gel = fread(puffer,1,2048,datei);
int gesendet = send(sock,puffer,gel,0);
}
printf("->Datei %s wurde versendet\n",pfad);
fclose(datei);
close(sock);
headerFreigeben(antwHead);
}
_httpHeader *antwortHeaderErstellen(int contentLength,int status){
char puffer[2048];
int laenge = 0;
_httpHeader *rueck = malloc(sizeof(_httpHeader));
if(status==200){strcpy(puffer,"HTTP/1.0 200 OK\r\n");}
if(status==404){strcpy(puffer,"HTTP/1.0 404 Not found \r\n");}
strcat(puffer,"Server: RedneckHTTP Server PSP\r\nConnection: Close \r\n");
laenge = strlen(puffer);
sprintf(&puffer[laenge],"Content-Length: %d \r\n",contentLength);
strcat(puffer,"\r\n");
laenge = strlen(puffer);
rueck->text = malloc(laenge+1);
strcpy(rueck->text,puffer);
return rueck;
}
void klientThreadStarten(int socket){
char name[32];
SceUID thid;
sprintf(name,"Client%d",gesamtAnfragen);
while ((thid = sceKernelCreateThread(name,klientBedienen,0x18,0x8000,0,NULL ))<0) {
printf("Thread %s: Warte auf Ressourcen\n", name);
sceKernelDelayThread(100);
}
printf("Starte Thread %s ; ID: 0x%8X ...",name,thid);
//Hier hängt sichs auf:
int tRueck = sceKernelStartThread(thid,sizeof(socket),&socket);
printf("...Thread %s gestartet\n",name);
}
void beendenFunktion(){
SceCtrlData pad;
while(1){
sceCtrlReadBufferPositive(&pad,1);
if(pad.Buttons&PSP_CTRL_CIRCLE){
printf("-->SERVER wird beendet<--");
sceKernelExitGame();
}
sceKernelDelayThread(100000);
}
}
//{TESTZWECKE
/*Testzwecke
struct sockaddr_in clientAdresse;
socklen_t len = sizeof(clientAdresse);
printf("Warte auf Anfragen\n");
int testSock = accept(inSocket,(struct sockaddr*)&clientAdresse,&len);
printf("Anfrage erhalen\n");
char puffer[2048];
recv(testSock,puffer,2048,0);
char testnachr[] = "HTTP/1.0 200 OK \n\rServer: PSP \n\rContent-Length: 10\n\r Connection: Close\n\r\n\rTestTest12";
send(testSock,testnachr,strlen(testnachr),0);
close(testSock);
Ende Testzwecke*/
//}