/*http://en.wikibooks.org/wiki/C_Programming/Networking_in_UNIX using: default port is 8080 You can give port as commandline parameter todo check memory leaks! Issue about vulnerability: If server is runned as root and local user has write access to directory. If the size of the file changes between size-checking and reading it -> overflow the buffer. Issue about SO_KEEPALIVE,case: If client connects but not request anything -Is there some build-in timeout? maube SO_KEEPALIVE */ #include #include #include #include #include #include #include #include #define MAXRCVLEN 500 #define PORTNUM 8080 #define SERVER_NAME "aa-http" #define SERVER_URL "moko" #define PROTOCOL "HTTP/1.0" #define RFC1123FMT "%a, %d %b %Y %H:%M:%S GMT" #include #include #include #include #include #include //how big sended files can be: (10M) #define MAXFILESIZE 10000000 #include "helpers.c" /* helpers contains some stuff: static char* get_mime_type( char* name ); static void strdecode( char* to, char* from ); */ void* safe_malloc(size_t size) { void* ptr = malloc(size); printf("=====allocating %d bytes on %s:%d====================\n", size, __FILE__, __LINE__); if (!ptr) printf("ERROR: cannot allocate %d bytes on %s:%d /ERROR:\n", size, __FILE__, __LINE__); return ptr; } /* Forwards. */ void send_file(int socket,char *parametri); void file_details( char* dir, char* name ); void send_error( int status, char* title, char* extra_header, char* text ); char *make_header( int status, char* title, char* extra_header, char* mime_type, off_t length, time_t mod ); char *make_error(int status, char *text); /*GLOBAL*/ int g_running=1; /*not used yet, but now server can be shutdowned*/ void *do_vibra() { system("echo 255 > /sys/class/leds/neo1973:vibrator/brightness; sleep 2; echo 0 > /sys/class/leds/neo1973:vibrator/brightness"); pthread_exit(NULL); } char *make_vibra() { char _page[]= "2seconds vibration - Done"; char *page =safe_malloc (10000000*sizeof(char)); snprintf(page,10000000*sizeof(char),"%s",_page); //use thread pthread_t vibra_thread; pthread_create(&vibra_thread, NULL, do_vibra, NULL); return page; } /** length_of_data is setted after reading returns content of given FILE* in char*. prerequisitor: file exist, is readable, already opened */ static char *page_from_file(FILE* fp, int* length_of_data) { //printf("reading from file\n"); char *page; unsigned int countx=0,count=0; unsigned long lSize=0; fseek (fp , 0 , SEEK_END); lSize = ftell (fp); rewind (fp); page = safe_malloc(lSize) ; while (count= 0 ) { //make dynamic listing: //... //or //use index.html char index[20000]; snprintf(index, sizeof(index), "%sindex.html", file ); file = index; if (file_forbidden(&fp,file,&header,&page) != 1) { printf("*Sending implicitely index.html\n"); header = make_header( 200, "Ok", (char*) 0, get_mime_type( file ), sb.st_size, sb.st_mtime ); page=page_from_file(fp,&length_of_data); } } #ifdef dynamic_listing else { header=make_header( 200, "Ok", (char*) 0, "text/html", -1, sb.st_mtime ); //generate directory list://scketch: /* char directory_list[100000]; n = scandir( file, &dl, NULL, alphasort ); if ( n < 0 ) perror( "scandir" ); else for ( i = 0; i < n; ++i ) directory_list=file_details( file, dl[i]->d_name ); */ snprintf(page,sizeof(page),"Index of %s\n

Index of %s

