Simples servidor http com concorrência feito em C
/*
* Autor: Robson Oliveira
* Obs.: Livre para qualquer alteração
*/
#include <stdio.h> /* printf */
#include <stdlib.h> /* exit */
#include <string.h> /* bzero */
#include <sys/socket.h> /* struct sockaddr, socket, listen, bind, accept, recv, send */
#include <sys/wait.h> /* waitpid */
#include <arpa/inet.h> /* struct sockaddr */
#include <unistd.h> /* exit, fork */
#include <signal.h> /* signal */
#include <time.h> /* TIME, time_t */
#include <pthread.h> /* pthread_t, pthread_create */
#include <sys/stat.h> /* lstat() */
#include <sys/types.h> /* mode_t */
/*define variaveis constantes e seus respectivos valores */
#define BUFFSIZE 800
#define MAXPENDING 5
#define SA struct sockaddr
#define SAI struct sockaddr_in
#define TYPE 16
#define tipoData "%a, %m %b %Y %X %Z"
#define SERVER "AS(2008-2011)"
void error(char *msg); /* imprime mensagens de erro */
void sig_chld(int sinal); /* trata o sinal, para evitar filhos zumbis */
char *extensao(char *nome); /* verifica e retorna a extensao do arquivo para respota HTTP*/
int redirect(char *caminho); /* Verifica se o arquivo não sofreu uma modificação permanente*/
void respostaHTTP(char *resposta, char *tipo, char* caminho, int connfd, char *size); /* Cria uma resposta Http e envia ao cliente*/
void enviaArquivo(char *caminho, int connfd); /* Envia o arquivo solicitado ao Cliente */
long verificaArquivo(char *caminho); /* Verifica se o arquivo solicitado existe na raiz */
/* Verifica o que é pedido no protocolo Http solicitado pelo cliente*/
int TratandoPedido(char *metodo, char *versao, char *caminho, char *p, char *tipo, int i);
int pedidoHTTP(char *p, char *caminho, char *tipo);/* Manipula pedido do cliente essa função necessita da TratandoPedido */
int *criarSocket(int porta); /* Cria um socket utilizando TCP/IP */
void dec_string(long size, char *s); /* Transforma um inteiro em uma String*/
void execucao(int connfd); /* execucao da conexao com o metodo fork */
void in_fork(int *listenfd); /* metodo que utiliza o fork para execucao */
static void *execucao_thread(void *arg); /* execucao da conexao com o metodo thread */
void in_thread(int *listenfd); /* metodo que utiliza threads para execucao */
/* Função Principal*/
int main(int argc, char *argv[]){
int *listenfd, porta, concorrencia;
/* Caso o usuario nao coloque os 3 parametros necessarios */
if(argc != 3)
error("Use: HttpServer <porta> -[thread ou fork]");
/* define o modelo de concorrencia */
if(strcmp(argv[2], "-thread") == 0)
concorrencia = 1;
else if(strcmp(argv[2], "-fork") == 0)
concorrencia = 2;
else
error("Por favor, escolha a concorrência sendo ela -fork ou -thread .");
porta = atoi(argv[1]); /*define a porta */
listenfd = criarSocket(porta); /* chama a funcao criarSocket */
/* Estipula a fila para o Servidor */
if(listen(*listenfd, MAXPENDING) < 0)
error("Falha ao tentar escutar o socket do servidor");
if(concorrencia == 2) /* se concorrencia for fork */
signal(SIGCHLD, sig_chld); /* vai tratar os filhos zumbis */
if(concorrencia == 1){ /* se concorencia for thread */
in_thread(listenfd); /* chama o metodo in_thread */
}
else if(concorrencia == 2){ /* se concorrencia for fork */
in_fork(listenfd); /* chama o metodo in_fork */
}
free(listenfd);
return 0;
}
/* Imprime mensagens de erro */
void error(char *msg){
printf("%s\n", msg);
exit(0);
return;
}
/* verifica e retorna a extensao do arquivo */
char *extensao(char *nome){
char ext[20];
strcpy(ext, ".");
strcat(ext, nome);
if (strcmp(ext, ".html") == 0 || strcmp(ext, ".htm") == 0) return "text/html";
if (strcmp(ext, ".jpg") == 0 || strcmp(ext, ".jpeg") == 0) return "image/jpeg";
if (strcmp(ext, ".gif") == 0) return "image/gif";
if (strcmp(ext, ".png") == 0) return "image/png";
if (strcmp(ext, ".css") == 0) return "text/css";
if (strcmp(ext, ".au") == 0) return "audio/basic";
if (strcmp(ext, ".wav") == 0) return "audio/wav";
if (strcmp(ext, ".avi") == 0) return "video/x-msvideo";
if (strcmp(ext, ".mpeg") == 0 || strcmp(ext, ".mpg") == 0) return "video/mpeg";
if (strcmp(ext, ".mp3") == 0) return "audio/mpeg";
if (strcmp(ext, ".js") == 0) return "text/javascript";
if (strcmp(ext, ".ico") == 0) return "image/x-icon";
return NULL;
}
void respostaHTTP(char *resposta, char *tipo, char *caminho, int connfd, char *size){
time_t rawtime;
struct tm *timeinfo, *ltime;
struct stat arq;
char timebuf[50], encaminhar[BUFFSIZE], *aux, lastime[50];
long s;
lstat(caminho, &arq);
time(&rawtime);
timeinfo = localtime(&rawtime);
ltime = localtime(&arq.st_mtime);
strftime(lastime, sizeof(lastime), tipoData, ltime);
strftime(timebuf, sizeof(timebuf), tipoData, timeinfo);
if(strcmp(resposta, "HTTP/1.1 200 OK") == 0){
strcpy(encaminhar, resposta);
strcat(encaminhar, "\r\n");
strcat(encaminhar, "Connection: close\r\n");
strcat(encaminhar, "Date: ");
strcat(encaminhar, timebuf);
strcat(encaminhar, "\r\n");
strcat(encaminhar, "Server: ");
strcat(encaminhar, SERVER);
strcat(encaminhar, "\r\n");
strcat(encaminhar, "Content-Length: ");
strcat(encaminhar, size);
strcat(encaminhar, "\r\n");
strcat(encaminhar, "Last-Modified: ");
strcat(encaminhar, lastime);
strcat(encaminhar, "\r\n");
strcat(encaminhar, "Content-Type: ");
if(strcmp(tipo, "/") == 0){
aux = extensao("html");
strcat(encaminhar, aux);
}
else{
aux = extensao(tipo);
if(aux != NULL)
strcat(encaminhar, aux);
else{
s= verificaArquivo("badrequest.html");
dec_string(s, size);
respostaHTTP("HTTP/1.1 400 Bad Request", tipo, "badrequest.html", connfd, size);
enviaArquivo("badrequest.html", connfd);
close(connfd);
exit(0);
}
}
strcat(encaminhar, "\r\n");
strcat(encaminhar, "\r\n");
printf("%s\n", encaminhar);
send(connfd, encaminhar, strlen(encaminhar), 0);
}
else if(strcmp(resposta, "HTTP/1.1 404 Not Found") == 0){
strcpy(encaminhar, resposta);
strcat(encaminhar, "\r\n");
strcat(encaminhar, "Connection: close\r\n");
strcat(encaminhar, "Date: ");
strcat(encaminhar, timebuf);
strcat(encaminhar, "\r\n");
strcat(encaminhar, "Server: ");
strcat(encaminhar, SERVER);
strcat(encaminhar, "\r\n");
strcat(encaminhar, "Content-Length: ");
strcat(encaminhar, size);
strcat(encaminhar, "\r\n");
strcat(encaminhar, "Last-Modified: ");
strcat(encaminhar, lastime);
strcat(encaminhar, "\r\n");
strcat(encaminhar, "Content-Type: ");
aux = extensao("html");
strcat(encaminhar, aux);
strcat(encaminhar, "\r\n");
strcat(encaminhar, "\r\n");
printf("%s\n", encaminhar);
}
else if(strcmp(resposta, "HTTP/1.1 505 HTTP Version Not Supported") == 0){
strcpy(encaminhar, resposta);
strcat(encaminhar, "\r\n");
strcat(encaminhar, "Connection: close\r\n");
strcat(encaminhar, "Date: ");
strcat(encaminhar, timebuf);
strcat(encaminhar, "\r\n");
strcat(encaminhar, "Server: ");
strcat(encaminhar, SERVER);
strcat(encaminhar, "\r\n");
strcat(encaminhar, "Content-Length: ");
strcat(encaminhar, size);
strcat(encaminhar, "\r\n");
strcat(encaminhar, "Last-Modified: ");
strcat(encaminhar, lastime);
strcat(encaminhar, "\r\n");
strcat(encaminhar, "Content-Type: ");
aux = extensao("html");
strcat(encaminhar, aux);
strcat(encaminhar, "\r\n");
strcat(encaminhar, "\r\n");
printf("%s\n", encaminhar);
}
else if(strcmp(resposta, "HTTP/1.1 400 Bad Request") == 0){
strcpy(encaminhar, resposta);
strcat(encaminhar, "\r\n");
strcat(encaminhar, "Connection: close\r\n");
strcat(encaminhar, "Date: ");
strcat(encaminhar, timebuf);
strcat(encaminhar, "\r\n");
strcat(encaminhar, "Server: ");
strcat(encaminhar, SERVER);
strcat(encaminhar, "\r\n");
strcat(encaminhar, "Content-Length: ");
strcat(encaminhar, size);
strcat(encaminhar, "\r\n");
strcat(encaminhar, "Last-Modified: ");
strcat(encaminhar, lastime);
strcat(encaminhar, "\r\n");
strcat(encaminhar, "Content-Type: ");
aux = extensao("html");
strcat(encaminhar, aux);
strcat(encaminhar, "\r\n");
strcat(encaminhar, "\r\n");
printf("%s\n", encaminhar);
}
else if(strcmp(resposta, "HTTP/1.1 301 Moved Permanently") == 0){
strcpy(encaminhar, resposta);
strcat(encaminhar, "\r\n");
strcat(encaminhar, "Connection: close\r\n");
strcat(encaminhar, "Date: ");
strcat(encaminhar, timebuf);
strcat(encaminhar, "\r\n");
strcat(encaminhar, "Server: ");
strcat(encaminhar, SERVER);
strcat(encaminhar, "\r\n");
strcat(encaminhar, "Content-Length: ");
strcat(encaminhar, size);
strcat(encaminhar, "\r\n");
strcat(encaminhar, "Location: ");
strcat(encaminhar, caminho);
strcat(encaminhar, "\r\n");
strcat(encaminhar, "Last-Modified: ");
strcat(encaminhar, lastime);
strcat(encaminhar, "\r\n");
strcat(encaminhar, "Content-Type: ");
aux = extensao("html");
strcat(encaminhar, aux);
strcat(encaminhar, "\r\n");
strcat(encaminhar, "\r\n");
printf("%s\n", encaminhar);
}
return;
}
/* Envia o arquivo solicitado ao cliente */
void enviaArquivo(char *caminho, int connfd){
FILE *file;
long size;
char *c;
file = fopen(caminho, "rb");
if(file){
fseek(file , 0 , SEEK_END);
size = ftell(file);
rewind(file);
c = (char*) malloc(sizeof(char) * size);
fread(c, 1, size, file);
send(connfd, c, size, 0);
fclose(file);
free(c);
}
return;
}
long verificaArquivo(char *caminho){
FILE *file;
long size;
file = fopen(caminho, "rb");
if(file){
fseek(file , 0 , SEEK_END);
size = ftell(file);
rewind(file);
fclose(file);
return size;
}
else
return 0;
}
int TratandoPedido(char *metodo, char *versao, char *caminho, char *p, char *tipo, int i){
char *HTTP="HTTP/1.1";
int k;
for(i = i+1, k = 0; p[i] != ' ' && p[i] != '{FONTE}'; i++, k++)
caminho[k] = p[i];
caminho[k] = '{FONTE}';
for(i = i+1, k = 0; p[i] != '{FONTE}' && k < 8; i++, k++)
versao[k] = p[i];
versao[k] = '{FONTE}';
if((strcmp(HTTP, versao) != 0) && (strcmp("HTTP/1.0", versao) != 0))
return 0;
if(strcmp(caminho, "/") != 0){
for(i = strlen(caminho); p[i] != '.' && i >=0; i--);
for(i = i+1, k = 0; p[i] != '{FONTE}' && p[i] != ' '; i++, k++)
tipo[k] = p[i];
tipo[k] = '{FONTE}';
}
else
strcpy(tipo, "/");
return 1;
}
int pedidoHTTP(char *p, char *caminho, char *tipo){
char *GET="GET", *POST="POST", metodo[9], versao[10];
char aux;
int i, k, l;
for(i = 0; p[i] != ' ' && p[i] != '{FONTE}' && i < 9; i++)
metodo[i] = p[i];
metodo[i] = '{FONTE}';
if(strcmp(GET, metodo) == 0){
if(!TratandoPedido(metodo, versao, caminho, p, tipo, i))
return 2;
}
else if(strcmp(POST, metodo) == 0){
i = strlen(p) - 1;
for(k = 0; p[i] != '\n'; k++, i--)
tipo[k] = p[i];
tipo[k] = '{FONTE}';
l = strlen(tipo) - 1;
for(k = 0, i = l; k <= l/2; k++, i--){
aux = tipo[k];
tipo[k] = tipo[i];
tipo[i] = aux;
}
return 3;
}
else{
return 0;
}
return 1;
}
/* Cria um socket TCP/IP */
int *criarSocket(int porta){
int *listenfd;
struct sockaddr_in servaddr; /* Define um socket para o servidor */
listenfd = (int *) malloc(sizeof(int)); /* malloc define um ponteiro para um espaco de memoria do tamanho solicidado */
/* chama a funcao socket para especificar o tipo do protocolo */
if((*listenfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
error("Falha ao criar o socket");
/*populando os dados do servidor*/
bzero(&servaddr, sizeof(servaddr)); /*zera a estrutura que armazenarah os dados do servidor */
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY); /* Aceita qualquer faixa de IP que a maquina possa responder. */
servaddr.sin_port = htons(porta); /* define a porta */
/* vincula um socket a um endereco */
if(bind(*listenfd, (SA *) &servaddr, sizeof(servaddr)) < 0)
error("Falha ao observar o socket do servidor");
return listenfd;
}
int redirect(char *caminho){
FILE *file;
char novo[BUFFSIZE], antigo[BUFFSIZE];
file = fopen("htaccess.serv", "rb");
if(file){
while(!feof(file)){
fscanf(file, "%s %s", antigo, novo);
if(strcmp(antigo, caminho) == 0){
strcpy(caminho, novo);
return 1;
}
}
return 0;
}
else
return 0;
}
void dec_string(long size, char *s){
int i, j, l;
char aux;
for(i = 0; size > 0; size = size/10, i++){
s[i] = '0' + ((size%10) - 0);
}
s[i] = '{FONTE}';
j = strlen(s) - 1;
for(l = 0; l < i/2; l++, j--){
aux = s[l];
s[l] = s[j];
s[j] = aux;
}
return;
}
void execucao(int connfd){
char buffer[BUFFSIZE], caminho[BUFFSIZE], tipo[BUFFSIZE], sizechar[TYPE];
char POST[BUFFSIZE];
int situacao, n, i, novo;
long size;
/*Rebendo Protocolo http do cliente*/
if((n = recv(connfd, buffer, BUFFSIZE, 0)) < 0)
error("Falhou ao receber os dados iniciais do cliente");
buffer[n] = '{FONTE}';
printf("%s\n", buffer);
printf("-------------------- Resposta Servidor -------------------\n");
situacao = pedidoHTTP(buffer, caminho, tipo);
if(situacao == 1){
/*Verica se o link foi mudado, veja o arquivo htaccess.serv.*/
novo = redirect(caminho);
if(strcmp(caminho, "/") == 0)
strcpy(caminho, "index.html");
else{
for(i = strlen(caminho); i>=0; i--)
caminho[i+1] = caminho[i];
caminho[0] = '.';
}
size = verificaArquivo(caminho);
if(size){
dec_string(size, sizechar);
if(!novo){
respostaHTTP("HTTP/1.1 200 OK", tipo, caminho, connfd, sizechar);
enviaArquivo(caminho, connfd);
}
else{
respostaHTTP("HTTP/1.1 301 Moved Permanently", tipo, caminho, connfd, sizechar);
enviaArquivo(caminho, connfd);
}
}
else{
size = verificaArquivo("notfound.html");
dec_string(size, sizechar);
respostaHTTP("HTTP/1.1 404 Not Found", "html", caminho, connfd, sizechar);
enviaArquivo("notfound.html", connfd);
}
}
else if(situacao == 2){
size = verificaArquivo("notsupported.html");
dec_string(size, sizechar);
respostaHTTP("HTTP/1.1 505 HTTP Version Not Supported", "html", caminho, connfd, sizechar);
enviaArquivo("notsupported.html", connfd);
}
else if(situacao == 3){
size = sizeof(tipo);
dec_string(size, sizechar);
respostaHTTP("HTTP/1.1 200 OK", "html", caminho, connfd, sizechar);
strcpy(POST, "<hmtl>\n<head>\n<title>Post</title>\n</head>\n<body>");
strcat(POST, "\n<b>Post:</b> ");
strcat(POST, tipo);
strcat(POST, "\n</body>\n</html>");
send(connfd, POST, sizeof(POST), 0);
}
else{
size = verificaArquivo("badrequest.html");
dec_string(size, sizechar);
respostaHTTP("HTTP/1.1 400 Bad Request", "html", caminho, connfd, sizechar);
enviaArquivo("badrequest.html", connfd);
}
printf("--------------------- Fim Comunicação --------------------\n\n");
return;
}
/* Trata o sinal enviado pelo sistema */
void sig_chld(int sinal){
pid_t pid;
int stat;
while((pid = waitpid(-1, &stat, WNOHANG)) > 0);
return;
}
void in_fork(int *listenfd){
struct sockaddr_in client;
int connfd;
socklen_t clientlen;
pid_t pid;
for( ; ; ){
clientlen = sizeof(client);
/* aceita a conexao com o cliente */
if((connfd = accept(*listenfd, (SA *) &client, &clientlen)) < 0)
error("Falhou ao aceitar a conexao do cliente");
printf("------------------ Pedido de: %s ------------------\n", inet_ntoa(client.sin_addr)); /* imprime IP do cliente */
if((pid = fork()) == 0){
close(*listenfd);
execucao(connfd);
close(connfd); /* fecha a conexao */
exit(0);
}
close(connfd); /*fecha a conexao*/
}
close(*listenfd); /*fecha a escuta*/
exit(0);
return;
}
/* Função de execução da Thread */
static void *execucao_thread(void *arg){
int connfd;
connfd = *((int *) arg);
pthread_detach(pthread_self());
execucao(connfd);
close(connfd);
return NULL;
}
/* metodo que utiliza threads para execucao */
void in_thread(int *listenfd){
struct sockaddr_in client; /* define um socket para o cliente */
socklen_t clientlen;
int *iptr;
pthread_t tid;
for( ; ; ){
iptr = (int *) malloc(sizeof(int)); /* aloca iptr para cada thread */
*iptr = accept(*listenfd, (SA *) &client, &clientlen); /* iptr aceita a escuta do cliente */
printf("------------------ Pedido de: %s ------------------\n", inet_ntoa(client.sin_addr)); /* imprime o endereco IP do cliente */
/* cria uma thread */
pthread_create(&tid, NULL, &execucao_thread, iptr);
}
return;
}
* Autor: Robson Oliveira
* Obs.: Livre para qualquer alteração
*/
#include <stdio.h> /* printf */
#include <stdlib.h> /* exit */
#include <string.h> /* bzero */
#include <sys/socket.h> /* struct sockaddr, socket, listen, bind, accept, recv, send */
#include <sys/wait.h> /* waitpid */
#include <arpa/inet.h> /* struct sockaddr */
#include <unistd.h> /* exit, fork */
#include <signal.h> /* signal */
#include <time.h> /* TIME, time_t */
#include <pthread.h> /* pthread_t, pthread_create */
#include <sys/stat.h> /* lstat() */
#include <sys/types.h> /* mode_t */
/*define variaveis constantes e seus respectivos valores */
#define BUFFSIZE 800
#define MAXPENDING 5
#define SA struct sockaddr
#define SAI struct sockaddr_in
#define TYPE 16
#define tipoData "%a, %m %b %Y %X %Z"
#define SERVER "AS(2008-2011)"
void error(char *msg); /* imprime mensagens de erro */
void sig_chld(int sinal); /* trata o sinal, para evitar filhos zumbis */
char *extensao(char *nome); /* verifica e retorna a extensao do arquivo para respota HTTP*/
int redirect(char *caminho); /* Verifica se o arquivo não sofreu uma modificação permanente*/
void respostaHTTP(char *resposta, char *tipo, char* caminho, int connfd, char *size); /* Cria uma resposta Http e envia ao cliente*/
void enviaArquivo(char *caminho, int connfd); /* Envia o arquivo solicitado ao Cliente */
long verificaArquivo(char *caminho); /* Verifica se o arquivo solicitado existe na raiz */
/* Verifica o que é pedido no protocolo Http solicitado pelo cliente*/
int TratandoPedido(char *metodo, char *versao, char *caminho, char *p, char *tipo, int i);
int pedidoHTTP(char *p, char *caminho, char *tipo);/* Manipula pedido do cliente essa função necessita da TratandoPedido */
int *criarSocket(int porta); /* Cria um socket utilizando TCP/IP */
void dec_string(long size, char *s); /* Transforma um inteiro em uma String*/
void execucao(int connfd); /* execucao da conexao com o metodo fork */
void in_fork(int *listenfd); /* metodo que utiliza o fork para execucao */
static void *execucao_thread(void *arg); /* execucao da conexao com o metodo thread */
void in_thread(int *listenfd); /* metodo que utiliza threads para execucao */
/* Função Principal*/
int main(int argc, char *argv[]){
int *listenfd, porta, concorrencia;
/* Caso o usuario nao coloque os 3 parametros necessarios */
if(argc != 3)
error("Use: HttpServer <porta> -[thread ou fork]");
/* define o modelo de concorrencia */
if(strcmp(argv[2], "-thread") == 0)
concorrencia = 1;
else if(strcmp(argv[2], "-fork") == 0)
concorrencia = 2;
else
error("Por favor, escolha a concorrência sendo ela -fork ou -thread .");
porta = atoi(argv[1]); /*define a porta */
listenfd = criarSocket(porta); /* chama a funcao criarSocket */
/* Estipula a fila para o Servidor */
if(listen(*listenfd, MAXPENDING) < 0)
error("Falha ao tentar escutar o socket do servidor");
if(concorrencia == 2) /* se concorrencia for fork */
signal(SIGCHLD, sig_chld); /* vai tratar os filhos zumbis */
if(concorrencia == 1){ /* se concorencia for thread */
in_thread(listenfd); /* chama o metodo in_thread */
}
else if(concorrencia == 2){ /* se concorrencia for fork */
in_fork(listenfd); /* chama o metodo in_fork */
}
free(listenfd);
return 0;
}
/* Imprime mensagens de erro */
void error(char *msg){
printf("%s\n", msg);
exit(0);
return;
}
/* verifica e retorna a extensao do arquivo */
char *extensao(char *nome){
char ext[20];
strcpy(ext, ".");
strcat(ext, nome);
if (strcmp(ext, ".html") == 0 || strcmp(ext, ".htm") == 0) return "text/html";
if (strcmp(ext, ".jpg") == 0 || strcmp(ext, ".jpeg") == 0) return "image/jpeg";
if (strcmp(ext, ".gif") == 0) return "image/gif";
if (strcmp(ext, ".png") == 0) return "image/png";
if (strcmp(ext, ".css") == 0) return "text/css";
if (strcmp(ext, ".au") == 0) return "audio/basic";
if (strcmp(ext, ".wav") == 0) return "audio/wav";
if (strcmp(ext, ".avi") == 0) return "video/x-msvideo";
if (strcmp(ext, ".mpeg") == 0 || strcmp(ext, ".mpg") == 0) return "video/mpeg";
if (strcmp(ext, ".mp3") == 0) return "audio/mpeg";
if (strcmp(ext, ".js") == 0) return "text/javascript";
if (strcmp(ext, ".ico") == 0) return "image/x-icon";
return NULL;
}
void respostaHTTP(char *resposta, char *tipo, char *caminho, int connfd, char *size){
time_t rawtime;
struct tm *timeinfo, *ltime;
struct stat arq;
char timebuf[50], encaminhar[BUFFSIZE], *aux, lastime[50];
long s;
lstat(caminho, &arq);
time(&rawtime);
timeinfo = localtime(&rawtime);
ltime = localtime(&arq.st_mtime);
strftime(lastime, sizeof(lastime), tipoData, ltime);
strftime(timebuf, sizeof(timebuf), tipoData, timeinfo);
if(strcmp(resposta, "HTTP/1.1 200 OK") == 0){
strcpy(encaminhar, resposta);
strcat(encaminhar, "\r\n");
strcat(encaminhar, "Connection: close\r\n");
strcat(encaminhar, "Date: ");
strcat(encaminhar, timebuf);
strcat(encaminhar, "\r\n");
strcat(encaminhar, "Server: ");
strcat(encaminhar, SERVER);
strcat(encaminhar, "\r\n");
strcat(encaminhar, "Content-Length: ");
strcat(encaminhar, size);
strcat(encaminhar, "\r\n");
strcat(encaminhar, "Last-Modified: ");
strcat(encaminhar, lastime);
strcat(encaminhar, "\r\n");
strcat(encaminhar, "Content-Type: ");
if(strcmp(tipo, "/") == 0){
aux = extensao("html");
strcat(encaminhar, aux);
}
else{
aux = extensao(tipo);
if(aux != NULL)
strcat(encaminhar, aux);
else{
s= verificaArquivo("badrequest.html");
dec_string(s, size);
respostaHTTP("HTTP/1.1 400 Bad Request", tipo, "badrequest.html", connfd, size);
enviaArquivo("badrequest.html", connfd);
close(connfd);
exit(0);
}
}
strcat(encaminhar, "\r\n");
strcat(encaminhar, "\r\n");
printf("%s\n", encaminhar);
send(connfd, encaminhar, strlen(encaminhar), 0);
}
else if(strcmp(resposta, "HTTP/1.1 404 Not Found") == 0){
strcpy(encaminhar, resposta);
strcat(encaminhar, "\r\n");
strcat(encaminhar, "Connection: close\r\n");
strcat(encaminhar, "Date: ");
strcat(encaminhar, timebuf);
strcat(encaminhar, "\r\n");
strcat(encaminhar, "Server: ");
strcat(encaminhar, SERVER);
strcat(encaminhar, "\r\n");
strcat(encaminhar, "Content-Length: ");
strcat(encaminhar, size);
strcat(encaminhar, "\r\n");
strcat(encaminhar, "Last-Modified: ");
strcat(encaminhar, lastime);
strcat(encaminhar, "\r\n");
strcat(encaminhar, "Content-Type: ");
aux = extensao("html");
strcat(encaminhar, aux);
strcat(encaminhar, "\r\n");
strcat(encaminhar, "\r\n");
printf("%s\n", encaminhar);
}
else if(strcmp(resposta, "HTTP/1.1 505 HTTP Version Not Supported") == 0){
strcpy(encaminhar, resposta);
strcat(encaminhar, "\r\n");
strcat(encaminhar, "Connection: close\r\n");
strcat(encaminhar, "Date: ");
strcat(encaminhar, timebuf);
strcat(encaminhar, "\r\n");
strcat(encaminhar, "Server: ");
strcat(encaminhar, SERVER);
strcat(encaminhar, "\r\n");
strcat(encaminhar, "Content-Length: ");
strcat(encaminhar, size);
strcat(encaminhar, "\r\n");
strcat(encaminhar, "Last-Modified: ");
strcat(encaminhar, lastime);
strcat(encaminhar, "\r\n");
strcat(encaminhar, "Content-Type: ");
aux = extensao("html");
strcat(encaminhar, aux);
strcat(encaminhar, "\r\n");
strcat(encaminhar, "\r\n");
printf("%s\n", encaminhar);
}
else if(strcmp(resposta, "HTTP/1.1 400 Bad Request") == 0){
strcpy(encaminhar, resposta);
strcat(encaminhar, "\r\n");
strcat(encaminhar, "Connection: close\r\n");
strcat(encaminhar, "Date: ");
strcat(encaminhar, timebuf);
strcat(encaminhar, "\r\n");
strcat(encaminhar, "Server: ");
strcat(encaminhar, SERVER);
strcat(encaminhar, "\r\n");
strcat(encaminhar, "Content-Length: ");
strcat(encaminhar, size);
strcat(encaminhar, "\r\n");
strcat(encaminhar, "Last-Modified: ");
strcat(encaminhar, lastime);
strcat(encaminhar, "\r\n");
strcat(encaminhar, "Content-Type: ");
aux = extensao("html");
strcat(encaminhar, aux);
strcat(encaminhar, "\r\n");
strcat(encaminhar, "\r\n");
printf("%s\n", encaminhar);
}
else if(strcmp(resposta, "HTTP/1.1 301 Moved Permanently") == 0){
strcpy(encaminhar, resposta);
strcat(encaminhar, "\r\n");
strcat(encaminhar, "Connection: close\r\n");
strcat(encaminhar, "Date: ");
strcat(encaminhar, timebuf);
strcat(encaminhar, "\r\n");
strcat(encaminhar, "Server: ");
strcat(encaminhar, SERVER);
strcat(encaminhar, "\r\n");
strcat(encaminhar, "Content-Length: ");
strcat(encaminhar, size);
strcat(encaminhar, "\r\n");
strcat(encaminhar, "Location: ");
strcat(encaminhar, caminho);
strcat(encaminhar, "\r\n");
strcat(encaminhar, "Last-Modified: ");
strcat(encaminhar, lastime);
strcat(encaminhar, "\r\n");
strcat(encaminhar, "Content-Type: ");
aux = extensao("html");
strcat(encaminhar, aux);
strcat(encaminhar, "\r\n");
strcat(encaminhar, "\r\n");
printf("%s\n", encaminhar);
}
return;
}
/* Envia o arquivo solicitado ao cliente */
void enviaArquivo(char *caminho, int connfd){
FILE *file;
long size;
char *c;
file = fopen(caminho, "rb");
if(file){
fseek(file , 0 , SEEK_END);
size = ftell(file);
rewind(file);
c = (char*) malloc(sizeof(char) * size);
fread(c, 1, size, file);
send(connfd, c, size, 0);
fclose(file);
free(c);
}
return;
}
long verificaArquivo(char *caminho){
FILE *file;
long size;
file = fopen(caminho, "rb");
if(file){
fseek(file , 0 , SEEK_END);
size = ftell(file);
rewind(file);
fclose(file);
return size;
}
else
return 0;
}
int TratandoPedido(char *metodo, char *versao, char *caminho, char *p, char *tipo, int i){
char *HTTP="HTTP/1.1";
int k;
for(i = i+1, k = 0; p[i] != ' ' && p[i] != '{FONTE}'; i++, k++)
caminho[k] = p[i];
caminho[k] = '{FONTE}';
for(i = i+1, k = 0; p[i] != '{FONTE}' && k < 8; i++, k++)
versao[k] = p[i];
versao[k] = '{FONTE}';
if((strcmp(HTTP, versao) != 0) && (strcmp("HTTP/1.0", versao) != 0))
return 0;
if(strcmp(caminho, "/") != 0){
for(i = strlen(caminho); p[i] != '.' && i >=0; i--);
for(i = i+1, k = 0; p[i] != '{FONTE}' && p[i] != ' '; i++, k++)
tipo[k] = p[i];
tipo[k] = '{FONTE}';
}
else
strcpy(tipo, "/");
return 1;
}
int pedidoHTTP(char *p, char *caminho, char *tipo){
char *GET="GET", *POST="POST", metodo[9], versao[10];
char aux;
int i, k, l;
for(i = 0; p[i] != ' ' && p[i] != '{FONTE}' && i < 9; i++)
metodo[i] = p[i];
metodo[i] = '{FONTE}';
if(strcmp(GET, metodo) == 0){
if(!TratandoPedido(metodo, versao, caminho, p, tipo, i))
return 2;
}
else if(strcmp(POST, metodo) == 0){
i = strlen(p) - 1;
for(k = 0; p[i] != '\n'; k++, i--)
tipo[k] = p[i];
tipo[k] = '{FONTE}';
l = strlen(tipo) - 1;
for(k = 0, i = l; k <= l/2; k++, i--){
aux = tipo[k];
tipo[k] = tipo[i];
tipo[i] = aux;
}
return 3;
}
else{
return 0;
}
return 1;
}
/* Cria um socket TCP/IP */
int *criarSocket(int porta){
int *listenfd;
struct sockaddr_in servaddr; /* Define um socket para o servidor */
listenfd = (int *) malloc(sizeof(int)); /* malloc define um ponteiro para um espaco de memoria do tamanho solicidado */
/* chama a funcao socket para especificar o tipo do protocolo */
if((*listenfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
error("Falha ao criar o socket");
/*populando os dados do servidor*/
bzero(&servaddr, sizeof(servaddr)); /*zera a estrutura que armazenarah os dados do servidor */
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY); /* Aceita qualquer faixa de IP que a maquina possa responder. */
servaddr.sin_port = htons(porta); /* define a porta */
/* vincula um socket a um endereco */
if(bind(*listenfd, (SA *) &servaddr, sizeof(servaddr)) < 0)
error("Falha ao observar o socket do servidor");
return listenfd;
}
int redirect(char *caminho){
FILE *file;
char novo[BUFFSIZE], antigo[BUFFSIZE];
file = fopen("htaccess.serv", "rb");
if(file){
while(!feof(file)){
fscanf(file, "%s %s", antigo, novo);
if(strcmp(antigo, caminho) == 0){
strcpy(caminho, novo);
return 1;
}
}
return 0;
}
else
return 0;
}
void dec_string(long size, char *s){
int i, j, l;
char aux;
for(i = 0; size > 0; size = size/10, i++){
s[i] = '0' + ((size%10) - 0);
}
s[i] = '{FONTE}';
j = strlen(s) - 1;
for(l = 0; l < i/2; l++, j--){
aux = s[l];
s[l] = s[j];
s[j] = aux;
}
return;
}
void execucao(int connfd){
char buffer[BUFFSIZE], caminho[BUFFSIZE], tipo[BUFFSIZE], sizechar[TYPE];
char POST[BUFFSIZE];
int situacao, n, i, novo;
long size;
/*Rebendo Protocolo http do cliente*/
if((n = recv(connfd, buffer, BUFFSIZE, 0)) < 0)
error("Falhou ao receber os dados iniciais do cliente");
buffer[n] = '{FONTE}';
printf("%s\n", buffer);
printf("-------------------- Resposta Servidor -------------------\n");
situacao = pedidoHTTP(buffer, caminho, tipo);
if(situacao == 1){
/*Verica se o link foi mudado, veja o arquivo htaccess.serv.*/
novo = redirect(caminho);
if(strcmp(caminho, "/") == 0)
strcpy(caminho, "index.html");
else{
for(i = strlen(caminho); i>=0; i--)
caminho[i+1] = caminho[i];
caminho[0] = '.';
}
size = verificaArquivo(caminho);
if(size){
dec_string(size, sizechar);
if(!novo){
respostaHTTP("HTTP/1.1 200 OK", tipo, caminho, connfd, sizechar);
enviaArquivo(caminho, connfd);
}
else{
respostaHTTP("HTTP/1.1 301 Moved Permanently", tipo, caminho, connfd, sizechar);
enviaArquivo(caminho, connfd);
}
}
else{
size = verificaArquivo("notfound.html");
dec_string(size, sizechar);
respostaHTTP("HTTP/1.1 404 Not Found", "html", caminho, connfd, sizechar);
enviaArquivo("notfound.html", connfd);
}
}
else if(situacao == 2){
size = verificaArquivo("notsupported.html");
dec_string(size, sizechar);
respostaHTTP("HTTP/1.1 505 HTTP Version Not Supported", "html", caminho, connfd, sizechar);
enviaArquivo("notsupported.html", connfd);
}
else if(situacao == 3){
size = sizeof(tipo);
dec_string(size, sizechar);
respostaHTTP("HTTP/1.1 200 OK", "html", caminho, connfd, sizechar);
strcpy(POST, "<hmtl>\n<head>\n<title>Post</title>\n</head>\n<body>");
strcat(POST, "\n<b>Post:</b> ");
strcat(POST, tipo);
strcat(POST, "\n</body>\n</html>");
send(connfd, POST, sizeof(POST), 0);
}
else{
size = verificaArquivo("badrequest.html");
dec_string(size, sizechar);
respostaHTTP("HTTP/1.1 400 Bad Request", "html", caminho, connfd, sizechar);
enviaArquivo("badrequest.html", connfd);
}
printf("--------------------- Fim Comunicação --------------------\n\n");
return;
}
/* Trata o sinal enviado pelo sistema */
void sig_chld(int sinal){
pid_t pid;
int stat;
while((pid = waitpid(-1, &stat, WNOHANG)) > 0);
return;
}
void in_fork(int *listenfd){
struct sockaddr_in client;
int connfd;
socklen_t clientlen;
pid_t pid;
for( ; ; ){
clientlen = sizeof(client);
/* aceita a conexao com o cliente */
if((connfd = accept(*listenfd, (SA *) &client, &clientlen)) < 0)
error("Falhou ao aceitar a conexao do cliente");
printf("------------------ Pedido de: %s ------------------\n", inet_ntoa(client.sin_addr)); /* imprime IP do cliente */
if((pid = fork()) == 0){
close(*listenfd);
execucao(connfd);
close(connfd); /* fecha a conexao */
exit(0);
}
close(connfd); /*fecha a conexao*/
}
close(*listenfd); /*fecha a escuta*/
exit(0);
return;
}
/* Função de execução da Thread */
static void *execucao_thread(void *arg){
int connfd;
connfd = *((int *) arg);
pthread_detach(pthread_self());
execucao(connfd);
close(connfd);
return NULL;
}
/* metodo que utiliza threads para execucao */
void in_thread(int *listenfd){
struct sockaddr_in client; /* define um socket para o cliente */
socklen_t clientlen;
int *iptr;
pthread_t tid;
for( ; ; ){
iptr = (int *) malloc(sizeof(int)); /* aloca iptr para cada thread */
*iptr = accept(*listenfd, (SA *) &client, &clientlen); /* iptr aceita a escuta do cliente */
printf("------------------ Pedido de: %s ------------------\n", inet_ntoa(client.sin_addr)); /* imprime o endereco IP do cliente */
/* cria uma thread */
pthread_create(&tid, NULL, &execucao_thread, iptr);
}
return;
}