Unconfigured Ad Widget

Collapse

Anúncio

Collapse
No announcement yet.

[script]Simples servidor http com concorrência feito em C

Collapse
X
 
  • Filter
  • Tempo
  • Show
Clear All
new posts

  • Font Size
    #1

    [script]Simples servidor http com concorrência feito em C

    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;
    }
    Créditos: Robson Oliveira
    Last edited by Lord Beni-Aretz; 05-08-2011, 10:24.
    Não Acha Estranha Essa Frase:
    Eu Sou Hacker e Uso Windows XP!

    Use Débian, Aprenda Slackware e Brinque Muito Com Back|Track


    Fã ->Nickguitar.dll


    Quer ajudar nossso fórum e não sabe como?
    Então click na imagem e ajude-nos com os links off
X
Working...
X