/* Chee-Z-Serv, posix threaded, chroot()ed, and logged version */
#include <pthread.h>
#include <stdio.h>
#include <errno.h>
#include <signal.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/wait.h>
#include <sys/time.h>
#include <netinet/in.h>
#include <netdb.h>
#include <stdarg.h>
#include <fcntl.h>
#include <resolv.h>

int hits=0;

void loghit(int s)
{
    struct sockaddr_in name;
    struct hostent *host;
    int n=sizeof(struct sockaddr_in);

    getpeername(s, (struct sockaddr *)&name, &n); 
    host=gethostbyaddr((char *)&(name.sin_addr.s_addr), 4, AF_INET);
    printf("Hit from %s, total hits so far %i\n", host->h_name, ++hits);
    fflush(stdout);
}

void handle_connection(int *skt)
{
    char   myname[513], *fooz, *barz;
    int f, t=*skt, z, r;

    z=recv(t, myname, sizeof(myname), 0);
    if(myname[z-2]=='\n' || myname[z-2]=='\r') myname[z-2]=0;
    else if(myname[z-1]=='\n' || myname[z-1]=='\r') myname[z-1]=0;
    if(strncasecmp(myname, "GET", 3)==0)
    {
    	fooz=&myname[4];
    	barz=fooz;
    	while(*barz!=' ' && *barz!=0) barz++;
    	*barz=0;
    	if(fooz[0]=='/' && fooz[1]==0) 
    		strcpy(fooz, "/index.html");
    	fooz--;
    	fooz[0]='.';
    	if((f=open(fooz, O_RDONLY))==-1)
    		send(t, "404 / File not found\r\n",22, 0);
    	else 
    	{
    		for(;;)
    		{
    			if((r=read(f, myname, 500))<1) break;
    			send(t, myname, r, 0);
    		}
    		close(f);
    	}
    	loghit(t);
    }
    else send(t, 
    	"501 / I don't know how to do what you're asking!\r\n",
    	50, 0);
    close(t);
}


void main()
{
    char   myname[513];
    int    s, t, z, r;
    struct sockaddr_in sa;
    struct hostent *hp;
    pthread_t thread;

    memset(&sa, 0, sizeof(struct sockaddr_in));
    gethostname(myname, 255);
    hp = gethostbyname(myname);
    if (hp == NULL)
        return;
    sa.sin_family= hp->h_addrtype;
    sa.sin_port= htons(80);
    if ((s= socket(AF_INET, SOCK_STREAM, 0)) < 0)
        return;
    if (bind(s,(struct sockaddr*)&sa,sizeof(struct sockaddr_in)) < 0)
    {
        close(s);
        return;
    }
    listen(s, 5);

    getcwd(myname, sizeof(myname));
    chroot(myname);

    for(;;)
    {
        t=accept(s, NULL, NULL);
    	pthread_create(&thread, NULL,
    		(void *)&handle_connection, (void *)&t);
    }
}