// CREDITS : F. Harrouet, www.enib.fr/~harrouet //====================================================================== #include "main.h" #include "httpServerLib.h" #define BUFFER_SIZE 0x1000 //====================================================================== void * dialogThread(void *arg) { pthread_detach(pthread_self()); char buffer[BUFFER_SIZE]; Request *req=(Request *)arg; //---- receive and analyse HTTP request line by line ---- bool first=true; for(;;) { if(recvLine(req->sock,buffer,BUFFER_SIZE)<=0) { break; } printf("%s",buffer); if(first) { first=false; sscanf(buffer,"%s %s",req->requestMethod,req->requestUri); } else if(!strcmp(buffer,"\n")||!strcmp(buffer,"\r\n")) { break; } } //---- prepare and send HTTP reply ---- sprintf(req->fileName,"./www%s",req->requestUri); char *params=strchr(req->fileName,'?'); if(params) { *params='\0'; } struct stat st; int r=stat(req->fileName,&st); if((r!=-1)&&S_ISDIR(st.st_mode)) { strcat(req->fileName,"/index.html"); r=stat(req->fileName,&st); } int input=open(req->fileName,O_RDONLY); if(input==-1) { r=sprintf(buffer,"HTTP/1.0 404 Not Found\n" "Connection: close\n" "Content-Type: text/html\n" "\n" "\n" "404 - Not Found
\n" "method: %s
\n" "uri: %s
\n" "fileName: %s
\n" "\n", req->requestMethod, req->requestUri, req->fileName); sendAll(req->sock,buffer,r); } else { const char *contentType="unknown/unknown"; const char *ext=strrchr(req->fileName,'.'); if(ext) { if(!strcmp(ext,".html")) contentType="text/html"; else if(!strcmp(ext,".png")) contentType="image/png"; else if(!strcmp(ext,".ico")) contentType="image/vnd.microsoft.icon"; } r=sprintf(buffer,"HTTP/1.0 200 OK\n" "Connection: close\n" "Content-Type: %s\n" "Content-Length: %ld\n\n", contentType, st.st_size); sendAll(req->sock,buffer,r); for(;;) { r=read(input,buffer,BUFFER_SIZE); if(r<=0) break; sendAll(req->sock,buffer,r); } close(input); } destroyRequest(req); return (void *)0; } //====================================================================== // MAIN //====================================================================== int main(int argc, char **argv) { //---- avoid exiting on broken client connection (ignore SIGPIPE) ---- struct sigaction sa; memset(&sa,0,sizeof(struct sigaction)); sa.sa_handler=SIG_IGN; if(sigaction(SIGPIPE,&sa,(struct sigaction *)0)==-1) { perror("sigaction"); exit(1); } //---- check command line arguments ---- if(argc!=2) { fprintf(stderr,"usage: %s http_port\n",argv[0]); exit(1); } //---- extract local port number ---- int httpPortNumber; if(sscanf(argv[1],"%d",&httpPortNumber)!=1) { fprintf(stderr,"invalid port %s\n",argv[1]); exit(1); } //---- multithreaded TCP server launching dialogThread() ---- //---- create HTTP listen socket ---- int httpSocket=socket(PF_INET,SOCK_STREAM,0); if(httpSocket==-1) { perror("socket"); exit(1); } // ... avoiding timewait problems (optional) int on=1; if(setsockopt(httpSocket,SOL_SOCKET,SO_REUSEADDR,&on,sizeof(int))==-1) { perror("setsockopt"); exit(1); } // ... bound to any local address on the specified port struct sockaddr_in myAddr; myAddr.sin_family=AF_INET; myAddr.sin_port=htons(httpPortNumber); myAddr.sin_addr.s_addr=htonl(INADDR_ANY); if(bind(httpSocket,(struct sockaddr *)&myAddr,sizeof(myAddr))==-1) { perror("bind"); exit(1); } // ... listening connections if(listen(httpSocket,10)==-1) { perror("listen"); exit(1); } for(;;) { //---- accept new HTTP connection ---- struct sockaddr_in fromAddr; socklen_t len=sizeof(fromAddr); int dialogSocket=accept(httpSocket,(struct sockaddr *)&fromAddr,&len); if(dialogSocket==-1) { perror("accept"); exit(1); } printf("new HTTP connection from %s:%d\n", inet_ntoa(fromAddr.sin_addr),ntohs(fromAddr.sin_port)); //---- start a new dialog thread ---- pthread_t th; if(pthread_create(&th,(pthread_attr_t *)0, dialogThread,createRequest(dialogSocket))) { fprintf(stderr,"cannot create thread\n"); exit(1); } } close(httpSocket); return 0; } //^^^^^^^^^^^^^^^^^^^^^^^^^^ EOF ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^