Browse Source

Port web server code from mptsd

Georgi Chorbadzhiyski 7 years ago
parent
commit
217cae29b8
7 changed files with 377 additions and 89 deletions
  1. 1
    1
      Makefile
  2. 50
    0
      config.h
  3. 92
    88
      tomcast.c
  4. 45
    0
      web_pages.c
  5. 24
    0
      web_pages.h
  6. 139
    0
      web_server.c
  7. 26
    0
      web_server.h

+ 1
- 1
Makefile View File

@@ -9,7 +9,7 @@ LIBS = -lpthread
9 9
 FUNCS_DIR = libfuncs
10 10
 FUNCS_LIB = $(FUNCS_DIR)/libfuncs.a
11 11
 
12
-tomcast_OBJS =  tomcast.o $(FUNCS_LIB)
12
+tomcast_OBJS =  tomcast.o web_pages.o web_server.o $(FUNCS_LIB)
13 13
 
14 14
 all: tomcast
15 15
 

+ 50
- 0
config.h View File

@@ -0,0 +1,50 @@
1
+/*
2
+ * mptsd configuration header file
3
+ * Copyright (C) 2010-2011 Unix Solutions Ltd.
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 version 2
7
+ * as published by the Free Software Foundation.
8
+ *
9
+ * This program is distributed in the hope that it will be useful,
10
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
+ * GNU General Public License for more details.
13
+ *
14
+ * You should have received a copy of the GNU General Public License
15
+ * along with this program; if not, write to the Free Software
16
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
17
+ */
18
+#ifndef CONFIG_H
19
+#define CONFIG_H
20
+
21
+#include <pthread.h>
22
+#include <arpa/inet.h>
23
+#include <netinet/in.h>
24
+
25
+#include "libfuncs/libfuncs.h"
26
+
27
+struct config {
28
+	char				*ident;
29
+	char				*pidfile;
30
+
31
+	int					syslog_active;
32
+	char				*logident;
33
+	char				*loghost;
34
+	int					logport;
35
+
36
+	struct sockaddr_in	server;
37
+	char				*server_addr;
38
+	int					server_port;
39
+	int					server_socket;
40
+	pthread_t			server_thread;
41
+
42
+	char				*channels_file;
43
+
44
+	LIST				*chanconf;
45
+	LIST				*restreamer;
46
+
47
+	pthread_mutex_t		channels_lock;
48
+};
49
+
50
+#endif

+ 92
- 88
tomcast.c View File

@@ -31,6 +31,9 @@
31 31
 #include <netdb.h> // for uint32_t
32 32
 
33 33
 #include "libfuncs/libfuncs.h"
34
+#include "config.h"
35
+
36
+#include "web_server.h"
34 37
 
35 38
 #define DNS_RESOLVER_TIMEOUT 5000
36 39
 
@@ -105,6 +108,8 @@ typedef struct {
105 108
 	pthread_t thread;
106 109
 } RESTREAMER;
107 110
 
111
+static struct config config;
112
+
108 113
 channel_source get_sproto(char *url) {
109 114
 	return strncmp(url, "http", 4)==0 ? tcp_sock : udp_sock;
110 115
 }
@@ -288,27 +293,10 @@ void free_restreamer(RESTREAMER *r) {
288 293
 	FREE(r);
289 294
 }
290 295
 
291
-
292
-
293
-
294
-char *pidfile = NULL;
295
-char *ident = NULL;
296
-char *logident = NULL;
297
-char *loghost = NULL;
298
-int logport = 514;
299
-
300
-char *channels_file = NULL;
301
-int syslog_active = 0;
302
-
303 296
 char TS_NULL_FRAME[FRAME_PACKET_SIZE];
304 297
 
305 298
 regex_t http_response;
306 299
 
