Below is a sample .ini file
; Config file for ASK server [Protocol] Version=6 ; IPv6 [Web] http_version=HTTP/1.1 root_dir = www/ default_page = index.html error_page = error.html backlog = 10 max_header_size=1024 [Codes] 200 = OK 404 = Content Not Found
Below is the askserver.c source file. First the configurations are loaded and waiting for incoming requests. Then whenever a request is arrived the server check for the file requested. If it is available send a message code 200 and the file type server is going to send to the client. If the requested file was not fond, then send the message code 400 content not found.
When a available file is send to the client, method is used.
sendfile(destination, source, offset,size);
//******************** askserver.c ******************/ // Aruna Sujith Karunarathna #include <unistd.h> #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <errno.h> #include <string.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <netdb.h> #include <arpa/inet.h> #include <sys/wait.h> #include <signal.h> #include <fcntl.h> #include <sys/sendfile.h> #include <sys/stat.h> #include <sys/types.h> #include <netinet/tcp.h> #include <limits.h> #include <unistd.h> #include <assert.h> #include "ini.h" #define CONFIGURATION_FILE "configuration/ask.ini" typedef struct{ int version; int backlog; int max_header_size; const char* http_version; const char* root_dir; const char* default_page; const char* error_page; } configuration; configuration config; void sigchld_handler(int s){ while(waitpid(-1, NULL, WNOHANG) > 0); } // get sockaddr, IPv4 or IPv6: void *get_in_addr(struct sockaddr *sa){ if (sa->sa_family == AF_INET) { return &(((struct sockaddr_in*)sa)->sin_addr); } return &(((struct sockaddr_in6*)sa)->sin6_addr); } static int handler(void* user, const char* section, const char* name,const char* value){ configuration* pconfig = (configuration*)user; #define MATCH(s, n) strcasecmp(section, s) == 0 && strcasecmp(name, n) == 0 if (MATCH("protocol", "version")) { pconfig->version = atoi(value); } else if (MATCH("web", "http_version")) { pconfig->http_version = strdup(value); } else if (MATCH("web", "root_dir")) { pconfig->root_dir = strdup(value); } else if (MATCH("web", "default_page")) { pconfig->default_page = strdup(value); } else if (MATCH("web", "error_page")) { pconfig->error_page = strdup(value); } else if (MATCH("web", "backlog")) { pconfig->backlog = atoi(value); } else if (MATCH("web", "max_header_size")) { pconfig->max_header_size = atoi(value); } else { return 0; /* unknown section/name, error */ } return 1; } char* get_extension(char* file_name){ char* extension; extension = strchr(file_name,'.')+1 ; printf("EXTENSION %s \n",extension); return extension; } char* get_content_type(char* extension){ char* type; if(strcmp(extension,"html")==0) type = "text/html"; else if(strcmp(extension,"css")==0) type = "text/css"; else if(strcmp(extension,"txt")==0) type = "application/text"; else if(strcmp(extension,"pdf")==0) type = "application/pdf"; else if(strcmp(extension,"zip")==0) type = "application/zip"; else if(strcmp(extension,"xml")==0) type = "application/xml"; else if(strcmp(extension,"js")==0) type = "application/javascript"; else if(strcmp(extension,"jpg")==0) type = "image/jpg"; else if(strcmp(extension,"png")==0) type = "image/png"; else if(strcmp(extension,"exe")==0) type = "application/octet-stream"; else if(strcmp(extension,"ico")==0) type = "image/x-icon"; else if(strcmp(extension,"php")==0) type = "text/html"; printf("TYPE %s ",type); return type; } int set_header(char *header,int status_code,char *file_name,int file_length){ if(status_code==404){ //printf("%s %d File Not Found\n",config.http_version,status_code); sprintf(header, "%s %d File Not Found\n" "\n",config.http_version,status_code); printf("\nHEADER MESSAGE %s \n",header); return -1; } if(status_code==400){ sprintf(header, "%s %d Bad Request\n" "\n",config.http_version,status_code); return -1; } if(status_code==501){ sprintf(header,"%s %d POST Not Implemented\n " "\n POST Not Implemented",config.http_version,status_code); return -1; } char *extension; extension = get_extension(file_name); char *content_type; content_type = get_content_type(extension); sprintf(header,"%s %d OK \n" "Content-Type: %s\n" "Content-Length: %i\n" "\n",config.http_version,status_code,content_type ,file_length); printf("\nHEADER MESSAGE %s \n",header); } char* check_request(char * request){ char* ptr; ptr = strstr(request," HTTP/"); // printf("CHK REQUEST %s \n",request); if(ptr == NULL) { printf("Not HTTP request\n"); }else{ /* *** HTTP request received *** */ /* *** check for GET request *** */ if(strncmp(request,"GET ",4) == 0) { ptr="GET"; } /* *** check for POST request, give 501 error if received *** */ else if(strncmp(request,"POST ",5) == 0){ printf("501 Method not implemented\n"); ptr="POST"; } } return ptr; } char* get_path(char *request) { int i=0; // printf("REQUEST %s \n",request); char *token = NULL; token = strtok(request, " "); token = strtok(NULL, " "); return token; } int send_content(char* file_name, int socket, int status_code){ int sent_size; char header[config.max_header_size]; int open_file; /* file descriptor for source file */ struct stat stat_buf; /* hold information about input file */ off_t offset = 0; /* byte offset used by sendfile */ int return_code; /* return code from sendfile */ open_file = open(file_name, O_RDONLY);/* check that source file exists and can be opened */ fstat(open_file, &stat_buf); /* get size and permissions of the source file */ set_header(header,status_code,file_name,(int)stat_buf.st_size); sent_size=send(socket, header, strlen(header), 0); /* copy file using sendfile ####################################### */ // sendfile(destination, source, offset,size); return_code = sendfile (socket, open_file, &offset, stat_buf.st_size); printf("file size %d Bytes \n\n",return_code); if (return_code == -1) { fprintf(stderr, "error from sendfile: %s\n", strerror(errno)); } else if (return_code != stat_buf.st_size) { fprintf(stderr, "incomplete transfer from sendfile: %d of %d bytes\n", return_code, (int)stat_buf.st_size); } /* clean up and exit */ close(socket); close(open_file); return 0; } int main(int argc, char* argv[]){ if (ini_parse(CONFIGURATION_FILE , handler, &config) < 0) { printf("Can't load 'ask.ini'\n"); return 1; } printf("Config loaded from 'ask.ini':\nversion=%d\nbacklog=%d\nmax_header_size=%d \nhttp_version=%s\n", config.version, config.backlog, config.max_header_size, config.http_version); int sockfd, new_fd; // listen on sock_fd, new connection on new_fd struct addrinfo hints, *servinfo, *p; struct sockaddr_storage their_addr; // connector's address information socklen_t sin_size; struct sigaction sa; int yes=1; char s[INET6_ADDRSTRLEN]; int rv; memset(&hints, 0, sizeof hints); hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; hints.ai_flags = AI_PASSIVE; // use my IP if ((rv = getaddrinfo(NULL, argv[1], &hints, &servinfo)) != 0) { fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv)); return 1; } // loop through all the results and bind to the first we can for(p = servinfo; p != NULL; p = p->ai_next) { if ((sockfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) == -1) { perror("server: socket"); continue; } if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1) { perror("setsockopt"); exit(1); } if (bind(sockfd, p->ai_addr, p->ai_addrlen) == -1) { close(sockfd); perror("server: bind"); continue; } break; } if (p == NULL) { fprintf(stderr, "server: failed to bind\n"); return 2; } freeaddrinfo(servinfo); // all done with this structure if (listen(sockfd, config.backlog) == -1) { perror("listen"); exit(1); } sa.sa_handler = sigchld_handler; // reap all dead processes sigemptyset(&sa.sa_mask); sa.sa_flags = SA_RESTART; if (sigaction(SIGCHLD, &sa, NULL) == -1) { perror("sigaction"); exit(1); } printf("ASK_SERVER: waiting for connections...\n"); while(1) { // main accept() loop sin_size = sizeof their_addr; new_fd = accept(sockfd, (struct sockaddr *)&their_addr, &sin_size); if (new_fd == -1) { perror("accept"); continue; } inet_ntop(their_addr.ss_family,get_in_addr((struct sockaddr *)&their_addr),s, sizeof s); printf("ASK_SERVER: got connection from %s\n", s); if (!fork()) { // this is the child process close(sockfd); // child doesn't need the listener int buffer_size =1024; char* char_buffer = malloc(buffer_size); //get the client request read(new_fd,char_buffer,buffer_size); char *path; //printf("REQUEST ------ %s \n",char_buffer); //printf("CHECK_REQUEST %s \n",check_request(char_buffer)); char* request_type = check_request(char_buffer); printf("REQUEST TYPE ::::::: %s\n",request_type); char* header=malloc(200); memset(header,0,200); if(request_type==NULL){ set_header(header,400,NULL,0); send(new_fd, header, strlen(header), 0); return 0; } else if(strcmp(request_type,"POST")==0){ set_header(header,501,NULL,0); send(new_fd, header, strlen(header), 0); return 0; } path = get_path(char_buffer); if(strcmp("/",path)==0){ path = (char*)config.default_page; // path = config.default_page; } char *root_dir=malloc(100); memset(root_dir,0,sizeof root_dir); strcpy(root_dir,config.root_dir); path=strcat(root_dir,path); //printf("11111111111 real %s \n", path); /* ******* REQUEST FILE FOUND ********** */ if(access(path, F_OK ) != -1){ send_content(path,new_fd,200); //printf("OKKKKKKKKK %s \n", path); } else{ memset(root_dir,0,100); strcpy(root_dir,config.root_dir); path=strcat(root_dir,"/"); path=strcat(root_dir,config.error_page); //printf("ERRRRRRRRRRORRR %s \n",path); send_content(path,new_fd,404); } // if (send(new_fd, "Hello, world!", 13, 0) == -1) // perror("send"); free(char_buffer); close(new_fd); exit(0); } close(new_fd); // parent doesn't need this } printf("Config loaded from 'ask.ini': version=%d, backlog=%d,max_header_size=%d , http_version=%s\n", config.version, config.backlog, config.max_header_size, config.http_version); return 0; }
I have included a sample www folder in the same directory to simulate the web server.
Download the full project from here.... DOWNLOAD
How to Test the Sample ASK Server.
Open a Terminal and Type the Following Commands.
[aruna@ubuntu]~$ makefile
[aruna@ubuntu]~$ ./askserver 7788
The argument 7788 is the port that we bind the webserver. Now open a web browser and type the following address localhost:7788
You'll see the web server is up and running. :)
Great article. I am fully impressed.
ReplyDeleteLG Networks, Inc. is a Microsoft Certified and a leading Microsoft Exchange Server Consulting firm.
Our Emergency Exchange Support consultants can help you attain the maximum benefit and stability from
Microsoft Exchange Server with administrative, technical and onsite or remote troubleshooting support.
Waoou... What a tutorial you made? I think any body will be clear after seen this. Just not only looking nice , also
more helpful.
Emergency Exchange Support