Adesso fa un po' meno schifo
[gapil.git] / sources / wwwd.c
1 /* wwwd.c
2  * 
3  * Copyright (C) 2005 Simone Piccardi
4  * 
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or (at
8  * your option) any later version.
9  * 
10  * This program is distributed in the hope that it will be useful, but
11  * WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * General Public License for more details.
14  * 
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18  */
19 /****************************************************************
20  *
21  * Program wwwd 
22  * Elementary WWW server (port 80)
23  *
24  * Author: Simone Piccardi
25  * Mar. 2005
26  *
27  * Usage: wwwd -h give all info
28  *
29  * $Id$ 
30  *
31  ****************************************************************/
32 /* 
33  * Include needed headers
34  */
35 #define _GNU_SOURCE
36 #include <string.h>      /* error strings */
37 #include <sys/types.h>   /* predefined types */
38 #include <unistd.h>      /* include unix standard library */
39 #include <arpa/inet.h>   /* IP addresses conversion utiliites */
40 #include <sys/socket.h>  /* socket library */
41 #include <stdio.h>       /* include standard I/O library */
42 #include <time.h>
43 #include <syslog.h>      /* syslog system functions */
44 #include <signal.h>      /* signal functions */
45 #include <errno.h>       /* error code */
46 #include <stdlib.h>
47
48 #include "Gapil.h"
49
50 #define BACKLOG 10
51 #define MAXLINE 256
52 int demonize  = 1;  /* daemon use option: default is daemon */
53 int debugging = 0;  /* debug info printing option: default is no debug */
54
55 /* Subroutines declaration */
56 void usage(void);
57 void ServPage(int sockfd);
58 void PrintErr(char * error);
59 void print_headers(FILE *file);
60 void print_err404(FILE *file, char *filename);
61 void print_err400(FILE *file, char *string);
62 void print_err500(FILE *file, char *string);
63
64 /* Program beginning */
65 int main(int argc, char *argv[])
66 {
67 /* 
68  * Variables definition  
69  */
70     int list_fd, conn_fd;
71     int waiting = 0;
72     int compat = 0;
73     pid_t pid;
74     struct sockaddr_in cli_add;
75     socklen_t len;
76     char debug[MAXLINE], ipaddr[20];
77     /*
78      * Input section: decode parameters passed in the calling 
79      * Use getopt function
80      */
81     int i;
82     opterr = 0;  /* don't want writing to stderr */
83     while ( (i = getopt(argc, argv, "hdicw:")) != -1) {
84         switch (i) {
85         /* 
86          * Handling options 
87          */ 
88         case 'h':  
89             printf("Wrong -h option use\n");
90             usage();
91             return(0);
92             break;
93         case 'i':
94             demonize = 0;
95             break;
96         case 'c':
97             compat = 1;
98             break;
99         case 'd':
100             debugging = 1;
101             break;
102         case 'w':
103             waiting = strtol(optarg, NULL, 10);
104             break;
105         case '?':   /* unrecognized options */
106             printf("Unrecognized options -%c\n",optopt);
107             usage();
108         default:    /* should not reached */
109             usage();
110         }
111     }
112     /* ***********************************************************
113      * 
114      *           Options processing completed
115      *
116      *                Main code beginning
117      * 
118      * ***********************************************************/
119     /* Main code begin here */
120     if (compat) {                             /* install signal handler */
121         Signal(SIGCHLD, HandSigCHLD);         /* non restarting handler */
122     } else {
123         SignalRestart(SIGCHLD, HandSigCHLD);  /* restarting handler */
124     }
125     /* create and bind socket */
126     if ( (list_fd = sockbind2(argv[optind], "www", 6, SOCK_STREAM)) < 0) {
127         return 1;
128     }   
129     /* release privileges and go daemon */
130     if (setgid(65534) !=0) { /* first give away group privileges */
131         perror("cannot give away group privileges");
132         exit(1);
133     }
134     if (setuid(65534) !=0) { /* and only after user ... */
135         perror("cannot give away user privileges");
136         exit(1);
137     }
138     if (demonize) {          /* go daemon */
139         openlog(argv[0], 0, LOG_DAEMON); /* open logging */
140         if (daemon(0, 0) != 0) {
141             perror("cannot start as daemon");
142             exit(1);
143         }
144     }
145     /* main body */
146     if (listen(list_fd, BACKLOG) < 0 ) {
147         PrintErr("listen error");
148         exit(1);
149     }
150     if (waiting) sleep(waiting);
151     /* handle echo to client */
152     while (1) {
153         /* accept connection */
154         len = sizeof(cli_add);
155         while (((conn_fd = accept(list_fd, (struct sockaddr *)&cli_add, &len)) 
156                 < 0) && (errno == EINTR)); 
157         if (conn_fd < 0) {
158             PrintErr("accept error");
159             exit(1);
160         }
161         if (debugging) {
162             inet_ntop(AF_INET, &cli_add.sin_addr, ipaddr, sizeof(ipaddr));
163             snprintf(debug, MAXLINE, "Accepted connection form %s\n", ipaddr);
164             if (demonize) {
165                 syslog(LOG_DEBUG, debug);
166             } else {
167                 printf("%s", debug);
168             }
169         }
170         /* fork to handle connection */
171         if ( (pid = fork()) < 0 ){
172             PrintErr("fork error");
173             exit(1);
174         }
175         if (pid == 0) {      /* child */
176             close(list_fd);          /* close listening socket */   
177             ServPage(conn_fd);       /* handle echo */
178             if (debugging) {
179                 snprintf(debug, MAXLINE, "Closed connection %s\n", ipaddr);
180                 if (demonize) {
181                     syslog(LOG_DEBUG, debug);
182                 } else {
183                     printf("%s", debug);
184                 }
185             }
186             exit(0);
187         } else {             /* parent */
188             close(conn_fd);          /* close connected socket */
189         }
190     }
191     /* normal exit, never reached */
192     exit(0);
193 }
194 /*
195  * routine to print usage info and exit
196  */
197 void usage(void) 
198 {
199     printf("Elementary echo server\n");
200     printf("Usage:\n");
201     printf("  echod [-h] \n");
202     printf("  -h           print this help\n");
203     printf("  -d           write debug info\n");
204     printf("  -i           use interactively\n");
205     printf("  -c           disable BSD semantics\n");
206     printf("  -w N         wait N sec. before calling accept\n");
207     exit(1);
208 }
209 /*
210  * routine to handle echo for connection
211  */
212 void ServPage(int sockfd) 
213 {
214     char buffer[MAXLINE];
215     char outbuf[1024];
216     FILE *sock, *file;
217     char *line, *copy, *method, *ptr, *filename, *version;
218     char *methods[] = { "GET", "PUT", NULL };
219     char *codes[] = {
220         "200 OK",
221         "400 Bad Request",
222         "404 Not Found",
223         "500 Internal Server Error",
224         NULL
225     };
226     int nleft;
227     int i, j;
228
229     sock = fdopen(sockfd, "w+");
230     /* main loop, reading 0 char means client close connection */
231     line = fgets(buffer, MAXLINE, sock);
232     if (line == NULL) {
233         PrintErr("Errore in lettura");
234         return;
235     }
236     /* parsing first line, getting method and filename */
237     copy = strndupa(line, MAXLINE);
238     if ((method = strtok_r(copy, " ", &ptr)) == NULL) {
239         fprintf(sock, "HTTP/1.0 %s\n", codes[2]);
240         print_headers(sock);
241         print_err400(sock, line);
242         return;
243     }
244     if ((filename = strtok_r(NULL, " ", &ptr)) == NULL) {
245         fprintf(sock, "HTTP/1.0 %s\n", codes[2]);
246         print_headers(sock);
247         print_err400(sock, line);
248         return;
249     }
250     if ((version = strtok_r(NULL, " ", &ptr)) == NULL) {
251         fprintf(sock, "HTTP/1.0 %s\n", codes[2]);
252         print_headers(sock);
253         print_err400(sock, line);
254         return;
255     }
256     i = 0;
257     while ( (ptr = methods[i]) != NULL) {
258         if ( (strncmp(ptr, method, strlen(ptr)) == 0)) {
259             break;
260         }
261         i++;
262     }
263     if (i>=2) {
264         fprintf(sock, "HTTP/1.0 %s\n", codes[2]);
265         print_headers(sock);
266         print_err400(sock, line);
267         return;
268     }
269
270     while (strcmp(line,"\r\n")) {
271         line = fgets(buffer, MAXLINE, sock);
272     }
273
274     if ( (file = fopen(filename, "r")) == NULL) {
275         fprintf(sock, "HTTP/1.0 %s\n", codes[2]);
276         print_headers(sock);
277         print_err404(sock, filename);
278         return;
279     }
280     fprintf(sock, "HTTP/1.0 %s\n", codes[0]);
281     print_headers(sock);
282
283     j = 0;
284     while (!feof(file)) {
285         printf("Loop %d\n", j++);
286         if ( (nleft = full_fread(file, outbuf, 1024)) != 0) {
287             if (ferror(file)) {
288                 fprintf(sock, "HTTP/1.0 %s\n", codes[3]);
289                 print_headers(sock);
290                 snprintf(buffer, MAXLINE, "reading %s", filename);
291                 print_err500(sock, buffer);
292                 return;
293             }
294         }
295         printf("Loop %d rimasti %d\n", j, nleft);
296         if (full_fwrite(sock, outbuf, 1024-nleft) != 0) {
297             if (ferror(file)) {
298                 fprintf(sock, "HTTP/1.0 %s\n", codes[3]);
299                 print_headers(sock);
300                 snprintf(buffer, MAXLINE, "writing");
301                 print_err500(sock, buffer);
302                 return;
303             }   
304         }
305     }
306     printf("Ok fin qui!");
307 //    line = fgets(buffer, MAXLINE, sock);
308     fclose(file);
309     fclose(sock);
310     return;
311 }
312 /*
313  * routine to print error on stout or syslog
314  */
315 void PrintErr(char * error) 
316 {
317     if (demonize) {                       /* daemon mode */
318         syslog(LOG_ERR, "%s: %m", error); /* log string and error message */
319     } else {
320         perror(error);
321     }
322     return;
323 }
324
325 void print_headers(FILE *file)
326 {
327     time_t tempo;
328
329     time(&tempo);
330     fprintf(file, "Date: %s", ctime(&tempo));
331     fprintf(file, "Server: WWWd test server\n");
332     fprintf(file, "Connection: close\n");
333     fprintf(file, "Content-Type: text/html; charset=iso-8859-1\n");
334     fprintf(file, "\n");
335     return;
336 }
337
338 void print_err404(FILE *file, char *filename)
339 {
340     fprintf(file, "<HTML><HEAD><TITLE>404 Not Found</TITLE></HEAD>\n");
341     fprintf(file, "<BODY><H1>Not Found</H1>\nThe requested ");
342     fprintf(file, "URL %s was not found on this server.<P><HR>", filename);
343     fprintf(file, "<ADDRESS>WWWd by Simone Piccardi</ADDRESS></BODY></HTML>");
344     return;
345 }
346
347 void print_err400(FILE *file, char *string)
348 {
349     fprintf(file, "<HTML><HEAD><TITLE>404 Bad Request</TITLE></HEAD>\n");
350     fprintf(file, "<BODY><H1>Bad Request</H1>\n ");
351     fprintf(file, "Your browser sent a request that this server could not ");
352     fprintf(file, "understand.<P>The request line<P> %s <P>", string);
353     fprintf(file, "is invalid following the protocol<p><HR>");
354     fprintf(file, "<ADDRESS>WWWd by Simone Piccardi </ADDRESS></BODY></HTML>");
355     return;
356 }
357
358
359 void print_err500(FILE *file, char *string)
360 {
361     fprintf(file, "<HTML><HEAD><TITLE>500 Internal Server Error</TITLE>\n");
362     fprintf(file, "</HEAD><BODY><H1>Internal Server Error</H1>\n ");
363     fprintf(file, "We got an error processing your request.<P>");
364     fprintf(file, "Error is: %s <P><HR>\n", string);
365     fprintf(file, "<ADDRESS>WWWd by Simone Piccardi </ADDRESS></BODY></HTML>");
366     return;
367 }