aboutsummaryrefslogtreecommitdiff
path: root/src/server.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/server.c')
-rw-r--r--src/server.c448
1 files changed, 448 insertions, 0 deletions
diff --git a/src/server.c b/src/server.c
new file mode 100644
index 00000000..f21e9697
--- /dev/null
+++ b/src/server.c
@@ -0,0 +1,448 @@
1/* Copyrights 2002 Luis Figueiredo (stdio@netc.pt) All rights reserved.
2 *
3 * See the LICENSE file
4 *
5 * The origin of this software must not be misrepresented, either by
6 * explicit claim or by omission. Since few users ever read sources,
7 * credits must appear in the documentation.
8 *
9 * date: Sat Mar 30 14:44:42 GMT 2002
10 *
11 * -- core server functions
12 *
13 */
14
15#include "server.h"
16#include "logo.h"
17
18#ifdef WIN32
19 #define _SERVER_VERSION "libwebserver/0.5.3(win32)" // update allways when changing version (damn win)
20#endif
21
22#ifndef _SERVER_VERSION
23 #define _SERVER_VERSION "libwebserver/(unknow)"
24#endif
25
26#ifdef DEBUG
27 char *_libwebserver_version= _SERVER_VERSION "(debug)";
28#else
29 char *_libwebserver_version= _SERVER_VERSION;
30#endif
31
32struct web_server *current_web_server;
33
34
35/*********************************************************************************************************/
36/*
37 * Define certificate file (open_ssl)
38 */
39void web_server_useSSLcert(struct web_server *server,const char *file) {
40#ifdef HAVE_OPENSSL
41 if(!(server->cert_file=__ILWS_malloc(strlen(file)+1))) {
42 LWSERR(LE_MEMORY);
43 return;
44 };
45 memcpy(server->cert_file,file,strlen(file));
46 server->cert_file[strlen(file)]=0;
47#else
48 printf("OpenSSL not supported in this compilation\n");
49#endif
50}
51
52void web_server_useMIMEfile(struct web_server *server,const char *file) {
53 if(!(server->mimefile=__ILWS_malloc(strlen(file)+1))) {
54 LWSERR(LE_MEMORY);
55 return;
56 };
57 memcpy(server->mimefile,file,strlen(file));
58 server->mimefile[strlen(file)]=0;
59};
60/*********************************************************************************************************/
61/*
62 * Handler for libwebserver logotipe
63 */
64void _web_server_logo() {
65 printf("Content-type: image/gif\r\n\r\n");
66 fwrite((char *)_logo,sizeof(_logo),1,stdout);
67}
68
69
70/*********************************************************************************************************/
71/*
72 * Add an handler to request data
73 */
74int web_server_addhandler(struct web_server *server,const char *mstr,void (*func)(),int flag) {
75 _logfile=server->weblog;
76 // xor?
77 flag ^= (server->flags & WS_LOCAL); // global flag to handler flag
78 flag ^= (server->flags & WS_DYNVAR); // global flag to handler flag
79 flag ^= (server->flags & WS_USELEN); // global flag to handler flag
80 web_log("[%s] Adding handler %s <--%s%s%s\n",__ILWS_date(time(NULL),"%d/%b/%Y:%H:%M:%S %z"),mstr, ((flag & WS_LOCAL) == WS_LOCAL && !((server->flags & WS_LOCAL) == WS_LOCAL))?"[LOCAL] ":"", ((flag & WS_DYNVAR) == WS_DYNVAR)?"[DYNVAR]":"", ((flag & WS_USELEN) == WS_USELEN)?"[USELEN]":"");
81 return __ILWS_add_handler((struct gethandler *)server->gethandler,mstr,func,NULL,flag,GH_FUNCTION);
82}
83
84/*********************************************************************************************************/
85/*
86 * Add an alias dir (new on 0.5.2)
87 */
88int web_server_aliasdir(struct web_server *server, const char *str, char *path,int flag) {
89 char *mstr;
90 int ret;
91 mstr=__ILWS_malloc(strlen(str)+7);
92 if(!strlen(str)) {
93 snprintf(mstr,strlen(str)+7,"* /*");
94 } else {
95 snprintf(mstr,strlen(str)+7,"* /%s/*",str);
96 };
97 _logfile=server->weblog;
98 flag ^= (server->flags & WS_LOCAL); // global flag to handler flag
99 flag ^= (server->flags & WS_DYNVAR); // global flag to handler flag
100 flag ^= (server->flags & WS_USELEN); // global flag to handler flag
101 web_log("[%s] Adding directory %s <--%s%s%s\n",__ILWS_date(time(NULL),"%d/%b/%Y:%H:%M:%S %z"),mstr, ((flag & WS_LOCAL) == WS_LOCAL && !((server->flags & WS_LOCAL) == WS_LOCAL))?"[LOCAL] ":"", ((flag & WS_DYNVAR) == WS_DYNVAR)?"[DYNVAR]":"", ((flag & WS_USELEN) == WS_USELEN)?"[USELEN]":"");
102 ret=__ILWS_add_handler((struct gethandler *)server->gethandler,mstr,NULL,path,flag,GH_DIRECTORY);
103 __ILWS_free(mstr);
104 return ret;
105};
106
107
108/*********************************************************************************************************/
109/*
110 * Personal config (new on 0.5.0)
111 */
112char *web_server_getconf(struct web_server *server, const char *topic,const char *key) {
113 char *dataconf;
114 char *tmp1,*tmp2,*tmp3;
115 long tmpsize=0;
116
117 dataconf=__ILWS_stristr(server->dataconf,topic);
118 if(dataconf==NULL) {
119 return NULL;
120 };
121 dataconf+=strlen(topic);
122 tmp1=__ILWS_stristr(dataconf,key);
123 do {
124 tmp1=__ILWS_stristr(dataconf,key);
125 dataconf+=1;
126 if(dataconf[0]==0) {
127 return NULL;
128 };
129 if(dataconf[0]=='[' && dataconf[-1]=='\n') {
130 return NULL;
131 };
132 }while(!(tmp1!=NULL && tmp1[-1]=='\n' && tmp1[strlen(key)]=='='));
133
134 tmp1+=strlen(key)+1;
135 tmp2=__ILWS_stristr(tmp1,"\n");
136 if(tmp2==NULL) {
137 tmp2=tmp1+strlen(tmp1);
138 };
139 tmpsize=tmp2-tmp1;
140 if(!(tmp3=__ILWS_malloc(tmpsize+1))) {
141 LWSERR(LE_MEMORY);
142 return NULL;
143 };
144 memcpy(tmp3,tmp1,tmpsize);
145 tmp3[tmpsize]=0;
146 return tmp3;
147};
148
149/*********************************************************************************************************/
150/*
151 * Define config file to setup server (new on 0.5.0)
152 */
153int web_server_setup(struct web_server *server,const char *conffile) {
154 FILE *tmpf;
155 char *tmp3;
156 //long tmpsize=0;
157 long sizec;
158 struct stat statf; // tested only on win
159
160 if(!(server->conffile=__ILWS_malloc(strlen(conffile)+1))) {
161 LWSERR(LE_MEMORY);
162 return 0;
163 };
164
165 memcpy(server->conffile,conffile,strlen(conffile));
166 server->conffile[strlen(conffile)]=0;
167
168 tmpf=fopen(server->conffile,"r");
169 if(tmpf==NULL) {
170 printf("no config file found\r\n");
171 server->dataconf="";
172 return(0);
173 };
174 fseek(tmpf,SEEK_SET,SEEK_END);
175 sizec=ftell(tmpf);
176 fseek(tmpf,0,SEEK_SET);
177 if(!(server->dataconf=__ILWS_malloc(sizec+1))) {
178 LWSERR(LE_MEMORY);
179 return 0;
180 };
181 fread(server->dataconf,sizec,1,tmpf);
182 server->dataconf[sizec]=0; // Hilobok Andrew (han@km.if.ua) said to remove the -9 :)
183 fclose(tmpf);
184
185 stat(server->conffile,&statf); // tested only on win
186 server->conffiletime=statf.st_mtime; // tested only on win
187
188 if((server->logfile=web_server_getconf(server,"LIBWEBSERVER","LOG"))) {
189 web_log("\nUsing logfile [%s]\n",server->logfile);
190 server->weblog=open_weblog(server->logfile);
191 } else {
192 web_log("\nLOG entry not found\r\n");
193 server->weblog=NULL;
194 };
195 if((tmp3=web_server_getconf(server,"LIBWEBSERVER","PORT"))) {
196 web_log("\nListen port [%s]\n",tmp3);
197 server->port=atoi(tmp3);
198 __ILWS_free(tmp3);
199 } else {
200 web_log("PORT entry not found\r\n");
201 server->port=0;
202 };
203#ifdef HAVE_OPENSSL
204 // Fetch SSL
205 if((tmp3=web_server_getconf(server,"LIBWEBSERVER","USESSL"))) {
206 if(tmp3[0]=='1') {
207 server->flags = server->flags | WS_USESSL;
208 }else if(tmp3[0]=='0') {
209 server->flags = server->flags & ~WS_USESSL;
210 } else {
211 fprintf(stderr,"[USESSL=] argument invalid\n");
212 };
213 __ILWS_free(tmp3);
214 }
215 // Fetch CERTFILE
216 server->cert_file=web_server_getconf(server,"LIBWEBSERVER","CERTFILE");
217 server->mimefile=web_server_getconf(server,"LIBWEBSERVER","MIMEFILE");
218#endif
219 // Fetch LOCAL
220 if((tmp3=web_server_getconf(server,"LIBWEBSERVER","LOCAL"))) {
221 if(tmp3[0]=='1') {
222 server->flags = server->flags | WS_LOCAL;
223 } else if(tmp3[0]=='0') {
224 server->flags=server->flags & ~WS_LOCAL;
225 }else {
226 fprintf(stderr,"[LOCAL=] argument invalid\n");
227 };
228 __ILWS_free(tmp3);
229 }
230
231 return 1;
232};
233
234/*********************************************************************************************************/
235/*
236 * This function initialize one web_server handler
237 */
238int web_server_init(struct web_server *server,int port,const char *logfile,int flags) {
239#ifdef WIN32
240 unsigned long t=IOC_INOUT;
241 WSADATA WSAinfo;
242 WSAStartup(2,&WSAinfo); // Damn w32 sockets
243#endif
244
245 current_web_server=server;
246 server->port=port;
247 server->conffile=NULL;
248 server->mimefile=NULL;
249 server->weblog=NULL;
250 server->usessl=0;
251 server->flags=flags;
252 server->dataconf="";
253 if((flags & WS_USEEXTCONF) == WS_USEEXTCONF) {
254 if(!(web_server_setup(server,logfile))) {
255#ifdef WIN32
256 WSACleanup();
257#endif
258 return 0;
259 };
260 _logfile=server->weblog; // Set current log stream
261 web_log("%s using config file %s\n",_libwebserver_version,logfile);
262 };
263 // Create a listen socket port 'port' and listen addr (0) (all interfaces)
264 server->socket=__ILWS_listensocket((short)server->port,0);
265 if(server->socket==-1) {
266 LWSERR(LE_NET);
267#ifdef WIN32
268 WSACleanup();
269#endif
270 return 0;
271 };
272#ifdef WIN32
273 ioctlsocket(server->socket,FIONBIO,&t); //non blocking sockets for win32
274#else
275 fcntl(server->socket,F_SETFL,O_NONBLOCK);
276#endif
277 // Setup FILE structure of logfile
278 if(logfile!=NULL && !((flags & WS_USEEXTCONF) == WS_USEEXTCONF)) {
279 server->logfile=__ILWS_malloc(strlen(logfile)+1);
280 memcpy(server->logfile,logfile,strlen(logfile));
281 server->logfile[strlen(logfile)]=0;
282 server->weblog=open_weblog(logfile); // Create File stream for log
283 };
284
285 web_log("\n[%s] Server started at port %d (%s)\n",__ILWS_date(time(NULL),"%d/%b/%Y:%H:%M:%S %z"),server->port,_libwebserver_version);
286
287 // Setup Flags
288
289 // openssl
290#ifdef HAVE_OPENSSL
291 if((server->flags & WS_USESSL) == WS_USESSL) {
292 web_log("[%s] (FLAG) Using SSL in connections\n",__ILWS_date(time(NULL),"%d/%b/%Y:%H:%M:%S %z"));
293 web_log(" +-- %s certificate file\n",server->cert_file);
294 SSL_load_error_strings();
295 SSLeay_add_ssl_algorithms();
296 server->ctx=SSL_CTX_new (SSLv23_server_method());
297 if (SSL_CTX_use_certificate_file(server->ctx, server->cert_file, SSL_FILETYPE_PEM) <= 0) {
298 ERR_print_errors_fp(stderr);
299 exit(3);
300 }
301 if (SSL_CTX_use_PrivateKey_file(server->ctx, server->cert_file, SSL_FILETYPE_PEM) <= 0) {
302 ERR_print_errors_fp(stderr);
303 exit(4);
304 }
305 if (SSL_CTX_check_private_key(server->ctx)<= 0) {
306 ERR_print_errors_fp(stderr);
307 exit(4);
308 };
309 server->usessl=1;
310 };
311#endif
312 if((server->flags & WS_LOCAL) == WS_LOCAL) {
313 web_log("[%s] (FLAG) Accepting only local connections\n",__ILWS_date(time(NULL),"%d/%b/%Y:%H:%M:%S %z"));
314 };
315 server->client=__ILWS_init_client_list(); // Initializate client list
316 server->gethandler=__ILWS_init_handler_list(); // Initializate handlers list
317 web_server_addhandler(server,"* /libwebserver.gif",_web_server_logo,0); // Add logo default handler
318
319#ifndef WIN32
320 signal(SIGPIPE,SIG_IGN);
321#endif
322 return 1;
323}
324
325
326/*********************************************************************************************************/
327/*
328 * This function shuts down a running web server, frees its allocated memory,
329 * and closes its socket. If called on a struct web_server that has already
330 * been shut down, this is a noop.
331 */
332void web_server_shutdown(struct web_server *server) {
333 // free and close things in opposite order of web_server_init
334
335 __ILWS_delete_handler_list(server->gethandler);
336 server->gethandler = NULL;
337 __ILWS_delete_client_list(server->client);
338 server->client = NULL;
339
340 if(server->socket > 0) {
341#ifdef WIN32
342 closesocket(server->socket);
343#else
344 close(server->socket);
345#endif
346 server->socket = -1;
347 }
348
349 if(server->weblog) {
350 fclose(server->weblog);
351 server->weblog = NULL;
352 __ILWS_free(server->logfile);
353 server->logfile = NULL;
354 }
355
356#ifdef WIN32
357 WSACleanup();
358#endif
359}
360
361/*********************************************************************************************************/
362/*
363 * Core function, return 2 if no client to process, 1 if some client processed, 0 if error
364 */
365int web_server_run(struct web_server *server) {
366 struct web_client *client;
367 int rt;
368 int tsalen=0;
369 int tsocket=0;
370 struct sockaddr_in tsa;
371 _logfile=server->weblog;
372 current_web_server=server;
373 if(server->client->next==NULL) {
374 //if(__ILWS_newdata(server->socket)); // does nothing but act like usleep
375 };
376// search for client
377 tsalen=sizeof(client->sa);
378 tsocket=accept(server->socket,(struct sockaddr *)&tsa,&tsalen);
379 if(tsocket==-1) {
380#ifdef WIN32
381 if(WSAGetLastError()!=WSAEWOULDBLOCK) {
382#else
383 if(errno!=EAGAIN) {
384#endif
385 fprintf(stderr,"What kind of error is this?\n"); // REMOVE
386 // client fucked up? warn somebody? (error or log or something?)
387 return 0; // don't process nothing
388 };
389 } else {
390 client=__ILWS_malloc(sizeof(struct web_client));
391 if(client==NULL) {
392 rt=shutdown(tsocket,SHUT_RDWR);
393#ifdef WIN32
394 rt=closesocket(tsocket);
395#else
396 rt=close(tsocket);
397#endif
398 LWSERR(LE_MEMORY);
399 return 0;
400 };
401 client->salen=tsalen;
402 client->socket=tsocket;
403 client->sa=tsa;
404#ifdef HAVE_OPENSSL
405 if((server->flags & WS_USESSL) == WS_USESSL) {
406 client->ssl = SSL_new(server->ctx);
407 SSL_set_fd(client->ssl,client->socket);
408 SSL_accept(client->ssl);
409 //client->cert = SSL_get_peer_certificate (client->ssl);
410 } else {
411 client->ssl=NULL;
412 };
413#endif
414 if(!__ILWS_add_client(server->client,client)) {
415 fprintf(stderr,"No client?\n"); // REMOVE
416 return 0;
417 }else {
418 web_log("%s - - [%s] Connected\n",inet_ntoa(client->sa.sin_addr),__ILWS_date(time(NULL),"%d/%b/%Y:%H:%M:%S %z")); //REMOBE
419 };
420 };
421 // end search for client
422 client=server->client; // init list
423 if(!client->next) { // think of Rocco Carbone (rocco@tecsiel.it)
424 return 2; // i don't need to process the list (nothing next) returns 2 if there is no client to process
425 };
426 while(client->next!=NULL) { // Process the client and swap to next;
427 current_web_client=client->next;
428 switch(client->next->stat) {
429 case 1: {
430 __ILWS_read_client(current_web_client);
431 };break;
432 case 2: {
433 __ILWS_process_client(current_web_client,server->gethandler);
434 };break;
435 case 4: {
436 __ILWS_output_client(current_web_client);
437 };break;
438 case 5: {
439 __ILWS_delete_next_client(client);
440 continue;
441 };break;
442 };
443 client=client->next;
444
445 };
446 return 1; // return 1 if something processed
447}
448