first http server working
[webserver.git] / webserver.c
CommitLineData
8512671a
LM
1/* depend: */
2/* cflags: */
4baf6839 3/* linker: color.o debug.o file.o http.o server.o */
8512671a 4
184be781 5#include <assert.h>
4baf6839 6#include <dirent.h>
8512671a
LM
7#include <stdio.h>
8#include <stdlib.h>
89f0e084 9#include <unistd.h>
8512671a
LM
10
11#include "debug.h"
96748ca7 12#include "http.h"
00afbb65 13#include "server.h"
8512671a 14
184be781
LM
15/* types */
16
8512671a
LM
17/* constants */
18
19#define BUFFER_SIZE 4096
4baf6839 20#define ROOT_DIR "webroot"
8512671a
LM
21
22/* macros */
23
24/* gobal variables */
25
26char *progname = NULL;
21ac031b 27int port = 8080;
4baf6839 28char *root = ROOT_DIR;
8512671a
LM
29
30/* help function */
31
32int usage (int ret)
33{
34 FILE *fid = ret ? stderr : stdout;
35 fprintf (fid, "usage: %s\n", progname);
36 fprintf (fid, " -h : help message\n");
21ac031b 37 fprintf (fid, " -p : port number (%d)\n", port);
4baf6839 38 fprintf (fid, " -r : web root directory (%s)\n", root);
8512671a
LM
39 fprintf (fid, " -v : verbose level (%d)\n", verbose);
40
41 return ret;
42}
43
44/* main function */
45
46int main (int argc, char *argv[])
47{
48 int i = 0;
8512671a
LM
49
50 /* program name */
51
52 progname = argv[0];
53 while (progname[i] != '\0') {
54 if ((progname[i] == '/') || (progname[i] == '\\')) {
55 progname += i + 1;
56 i = 0;
57 } else {
58 i++;
59 }
60 }
61
62 /* argument processing */
63
4baf6839 64 while (argc-- > 1) {
8512671a
LM
65 char *arg = *(++argv);
66 if (arg[0] != '-') {
163f56b1 67 VERBOSE (ERROR, PERROR ("%s: invalid option -- '%s'\n", progname, arg); usage (1));
8512671a
LM
68 return 1;
69 }
70 char c = arg[1];
71 switch (c) {
21ac031b 72 case 'p':
8512671a
LM
73 arg = (arg[2]) ? arg + 2 : (--argc > 0) ? *(++argv) : NULL;
74 if (arg == NULL) {
163f56b1 75 VERBOSE (ERROR, PERROR ("%s: missing port number\n", progname); usage (1));
21ac031b
LM
76 return 1;
77 }
78 port = atoi (arg);
79 if (port <= 0) {
163f56b1 80 VERBOSE (ERROR, PERROR ("%s: incorrect port number (%s)\n", progname, arg); usage (1));
8512671a
LM
81 return 1;
82 }
8512671a 83 break;
4baf6839
LM
84 case 'r':
85 arg = (arg[2]) ? arg + 2 : (--argc > 0) ? *(++argv) : NULL;
86 if (arg == NULL) {
87 VERBOSE (ERROR, PERROR ("%s: missing directory name\n", progname); usage (1));
88 return 1;
89 }
90 root = arg;
91 break;
8512671a
LM
92 case 'v':
93 arg = (arg[2]) ? arg + 2 : (--argc > 0) ? *(++argv) : NULL;
94 if (arg == NULL) {
163f56b1 95 VERBOSE (ERROR, PERROR ("%s: missing verbose level\n", progname); usage (1));
8512671a
LM
96 return 1;
97 }
98 verbose = atoi (arg);
99 break;
100 case 'h':
101 default:
102 return usage (c != 'h');
103 }
104 }
105
4baf6839
LM
106 /* check root directory */
107 VERBOSE (DEBUG, PRINT ("Check web root\n"));
108 DIR *pdir = opendir (root);
109 if (pdir == NULL) {
110 VERBOSE (ERROR, PERROR ("Can't read directory (%s)\n", root));
111 return 1;
112 }
113 closedir (pdir);
114
115 /* init network stack */
163f56b1 116 VERBOSE (DEBUG, PRINT ("Initializing socket\n"));
89f0e084 117 init_network_context ();
7d4815a1 118 if (open_listening_socket (port) == 0) {
163f56b1 119 VERBOSE (ERROR, PERROR ("Can't open listening socket\n"));
184be781
LM
120 return 1;
121 }
163f56b1
LM
122 VERBOSE (INFO, PRINT ("Listening socket on port %d\n", port));
123
04a2223d
LM
124 /* main loop */
125 while (1) {
7d4815a1 126 if (accept_incoming_connection () == 0) {
89f0e084 127 usleep (1e5);
04a2223d
LM
128 continue;
129 }
130
163f56b1 131 VERBOSE (DEBUG, PRINT ("Server connected, waiting for data\n"));
04a2223d 132
135b5dee
LM
133 char *data = NULL;
134 char *output = NULL;
04a2223d 135
7d4815a1 136 int len = receive_data (&data);
89f0e084 137 if (len == 0) {
163f56b1 138 VERBOSE (WARNING, PRINT ("Connection closed by peer (rx)\n"));
89f0e084 139 } else if (len < 0) {
163f56b1 140 VERBOSE (WARNING, PRINT ("Connection in error (rx)\n"));
89f0e084 141 } else {
96748ca7 142 VERBOSE (DEBUG, PRINT ("Received %d bytes\n", len));
04a2223d
LM
143
144 // processing
96748ca7 145 VERBOSE (DEBUG, PRINT ("Processing %s\n", data));
135b5dee 146 len = processing (data, len, root, &output);
89f0e084 147
6add28e9
LM
148 VERBOSE (DEBUG, PRINT ("Sending data (%d)\n%s\n", len, data));
149 int rc = send_data (output, len);
89f0e084 150 if (rc == 0) {
163f56b1 151 VERBOSE (WARNING, PRINT ("Connection closed by peer (tx)\n"));
89f0e084 152 } else if (rc < 0) {
163f56b1 153 VERBOSE (WARNING, PRINT ("Connection in error (tx)\n"));
04a2223d 154 }
89f0e084 155 }
04a2223d 156
163f56b1 157 VERBOSE (DEBUG, PRINT ("Closing connection\n"));
89f0e084
LM
158 if (data) {
159 free (data);
04a2223d 160 }
6add28e9
LM
161 if (output) {
162 free (output);
163 }
7d4815a1 164 close_connection ();
04a2223d 165 }
89f0e084 166
163f56b1 167 VERBOSE (DEBUG, PRINT ("Closing socket\n"));
89f0e084 168 terminate_network_context ();
184be781 169
06ec8057 170 return 2;
8512671a
LM
171}
172
173// test: webserver.exe -h
174// test: webserver.exe -h | awk '/usage:/ { rc=1 } END { exit (1-rc) }'
21ac031b 175// test: webserver.exe -_ 2> /dev/null | wc -l | xargs test 0 =
8512671a
LM
176// test: webserver.exe -_ 2>&1 | awk '/usage:/ { rc=1 } END { exit (1-rc) }'
177// test: webserver.exe error 2>&1 | grep -q 'invalid option'
21ac031b
LM
178// test: webserver.exe -v 2>&1 | grep -q 'missing verbose level'
179// test: webserver.exe -p 2>&1 | grep -q 'missing port number'
180// test: webserver.exe -p -1 2>&1 | grep -q 'incorrect port number'
7d4815a1
LM
181// test: webserver.exe > test.log & pid=$!; sleep 1; kill -QUIT $pid; grep -q 'Listening socket on port 8080' test.log
182// test: webserver.exe -p 8000 > test.log & pid=$!; sleep 1; kill -ABRT $pid; grep -q 'Listening socket on port 8000' test.log
163f56b1 183// test: webserver.exe & pid=$!; sleep 1; kill -TERM $pid; ps aux | grep -q [w]ebserver.exe && kill -9 $pid || rc=1; test x$rc = x1
8512671a
LM
184
185/* vim: set ts=4 sw=4 et: */