\n
\nNot showing directory listing
\n
\n
%s
\n\n", file, file,SERVER_URL, SERVER_NAME ); } #endif } else if (file_forbidden(&fp,file,&header,&page) != 1) { header = make_header( 200, "Ok", (char*) 0, get_mime_type( file ), sb.st_size, sb.st_mtime ); page=page_from_file(fp,&length_of_data); printf("*Asked file loaded and served\n"); } } } send(consocket, header, strlen(header), 0); if (length_of_data==-1) length_of_data=strlen(page); send(consocket, page, length_of_data, 0); close(consocket); free(page); free(header); printf("free'ed two items\n"); pthread_exit(NULL); } int main(int argc, char *argv[]) { struct sockaddr_in dest; /* socket info about the machine connecting to us */ struct sockaddr_in serv; /* socket info about our server */ int mysocket; /* socket used to listen for incoming connections */ unsigned int socksize = sizeof(struct sockaddr_in); memset(&dest, 0, sizeof(dest)); /* zero the struct before filling the fields */ serv.sin_family = AF_INET; /* set the type of connection to TCP/IP */ serv.sin_addr.s_addr = INADDR_ANY; /* set our address to any interface */ if (argc==2) serv.sin_port = htons(atoi(argv[1])); else serv.sin_port = htons(PORTNUM); /* set the server port number */ mysocket = socket(AF_INET, SOCK_STREAM, 0); //without this, server dies, if clients doesn't take sendings struct sigaction act; act.sa_handler = SIG_IGN; sigemptyset (&act.sa_mask); act.sa_flags = 0; sigaction (SIGPIPE, &act, NULL); //we ignore signal 'broken pipe' /* bind serv information to mysocket */ bind(mysocket, (struct sockaddr *)&serv, sizeof(struct sockaddr)); /* start listening, allowing a queue of up to 1 pending connection */ listen(mysocket, 1); /* set thread create attributes */ //some reason, this doesn't work //I want that every thread frees its memory when it dies pthread_attr_t pattr; pthread_attr_init(&pattr); pthread_attr_setdetachstate(&pattr, PTHREAD_CREATE_DETACHED); if ( pthread_attr_setdetachstate( &pattr, PTHREAD_CREATE_DETACHED ) != 0 ) { printf("error putting automagic detach\n" ); } //this is how it be free'ed by hands, but because we do not know when thread is ready //pthread_detach( handling_thread); while(g_running) { int new_conection_socket = accept(mysocket, (struct sockaddr *)&dest, &socksize); // we stops on this row pthread_t handling_thread; pthread_create(&handling_thread, &pattr, handle_connection, (void *)new_conection_socket); } close(mysocket); return EXIT_SUCCESS; } char *make_error(int status, char *text) { int size=10000000*sizeof(char); char *error_content = safe_malloc(size); snprintf(error_content,size,"%d %s\n

%d %s

\n%s\n
\n
%s
\n\n", status, text, status, text,text,SERVER_URL, SERVER_NAME ); return error_content; } char *make_header( int status, char* title, char* extra_header, char* mime_type, off_t length, time_t mod) { int header_length=10000000*sizeof(char); //fix, use given parameter char *header =safe_malloc(header_length); char _extra_header[100]; if (extra_header == (char*) 0) _extra_header[0]='\0'; else snprintf(_extra_header,100,"%s\015\012",extra_header); char _mime[100]; if (mime_type == (char*) 0) _mime[0]='\0'; else snprintf(_mime,100,"Content-Type: %s\015\012",mime_type); char _length[10000]; if ( length >= 0 ) snprintf(_length,10000,"Content-Length: %lld\015\012", (int64_t) length ); else _length[0]='\0'; time_t now; now = time( (time_t*) 0 ); char timebuf[100]; (void) strftime( timebuf, 100, RFC1123FMT, gmtime( &now ) ); char timebuf2[100]; char _last_modified[10000]; if ( mod != (time_t) -1 ) { strftime( timebuf2, 100, RFC1123FMT, gmtime( &mod ) ); snprintf(_last_modified,10000,"Last-Modified: %s\015\012", timebuf2 ); } /* character '\' in the end of each row is only for code typesetting*/ snprintf(header,header_length, "\015\012\ %s %d %s\015\012\ %s\ %s\ MIME-version: 1.0\r\n\ %s\ Date: %s\015\012\ Server: %s\015\012\ %s\ \015\012", PROTOCOL, status, title, _extra_header, _mime, _last_modified, timebuf, SERVER_NAME, _length); //printf("HEADER\n%s\n/HEADER\n",header); return header; }