/* Raydium - CQFD Corp. http://raydium.org/ License: GPL - GNU General Public License, see "gpl.txt" file. */ #ifndef DONT_INCLUDE_HEADERS #include "index.h" #else #include "headers/web.h" #endif #include "web.h" void raydium_web_answer(char *message, int fd) { char buffer[RAYDIUM_WEB_BUFSIZE*2]; // for header char title[RAYDIUM_WEB_BUFSIZE]; char *body_start; body_start=strchr(message,'\n'); // WARNING: do not change "Type: message" header offset ! // See raydium_web_client_get() otherwise. sprintf(buffer,"HTTP/1.0 200 OK\r\nContent-Type: text/html\r\nType: message\r\n\r\n"); send(fd,buffer,strlen(buffer),0); buffer[0]=0; sprintf(buffer+strlen(buffer),raydium_web_header,raydium_web_title); if(!body_start) { sprintf(buffer+strlen(buffer),"%s",message); sprintf(buffer+strlen(buffer),raydium_web_footer,raydium_web_body_default); raydium_log("web: %s",message); } else { strncpy(title,message,body_start-message); title[body_start-message]=0; sprintf(buffer+strlen(buffer),"%s",title); sprintf(buffer+strlen(buffer),raydium_web_footer,body_start+1); raydium_log("web: %s",title); } send(fd,buffer,strlen(buffer),0); } /* this is a child web server process, so we can exit on errors */ void raydium_web_request(int fd) { int j, file_fd, buflen, len; long i, ret; char * fstr; static char buffer[RAYDIUM_WEB_BUFSIZE+1]; /* static so zero filled */ static char answer[RAYDIUM_WEB_BUFSIZE+1]; /* static so zero filled */ signed char (*handler)(char *,char *, int); ret=recv(fd,buffer,RAYDIUM_WEB_BUFSIZE,0); if(ret == 0 || ret == -1) { /* read failure stop now */ perror("read"); raydium_web_answer("error: Failed to read browser request",fd); return; } if(ret > 0 && ret < RAYDIUM_WEB_BUFSIZE) /* return code is valid chars */ buffer[ret]=0; /* terminate the buffer */ else buffer[0]=0; for(i=0;i 0 ) { send(fd,buffer,ret,0); } } void raydium_web_start(char *title) { char opt[32]; if(raydium_web_active) { raydium_log("web: warning: server already started"); return; } raydium_log("web: starting Raydium HTTP server on port %i",RAYDIUM_NETWORK_PORT); if((raydium_web_listenfd = socket(AF_INET, SOCK_STREAM,0)) <0) { raydium_log("web: error: socket failed"); return; } // avoiding bind's "Address already in use" error setsockopt(raydium_web_listenfd, SOL_SOCKET, SO_REUSEADDR, opt, 32); raydium_web_serv_addr.sin_family=AF_INET; raydium_web_serv_addr.sin_addr.s_addr=htonl(INADDR_ANY); raydium_web_serv_addr.sin_port=htons(RAYDIUM_NETWORK_PORT); if(bind(raydium_web_listenfd, (struct sockaddr *)&raydium_web_serv_addr,sizeof(raydium_web_serv_addr)) <0) { raydium_log("web: error: bind failed"); perror("bind"); return; } if(listen(raydium_web_listenfd,64) <0) { raydium_log("web: error: listen failed"); return; } strcpy(raydium_web_title,title); raydium_web_active=1; } void raydium_web_callback(void) { static int socketfd; static struct sockaddr_in cli_addr; /* static = initialised to zeros */ size_t length; if(!raydium_web_active) return; if(!raydium_network_socket_is_readable(raydium_web_listenfd)) return; length = sizeof(cli_addr); if((socketfd = accept(raydium_web_listenfd, (struct sockaddr *)&cli_addr, (socklen_t *)&length)) < 0) return; // /!\ FIXME ! must fork here. (see original nweb for details) raydium_web_request(socketfd); raydium_network_socket_close(socketfd); } #ifdef RAYDIUM_NETWORK_ONLY void raydium_web_sigpipe_hack(int sig) { raydium_log("SIGPIPE (%i)",sig); } #endif void raydium_web_init(void) { static char *header="\ \ \ \ Raydium 3D Game Engine\ \ \
\
\
%s > message