307
-LIST *chanconf = NULL;
308
-LIST *restreamer = NULL;
309
-
310
-static pthread_mutex_t channels_lock = PTHREAD_MUTEX_INITIALIZER;
311
-
312 300
 void proxy_log(RESTREAMER *r, char *msg, char *info) {
313 301
 	LOGf("%s: %sChan: %s Src: %s Dst: udp://%s:%d SrcIP: %s SrcFD: %i DstFD: %i\n",
314 302
 		msg,
@@ -323,17 +311,17 @@ void proxy_log(RESTREAMER *r, char *msg, char *info) {
323 311
 	);
324 312
 }
325 313
 
326
-int load_channels_config() {
314
+int load_channels_config(struct config *cfg) {
327 315
 	regex_t re;
328 316
 	regmatch_t res[5];
329 317
 	char line[1024];
330 318
 	int fd;
331 319
 	int num_channels = 0;
332 320
 
333
-	if (pthread_mutex_trylock(&channels_lock) != 0)
321
+	if (pthread_mutex_trylock(&cfg->channels_lock) != 0)
334 322
 		return -1;
335 323
 
336
-	fd = open(channels_file, O_RDONLY);
324
+	fd = open(cfg->channels_file, O_RDONLY);
337 325
 
338 326
 	if (fd != -1) {
339 327
 		struct timeval tv;
@@ -385,18 +373,18 @@ report_error:
385 373
 		regfree(&re);
386 374
 		shutdown_fd(&fd);
387 375
 		/* Save current chanconf */
388
-		old_chanconf = chanconf;
376
+		old_chanconf = cfg->chanconf;
389 377
 		/* Switch chanconf */
390
-		chanconf = new_chanconf;
378
+		cfg->chanconf = new_chanconf;
391 379
 		/* Rewrite restreamer channels */
392 380
 		LNODE *lc, *lr, *lctmp, *lrtmp;
393 381
 		CHANNEL *chan;
394
-		list_lock(restreamer);	// Unlocked after second list_for_each(restreamer)
382
+		list_lock(cfg->restreamer);	// Unlocked after second list_for_each(restreamer)
395 383
 
396
-		list_lock(chanconf);
397
-		list_for_each(chanconf, lc, lctmp) {
384
+		list_lock(cfg->chanconf);
385
+		list_for_each(cfg->chanconf, lc, lctmp) {
398 386
 			chan = lc->data;
399
-			list_for_each(restreamer, lr, lrtmp) {
387
+			list_for_each(cfg->restreamer, lr, lrtmp) {
400 388
 				if (strcmp(chan->name, ((RESTREAMER *)lr->data)->name)==0) {
401 389
 					RESTREAMER *restr = lr->data;
402 390
 					/* Mark the restreamer as valid */
@@ -425,10 +413,10 @@ report_error:
425 413
 				}
426 414
 			}
427 415
 		}
428
-		list_unlock(chanconf);
416
+		list_unlock(cfg->chanconf);
429 417
 
430 418
 		/* Kill restreamers that serve channels that no longer exist */
431
-		list_for_each(restreamer, lr, lrtmp) {
419
+		list_for_each(cfg->restreamer, lr, lrtmp) {
432 420
 			RESTREAMER *r = lr->data;
433 421
 			/* This restreamer should no longer serve clients */
434 422
 			if (r->cookie != cookie) {
@@ -439,14 +427,14 @@ report_error:
439 427
 				r->dienow = 1;
440 428
 			}
441 429
 		}
442
-		list_unlock(restreamer);
430
+		list_unlock(cfg->restreamer);
443 431
 
444 432
 		/* Free old_chanconf */
445 433
 		list_free(&old_chanconf, free_channel_p, NULL);
446 434
 	} else {
447 435
 		num_channels = -1;
448 436
 	}
449
-	pthread_mutex_unlock(&channels_lock);
437
+	pthread_mutex_unlock(&cfg->channels_lock);
450 438
 	if (num_channels == -1)
451 439
 		LOGf("CONF : Error loading channels!\n");
452 440
 	else
@@ -457,7 +445,7 @@ report_error:
457 445
 void proxy_close(RESTREAMER *r) {
458 446
 	proxy_log(r, "STOP ","");
459 447
 	// If there are no clients left, no "Timeout" messages will be logged
460
-	list_del_entry(restreamer, r);
448
+	list_del_entry(config.restreamer, r);
461 449
 	free_restreamer(r);
462 450
 }
463 451
 
@@ -523,7 +511,7 @@ int connect_source(RESTREAMER *r, int retries, int readbuflen, int *http_code) {
523 511
 		}
524 512
 
525 513
 		snprintf(buf,sizeof(buf)-1, "GET /%s HTTP/1.0\r\nHost: %s:%u\r\nX-Smart-Client: yes\r\nUser-Agent: %s %s (%s)\r\n\r\n",
526
-		         src->path, src->host, src->port, server_sig, server_ver, ident);
514
+		         src->path, src->host, src->port, server_sig, server_ver, config.ident);
527 515
 		buf[sizeof(buf)-1] = 0;
528 516
 		fdwrite(r->sock, buf, strlen(buf));
529 517
 
@@ -893,13 +881,16 @@ void show_usage(int ident_only) {
893 881
 	puts("\t-l host\t\tSyslog host (default: disabled)");
894 882
 	puts("\t-L port\t\tSyslog port (default: 514)");
895 883
 	puts("\t-R\t\tSend reset packets when changing sources.");
884
+	puts("Server settings:");
885
+	puts("\t-b addr\t\tLocal IP address to bind.   (default: 0.0.0.0)");
886
+	puts("\t-p port\t\tPort to listen.             (default: 0)");
896 887
 	puts("");
897 888
 }
898 889
 
899
-void set_ident(char *new_ident) {
900
-	ident = new_ident;
901
-	logident = strdup(ident);
902
-	char *c = logident;
890
+void set_ident(char *new_ident, struct config *cfg) {
891
+	cfg->ident = new_ident;
892
+	cfg->logident = strdup(new_ident);
893
+	char *c = cfg->logident;
903 894
 	while (*c) {
904 895
 		if (*c=='/')
905 896
 			*c='-';
@@ -907,18 +898,24 @@ void set_ident(char *new_ident) {
907 898
 	}
908 899
 }
909 900
 
910
-void parse_options(int argc, char **argv) {
901
+void parse_options(int argc, char **argv, struct config *cfg) {
911 902
 	int j, ttl;
912 903
 	while ((j = getopt(argc, argv, "i:c:d:t:o:l:L:RHh")) != -1) {
913 904
 		switch (j) {
905
+			case 'b':
906
+				cfg->server_addr = optarg;
907
+				break;
908
+			case 'p':
909
+				cfg->server_port = atoi(optarg);
910
+				break;
914 911
 			case 'i':
915
-				set_ident(optarg);
912
+				set_ident(optarg, cfg);
916 913
 				break;
917 914
 			case 'c':
918
-				channels_file = optarg;
915
+				cfg->channels_file = optarg;
919 916
 				break;
920 917
 			case 'd':
921
-				pidfile = optarg;
918
+				cfg->pidfile = optarg;
922 919
 				break;
923 920
 			case 'o':
924 921
 				if (inet_aton(optarg, &output_intf) == 0) {
@@ -931,11 +928,11 @@ void parse_options(int argc, char **argv) {
931 928
 				multicast_ttl = (ttl && ttl < 127) ? ttl : 1;
932 929
 				break;
933 930
 			case 'l':
934
-				loghost = optarg;
935
-				syslog_active = 1;
931
+				cfg->loghost = optarg;
932
+				cfg->syslog_active = 1;
936 933
 				break;
937 934
 			case 'L':
938
-				logport = atoi(optarg);
935
+				cfg->logport = atoi(optarg);
939 936
 				break;
940 937
 			case 'R':
941 938
 				send_reset_opt = 1;
@@ -948,38 +945,41 @@ void parse_options(int argc, char **argv) {
948 945
 		}
949 946
 	}
950 947
 
951
-	if (!channels_file) {
948
+	if (!cfg->channels_file) {
952 949
 		show_usage(0);
953 950
 		fprintf(stderr, "ERROR: No channels file is set (use -c option).\n");
954 951
 		exit(1);
955 952
 	}
956 953
 
957
-	if (!ident) {
958
-		set_ident("unixsol/tomcast");
954
+	if (!cfg->ident) {
955
+		set_ident("unixsol/tomcast", cfg);
959 956
 	}
960 957
 
961 958
 	printf("Configuration:\n");
962
-	printf("\tServer ident      : %s\n", ident);
963
-	printf("\tChannels file     : %s\n", channels_file);
959
+	printf("\tServer ident      : %s\n", cfg->ident);
960
+	printf("\tChannels file     : %s\n", cfg->channels_file);
964 961
 	printf("\tOutput iface addr : %s\n", inet_ntoa(output_intf));
965 962
 	printf("\tMulticast ttl     : %d\n", multicast_ttl);
966
-	if (syslog_active) {
967
-		printf("\tSyslog host       : %s\n", loghost);
968
-		printf("\tSyslog port       : %d\n", logport);
963
+	if (cfg->syslog_active) {
964
+		printf("\tSyslog host       : %s\n", cfg->loghost);
965
+		printf("\tSyslog port       : %d\n", cfg->logport);
969 966
 	} else {
970 967
 		printf("\tSyslog disabled.\n");
971 968
 	}
972 969
 	if (send_reset_opt)
973 970
 		printf("\tSend reset packets.\n");
974
-	if (pidfile) {
975
-		printf("\tDaemonize         : %s\n", pidfile);
971
+	if (cfg->pidfile) {
972
+		printf("\tDaemonize         : %s\n", cfg->pidfile);
976 973
 	} else {
977 974
 		printf("\tDo not daemonize.\n");
978 975
 	}
976
+
977
+	if (cfg->server_port)
978
+		init_server_socket(cfg->server_addr, cfg->server_port, &cfg->server, &cfg->server_socket);
979 979
 }
980 980
 
981
-void init_vars() {
982
-	restreamer = list_new("restreamer");
981
+void init_vars(struct config *cfg) {
982
+	cfg->restreamer = list_new("restreamer");
983 983
 	regcomp(&http_response, "^HTTP/1.[0-1] (([0-9]{3}) .*)", REG_EXTENDED);
984 984
 	memset(&TS_NULL_FRAME, 0xff, FRAME_PACKET_SIZE);
985 985
 	int i;
@@ -991,29 +991,29 @@ void init_vars() {
991 991
 	}
992 992
 }
993 993
 
994
-void spawn_proxy_threads() {
994
+void spawn_proxy_threads(struct config *cfg) {
995 995
 	LNODE *lc, *lctmp;
996 996
 	LNODE *lr, *lrtmp;
997 997
 	int spawned = 0;
998
-	list_for_each(chanconf, lc, lctmp) {
998
+	list_for_each(cfg->chanconf, lc, lctmp) {
999 999
 		CHANNEL *c = lc->data;
1000 1000
 		int restreamer_active = 0;
1001
-		list_lock(restreamer);
1002
-		list_for_each(restreamer, lr, lrtmp) {
1001
+		list_lock(cfg->restreamer);
1002
+		list_for_each(cfg->restreamer, lr, lrtmp) {
1003 1003
 			RESTREAMER *r = lr->data;
1004 1004
 			if (strcmp(r->name, c->name)==0) {
1005 1005
 				restreamer_active = 1;
1006 1006
 				break;
1007 1007
 			}
1008 1008
 		}
1009
-		list_unlock(restreamer);
1009
+		list_unlock(cfg->restreamer);
1010 1010
 		if (!restreamer_active) {
1011 1011
 			RESTREAMER *nr = new_restreamer(c->name, c);
1012 1012
 			if (nr->clientsock < 0) {
1013 1013
 				LOGf("Error creating proxy socket for %s\n", c->name);
1014 1014
 				free_restreamer(nr);
1015 1015
 			} else {
1016
-				list_add(restreamer, nr);
1016
+				list_add(cfg->restreamer, nr);
1017 1017
 				if (pthread_create(&nr->thread, NULL, &proxy_ts_stream, nr) == 0) {
1018 1018
 					spawned++;
1019 1019
 					pthread_detach(nr->thread);
@@ -1026,44 +1026,47 @@ void spawn_proxy_threads() {
1026 1026
 	LOGf("INFO : %d proxy threads spawned\n", spawned);
1027 1027
 }
1028 1028
 
1029
-void kill_proxy_threads() {
1029
+void kill_proxy_threads(struct config *cfg) {
1030 1030
 	LNODE *l, *tmp;
1031 1031
 	int killed = 0;
1032
-	list_lock(restreamer);
1033
-	list_for_each(restreamer, l, tmp) {
1032
+	list_lock(cfg->restreamer);
1033
+	list_for_each(cfg->restreamer, l, tmp) {
1034 1034
 		RESTREAMER *r = l->data;
1035 1035
 		r->dienow = 1;
1036 1036
 		killed++;
1037 1037
 	}
1038
-	list_unlock(restreamer);
1038
+	list_unlock(cfg->restreamer);
1039 1039
 	LOGf("INFO : %d proxy threads killed\n", killed);
1040 1040
 }
1041 1041
 
1042
+int keep_going = 1;
1043
+
1042 1044
 void signal_quit(int sig) {
1043
-	kill_proxy_threads();
1045
+	keep_going = 0;
1046
+	kill_proxy_threads(&config);
1044 1047
 	usleep(500000);
1045
-	LOGf("KILL : Signal %i | %s %s (%s)\n", sig, server_sig, server_ver, ident);
1048
+	LOGf("KILL : Signal %i | %s %s (%s)\n", sig, server_sig, server_ver, config.ident);
1046 1049
 	usleep(100000);
1047 1050
 	log_close();
1048
-	if (pidfile && strlen(pidfile))
1049
-		unlink(pidfile);
1051
+	if (config.pidfile && strlen(config.pidfile))
1052
+		unlink(config.pidfile);
1050 1053
 	signal(sig, SIG_DFL);
1051 1054
 	raise(sig);
1052 1055
 }
1053 1056
 
1054 1057
 void do_reconnect() {
1055 1058
 	LNODE *l, *tmp;
1056
-	list_lock(restreamer);
1057
-	list_for_each(restreamer, l, tmp) {
1059
+	list_lock(config.restreamer);
1060
+	list_for_each(config.restreamer, l, tmp) {
1058 1061
 		RESTREAMER *r = l->data;
1059 1062
 		r->reconnect = 1;
1060 1063
 	}
1061
-	list_unlock(restreamer);
1064
+	list_unlock(config.restreamer);
1062 1065
 }
1063 1066
 
1064 1067
 void do_reconf() {
1065
-	load_channels_config();
1066
-	spawn_proxy_threads();
1068
+	load_channels_config(&config);
1069
+	spawn_proxy_threads(&config);
1067 1070
 }
1068 1071
 
1069 1072
 void init_signals() {
@@ -1077,13 +1080,13 @@ void init_signals() {
1077 1080
 	signal(SIGTERM, signal_quit);
1078 1081
 }
1079 1082
 
1080
-void do_daemonize() {
1081
-	if (!pidfile)
1083
+void do_daemonize(struct config *cfg) {
1084
+	if (!cfg->pidfile)
1082 1085
 		return;
1083 1086
 	fprintf(stderr, "Daemonizing.\n");
1084 1087
 	pid_t pid = fork();
1085 1088
 	if (pid > 0) {
1086
-		FILE *F = fopen(pidfile,"w");
1089
+		FILE *F = fopen(cfg->pidfile,"w");
1087 1090
 		if (F) {
1088 1091
 			fprintf(F,"%i\n",pid);
1089 1092
 			fclose(F);
@@ -1098,25 +1101,26 @@ void do_daemonize() {
1098 1101
 }
1099 1102
 
1100 1103
 /* Must be called after daemonize! */
1101
-void init_logger() {
1102
-	if (syslog_active)
1103
-		fprintf(stderr, "Logging to %s:%d\n", loghost, logport);
1104
-	log_init(logident, syslog_active, pidfile == NULL, loghost, logport);
1104
+void init_logger(struct config *cfg) {
1105
+	if (cfg->syslog_active)
1106
+		fprintf(stderr, "Logging to %s:%d\n", cfg->loghost, cfg->logport);
1107
+	log_init(cfg->logident, cfg->syslog_active, cfg->pidfile == NULL, cfg->loghost, cfg->logport);
1105 1108
 }
1106 1109
 
1107 1110
 int main(int argc, char **argv) {
1108 1111
 	set_http_response_server_ident(server_sig, server_ver);
1109 1112
 	show_usage(1); // Show copyright and version
1110
-	init_vars();
1111
-	parse_options(argc, argv);
1112
-	do_daemonize();
1113
-	init_logger();
1113
+	init_vars(&config);
1114
+	parse_options(argc, argv, &config);
1115
+	do_daemonize(&config);
1116
+	init_logger(&config);
1114 1117
 	init_signals();
1115 1118
 
1116
-	LOGf("INIT : %s %s (%s)\n" , server_sig, server_ver, ident);
1119
+	LOGf("INIT : %s %s (%s)\n" , server_sig, server_ver, config.ident);
1117 1120
 
1118
-	load_channels_config();
1119
-	spawn_proxy_threads();
1121
+	load_channels_config(&config);
1122
+	spawn_proxy_threads(&config);
1123
+	web_server_start(&config);
1120 1124
 
1121 1125
 	do {
1122 1126
 		sleep(60);

+ 45
- 0
web_pages.c View File

@@ -0,0 +1,45 @@
1
+/*
2
+ * mptsd internal web pages
3
+ * Copyright (C) 2010-2011 Unix Solutions Ltd.
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 version 2
7
+ * as published by the Free Software Foundation.
8
+ *
9
+ * This program is distributed in the hope that it will be useful,
10
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
+ * GNU General Public License for more details.
13
+ *
14
+ * You should have received a copy of the GNU General Public License
15
+ * along with this program; if not, write to the Free Software
16
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
17
+ */
18
+#include <stdlib.h>
19
+#include <string.h>
20
+#include <sys/types.h>
21
+#include <sys/stat.h>
22
+#include <fcntl.h>
23
+#include <unistd.h>
24
+
25
+#include "libfuncs/io.h"
26
+#include "libfuncs/log.h"
27
+#include "libfuncs/list.h"
28
+#include "libfuncs/http_response.h"
29
+
30
+#include "config.h"
31
+
32
+extern struct config *config;
33
+
34
+void cmd_index(int clientsock) {
35
+	send_200_ok(clientsock);
36
+	send_header_textplain(clientsock);
37
+	fdputs(clientsock, "\nHi from tomcast.\n");
38
+}
39
+
40
+void cmd_reconnect(int clientsock) {
41
+	send_200_ok(clientsock);
42
+	send_header_textplain(clientsock);
43
+	fdputsf(clientsock, "\nReconnecting %d inputs.\n", 123);
44
+//	fdputsf(clientsock, "\nReconnecting %d inputs.\n", config->inputs->items);
45
+}

+ 24
- 0
web_pages.h View File

@@ -0,0 +1,24 @@
1
+/*
2
+ * mptsd internal web pages header file
3
+ * Copyright (C) 2010-2011 Unix Solutions Ltd.
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 version 2
7
+ * as published by the Free Software Foundation.
8
+ *
9
+ * This program is distributed in the hope that it will be useful,
10
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
+ * GNU General Public License for more details.
13
+ *
14
+ * You should have received a copy of the GNU General Public License
15
+ * along with this program; if not, write to the Free Software
16
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
17
+ */
18
+#ifndef WEB_PAGES_H
19
+#define WEB_PAGES_H
20
+
21
+void cmd_index(int clientsock);
22
+void cmd_reconnect(int clientsock);
23
+
24
+#endif

+ 139
- 0
web_server.c View File

@@ -0,0 +1,139 @@
1
+/*
2
+ * mptsd internal web server
3
+ * Copyright (C) 2010-2011 Unix Solutions Ltd.
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 version 2
7
+ * as published by the Free Software Foundation.
8
+ *
9
+ * This program is distributed in the hope that it will be useful,
10
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
+ * GNU General Public License for more details.
13
+ *
14
+ * You should have received a copy of the GNU General Public License
15
+ * along with this program; if not, write to the Free Software
16
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
17
+ */
18
+#include <stdlib.h>
19
+#include <regex.h>
20
+#include <errno.h>
21
+#include <string.h>
22
+#include <signal.h>
23
+#include <arpa/inet.h>
24
+#include <netinet/in.h>
25
+
26
+#include "libfuncs/libfuncs.h"
27
+
28
+#include "web_pages.h"
29
+#include "web_server.h"
30
+
31
+typedef struct req_info {
32
+	int clientsock;
33
+	struct sockaddr_in client;
34
+} request_info;
35
+
36
+extern int keep_going;
37
+
38
+#define NEXT_CLIENT { FREE(path); FREE(buf); pthread_exit(0); }
39
+#define SHUTDOWN_CLIENT { FREE(path); FREE(buf); shutdown_fd(&clientsock); pthread_exit(0); }
40
+#define BUF_SIZE 1024
41
+
42
+void *process_web_request(void *);
43
+
44
+void *web_server_thread(void *data) {
45
+	struct config *conf = data;
46
+	while (keep_going) {
47
+		struct sockaddr_in client;
48
+		unsigned int clientlen = sizeof(client);
49
+		int clientsock;
50
+		clientsock = accept(conf->server_socket, (struct sockaddr *) &client, &clientlen);
51
+		if (clientsock < 0) {
52
+			if (conf->server_socket > -1)	// The server_socket is closed on exit, so do not report errors
53
+				LOGf("ERROR : Failed to accept client fd: %i err: %s\n", clientsock, strerror(errno));
54
+			if (errno==EMFILE || errno==ENFILE) /* No more FDs */
55
+				break;
56
+		} else {
57
+			request_info *req;
58
+			pthread_t req_thread;
59
+			req = malloc(sizeof(request_info));
60
+			if (!req) {
61
+				log_perror("Can't allocate request_info", errno);
62
+				continue;
63
+			}
64
+			req->clientsock = clientsock;
65
+			req->client = client;
66
+			if (pthread_create(&req_thread, NULL, (void *)&process_web_request, (void *)req)) {
67
+				log_perror("Error creating request processing thread.", errno);
68
+				exit(1);
69
+			}
70
+			pthread_detach(req_thread);
71
+		}
72
+	}
73
+
74
+	pthread_exit(0);
75
+}
76
+
77
+void web_server_start(struct config *conf) {
78
+	if (conf->server_socket > -1)
79
+		pthread_create(&conf->server_thread, NULL, &web_server_thread, conf);
80
+}
81
+
82
+void web_server_stop(struct config *conf) {
83
+	if (conf->server_socket > -1) {
84
+		shutdown_fd(&conf->server_socket);
85
+		pthread_join(conf->server_thread, NULL);
86
+	}
87
+}
88
+
89
+void *process_web_request(void *in_req) {
90
+	request_info *req = (request_info *)in_req;
91
+	int clientsock = req->clientsock;
92
+	regmatch_t res[3];
93
+	char *path=NULL, *buf=NULL;
94
+	FREE(req);
95
+
96
+	signal(SIGPIPE, SIG_IGN);
97
+
98
+	if (!keep_going)
99
+		pthread_exit(0);
100
+
101
+	buf = malloc(BUF_SIZE);
102
+	if (!buf) {
103
+		log_perror("Can't allocate buffer", errno);
104
+		SHUTDOWN_CLIENT;
105
+	}
106
+
107
+	if (fdgetline(clientsock,buf,BUF_SIZE)<=0) {
108
+		SHUTDOWN_CLIENT;
109
+	}
110
+
111
+	regex_t request_get;
112
+	regcomp(&request_get, "^GET /([^ ]*) HTTP/1.*$", REG_EXTENDED);
113
+	if (regexec(&request_get,buf,2,res,0)==REG_NOMATCH) {
114
+		send_501_not_implemented(clientsock);
115
+		SHUTDOWN_CLIENT;
116
+	}
117
+
118
+	buf[res[1].rm_eo]=0;
119
+	chomp(buf+res[1].rm_so);
120
+	if (buf[res[1].rm_eo-1]=='/') buf[res[1].rm_eo-1]=0;
121
+	path = strdup(buf+res[1].rm_so);
122
+	regfree(&request_get);
123
+
124
+	while (fdgetline(clientsock,buf,BUF_SIZE) > 0) {
125
+		if (buf[0] == '\n' || buf[0] == '\r') // End of headers
126
+			break;
127
+	}
128
+
129
+	if (strlen(path) == 0) {
130
+		cmd_index(clientsock);
131
+	} else if (strstr(path,"reconnect")==path) {
132
+		cmd_reconnect(clientsock);
133
+	} else {
134
+		send_404_not_found(clientsock);
135
+	}
136
+
137
+	SHUTDOWN_CLIENT;
138
+}
139
+

+ 26
- 0
web_server.h View File

@@ -0,0 +1,26 @@
1
+/*
2
+ * mptsd internal web server header file
3
+ * Copyright (C) 2010-2011 Unix Solutions Ltd.
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 version 2
7
+ * as published by the Free Software Foundation.
8
+ *
9
+ * This program is distributed in the hope that it will be useful,
10
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
+ * GNU General Public License for more details.
13
+ *
14
+ * You should have received a copy of the GNU General Public License
15
+ * along with this program; if not, write to the Free Software
16
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
17
+ */
18
+#ifndef WEB_SERVER_H
19
+# define WEB_SERVER_H
20
+
21
+#include "config.h"
22
+
23
+void web_server_start(struct config *conf);
24
+void web_server_stop(struct config *conf);
25
+
26
+#endif

Loading…
Cancel
Save