/* www.c (2) * * Versão 2.0 do Servidor HTTP * A diferença desta versão é que este servidor lê as páginas requisitadas pelo browser * caso nao encontre o arquivo ele manda o erro 404 Not Found * * Para terminar as kernel threads segue o mesmo principio, ou seja, request * para a pagina exit.html * * lynx http://localhost/exit.html * * 25/06/2002 */ #include <linux/module.h> #include <linux/kernel.h> #include <linux/sched.h> #include <linux/net.h> #include <linux/types.h> #include <linux/socket.h> #include <net/tcp.h> #include <net/ip.h> #include <linux/inet.h> #include <net/protocol.h> #include <net/sock.h> #include <linux/fs.h> #include <linux/slab.h> #include <asm/page.h> #include <linux/string.h> #define NUM_THREAD 5 // Número de kernel threads a ser criado #define ROOT_DIR "/tmp/www/html" // Caminho onde estao os arquivos html struct socket *MainSocket=NULL; int pid[NUM_THREAD]; int ServerPort = 80; //Número da porta /* * Monta a string com o nome do arquivo, ie, monta o PATH do arquivo requisitado * Para compreender melhor mande imprimir o buffer, que e o conteudo da * requisicao feita pelo browser */ char * acha_arquivo(char *buffer) { char *start_name, *end_name, *arquivo; arquivo=kmalloc(25, GFP_KERNEL); start_name = strstr(buffer, "/"); end_name = strstr(start_name, "HTT"); *(end_name - 1) = 0; strcpy(arquivo, ROOT_DIR); // Caso venha uma requisicao para o /, ou seja, lynx http://localhost/ // mandamos o index.html if (*(start_name+1) == 0) strcat(arquivo, "/index.html"); else strcat(arquivo, start_name); return arquivo; } /* Função que todas as kernel threads irão executar */ int Accept(void *unused) { struct socket *newsock; struct file *fd; int error,i=0,tamanho; struct msghdr msg; struct iovec iov; mm_segment_t oldfs; char *fonte; char buf[4096], *sair = NULL; /* * Header necessário de respostas HTTP */ char header_200[]= "HTTP/1.1 200 OK\r\nContent-type: text/html\r\n\r\n"; char header_404[]= "HTTP/1.1 404 Not Found\r\nContent-type: text/html\r\n\r\n"; char pagina_404[]="<HTML><HEAD><TITLE>Server WWW 2.0</TITLE></HEAD><BODY><H1>404\ Not Found</BODY></HTML>"; char *pagina, *nome; daemonize(); sprintf(current->comm,"www_server"); while(!sair){ newsock = sock_alloc(); if (newsock==NULL) { printk(KERN_ALERT "kernel_thread : Erro durante criacao newsock\n"); return -1; } newsock->type = MainSocket->type; newsock->ops = MainSocket->ops; error = MainSocket->ops->accept(MainSocket, newsock, O_RDWR); if (error<0) { printk(KERN_ALERT "kernel_thread : ERRO accept\n"); return -1; } newsock->sk->reuse = 1; if (MainSocket->sk->state != TCP_LISTEN) { printk(KERN_ALERT "kernel_thread : TCP DON´T LISTEN\n"); return -1; } fonte = in_ntoa(newsock->sk->daddr); printk(KERN_ALERT "kernel_thread : fonte = %s\n",fonte); printk(KERN_ALERT "kernel_thread : pid = %d\n",current->pid); buf[0] = 0; iov.iov_base = (void *)buf; iov.iov_len = sizeof(buf); msg.msg_name = NULL; msg.msg_namelen = 0; msg.msg_iov = &iov; msg.msg_iovlen = 1; msg.msg_control = NULL; msg.msg_controllen = 0; msg.msg_flags = 0; oldfs = get_fs(); set_fs(KERNEL_DS); error = sock_recvmsg(newsock, &msg, sizeof(buf), 0); set_fs(oldfs); if (error<0) printk(KERN_ALERT "ERRO recv mesg"); nome = acha_arquivo(buf); printk(KERN_ALERT "abrir arquivo [%s]\n",nome); /* * Tentamos abrir o arquivo, caso nao exista enviamos erro 404 */ fd = filp_open(nome, O_RDONLY, 0); if (IS_ERR(fd)) { printk(KERN_ALERT "Erro nao pode abrir arquivo [%s]\n",nome); /* Configuramos e enviamos o header de erro */ iov.iov_base = (void *)header_404; iov.iov_len = sizeof(header_404); msg.msg_iov = &iov; oldfs = get_fs(); set_fs(KERNEL_DS); error = sock_sendmsg(newsock, &msg, sizeof(header_404)); set_fs(oldfs); if (error<0) printk(KERN_ALERT "ERRO durante envio header erro = %d\n",error); /* Configuramos e enviamos a pagina de erro */ iov.iov_base = (void *)pagina_404; iov.iov_len = sizeof(pagina_404); msg.msg_iov = &iov; oldfs = get_fs(); set_fs(KERNEL_DS); error = sock_sendmsg(newsock, &msg, sizeof(pagina_404)); set_fs(oldfs); if (error<0) printk(KERN_ALERT "ERRO durante envio pagina de erro = %d\n",error); } else { /* * Configuramos e enviamos o header HTTP */ iov.iov_base = (void *)header_200; iov.iov_len = sizeof(header_200); msg.msg_iov = &iov; oldfs = get_fs(); set_fs(KERNEL_DS); error = sock_sendmsg(newsock, &msg, sizeof(header_200)); set_fs(oldfs); if (error<0) printk(KERN_ALERT "ERRO durante envio header = %d\n",error); /* Configuramos e enviamos a pagina do arquivo lido */ // tamnho contem o tamho do arquivo em bytes tamanho = fd->f_dentry->d_inode->i_size; pagina = kmalloc(tamanho+1, GFP_KERNEL); fd->f_pos = 0; oldfs = get_fs(); set_fs(KERNEL_DS); i = generic_file_read(fd, pagina, tamanho, &fd->f_pos); set_fs(oldfs); if (i<0) printk(KERN_ALERT "ERRO ao ler arq %d\n",i); iov.iov_base = (void *)pagina; iov.iov_len = tamanho+1; msg.msg_iov = &iov; oldfs = get_fs(); set_fs(KERNEL_DS); error = sock_sendmsg(newsock, &msg, tamanho+1); set_fs(oldfs); if (error<0) printk(KERN_ALERT "ERRO durante envio pagina = %d\n",error); else printk(KERN_ALERT "Send msg ok\n"); i = filp_close(fd, NULL); kfree(pagina); } /* * Testa para ver se foi feito a requisição para a página exit.html */ sair = strstr(buf, "/exit.html"); sock_release(newsock); kfree(nome); } printk(KERN_ALERT "Kernel_Thread exit\n"); return 0; } /* * Cria o socket principal que será compartilhado por todas as kernel threads */ int Socket_Create(void) { struct sockaddr_in server; int error; printk(KERN_ALERT "Socket_Create : Hello\n"); error = sock_create(PF_INET,SOCK_STREAM,IPPROTO_TCP,&MainSocket); if (error<0) { printk(KERN_ALERT "Socket_Create : Error durante a criacao socket; terminating\n"); return -1; } server.sin_family = AF_INET; server.sin_addr.s_addr = INADDR_ANY; server.sin_port = htons((unsigned short)(ServerPort)); MainSocket->sk->reuse = 1; error = MainSocket->ops->bind(MainSocket,(struct sockaddr*)&server,sizeof(server)); if (error<0) { printk(KERN_ALERT "Socket_Create : Error binding socket\n"); return 1; } error = MainSocket->ops->listen(MainSocket,1); if (error!=0) { printk(KERN_ALERT "Socket_Create : Error listening on socket\n"); return -1; } else printk(KERN_ALERT "Socket_Create : Listening Socket OK \n"); printk(KERN_ALERT "Socket_Create : Server state %d\n",MainSocket->sk->state); return 0; } int www_init_module(void) { int binding, i; printk(KERN_ALERT "Servidor www 1.0\n"); binding = Socket_Create(); if (binding==0) { for (i=0;i<NUM_THREAD;i++) { /* * Cria as n kernel threads */ pid[i] = kernel_thread(Accept, NULL, CLONE_SIGHAND); if (pid[i] < 0) printk(KERN_ALERT "www: ERRO during kernel thread creation = %d\n",i); else printk(KERN_ALERT "www : kernel thread ok pid = %d\n",pid[i]); } } else printk(KERN_ALERT "ERRO www: binding, no threads\n"); return 0; } void www_cleanup_module(void) { sock_release(MainSocket); printk(KERN_ALERT "Servidor www. Bye\n"); } module_init(www_init_module); module_exit(www_cleanup_module); MODULE_DESCRIPTION("Exemplo de kernel thread e sockets"); MODULE_AUTHOR("Thobias Salazar Trevisan"); #ifndef MODULE_LICENSE #define MODULE_LICENSE(a) #endif MODULE_LICENSE("GPL"); EXPORT_NO_SYMBOLS;