\ "; static char *body="\ This server is used to be an entry point to application data. Only simple requests (GET) are supported yet, \ with a limited set of file types and directories. Right now, this server is able to send static and dynamic data, \ and dynamic scripted page support is to come, using Raydium's PHP parser.\

\ This server is a modified version of IBM's nweb server, from Nigel Griffiths (nag@uk.ibm.com).\

\ For more information, see Raydium website http://raydium.org/
\ See also raydium/web.h, raydium/web.c and raydium/headers/web.h files from the source directory.\ "; static char *footer="\

\ %s\
\ "; raydium_web_header=header; raydium_web_body_default=body; raydium_web_footer=footer; #ifdef RAYDIUM_NETWORK_ONLY // ... and ... #ifndef WIN32 // since we will not install our default signal handlers ... signal(SIGPIPE,raydium_web_sigpipe_hack); #endif #endif memset(&raydium_web_serv_addr,0,sizeof(struct sockaddr_in)); raydium_web_active=0; raydium_web_extension_count=0; strcpy(raydium_web_title,"Default"); raydium_log("webserver: OK"); } void raydium_web_extension_add(char *ext, char *mime, void *handler) { if(raydium_web_extension_count==RAYDIUM_MAX_EXTENSIONS) { raydium_log("web: extension: error: no more free slot (%i max)",RAYDIUM_MAX_EXTENSIONS); return; } strcpy(raydium_web_extensions[raydium_web_extension_count].ext,ext); if(mime) strcpy(raydium_web_extensions[raydium_web_extension_count].filetype,mime); else raydium_web_extensions[raydium_web_extension_count].filetype[0]=0; raydium_web_extensions[raydium_web_extension_count].handler=handler; raydium_web_extension_count++; } signed char raydium_web_client_get(char *filename) { int i,sockfd; char buffer[RAYDIUM_WEB_BUFSIZE]; char *data; char req[RAYDIUM_MAX_NAME_LEN]; char complete[RAYDIUM_MAX_NAME_LEN]; struct sockaddr_in serv_addr; struct hostent *hst; int chunk; FILE *fp; if(raydium_network_mode!=RAYDIUM_NETWORK_MODE_CLIENT) { raydium_log("web client: cannot get file: not connected to a server"); return 0; } if((sockfd = socket(AF_INET, SOCK_STREAM,0)) <0) { raydium_log("web: client: socket failure"); return 0; } hst=gethostbyname(raydium_network_connected_server); memcpy((char*)(&(serv_addr.sin_addr.s_addr)), hst->h_addr, hst->h_length); serv_addr.sin_family = AF_INET; serv_addr.sin_port = htons(RAYDIUM_NETWORK_PORT); if(connect(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) <0) { raydium_log("web: client: can't connect to server (%s)",raydium_network_connected_server); return 0; } sprintf(req,"GET /%s \r\n",filename); send(sockfd,req,strlen(req),0); chunk=0; while( (i=recv(sockfd,buffer,RAYDIUM_WEB_BUFSIZE,0)) > 0) { data=buffer; if(chunk==0) { int x; //check: "HTTP/1.x 200 OK" if(buffer[9]!='2' || buffer[10]!='0' || buffer[11]!='0') { buffer[12]=0; raydium_log("web: client: error: server said %s",buffer); raydium_network_socket_close(sockfd); return 0; } // is this real data or an simple message from Raydium webserver ? // See "Type" header here : // "HTTP/1.0 200 OK\r\nContent-Type: text/html\r\nType: message\r\n\r\n" strncpy(req,buffer,60); req[55]=0; if(!strcmp(req+42,"Type: message")) { raydium_log("web: client: error: no data, this is a server message (not found ?)"); raydium_network_socket_close(sockfd); return 0; } // ok, now search for \r\n\r\n for(x=12;x