Browse Source

Add web status/info/control interface

Georgi Chorbadzhiyski 7 years ago
parent
commit
19f2496670
8 changed files with 630 additions and 130 deletions
  1. 1
    1
      Makefile
  2. 65
    0
      README.WEB_ACCESS
  3. 96
    0
      config.h
  4. 143
    129
      tomcast.c
  5. 127
    0
      web_pages.c
  6. 27
    0
      web_pages.h
  7. 145
    0
      web_server.c
  8. 26
    0
      web_server.h

+ 1
- 1
Makefile View File

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

+ 65
- 0
README.WEB_ACCESS View File

@@ -0,0 +1,65 @@
1
+To enable the web access start tomcast with -b (listen address) and
2
+-p (listen port parameters).
3
+
4
+For example: tomcast -b 127.0.0.1 -p 8081
5
+
6
+Now you can access the web interface exposed by tomcast at
7
+
8
+    http://127.0.0.1:8081/
9
+
10
+The following endpoints are accessible:
11
+
12
+    http://127.0.0.1:8081/getconfig
13
+
14
+  Return currently configured channels in channels.conf format
15
+  that tomcast uses.
16
+
17
+
18
+    http://127.0.0.1:8081/reconnect
19
+
20
+  Reconnect all sources. If channels have more than one source
21
+  the source will be changed to the next available source.
22
+
23
+
24
+    http://127.0.0.1:8081/reload
25
+
26
+  Reload config file. This would start/stop new/removed channels.
27
+
28
+
29
+    http://127.0.0.1:8081/status
30
+
31
+  Return current channels status. The status looks like this:
32
+
33
+# Status   DestAddr             ConnTime  ReadBytes ChanName           ChanSource                                                       ProxyStatus
34
+CONN_OK    239.78.78.78:5000         123     148708 chan1              http://example.com:8080/stb/chan1.mpg                            Synced
35
+CONN_ERROR 239.79.79.79:5000          60      65800 chan2              http://ux.iptv.bg:8080/stb/chan2.mpg                             Synced
36
+CONN_ERROR 239.80.80.80:5000           0          0 chan3              udp://239.1.2.3:5000/                                            Connected
37
+
38
+  "Status" - current channel status which can be CONN_OK or CONN_ERROR
39
+
40
+    CONN_ERROR - Means that the source of the channel is currently
41
+                 not connected or bytes read are at least 1316 or
42
+                 ConnTime is 0
43
+
44
+  "ProxyStatus" - Last connection status
45
+
46
+    Connected
47
+    Working
48
+
49
+    Reconnecting
50
+
51
+    Dying
52
+    Forced reconnect
53
+
54
+    ERROR: Can not connect to source
55
+    ERROR: Can not resolve source host
56
+    ERROR: Can not sync mpeg
57
+    ERROR: Dns resolve timeout
58
+    ERROR: Read timeout
59
+    ERROR: Source returned invalid HTTP code
60
+    ERROR: Source returned no-signal
61
+    ERROR: Source returned unhandled error code
62
+    ERROR: Timeout while syncing mpeg
63
+    ERROR: Too many zero reads
64
+    ERROR: fdread() timeout while syncing mpeg
65
+    ERROR: fdread() timeout while syncing mpeg

+ 96
- 0
config.h View File

@@ -0,0 +1,96 @@
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
+typedef enum { udp_sock, tcp_sock } channel_source;
28
+
29
+typedef struct {
30
+	channel_source sproto;
31
+	char *proto;
32
+	char *host;
33
+	char *path;
34
+	unsigned int port;
35
+} CHANSRC;
36
+
37
+#define MAX_CHANNEL_SOURCES 8
38
+
39
+typedef struct {
40
+	char *name;
41
+	char *source; /* Full source url */
42
+	char *sources[MAX_CHANNEL_SOURCES];
43
+	uint8_t num_src;
44
+	uint8_t curr_src;
45
+	char *dest_host;
46
+	int dest_port;
47
+} CHANNEL;
48
+
49
+typedef struct {
50
+	char  *name;
51
+	CHANNEL *channel;
52
+	int sock;				/* Server socket */
53
+	struct sockaddr_in src_sockname;
54
+	int clientsock;			/* The udp socket */
55
+	struct sockaddr_in dst_sockname;
56
+	int reconnect:1,		/* Set to 1 to force proxy reconnect */
57
+	    connected:1,		/* It's set to 1 when proxy is connected and serving clients */
58
+	    dienow:1,			/* Stop serving clients and exit now */
59
+	    freechannel:1;		/* Free channel data on object free (this is used in chanconf) */
60
+	int cookie;				/* Used in chanconf to determine if the restreamer is alrady checked */
61
+	pthread_t thread;
62
+	pthread_rwlock_t lock;
63
+	time_t conn_ts;
64
+	uint64_t read_bytes;
65
+	char status[64];
66
+} RESTREAMER;
67
+
68
+
69
+struct config {
70
+	char				*ident;
71
+	char				*pidfile;
72
+
73
+	int					syslog_active;
74
+	char				*logident;
75
+	char				*loghost;
76
+	int					logport;
77
+
78
+	struct sockaddr_in	server;
79
+	char				*server_addr;
80
+	int					server_port;
81
+	int					server_socket;
82
+	pthread_t			server_thread;
83
+
84
+	char				*channels_file;
85
+
86
+	LIST				*chanconf;
87
+	LIST				*restreamer;
88
+
89
+	pthread_mutex_t		channels_lock;
90
+};
91
+
92
+extern void do_reconnect();
93
+extern void do_reconf();
94
+extern struct config *get_config(void);
95
+
96
+#endif

