Dopo notevoli ingrullimenti abbiamo il server WEB di esempio!
[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
61 /* Program beginning */
62 int main(int argc, char *argv[])
63 {
64 /* 
65  * Variables definition  
66  */
67     int list_fd, conn_fd;
68     int waiting = 0;
69     int compat = 0;
70     pid_t pid;
71     struct sockaddr_in cli_add;
72     socklen_t len;
73     char debug[MAXLINE], ipaddr[20];
74     /*
75      * Input section: decode parameters passed in the calling 
76      * Use getopt function
77      */
78     int i;
79     opterr = 0;  /* don't want writing to stderr */
80     while ( (i = getopt(argc, argv, "hdicw:")) != -1) {
81         switch (i) {
82         /* 
83          * Handling options 
84          */ 
85         case 'h':  
86             printf("Wrong -h option use\n");
87             usage();
88             return(0);
89             break;
90         case 'i':
91             demonize = 0;
92             break;
93         case 'c':
94             compat = 1;
95             break;
96         case 'd':
97             debugging = 1;
98             break;
99         case 'w':
100             waiting = strtol(optarg, NULL, 10);
101             break;
102         case '?':   /* unrecognized options */
103             printf("Unrecognized options -%c\n",optopt);
104             usage();
105         default:    /* should not reached */
106             usage();
107         }
108     }
109     /* ***********************************************************
110      * 
111      *           Options processing completed
112      *
113      *                Main code beginning
114      * 
115      * ***********************************************************/
116     /* Main code begin here */
117     if (compat) {                             /* install signal handler */
118         Signal(SIGCHLD, HandSigCHLD);         /* non restarting handler */
119     } else {
120         SignalRestart(SIGCHLD, HandSigCHLD);  /* restarting handler */
121     }
122     /* create and bind socket */
123     if ( (list_fd = sockbind2(argv[optind], "www", 6, SOCK_STREAM)) < 0) {
124         return 1;
125     }   
126     /* release privileges and go daemon */
127     if (setgid(65534) !=0) { /* first give away group privileges */
128         perror("cannot give away group privileges");
129         exit(1);
130     }
131     if (setuid(65534) !=0) { /* and only after user ... */
132         perror("cannot give away user privileges");
133         exit(1);
134     }
135     if (demonize) {          /* go daemon */
136         openlog(argv[0], 0, LOG_DAEMON); /* open logging */
137         if (daemon(0, 0) != 0) {
138             perror("cannot start as daemon");
139             exit(1);
140         }
141     }
142     /* main body */
143     if (listen(list_fd, BACKLOG) < 0 ) {
144         PrintErr("listen error");
145         exit(1);
146     }
147     if (waiting) sleep(waiting);
148     /* handle echo to client */
149     while (1) {
150         /* accept connection */
151         len = sizeof(cli_add);
152         while (((conn_fd = accept(list_fd, (struct sockaddr *)&cli_add, &len)) 
153                 < 0) && (errno == EINTR)); 
154         if (conn_fd < 0) {
155             PrintErr("accept error");
156             exit(1);
157         }
158         if (debugging) {
159             inet_ntop(AF_INET, &cli_add.sin_addr, ipaddr, sizeof(ipaddr));
160             snprintf(debug, MAXLINE, "Accepted connection form %s\n", ipaddr);
161             if (demonize) {
162                 syslog(LOG_DEBUG, debug);
163             } else {
164                 printf("%s", debug);
165             }
166         }
167         /* fork to handle connection */
168         if ( (pid = fork()) < 0 ){
169             PrintErr("fork error");
170             exit(1);
171         }
172         if (pid == 0) {      /* child */
173             close(list_fd);          /* close listening socket */   
174             ServPage(conn_fd);       /* handle echo */
175             if (debugging) {
176                 snprintf(debug, MAXLINE, "Closed connection %s\n", ipaddr);
177                 if (demonize) {
178                     syslog(LOG_DEBUG, debug);
179                 } else {
180                     printf("%s", debug);
181                 }
182             }
183             exit(0);
184         } else {             /* parent */
185             close(conn_fd);          /* close connected socket */
186         }
187     }
188     /* normal exit, never reached */
189     exit(0);
190 }
191 /*
192  * routine to print usage info and exit
193  */
194 void usage(void) 
195 {
196     printf("Elementary echo server\n");
197     printf("Usage:\n");
198     printf("  echod [-h] \n");
199     printf("  -h           print this help\n");
200     printf("  -d           write debug info\n");
201     printf("  -i           use interactively\n");
202     printf("  -c           disable BSD semantics\n");
203     printf("  -w N         wait N sec. before calling accept\n");
204     exit(1);
205 }
206 /*
207  * routine to handle echo for connection
208  */
209 void ServPage(int sockfd) 
210 {
211     char buffer[MAXLINE];
212     char outbuf[1024];
213     FILE *sock, *file;
214     char *line, *copy, *method, *ptr, *filename, *version;
215     char *methods[] = { "GET", "PUT", NULL };
216     char *codes[] = {
217         "200 OK",
218         "404 Not Found",
219         NULL
220     };
221     int nleft;
222     int i, j;
223
224     sock = fdopen(sockfd, "w+");
225     /* main loop, reading 0 char means client close connection */
226     line = fgets(buffer, MAXLINE, sock);
227     copy = strndupa(line, MAXLINE);
228
229     if (line == NULL) {
230         PrintErr("Errore in lettura");
231         return;
232     }
233     if ((method = strtok_r(copy, " ", &ptr)) == NULL) {
234         PrintErr("Non ho trovato il metodo");
235         return;
236     }
237     if ((filename = strtok_r(NULL, " ", &ptr)) == NULL) {
238         PrintErr("Non ho trovato il file");
239         return;
240     }
241     if ((version = strtok_r(NULL, " ", &ptr)) == NULL) {
242         PrintErr("Non ho trovato la versione");
243         return;
244     }
245     printf("metodo %s -- file %s -- versione %s\n", method, filename, version);
246     i = 0;
247     while ( (ptr = methods[i]) != NULL) {
248         if ( (strncmp(ptr, method, strlen(ptr)) == 0)) {
249             break;
250         }
251         i++;
252     }
253     if (i>=2) {
254         printf("No method %s found\n", method);
255         return;
256     }
257
258     while (strcmp(line,"\r\n")) {
259         line =  fgets(buffer, MAXLINE, sock);
260         printf("letto: %s\n", line);
261     }
262
263     if ( (file = fopen(filename, "r")) == NULL) {
264         printf("file %s", filename);
265         perror("Error opening");
266         fprintf(sock, "HTTP/1.0 %s\n", codes[1]);
267         print_headers(sock);
268         return;
269     }
270     fprintf(sock, "HTTP/1.0 %s\n", codes[0]);
271     //PrintHeader(sock);
272     print_headers(sock);
273
274     j = 0;
275     while (!feof(file)) {
276         printf("Loop %d\n", j++);
277         if ( (nleft = full_fread(file, outbuf, 1024)) != 0) {
278             if (ferror(file)) {
279                 printf("Errore in lettura");
280                 return;
281             }
282         }
283         printf("Loop %d rimasti %d\n", j, nleft);
284         if (full_fwrite(sock, outbuf, 1024-nleft) != 0) {
285             if (ferror(file)) {
286                 printf("Errore in scrittura");
287                 return;
288             }   
289         }
290     }
291     printf("Ok fin qui!");
292 //    line = fgets(buffer, MAXLINE, sock);
293     fclose(file);
294     fclose(sock);
295     return;
296 }
297 /*
298  * routine to print error on stout or syslog
299  */
300 void PrintErr(char * error) 
301 {
302     if (demonize) {                       /* daemon mode */
303         syslog(LOG_ERR, "%s: %m", error); /* log string and error message */
304     } else {
305         perror(error);
306     }
307     return;
308 }
309
310 void print_headers(FILE *file)
311 {
312     time_t tempo;
313
314     time(&tempo);
315     fprintf(file, "Date: %s", ctime(&tempo));
316     fprintf(file, "Server: WWWd test server\n");
317     fprintf(file, "Connection: close\n");
318     fprintf(file, "Content-Type: text/html; charset=iso-8859-1\n");
319     fprintf(file, "\n");
320     printf("Date: %s", ctime(&tempo));
321     printf("Server: WWWd test server\n");
322     printf("Connection: close\n");
323     printf("Content-Type: text/html; charset=iso-8859-1\n");
324     printf("\n");
325     return;
326 }