+ 143
- 129
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
 
@@ -68,42 +71,7 @@ char *server_sig = "tomcast";
68 71
 char *server_ver = "1.15";
69 72
 char *copyright  = "Copyright (C) 2010-2013 Unix Solutions Ltd.";
70 73
 
71
-typedef enum { udp_sock, tcp_sock } channel_source;
72
-
73
-typedef struct {
74
-	channel_source sproto;
75
-	char *proto;
76
-	char *host;
77
-	char *path;
78
-	unsigned int port;
79
-} CHANSRC;
80
-
81
-#define MAX_CHANNEL_SOURCES 8
82
-
83
-typedef struct {
84
-	char *name;
85
-	char *source; /* Full source url */
86
-	char *sources[MAX_CHANNEL_SOURCES];
87
-	uint8_t num_src;
88
-	uint8_t curr_src;
89
-	char *dest_host;
90
-	int dest_port;
91
-} CHANNEL;
92
-
93
-typedef struct {
94
-	char  *name;
95
-	CHANNEL *channel;
96
-	int sock;				/* Server socket */
97
-	struct sockaddr_in src_sockname;
98
-	int clientsock;			/* The udp socket */
99
-	struct sockaddr_in dst_sockname;
100
-	int reconnect:1,		/* Set to 1 to force proxy reconnect */
101
-	    connected:1,		/* It's set to 1 when proxy is connected and serving clients */
102
-	    dienow:1,			/* Stop serving clients and exit now */
103
-	    freechannel:1;		/* Free channel data on object free (this is used in chanconf) */
104
-	int cookie;				/* Used in chanconf to determine if the restreamer is alrady checked */
105
-	pthread_t thread;
106
-} RESTREAMER;
74
+static struct config config;
107 75
 
108 76
 channel_source get_sproto(char *url) {
109 77
 	return strncmp(url, "http", 4)==0 ? tcp_sock : udp_sock;
@@ -249,6 +217,11 @@ int connect_multicast(struct sockaddr_in send_to) {
249 217
 	return sendsock;
250 218
 }
251 219
 
220
+void proxy_set_status(RESTREAMER *r, const char *proxy_status) {
221
+	pthread_rwlock_wrlock(&r->lock);
222
+	snprintf(r->status, sizeof(r->status), "%s", proxy_status);
223
+	pthread_rwlock_unlock(&r->lock);
224
+}
252 225
 
253 226
 void connect_destination(RESTREAMER *r) {
254 227
 	CHANNEL *c = r->channel;
@@ -275,6 +248,7 @@ RESTREAMER * new_restreamer(const char *name, CHANNEL *channel) {
275 248
 	r->channel = channel;
276 249
 	r->clientsock = -1;
277 250
 	r->dst_sockname = sockname;
251
+	pthread_rwlock_init(&r->lock, NULL);
278 252
 	connect_destination(r);
279 253
 	return r;
280 254
 }
@@ -288,27 +262,10 @@ void free_restreamer(RESTREAMER *r) {
288 262
 	FREE(r);
289 263
 }
290 264
 
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 265
 char TS_NULL_FRAME[FRAME_PACKET_SIZE];
304 266
 
305 267
 regex_t http_response;
306 268
 
307
-LIST *chanconf = NULL;
308
-LIST *restreamer = NULL;
309
-
310
-static pthread_mutex_t channels_lock = PTHREAD_MUTEX_INITIALIZER;
311
-
312 269
 void proxy_log(RESTREAMER *r, char *msg, char *info) {
313 270
 	LOGf("%s: %sChan: %s Src: %s Dst: udp://%s:%d SrcIP: %s SrcFD: %i DstFD: %i\n",
314 271
 		msg,
@@ -323,17 +280,17 @@ void proxy_log(RESTREAMER *r, char *msg, char *info) {
323 280
 	);
324 281
 }
325 282
 
326
-int load_channels_config() {
283
+int load_channels_config(struct config *cfg) {
327 284
 	regex_t re;
328 285
 	regmatch_t res[5];
329 286
 	char line[1024];
330 287
 	int fd;
331 288
 	int num_channels = 0;
332 289
 
333
-	if (pthread_mutex_trylock(&channels_lock) != 0)
290
+	if (pthread_mutex_trylock(&cfg->channels_lock) != 0)
334 291
 		return -1;
335 292
 
336
-	fd = open(channels_file, O_RDONLY);
293
+	fd = open(cfg->channels_file, O_RDONLY);
337 294
 
338 295
 	if (fd != -1) {
339 296
 		struct timeval tv;
@@ -385,18 +342,18 @@ report_error:
385 342
 		regfree(&re);
386 343
 		shutdown_fd(&fd);
387 344
 		/* Save current chanconf */
388
-		old_chanconf = chanconf;
345
+		old_chanconf = cfg->chanconf;
389 346
 		/* Switch chanconf */
390
-		chanconf = new_chanconf;
347
+		cfg->chanconf = new_chanconf;
391 348
 		/* Rewrite restreamer channels */
392 349
 		LNODE *lc, *lr, *lctmp, *lrtmp;
393 350
 		CHANNEL *chan;
394
-		list_lock(restreamer);	// Unlocked after second list_for_each(restreamer)
351
+		list_lock(cfg->restreamer);	// Unlocked after second list_for_each(restreamer)
395 352
 
396
-		list_lock(chanconf);
397
-		list_for_each(chanconf, lc, lctmp) {
353
+		list_lock(cfg->chanconf);
354
+		list_for_each(cfg->chanconf, lc, lctmp) {
398 355
 			chan = lc->data;
399
-			list_for_each(restreamer, lr, lrtmp) {
356
+			list_for_each(cfg->restreamer, lr, lrtmp) {
400 357
 				if (strcmp(chan->name, ((RESTREAMER *)lr->data)->name)==0) {
401 358
 					RESTREAMER *restr = lr->data;
402 359
 					/* Mark the restreamer as valid */
@@ -425,10 +382,10 @@ report_error:
425 382
 				}
426 383
 			}
427 384
 		}
428
-		list_unlock(chanconf);
385
+		list_unlock(cfg->chanconf);
429 386
 
430 387
 		/* Kill restreamers that serve channels that no longer exist */
431
-		list_for_each(restreamer, lr, lrtmp) {
388
+		list_for_each(cfg->restreamer, lr, lrtmp) {
432 389
 			RESTREAMER *r = lr->data;
433 390
 			/* This restreamer should no longer serve clients */
434 391
 			if (r->cookie != cookie) {
@@ -439,14 +396,14 @@ report_error:
439 396
 				r->dienow = 1;
440 397
 			}
441 398
 		}
442
-		list_unlock(restreamer);
399
+		list_unlock(cfg->restreamer);
443 400
 
444 401
 		/* Free old_chanconf */
445 402
 		list_free(&old_chanconf, free_channel_p, NULL);
446 403
 	} else {
447 404
 		num_channels = -1;
448 405
 	}
449
-	pthread_mutex_unlock(&channels_lock);
406
+	pthread_mutex_unlock(&cfg->channels_lock);
450 407
 	if (num_channels == -1)
451 408
 		LOGf("CONF : Error loading channels!\n");
452 409
 	else
@@ -457,7 +414,7 @@ report_error:
457 414
 void proxy_close(RESTREAMER *r) {
458 415
 	proxy_log(r, "STOP ","");
459 416
 	// If there are no clients left, no "Timeout" messages will be logged
460
-	list_del_entry(restreamer, r);
417
+	list_del_entry(config.restreamer, r);
461 418
 	free_restreamer(r);
462 419
 }
463 420
 
@@ -501,10 +458,14 @@ int connect_source(RESTREAMER *r, int retries, int readbuflen, int *http_code) {
501 458
 	int active = 1;
502 459
 	int dret = async_resolve_host(src->host, src->port, &(r->src_sockname), DNS_RESOLVER_TIMEOUT, &active);
503 460
 	if (dret != 0) {
504
-		if (dret == 1)
461
+		if (dret == 1) {
505 462
 			proxy_log(r, "ERR  ","Can't resolve src host");
506
-		if (dret == 2)
463
+			proxy_set_status(r, "ERROR: Can not resolve source host");
464
+		}
465
+		if (dret == 2) {
507 466
 			proxy_log(r, "ERR  ","Timeout resolving src host");
467
+			proxy_set_status(r, "ERROR: Dns resolve timeout");
468
+		}
508 469
 		DO_RECONNECT;
509 470
 	}
510 471
 
@@ -519,11 +480,12 @@ int connect_source(RESTREAMER *r, int retries, int readbuflen, int *http_code) {
519 480
 		proxy_log(r, "NEW  ","");
520 481
 		if (do_connect(r->sock, (struct sockaddr *)&(r->src_sockname), sizeof(r->src_sockname), PROXY_CONNECT_TIMEOUT) < 0) {
521 482
 			LOGf("ERR  : Error connecting to %s srv_fd: %i err: %s\n", r->channel->source, r->sock, strerror(errno));
483
+			proxy_set_status(r, "ERROR: Can not connect to source");
522 484
 			DO_RECONNECT;
523 485
 		}
524 486
 
525 487
 		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);
488
+		         src->path, src->host, src->port, server_sig, server_ver, config.ident);
527 489
 		buf[sizeof(buf)-1] = 0;
528 490
 		fdwrite(r->sock, buf, strlen(buf));
529 491
 
@@ -556,14 +518,17 @@ int connect_source(RESTREAMER *r, int retries, int readbuflen, int *http_code) {
556 518
 		}
557 519
 		if (*http_code == 0) { // No valid HTTP response, retry
558 520
 			LOGf("DEBUG: Server returned not valid HTTP code | srv_fd: %i\n", r->sock);
521
+			proxy_set_status(r, "ERROR: Source returned invalid HTTP code");
559 522
 			DO_RECONNECT;
560 523
 		}
561 524
 		if (*http_code == 504) { // No signal, exit
562 525
 			LOGf("ERR  : Get no-signal for %s from %s on srv_fd: %i\n", r->channel->name, r->channel->source, r->sock);
526
+			proxy_set_status(r, "ERROR: Source returned no-signal");
563 527
 			FATAL_ERROR;
564 528
 		}
565 529
 		if (*http_code > 300) { // Unhandled or error codes, exit
566 530
 			LOGf("ERR  : Get code %i for %s from %s on srv_fd: %i exiting.\n", *http_code, r->channel->name, r->channel->source, r->sock);
531
+			proxy_set_status(r, "ERROR: Source returned unhandled error code");
567 532
 			FATAL_ERROR;
568 533
 		}
569 534
 		// connected ok, continue
@@ -604,6 +569,7 @@ int connect_source(RESTREAMER *r, int retries, int readbuflen, int *http_code) {
604 569
 	if (setsockopt(r->sock, SOL_SOCKET, SO_RCVBUF, (const char *)&readbuflen, sizeof(readbuflen)) < 0)
605 570
 		log_perror("play(): setsockopt(SO_RCVBUF)", errno);
606 571
 
572
+	proxy_set_status(r, "Connected");
607 573
 	r->connected = 1;
608 574
 
609 575
 	free_chansrc(src);
@@ -613,10 +579,12 @@ int connect_source(RESTREAMER *r, int retries, int readbuflen, int *http_code) {
613 579
 int check_restreamer_state(RESTREAMER *r) {
614 580
 	if (r->dienow) {
615 581
 		// LOGf("PROXY: Forced disconnect on srv_fd: %i | Channel: %s Source: %s\n", r->sock, r->channel->name, r->channel->source);
582
+		proxy_set_status(r, "Dying");
616 583
 		return 2;
617 584
 	}
618 585
 	if (r->reconnect) {
619 586
 		LOGf("PROXY: Forced reconnect on srv_fd: %i | Channel: %s Source: %s\n", r->sock, r->channel->name, r->channel->source);
587
+		proxy_set_status(r, "Forced reconnect");
620 588
 		return 1;
621 589
 	}
622 590
 	return 0;
@@ -640,7 +608,7 @@ int check_restreamer_state(RESTREAMER *r) {
640 608
 		0 = synced ok
641 609
 		1 = not synced, reconnect
642 610
 */
643
-int mpeg_sync(int proxysock, char *channel, channel_source source_proto) {
611
+int mpeg_sync(RESTREAMER *r, int proxysock, char *channel, channel_source source_proto) {
644 612
 	time_t sync_start = time(NULL);
645 613
 	unsigned int sync_packets = 0;
646 614
 	unsigned int read_bytes = 0;
@@ -656,6 +624,7 @@ int mpeg_sync(int proxysock, char *channel, channel_source source_proto) {
656 624
 resync:
657 625
 		if (fdread_ex(proxysock, syncframe, 1, _timeout, _retries, 1) != 1) {
658 626
 			LOGf("DEBUG: mpeg_sync fdread() timeout | Channel: %s\n", channel);
627
+			proxy_set_status(r, "ERROR: fdread() timeout while syncing mpeg");
659 628
 			return 1; // reconnect
660 629
 		}
661 630
 		// LOGf("DEBUG:     Read 0x%02x Offset %u Sync: %u\n", (uint8_t)syncframe[0], read_bytes, sync_packets);
@@ -664,6 +633,7 @@ resync:
664 633
 			ssize_t rdsz = fdread_ex(proxysock, syncframe, 188-1, _timeout, _retries, 1);
665 634
 			if (rdsz != 188-1) {
666 635
 				LOGf("DEBUG: mpeg_sync fdread() timeout | Channel: %s\n", channel);
636
+				proxy_set_status(r, "ERROR: fdread() timeout while syncing mpeg");
667 637
 				return 1; // reconnect
668 638
 			}
669 639
 			read_bytes += 188-1;
@@ -675,14 +645,21 @@ resync:
675 645
 		}
676 646
 		if (read_bytes > FRAME_PACKET_SIZE) { // Can't sync in 1316 bytes
677 647
 			LOGf("DEBUG: Can't sync after %d bytes | Channel: %s\n", FRAME_PACKET_SIZE, channel);
648
+			proxy_set_status(r, "ERROR: Can not sync mpeg");
678 649
 			return 1; // reconnect
679 650
 		}
680 651
 		if (sync_start+2 <= time(NULL)) { // Do not sync in two seconds
681 652
 			LOGf("DEBUG: Timeout while syncing (read %u bytes) | Channel: %s\n", read_bytes, channel);
653
+			proxy_set_status(r, "ERROR: Timeout while syncing mpeg");
682 654
 			return 1; // reconnect
683 655
 		}
684 656
 	} while (1);
657
+	pthread_rwlock_wrlock(&r->lock);
658
+	r->conn_ts = time(NULL);
659
+	r->read_bytes = read_bytes;
660
+	pthread_rwlock_unlock(&r->lock);
685 661
 	LOGf("SYNC : TS synced after %u bytes | Channel: %s\n", read_bytes-FRAME_PACKET_SIZE, channel);
662
+	proxy_set_status(r, "Working");
686 663
 	return 0;
687 664
 }
688 665
 
@@ -807,13 +784,16 @@ void * proxy_ts_stream(void *self) {
807 784
 
808 785
 	int http_code = 0;
809 786
 	while (1) {
787
+		r->conn_ts = 0;
788
+		r->read_bytes = 0;
789
+
810 790
 		int result = connect_source(self, 1, FRAME_PACKET_SIZE * 1000, &http_code);
811 791
 		if (result > 0)
812 792
 			goto RECONNECT;
813 793
 
814 794
 		channel_source sproto = get_sproto(r->channel->source);
815 795
 
816
-		int mpgsync = mpeg_sync(r->sock, r->channel->name, sproto);
796
+		int mpgsync = mpeg_sync(r, r->sock, r->channel->name, sproto);
817 797
 		if (mpgsync == 1) // Timeout
818 798
 			goto RECONNECT;
819 799
 
@@ -836,6 +816,7 @@ void * proxy_ts_stream(void *self) {
836 816
 				LOGf("PROXY: zero read on srv_fd: %i | Channel: %s Source: %s\n", r->sock, r->channel->name, r->channel->source);
837 817
 				if (--max_zero_reads == 0) {
838 818
 					LOGf("PROXY: %d zero reads on srv_fd: %i | Channel: %s Source: %s\n", MAX_ZERO_READS, r->sock, r->channel->name, r->channel->source);
819
+					proxy_set_status(r, "ERROR: Too many zero reads");
839 820
 					break;
840 821
 				}
841 822
 				continue;
@@ -848,6 +829,9 @@ void * proxy_ts_stream(void *self) {
848 829
 				//LOGf("DEBUG: Short read (%d) on retreamer srv_fd: %i | Channel: %s\n", readen, sock, chan->name);
849 830
 				memcpy(buf+readen, TS_NULL_FRAME+readen, FRAME_PACKET_SIZE - readen);
850 831
 			}
832
+			pthread_rwlock_wrlock(&r->lock);
833
+			r->read_bytes += readen;
834
+			pthread_rwlock_unlock(&r->lock);
851 835
 
852 836
 			if (send_reset) {
853 837
 				send_reset = 0;
@@ -860,8 +844,13 @@ void * proxy_ts_stream(void *self) {
860 844
 			}
861 845
 		}
862 846
 		LOGf("DEBUG: fdread timeout restreamer srv_fd: %i | Channel: %s\n", r->sock, r->channel->name);
847
+		proxy_set_status(r, "ERROR: Read timeout");
863 848
 RECONNECT:
849
+		pthread_rwlock_wrlock(&r->lock);
850
+		r->conn_ts = 0;
851
+		pthread_rwlock_unlock(&r->lock);
864 852
 		LOGf("DEBUG: reconnect srv_fd: %i | Channel: %s\n", r->sock, r->channel->name);
853
+		proxy_set_status(r, "Reconnecting");
865 854
 		shutdown_fd(&(r->sock));
866 855
 		next_channel_source(r->channel);
867 856
 		continue;
@@ -893,13 +882,16 @@ void show_usage(int ident_only) {
893 882
 	puts("\t-l host\t\tSyslog host (default: disabled)");
894 883
 	puts("\t-L port\t\tSyslog port (default: 514)");
895 884
 	puts("\t-R\t\tSend reset packets when changing sources.");
885
+	puts("Server settings:");
886
+	puts("\t-b addr\t\tLocal IP address to bind.   (default: 0.0.0.0)");
887
+	puts("\t-p port\t\tPort to listen.             (default: 0)");
896 888
 	puts("");
897 889
 }
898 890
 
899
-void set_ident(char *new_ident) {
900
-	ident = new_ident;
901
-	logident = strdup(ident);
902
-	char *c = logident;
891
+void set_ident(char *new_ident, struct config *cfg) {
892
+	cfg->ident = new_ident;
893
+	cfg->logident = strdup(new_ident);
894
+	char *c = cfg->logident;
903 895
 	while (*c) {
904 896
 		if (*c=='/')
905 897
 			*c='-';
@@ -907,18 +899,26 @@ void set_ident(char *new_ident) {
907 899
 	}
908 900
 }
909 901
 
910
-void parse_options(int argc, char **argv) {
902
+void parse_options(int argc, char **argv, struct config *cfg) {
911 903
 	int j, ttl;
912
-	while ((j = getopt(argc, argv, "i:c:d:t:o:l:L:RHh")) != -1) {
904
+	cfg->server_socket = -1;
905
+	pthread_mutex_init(&cfg->channels_lock, NULL);
906
+	while ((j = getopt(argc, argv, "i:b:p:c:d:t:o:l:L:RHh")) != -1) {
913 907
 		switch (j) {
908
+			case 'b':
909
+				cfg->server_addr = optarg;
910
+				break;
911
+			case 'p':
912
+				cfg->server_port = atoi(optarg);
913
+				break;
914 914
 			case 'i':
915
-				set_ident(optarg);
915
+				set_ident(optarg, cfg);
916 916
 				break;
917 917
 			case 'c':
918
-				channels_file = optarg;
918
+				cfg->channels_file = optarg;
919 919
 				break;
920 920
 			case 'd':
921
-				pidfile = optarg;
921
+				cfg->pidfile = optarg;
922 922
 				break;
923 923
 			case 'o':
924 924
 				if (inet_aton(optarg, &output_intf) == 0) {
@@ -931,11 +931,11 @@ void parse_options(int argc, char **argv) {
931 931
 				multicast_ttl = (ttl && ttl < 127) ? ttl : 1;
932 932
 				break;
933 933
 			case 'l':
934
-				loghost = optarg;
935
-				syslog_active = 1;
934
+				cfg->loghost = optarg;
935
+				cfg->syslog_active = 1;
936 936
 				break;
937 937
 			case 'L':
938
-				logport = atoi(optarg);
938
+				cfg->logport = atoi(optarg);
939 939
 				break;
940 940
 			case 'R':
941 941
 				send_reset_opt = 1;
@@ -948,38 +948,44 @@ void parse_options(int argc, char **argv) {
948 948
 		}
949 949
 	}
950 950
 
951
-	if (!channels_file) {
951
+	if (!cfg->channels_file) {
952 952
 		show_usage(0);
953 953
 		fprintf(stderr, "ERROR: No channels file is set (use -c option).\n");
954 954
 		exit(1);
955 955
 	}
956 956
 
957
-	if (!ident) {
958
-		set_ident("unixsol/tomcast");
957
+	if (!cfg->ident) {
958
+		set_ident("unixsol/tomcast", cfg);
959 959
 	}
960 960
 
961 961
 	printf("Configuration:\n");
962
-	printf("\tServer ident      : %s\n", ident);
963
-	printf("\tChannels file     : %s\n", channels_file);
962
+	printf("\tServer ident      : %s\n", cfg->ident);
963
+	printf("\tChannels file     : %s\n", cfg->channels_file);
964 964
 	printf("\tOutput iface addr : %s\n", inet_ntoa(output_intf));
965 965
 	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);
966
+	if (cfg->syslog_active) {
967
+		printf("\tSyslog host       : %s\n", cfg->loghost);
968
+		printf("\tSyslog port       : %d\n", cfg->logport);
969 969
 	} else {
970 970
 		printf("\tSyslog disabled.\n");
971 971
 	}
972 972
 	if (send_reset_opt)
973 973
 		printf("\tSend reset packets.\n");
974
-	if (pidfile) {
975
-		printf("\tDaemonize         : %s\n", pidfile);
974
+	if (cfg->pidfile) {
975
+		printf("\tDaemonize         : %s\n", cfg->pidfile);
976 976
 	} else {
977 977
 		printf("\tDo not daemonize.\n");
978 978
 	}
979
+	if (cfg->server_port) {
980
+		init_server_socket(cfg->server_addr, cfg->server_port, &cfg->server, &cfg->server_socket);
981
+		printf("\tStarting web srv  : http://%s:%d/status (sock: %d)\n", cfg->server_addr, cfg->server_port, cfg->server_socket);
982
+	} else {
983
+		printf("\tNo web server\n");
984
+	}
979 985
 }
980 986
 
981
-void init_vars() {
982
-	restreamer = list_new("restreamer");
987
+void init_vars(struct config *cfg) {
988
+	cfg->restreamer = list_new("restreamer");
983 989
 	regcomp(&http_response, "^HTTP/1.[0-1] (([0-9]{3}) .*)", REG_EXTENDED);
984 990
 	memset(&TS_NULL_FRAME, 0xff, FRAME_PACKET_SIZE);
985 991
 	int i;
@@ -991,29 +997,29 @@ void init_vars() {
991 997
 	}
992 998
 }
993 999
 
994
-void spawn_proxy_threads() {
1000
+void spawn_proxy_threads(struct config *cfg) {
995 1001
 	LNODE *lc, *lctmp;
996 1002
 	LNODE *lr, *lrtmp;
997 1003
 	int spawned = 0;
998
-	list_for_each(chanconf, lc, lctmp) {
1004
+	list_for_each(cfg->chanconf, lc, lctmp) {
999 1005
 		CHANNEL *c = lc->data;
1000 1006
 		int restreamer_active = 0;
1001
-		list_lock(restreamer);
1002
-		list_for_each(restreamer, lr, lrtmp) {
1007
+		list_lock(cfg->restreamer);
1008
+		list_for_each(cfg->restreamer, lr, lrtmp) {
1003 1009
 			RESTREAMER *r = lr->data;
1004 1010
 			if (strcmp(r->name, c->name)==0) {
1005 1011
 				restreamer_active = 1;
1006 1012
 				break;
1007 1013
 			}
1008 1014
 		}
1009
-		list_unlock(restreamer);
1015
+		list_unlock(cfg->restreamer);
1010 1016
 		if (!restreamer_active) {
1011 1017
 			RESTREAMER *nr = new_restreamer(c->name, c);
1012 1018
 			if (nr->clientsock < 0) {
1013 1019
 				LOGf("Error creating proxy socket for %s\n", c->name);
1014 1020
 				free_restreamer(nr);
1015 1021
 			} else {
1016
-				list_add(restreamer, nr);
1022
+				list_add(cfg->restreamer, nr);
1017 1023
 				if (pthread_create(&nr->thread, NULL, &proxy_ts_stream, nr) == 0) {
1018 1024
 					spawned++;
1019 1025
 					pthread_detach(nr->thread);
@@ -1026,44 +1032,51 @@ void spawn_proxy_threads() {
1026 1032
 	LOGf("INFO : %d proxy threads spawned\n", spawned);
1027 1033
 }
1028 1034
 
1029
-void kill_proxy_threads() {
1035
+void kill_proxy_threads(struct config *cfg) {
1030 1036
 	LNODE *l, *tmp;
1031 1037
 	int killed = 0;
1032
-	list_lock(restreamer);
1033
-	list_for_each(restreamer, l, tmp) {
1038
+	list_lock(cfg->restreamer);
1039
+	list_for_each(cfg->restreamer, l, tmp) {
1034 1040
 		RESTREAMER *r = l->data;
1035 1041
 		r->dienow = 1;
1036 1042
 		killed++;
1037 1043
 	}
1038
-	list_unlock(restreamer);
1044
+	list_unlock(cfg->restreamer);
1039 1045
 	LOGf("INFO : %d proxy threads killed\n", killed);
1040 1046
 }
1041 1047
 
1048
+int keep_going = 1;
1049
+
1042 1050
 void signal_quit(int sig) {
1043
-	kill_proxy_threads();
1051
+	keep_going = 0;
1052
+	kill_proxy_threads(&config);
1044 1053
 	usleep(500000);
1045
-	LOGf("KILL : Signal %i | %s %s (%s)\n", sig, server_sig, server_ver, ident);
1054
+	LOGf("KILL : Signal %i | %s %s (%s)\n", sig, server_sig, server_ver, config.ident);
1046 1055
 	usleep(100000);
1047 1056
 	log_close();
1048
-	if (pidfile && strlen(pidfile))
1049
-		unlink(pidfile);
1057
+	if (config.pidfile && strlen(config.pidfile))
1058
+		unlink(config.pidfile);
1050 1059
 	signal(sig, SIG_DFL);
1051 1060
 	raise(sig);
1052 1061
 }
1053 1062
 
1063
+struct config *get_config(void) {
1064
+	return &config;
1065
+}
1066
+
1054 1067
 void do_reconnect() {
1055 1068
 	LNODE *l, *tmp;
1056
-	list_lock(restreamer);
1057
-	list_for_each(restreamer, l, tmp) {
1069
+	list_lock(config.restreamer);
1070
+	list_for_each(config.restreamer, l, tmp) {
1058 1071
 		RESTREAMER *r = l->data;
1059 1072
 		r->reconnect = 1;
1060 1073
 	}
1061
-	list_unlock(restreamer);
1074
+	list_unlock(config.restreamer);
1062 1075
 }
1063 1076
 
1064 1077
 void do_reconf() {
1065
-	load_channels_config();
1066
-	spawn_proxy_threads();
1078
+	load_channels_config(&config);
1079
+	spawn_proxy_threads(&config);
1067 1080
 }
1068 1081
 
1069 1082
 void init_signals() {
@@ -1077,13 +1090,13 @@ void init_signals() {
1077 1090
 	signal(SIGTERM, signal_quit);
1078 1091
 }
1079 1092
 
1080
-void do_daemonize() {
1081
-	if (!pidfile)
1093
+void do_daemonize(struct config *cfg) {
1094
+	if (!cfg->pidfile)
1082 1095
 		return;
1083 1096
 	fprintf(stderr, "Daemonizing.\n");
1084 1097
 	pid_t pid = fork();
1085 1098
 	if (pid > 0) {
1086
-		FILE *F = fopen(pidfile,"w");
1099
+		FILE *F = fopen(cfg->pidfile,"w");
1087 1100
 		if (F) {
1088 1101
 			fprintf(F,"%i\n",pid);
1089 1102
 			fclose(F);
@@ -1098,25 +1111,26 @@ void do_daemonize() {
1098 1111
 }
1099 1112
 
1100 1113
 /* 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);
1114
+void init_logger(struct config *cfg) {
1115
+	if (cfg->syslog_active)
1116
+		fprintf(stderr, "Logging to %s:%d\n", cfg->loghost, cfg->logport);
1117
+	log_init(cfg->logident, cfg->syslog_active, cfg->pidfile == NULL, cfg->loghost, cfg->logport);
1105 1118
 }
1106 1119
 
1107 1120
 int main(int argc, char **argv) {
1108 1121
 	set_http_response_server_ident(server_sig, server_ver);
1109 1122
 	show_usage(1); // Show copyright and version
1110
-	init_vars();
1111
-	parse_options(argc, argv);
1112
-	do_daemonize();
1113
-	init_logger();
1123
+	init_vars(&config);
1124
+	parse_options(argc, argv, &config);
1125
+	do_daemonize(&config);
1126
+	init_logger(&config);
1114 1127
 	init_signals();
1115 1128
 
1116
-	LOGf("INIT : %s %s (%s)\n" , server_sig, server_ver, ident);
1129
+	LOGf("INIT : %s %s (%s)\n" , server_sig, server_ver, config.ident);
1117 1130
 
1118
-	load_channels_config();
1119
-	spawn_proxy_threads();
1131
+	load_channels_config(&config);
1132
+	spawn_proxy_threads(&config);
1133
+	web_server_start(&config);
1120 1134
 
1121 1135
 	do {
1122 1136
 		sleep(60);

+ 127
- 0
web_pages.c View File

@@ -0,0 +1,127 @@
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 <ctype.h>
24
+#include <unistd.h>
25
+
26
+#include "libfuncs/io.h"
27
+#include "libfuncs/log.h"
28
+#include "libfuncs/list.h"
29
+#include "libfuncs/http_response.h"
30
+
31
+#include "config.h"
32
+
33
+extern struct config *config;
34
+
35
+void cmd_index(int clientsock) {
36
+	send_200_ok(clientsock);
37
+	send_header_textplain(clientsock);
38
+	fdputs(clientsock, "\nHi from tomcast.\n");
39
+}
40
+
41
+void cmd_status(int clientsock) {
42
+	send_200_ok(clientsock);
43
+	send_header_textplain(clientsock);
44
+	fdputs(clientsock, "\n");
45
+
46
+	LNODE *l, *tmp;
47
+	struct config *cfg = get_config();
48
+
49
+	time_t now = time(NULL);
50
+	fdputsf(clientsock, "%-10s %-20s %8s %10s %-18s %-64s %s\n",
51
+		"# Status",
52
+		"DestAddr",
53
+		"ConnTime",
54
+		"ReadBytes",
55
+		"ChanName",
56
+		"ChanSource",
57
+		"ProxyStatus"
58
+	);
59
+	pthread_mutex_lock(&cfg->channels_lock);
60
+	list_lock(cfg->restreamer);
61
+	list_for_each(cfg->restreamer, l, tmp) {
62
+		char dest[32];
63
+		int conn_status = 0;
64
+		RESTREAMER *r = l->data;
65
+		pthread_rwlock_rdlock(&r->lock);
66
+		snprintf(dest, sizeof(dest), "%s:%d", r->channel->dest_host, r->channel->dest_port);
67
+		if (r->connected && r->conn_ts > 0 && r->read_bytes >= 1316)
68
+			conn_status = 1;
69
+		fdputsf(clientsock, "%-10s %-20s %8lu %10llu %-18s %-64s %s\n",
70
+			conn_status ? "CONN_OK" : "CONN_ERROR",
71
+			dest,
72
+			r->conn_ts ? now - r->conn_ts : 0,
73
+			r->read_bytes,
74
+			r->channel->name,
75
+			r->channel->source,
76
+			r->status
77
+		);
78
+		pthread_rwlock_unlock(&r->lock);
79
+	}
80
+	list_unlock(cfg->restreamer);
81
+	pthread_mutex_unlock(&cfg->channels_lock);
82
+}
83
+
84
+void cmd_getconfig(int clientsock) {
85
+	send_200_ok(clientsock);
86
+	send_header_textplain(clientsock);
87
+	fdputs(clientsock, "\n");
88
+
89
+	LNODE *l, *tmp;
90
+	struct config *cfg = get_config();
91
+
92
+	pthread_mutex_lock(&cfg->channels_lock);
93
+	list_lock(cfg->restreamer);
94
+	list_for_each(cfg->restreamer, l, tmp) {
95
+		RESTREAMER *r = l->data;
96
+		pthread_rwlock_rdlock(&r->lock);
97
+		int i;
98
+		for (i = 0; i < r->channel->num_src; i++) {
99
+			fdputsf(clientsock, "%s\t%s:%d\t%s\n",
100
+				r->channel->name,
101
+				r->channel->dest_host,
102
+				r->channel->dest_port,
103
+				r->channel->sources[i]
104
+			);
105
+		}
106
+		pthread_rwlock_unlock(&r->lock);
107
+	}
108
+	list_unlock(cfg->restreamer);
109
+	pthread_mutex_unlock(&cfg->channels_lock);
110
+}
111
+
112
+void cmd_reconnect(int clientsock) {
113
+	send_200_ok(clientsock);
114
+	send_header_textplain(clientsock);
115
+	struct config *cfg = get_config();
116
+	pthread_mutex_lock(&cfg->channels_lock);
117
+	fdputsf(clientsock, "\nReconnecting %d inputs.\n", cfg->chanconf->items);
118
+	pthread_mutex_unlock(&cfg->channels_lock);
119
+	do_reconnect();
120
+}
121
+
122
+void cmd_reload(int clientsock) {
123
+	send_200_ok(clientsock);
124
+	send_header_textplain(clientsock);
125
+	fdputs(clientsock, "\nReloading config\n");
126
+	do_reconf();
127
+}

+ 27
- 0
web_pages.h View File

@@ -0,0 +1,27 @@
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_status(int clientsock);
23
+void cmd_getconfig(int clientsock);
24
+void cmd_reconnect(int clientsock);
25
+void cmd_reload(int clientsock);
26
+
27
+#endif

+ 145
- 0
web_server.c View File

@@ -0,0 +1,145 @@
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,"getconfig")==path) {
132
+		cmd_getconfig(clientsock);
133
+	} else if (strstr(path,"reconnect")==path) {
134
+		cmd_reconnect(clientsock);
135
+	} else if (strstr(path,"reload")==path) {
136
+		cmd_reload(clientsock);
137
+	} else if (strstr(path,"status")==path) {
138
+		cmd_status(clientsock);
139
+	} else {
140
+		send_404_not_found(clientsock);
141
+	}
142
+
143
+	SHUTDOWN_CLIENT;
144
+}
145
+

+ 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