winlin

add hls config

@@ -9,6 +9,10 @@ chunk_size 65000; @@ -9,6 +9,10 @@ chunk_size 65000;
9 # vhost list, the __defaultVhost__ is the default vhost 9 # vhost list, the __defaultVhost__ is the default vhost
10 # for which cannot identify the required vhost. 10 # for which cannot identify the required vhost.
11 vhost __defaultVhost__ { 11 vhost __defaultVhost__ {
  12 + enabled on;
  13 + gop_cache on;
  14 + hls on;
  15 + hls_path ./hls;
12 } 16 }
13 # the vhost disabled. 17 # the vhost disabled.
14 vhost removed.vhost.com { 18 vhost removed.vhost.com {
@@ -17,6 +21,16 @@ vhost removed.vhost.com { @@ -17,6 +21,16 @@ vhost removed.vhost.com {
17 # default: on 21 # default: on
18 enabled off; 22 enabled off;
19 } 23 }
  24 +# the vhost with hls specified.
  25 +vhost no-hls.vhost.com {
  26 + # whether the hls is enabled.
  27 + # if off, donot write hls(ts and m3u8) when publish.
  28 + # default: on
  29 + hls on;
  30 + # the hls output path.
  31 + # default: ./hls
  32 + hls_path /data/nginx/html/hls;
  33 +}
20 # the vhost with hls disabled. 34 # the vhost with hls disabled.
21 vhost no-hls.vhost.com { 35 vhost no-hls.vhost.com {
22 # whether the hls is enabled. 36 # whether the hls is enabled.
1 -/*  
2 -The MIT License (MIT)  
3 -  
4 -Copyright (c) 2013 winlin  
5 -  
6 -Permission is hereby granted, free of charge, to any person obtaining a copy of  
7 -this software and associated documentation files (the "Software"), to deal in  
8 -the Software without restriction, including without limitation the rights to  
9 -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of  
10 -the Software, and to permit persons to whom the Software is furnished to do so,  
11 -subject to the following conditions:  
12 -  
13 -The above copyright notice and this permission notice shall be included in all  
14 -copies or substantial portions of the Software.  
15 -  
16 -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR  
17 -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS  
18 -FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR  
19 -COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER  
20 -IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN  
21 -CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.  
22 -*/  
23 -  
24 -#include <srs_core_config.hpp>  
25 -  
26 -#include <stdio.h>  
27 -#include <stdlib.h>  
28 -#include <errno.h>  
29 -#include <string.h>  
30 -// file operations.  
31 -#include <unistd.h>  
32 -#include <sys/types.h>  
33 -#include <sys/stat.h>  
34 -#include <fcntl.h>  
35 -  
36 -#include <vector>  
37 -#include <algorithm>  
38 -  
39 -#include <srs_core_error.hpp>  
40 -#include <srs_core_log.hpp>  
41 -#include <srs_core_autofree.hpp>  
42 -  
43 -#define FILE_OFFSET(fd) lseek(fd, 0, SEEK_CUR)  
44 -  
45 -int64_t FILE_SIZE(int fd)  
46 -{  
47 - int64_t pre = FILE_OFFSET(fd);  
48 - int64_t pos = lseek(fd, 0, SEEK_END);  
49 - lseek(fd, pre, SEEK_SET);  
50 - return pos;  
51 -}  
52 -  
53 -#define LF (char)0x0a  
54 -#define CR (char)0x0d  
55 -  
56 -bool is_common_space(char ch)  
57 -{  
58 - return (ch == ' ' || ch == '\t' || ch == CR || ch == LF);  
59 -}  
60 -  
61 -#define CONF_BUFFER_SIZE 4096  
62 -  
63 -SrsFileBuffer::SrsFileBuffer()  
64 -{  
65 - fd = -1;  
66 - line = 0;  
67 -  
68 - pos = last = start = new char[CONF_BUFFER_SIZE];  
69 - end = start + CONF_BUFFER_SIZE;  
70 -}  
71 -  
72 -SrsFileBuffer::~SrsFileBuffer()  
73 -{  
74 - if (fd > 0) {  
75 - close(fd);  
76 - }  
77 - srs_freepa(start);  
78 -}  
79 -  
80 -int SrsFileBuffer::open(const char* filename)  
81 -{  
82 - assert(fd == -1);  
83 -  
84 - if ((fd = ::open(filename, O_RDONLY, 0)) < 0) {  
85 - srs_error("open conf file error. errno=%d(%s)", errno, strerror(errno));  
86 - return ERROR_SYSTEM_CONFIG_INVALID;  
87 - }  
88 -  
89 - line = 1;  
90 -  
91 - return ERROR_SUCCESS;  
92 -}  
93 -  
94 -SrsConfDirective::SrsConfDirective()  
95 -{  
96 -}  
97 -  
98 -SrsConfDirective::~SrsConfDirective()  
99 -{  
100 - std::vector<SrsConfDirective*>::iterator it;  
101 - for (it = directives.begin(); it != directives.end(); ++it) {  
102 - SrsConfDirective* directive = *it;  
103 - srs_freep(directive);  
104 - }  
105 - directives.clear();  
106 -}  
107 -  
108 -std::string SrsConfDirective::arg0()  
109 -{  
110 - if (args.size() > 0) {  
111 - return args.at(0);  
112 - }  
113 -  
114 - return "";  
115 -}  
116 -  
117 -std::string SrsConfDirective::arg1()  
118 -{  
119 - if (args.size() > 1) {  
120 - return args.at(1);  
121 - }  
122 -  
123 - return "";  
124 -}  
125 -  
126 -std::string SrsConfDirective::arg2()  
127 -{  
128 - if (args.size() > 2) {  
129 - return args.at(2);  
130 - }  
131 -  
132 - return "";  
133 -}  
134 -  
135 -SrsConfDirective* SrsConfDirective::at(int index)  
136 -{  
137 - return directives.at(index);  
138 -}  
139 -  
140 -SrsConfDirective* SrsConfDirective::get(std::string _name)  
141 -{  
142 - std::vector<SrsConfDirective*>::iterator it;  
143 - for (it = directives.begin(); it != directives.end(); ++it) {  
144 - SrsConfDirective* directive = *it;  
145 - if (directive->name == _name) {  
146 - return directive;  
147 - }  
148 - }  
149 -  
150 - return NULL;  
151 -}  
152 -  
153 -int SrsConfDirective::parse(const char* filename)  
154 -{  
155 - int ret = ERROR_SUCCESS;  
156 -  
157 - SrsFileBuffer buffer;  
158 -  
159 - if ((ret = buffer.open(filename)) != ERROR_SUCCESS) {  
160 - return ret;  
161 - }  
162 -  
163 - return parse_conf(&buffer, parse_file);  
164 -}  
165 -  
166 -// see: ngx_conf_parse  
167 -int SrsConfDirective::parse_conf(SrsFileBuffer* buffer, SrsDirectiveType type)  
168 -{  
169 - int ret = ERROR_SUCCESS;  
170 -  
171 - while (true) {  
172 - std::vector<std::string> args;  
173 - ret = read_token(buffer, args);  
174 -  
175 - /**  
176 - * ret maybe:  
177 - * ERROR_SYSTEM_CONFIG_INVALID error.  
178 - * ERROR_SYSTEM_CONFIG_DIRECTIVE directive terminated by ';' found  
179 - * ERROR_SYSTEM_CONFIG_BLOCK_START token terminated by '{' found  
180 - * ERROR_SYSTEM_CONFIG_BLOCK_END the '}' found  
181 - * ERROR_SYSTEM_CONFIG_EOF the config file is done  
182 - */  
183 - if (ret == ERROR_SYSTEM_CONFIG_INVALID) {  
184 - return ret;  
185 - }  
186 - if (ret == ERROR_SYSTEM_CONFIG_BLOCK_END) {  
187 - if (type != parse_block) {  
188 - srs_error("line %d: unexpected \"}\"", buffer->line);  
189 - return ret;  
190 - }  
191 - return ERROR_SUCCESS;  
192 - }  
193 - if (ret == ERROR_SYSTEM_CONFIG_EOF) {  
194 - if (type == parse_block) {  
195 - srs_error("line %d: unexpected end of file, expecting \"}\"", buffer->line);  
196 - return ret;  
197 - }  
198 - return ERROR_SUCCESS;  
199 - }  
200 -  
201 - if (args.empty()) {  
202 - srs_error("line %d: empty directive.", buffer->line);  
203 - return ret;  
204 - }  
205 -  
206 - // build directive tree.  
207 - SrsConfDirective* directive = new SrsConfDirective();  
208 -  
209 - directive->conf_line = buffer->line;  
210 - directive->name = args[0];  
211 - args.erase(args.begin());  
212 - directive->args.swap(args);  
213 -  
214 - directives.push_back(directive);  
215 -  
216 - if (ret == ERROR_SYSTEM_CONFIG_BLOCK_START) {  
217 - if ((ret = directive->parse_conf(buffer, parse_block)) != ERROR_SUCCESS) {  
218 - return ret;  
219 - }  
220 - }  
221 - }  
222 -  
223 - return ret;  
224 -}  
225 -  
226 -// see: ngx_conf_read_token  
227 -int SrsConfDirective::read_token(SrsFileBuffer* buffer, std::vector<std::string>& args)  
228 -{  
229 - int ret = ERROR_SUCCESS;  
230 -  
231 - char* pstart = buffer->pos;  
232 - int startline = buffer->line;  
233 -  
234 - bool sharp_comment = false;  
235 -  
236 - bool d_quoted = false;  
237 - bool s_quoted = false;  
238 -  
239 - bool need_space = false;  
240 - bool last_space = true;  
241 -  
242 - while (true) {  
243 - if ((ret = refill_buffer(buffer, d_quoted, s_quoted, startline, pstart)) != ERROR_SUCCESS) {  
244 - if (!args.empty() || !last_space) {  
245 - srs_error("line %d: unexpected end of file, expecting ; or \"}\"", buffer->line);  
246 - return ERROR_SYSTEM_CONFIG_INVALID;  
247 - }  
248 - return ret;  
249 - }  
250 -  
251 - char ch = *buffer->pos++;  
252 -  
253 - if (ch == LF) {  
254 - buffer->line++;  
255 - sharp_comment = false;  
256 - }  
257 -  
258 - if (sharp_comment) {  
259 - continue;  
260 - }  
261 -  
262 - if (need_space) {  
263 - if (is_common_space(ch)) {  
264 - last_space = true;  
265 - need_space = false;  
266 - continue;  
267 - }  
268 - if (ch == ';') {  
269 - return ERROR_SYSTEM_CONFIG_DIRECTIVE;  
270 - }  
271 - if (ch == '{') {  
272 - return ERROR_SYSTEM_CONFIG_BLOCK_START;  
273 - }  
274 - srs_error("line %d: unexpected '%c'", buffer->line, ch);  
275 - return ERROR_SYSTEM_CONFIG_INVALID;  
276 - }  
277 -  
278 - // last charecter is space.  
279 - if (last_space) {  
280 - if (is_common_space(ch)) {  
281 - continue;  
282 - }  
283 - pstart = buffer->pos - 1;  
284 - startline = buffer->line;  
285 - switch (ch) {  
286 - case ';':  
287 - if (args.size() == 0) {  
288 - srs_error("line %d: unexpected ';'", buffer->line);  
289 - return ERROR_SYSTEM_CONFIG_INVALID;  
290 - }  
291 - return ERROR_SYSTEM_CONFIG_DIRECTIVE;  
292 - case '{':  
293 - if (args.size() == 0) {  
294 - srs_error("line %d: unexpected '{'", buffer->line);  
295 - return ERROR_SYSTEM_CONFIG_INVALID;  
296 - }  
297 - return ERROR_SYSTEM_CONFIG_BLOCK_START;  
298 - case '}':  
299 - if (args.size() != 0) {  
300 - srs_error("line %d: unexpected '}'", buffer->line);  
301 - return ERROR_SYSTEM_CONFIG_INVALID;  
302 - }  
303 - return ERROR_SYSTEM_CONFIG_BLOCK_END;  
304 - case '#':  
305 - sharp_comment = 1;  
306 - continue;  
307 - case '"':  
308 - pstart++;  
309 - d_quoted = true;  
310 - last_space = 0;  
311 - continue;  
312 - case '\'':  
313 - pstart++;  
314 - s_quoted = true;  
315 - last_space = 0;  
316 - continue;  
317 - default:  
318 - last_space = 0;  
319 - continue;  
320 - }  
321 - } else {  
322 - // last charecter is not space  
323 - bool found = false;  
324 - if (d_quoted) {  
325 - if (ch == '"') {  
326 - d_quoted = false;  
327 - need_space = true;  
328 - found = true;  
329 - }  
330 - } else if (s_quoted) {  
331 - if (ch == '\'') {  
332 - s_quoted = false;  
333 - need_space = true;  
334 - found = true;  
335 - }  
336 - } else if (is_common_space(ch) || ch == ';' || ch == '{') {  
337 - last_space = true;  
338 - found = 1;  
339 - }  
340 -  
341 - if (found) {  
342 - int len = buffer->pos - pstart;  
343 - char* word = new char[len];  
344 - memcpy(word, pstart, len);  
345 - word[len - 1] = 0;  
346 -  
347 - args.push_back(word);  
348 - srs_freepa(word);  
349 -  
350 - if (ch == ';') {  
351 - return ERROR_SYSTEM_CONFIG_DIRECTIVE;  
352 - }  
353 - if (ch == '{') {  
354 - return ERROR_SYSTEM_CONFIG_BLOCK_START;  
355 - }  
356 - }  
357 - }  
358 - }  
359 -  
360 - return ret;  
361 -}  
362 -  
363 -int SrsConfDirective::refill_buffer(SrsFileBuffer* buffer, bool d_quoted, bool s_quoted, int startline, char*& pstart)  
364 -{  
365 - int ret = ERROR_SUCCESS;  
366 -  
367 - if (buffer->pos < buffer->last) {  
368 - return ret;  
369 - }  
370 -  
371 - int size = FILE_SIZE(buffer->fd) - FILE_OFFSET(buffer->fd);  
372 -  
373 - if (size <= 0) {  
374 - return ERROR_SYSTEM_CONFIG_EOF;  
375 - }  
376 -  
377 - int len = buffer->pos - buffer->start;  
378 - if (len >= CONF_BUFFER_SIZE) {  
379 - buffer->line = startline;  
380 -  
381 - if (!d_quoted && !s_quoted) {  
382 - srs_error("line %d: too long parameter \"%*s...\" started",  
383 - buffer->line, 10, buffer->start);  
384 -  
385 - } else {  
386 - srs_error("line %d: too long parameter, "  
387 - "probably missing terminating '%c' character", buffer->line, d_quoted? '"':'\'');  
388 - }  
389 - return ERROR_SYSTEM_CONFIG_INVALID;  
390 - }  
391 -  
392 - if (len) {  
393 - memmove(buffer->start, pstart, len);  
394 - }  
395 -  
396 - size = srs_min(size, buffer->end - (buffer->start + len));  
397 - int n = read(buffer->fd, buffer->start + len, size);  
398 - if (n != size) {  
399 - srs_error("read file read error. expect %d, actual %d bytes.", size, n);  
400 - return ERROR_SYSTEM_CONFIG_INVALID;  
401 - }  
402 -  
403 - buffer->pos = buffer->start + len;  
404 - buffer->last = buffer->pos + n;  
405 - pstart = buffer->start;  
406 -  
407 - return ret;  
408 -}  
409 -  
410 -SrsConfig* config = new SrsConfig();  
411 -  
412 -SrsConfig::SrsConfig()  
413 -{  
414 - show_help = false;  
415 - show_version = false;  
416 -  
417 - root = new SrsConfDirective();  
418 - root->conf_line = 0;  
419 - root->name = "root";  
420 -}  
421 -  
422 -SrsConfig::~SrsConfig()  
423 -{  
424 - srs_freep(root);  
425 -}  
426 -  
427 -int SrsConfig::reload()  
428 -{  
429 - int ret = ERROR_SUCCESS;  
430 -  
431 - SrsConfig conf;  
432 - if ((ret = conf.parse_file(config_file.c_str())) != ERROR_SUCCESS) {  
433 - srs_error("config reloader parse file failed. ret=%d", ret);  
434 - return ret;  
435 - }  
436 - srs_info("config reloader parse file success.");  
437 -  
438 - // store current root to old_root,  
439 - // and reap the root from conf to current root.  
440 - SrsConfDirective* old_root = root;  
441 - SrsAutoFree(SrsConfDirective, old_root, false);  
442 -  
443 - root = conf.root;  
444 - conf.root = NULL;  
445 -  
446 - // merge config.  
447 - std::vector<SrsReloadHandler*>::iterator it;  
448 -  
449 - // merge config: listen  
450 - if (!srs_directive_equals(root->get("listen"), old_root->get("listen"))) {  
451 - for (it = subscribes.begin(); it != subscribes.end(); ++it) {  
452 - SrsReloadHandler* subscribe = *it;  
453 - if ((ret = subscribe->on_reload_listen()) != ERROR_SUCCESS) {  
454 - srs_error("notify subscribes reload listen failed. ret=%d", ret);  
455 - return ret;  
456 - }  
457 - }  
458 - srs_trace("reload listen success.");  
459 - }  
460 - // merge config: pithy_print  
461 - if (!srs_directive_equals(root->get("pithy_print"), old_root->get("pithy_print"))) {  
462 - for (it = subscribes.begin(); it != subscribes.end(); ++it) {  
463 - SrsReloadHandler* subscribe = *it;  
464 - if ((ret = subscribe->on_reload_pithy_print()) != ERROR_SUCCESS) {  
465 - srs_error("notify subscribes pithy_print listen failed. ret=%d", ret);  
466 - return ret;  
467 - }  
468 - }  
469 - srs_trace("reload pithy_print success.");  
470 - }  
471 -  
472 - return ret;  
473 -}  
474 -  
475 -void SrsConfig::subscribe(SrsReloadHandler* handler)  
476 -{  
477 - std::vector<SrsReloadHandler*>::iterator it;  
478 -  
479 - it = std::find(subscribes.begin(), subscribes.end(), handler);  
480 - if (it != subscribes.end()) {  
481 - return;  
482 - }  
483 -  
484 - subscribes.push_back(handler);  
485 -}  
486 -  
487 -void SrsConfig::unsubscribe(SrsReloadHandler* handler)  
488 -{  
489 - std::vector<SrsReloadHandler*>::iterator it;  
490 -  
491 - it = std::find(subscribes.begin(), subscribes.end(), handler);  
492 - if (it == subscribes.end()) {  
493 - return;  
494 - }  
495 -  
496 - subscribes.erase(it);  
497 -}  
498 -  
499 -// see: ngx_get_options  
500 -int SrsConfig::parse_options(int argc, char** argv)  
501 -{  
502 - int ret = ERROR_SUCCESS;  
503 -  
504 - for (int i = 1; i < argc; i++) {  
505 - if ((ret = parse_argv(i, argv)) != ERROR_SUCCESS) {  
506 - return ret;  
507 - }  
508 - }  
509 -  
510 - if (show_help) {  
511 - print_help(argv);  
512 - }  
513 -  
514 - if (show_version) {  
515 - printf("%s\n", RTMP_SIG_SRS_VERSION);  
516 - }  
517 -  
518 - if (show_help || show_version) {  
519 - exit(0);  
520 - }  
521 -  
522 - if (config_file.empty()) {  
523 - ret = ERROR_SYSTEM_CONFIG_INVALID;  
524 - srs_error("config file not specified, see help: %s -h, ret=%d", argv[0], ret);  
525 - return ret;  
526 - }  
527 -  
528 - return parse_file(config_file.c_str());  
529 -}  
530 -  
531 -SrsConfDirective* SrsConfig::get_vhost(std::string vhost)  
532 -{  
533 - srs_assert(root);  
534 -  
535 - for (int i = 0; i < (int)root->directives.size(); i++) {  
536 - SrsConfDirective* conf = root->at(i);  
537 -  
538 - if (conf->name != "vhost") {  
539 - continue;  
540 - }  
541 -  
542 - if (conf->arg0() == vhost) {  
543 - return conf;  
544 - }  
545 - }  
546 -  
547 - if (vhost != RTMP_VHOST_DEFAULT) {  
548 - return get_vhost(RTMP_VHOST_DEFAULT);  
549 - }  
550 -  
551 - return NULL;  
552 -}  
553 -  
554 -SrsConfDirective* SrsConfig::get_gop_cache(std::string vhost)  
555 -{  
556 - SrsConfDirective* conf = get_vhost(vhost);  
557 -  
558 - if (!conf) {  
559 - return NULL;  
560 - }  
561 -  
562 - return conf->get("gop_cache");  
563 -}  
564 -  
565 -SrsConfDirective* SrsConfig::get_hls(std::string vhost)  
566 -{  
567 - SrsConfDirective* conf = get_vhost(vhost);  
568 -  
569 - if (!conf) {  
570 - return NULL;  
571 - }  
572 -  
573 - return conf->get("hls");  
574 -}  
575 -  
576 -SrsConfDirective* SrsConfig::get_refer(std::string vhost)  
577 -{  
578 - SrsConfDirective* conf = get_vhost(vhost);  
579 -  
580 - if (!conf) {  
581 - return NULL;  
582 - }  
583 -  
584 - return conf->get("refer");  
585 -}  
586 -  
587 -SrsConfDirective* SrsConfig::get_refer_play(std::string vhost)  
588 -{  
589 - SrsConfDirective* conf = get_vhost(vhost);  
590 -  
591 - if (!conf) {  
592 - return NULL;  
593 - }  
594 -  
595 - return conf->get("refer_play");  
596 -}  
597 -  
598 -SrsConfDirective* SrsConfig::get_refer_publish(std::string vhost)  
599 -{  
600 - SrsConfDirective* conf = get_vhost(vhost);  
601 -  
602 - if (!conf) {  
603 - return NULL;  
604 - }  
605 -  
606 - return conf->get("refer_publish");  
607 -}  
608 -  
609 -SrsConfDirective* SrsConfig::get_listen()  
610 -{  
611 - return root->get("listen");  
612 -}  
613 -  
614 -SrsConfDirective* SrsConfig::get_chunk_size()  
615 -{  
616 - return root->get("chunk_size");  
617 -}  
618 -  
619 -SrsConfDirective* SrsConfig::get_pithy_print_publish()  
620 -{  
621 - SrsConfDirective* pithy = root->get("pithy_print");  
622 - if (!pithy) {  
623 - return NULL;  
624 - }  
625 -  
626 - return pithy->get("publish");  
627 -}  
628 -  
629 -SrsConfDirective* SrsConfig::get_pithy_print_play()  
630 -{  
631 - SrsConfDirective* pithy = root->get("pithy_print");  
632 - if (!pithy) {  
633 - return NULL;  
634 - }  
635 -  
636 - return pithy->get("play");  
637 -}  
638 -  
639 -int SrsConfig::parse_file(const char* filename)  
640 -{  
641 - int ret = ERROR_SUCCESS;  
642 -  
643 - config_file = filename;  
644 -  
645 - if (config_file.empty()) {  
646 - return ERROR_SYSTEM_CONFIG_INVALID;  
647 - }  
648 -  
649 - if ((ret = root->parse(config_file.c_str())) != ERROR_SUCCESS) {  
650 - return ret;  
651 - }  
652 -  
653 - SrsConfDirective* conf = NULL;  
654 - if ((conf = get_listen()) == NULL || conf->args.size() == 0) {  
655 - ret = ERROR_SYSTEM_CONFIG_INVALID;  
656 - srs_error("line %d: conf error, "  
657 - "directive \"listen\" is empty, ret=%d", (conf? conf->conf_line:0), ret);  
658 - return ret;  
659 - }  
660 -  
661 - return ret;  
662 -}  
663 -  
664 -int SrsConfig::parse_argv(int& i, char** argv)  
665 -{  
666 - int ret = ERROR_SUCCESS;  
667 -  
668 - char* p = argv[i];  
669 -  
670 - if (*p++ != '-') {  
671 - ret = ERROR_SYSTEM_CONFIG_INVALID;  
672 - srs_error("invalid options(index=%d, value=%s), "  
673 - "must starts with -, see help: %s -h, ret=%d", i, argv[i], argv[0], ret);  
674 - return ret;  
675 - }  
676 -  
677 - while (*p) {  
678 - switch (*p++) {  
679 - case '?':  
680 - case 'h':  
681 - show_help = true;  
682 - break;  
683 - case 'v':  
684 - case 'V':  
685 - show_version = true;  
686 - break;  
687 - case 'c':  
688 - if (*p) {  
689 - config_file = p;  
690 - return ret;  
691 - }  
692 - if (argv[++i]) {  
693 - config_file = argv[i];  
694 - return ret;  
695 - }  
696 - ret = ERROR_SYSTEM_CONFIG_INVALID;  
697 - srs_error("option \"-c\" requires parameter, ret=%d", ret);  
698 - return ret;  
699 - default:  
700 - ret = ERROR_SYSTEM_CONFIG_INVALID;  
701 - srs_error("invalid option: \"%c\", see help: %s -h, ret=%d", *(p - 1), argv[0], ret);  
702 - return ret;  
703 - }  
704 - }  
705 -  
706 - return ret;  
707 -}  
708 -  
709 -void SrsConfig::print_help(char** argv)  
710 -{  
711 - printf(RTMP_SIG_SRS_NAME" "RTMP_SIG_SRS_VERSION  
712 - " Copyright (c) 2013 winlin\n"  
713 - "Usage: %s [-h?vV] [-c <filename>]\n"  
714 - "\n"  
715 - "Options:\n"  
716 - " -?-h : show help\n"  
717 - " -v-V : show version and exit\n"  
718 - " -c filename : set configuration file\n"  
719 - "\n"  
720 - RTMP_SIG_SRS_WEB"\n"  
721 - RTMP_SIG_SRS_URL"\n"  
722 - "Email: "RTMP_SIG_SRS_EMAIL"\n",  
723 - argv[0]);  
724 -}  
725 -  
726 -bool srs_directive_equals(SrsConfDirective* a, SrsConfDirective* b)  
727 -{  
728 - if (!a || !b) {  
729 - return false;  
730 - }  
731 -  
732 - if (a->name != b->name) {  
733 - return false;  
734 - }  
735 -  
736 - if (a->args.size() != b->args.size()) {  
737 - return false;  
738 - }  
739 -  
740 - for (int i = 0; i < (int)a->args.size(); i++) {  
741 - if (a->args.at(i) != b->args.at(i)) {  
742 - return false;  
743 - }  
744 - }  
745 -  
746 - if (a->directives.size() != b->directives.size()) {  
747 - return false;  
748 - }  
749 -  
750 - for (int i = 0; i < (int)a->directives.size(); i++) {  
751 - SrsConfDirective* a0 = a->at(i);  
752 - SrsConfDirective* b0 = b->at(i);  
753 -  
754 - if (!srs_directive_equals(a0, b0)) {  
755 - return false;  
756 - }  
757 - }  
758 -  
759 - return true;  
760 -}  
761 - 1 +/*
  2 +The MIT License (MIT)
  3 +
  4 +Copyright (c) 2013 winlin
  5 +
  6 +Permission is hereby granted, free of charge, to any person obtaining a copy of
  7 +this software and associated documentation files (the "Software"), to deal in
  8 +the Software without restriction, including without limitation the rights to
  9 +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
  10 +the Software, and to permit persons to whom the Software is furnished to do so,
  11 +subject to the following conditions:
  12 +
  13 +The above copyright notice and this permission notice shall be included in all
  14 +copies or substantial portions of the Software.
  15 +
  16 +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  17 +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
  18 +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
  19 +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
  20 +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  21 +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  22 +*/
  23 +
  24 +#include <srs_core_config.hpp>
  25 +
  26 +#include <stdio.h>
  27 +#include <stdlib.h>
  28 +#include <errno.h>
  29 +#include <string.h>
  30 +// file operations.
  31 +#include <unistd.h>
  32 +#include <sys/types.h>
  33 +#include <sys/stat.h>
  34 +#include <fcntl.h>
  35 +
  36 +#include <vector>
  37 +#include <algorithm>
  38 +
  39 +#include <srs_core_error.hpp>
  40 +#include <srs_core_log.hpp>
  41 +#include <srs_core_autofree.hpp>
  42 +
  43 +#define FILE_OFFSET(fd) lseek(fd, 0, SEEK_CUR)
  44 +
  45 +int64_t FILE_SIZE(int fd)
  46 +{
  47 + int64_t pre = FILE_OFFSET(fd);
  48 + int64_t pos = lseek(fd, 0, SEEK_END);
  49 + lseek(fd, pre, SEEK_SET);
  50 + return pos;
  51 +}
  52 +
  53 +#define LF (char)0x0a
  54 +#define CR (char)0x0d
  55 +
  56 +bool is_common_space(char ch)
  57 +{
  58 + return (ch == ' ' || ch == '\t' || ch == CR || ch == LF);
  59 +}
  60 +
  61 +#define CONF_BUFFER_SIZE 4096
  62 +
  63 +SrsFileBuffer::SrsFileBuffer()
  64 +{
  65 + fd = -1;
  66 + line = 0;
  67 +
  68 + pos = last = start = new char[CONF_BUFFER_SIZE];
  69 + end = start + CONF_BUFFER_SIZE;
  70 +}
  71 +
  72 +SrsFileBuffer::~SrsFileBuffer()
  73 +{
  74 + if (fd > 0) {
  75 + close(fd);
  76 + }
  77 + srs_freepa(start);
  78 +}
  79 +
  80 +int SrsFileBuffer::open(const char* filename)
  81 +{
  82 + assert(fd == -1);
  83 +
  84 + if ((fd = ::open(filename, O_RDONLY, 0)) < 0) {
  85 + srs_error("open conf file error. errno=%d(%s)", errno, strerror(errno));
  86 + return ERROR_SYSTEM_CONFIG_INVALID;
  87 + }
  88 +
  89 + line = 1;
  90 +
  91 + return ERROR_SUCCESS;
  92 +}
  93 +
  94 +SrsConfDirective::SrsConfDirective()
  95 +{
  96 +}
  97 +
  98 +SrsConfDirective::~SrsConfDirective()
  99 +{
  100 + std::vector<SrsConfDirective*>::iterator it;
  101 + for (it = directives.begin(); it != directives.end(); ++it) {
  102 + SrsConfDirective* directive = *it;
  103 + srs_freep(directive);
  104 + }
  105 + directives.clear();
  106 +}
  107 +
  108 +std::string SrsConfDirective::arg0()
  109 +{
  110 + if (args.size() > 0) {
  111 + return args.at(0);
  112 + }
  113 +
  114 + return "";
  115 +}
  116 +
  117 +std::string SrsConfDirective::arg1()
  118 +{
  119 + if (args.size() > 1) {
  120 + return args.at(1);
  121 + }
  122 +
  123 + return "";
  124 +}
  125 +
  126 +std::string SrsConfDirective::arg2()
  127 +{
  128 + if (args.size() > 2) {
  129 + return args.at(2);
  130 + }
  131 +
  132 + return "";
  133 +}
  134 +
  135 +SrsConfDirective* SrsConfDirective::at(int index)
  136 +{
  137 + return directives.at(index);
  138 +}
  139 +
  140 +SrsConfDirective* SrsConfDirective::get(std::string _name)
  141 +{
  142 + std::vector<SrsConfDirective*>::iterator it;
  143 + for (it = directives.begin(); it != directives.end(); ++it) {
  144 + SrsConfDirective* directive = *it;
  145 + if (directive->name == _name) {
  146 + return directive;
  147 + }
  148 + }
  149 +
  150 + return NULL;
  151 +}
  152 +
  153 +int SrsConfDirective::parse(const char* filename)
  154 +{
  155 + int ret = ERROR_SUCCESS;
  156 +
  157 + SrsFileBuffer buffer;
  158 +
  159 + if ((ret = buffer.open(filename)) != ERROR_SUCCESS) {
  160 + return ret;
  161 + }
  162 +
  163 + return parse_conf(&buffer, parse_file);
  164 +}
  165 +
  166 +// see: ngx_conf_parse
  167 +int SrsConfDirective::parse_conf(SrsFileBuffer* buffer, SrsDirectiveType type)
  168 +{
  169 + int ret = ERROR_SUCCESS;
  170 +
  171 + while (true) {
  172 + std::vector<std::string> args;
  173 + ret = read_token(buffer, args);
  174 +
  175 + /**
  176 + * ret maybe:
  177 + * ERROR_SYSTEM_CONFIG_INVALID error.
  178 + * ERROR_SYSTEM_CONFIG_DIRECTIVE directive terminated by ';' found
  179 + * ERROR_SYSTEM_CONFIG_BLOCK_START token terminated by '{' found
  180 + * ERROR_SYSTEM_CONFIG_BLOCK_END the '}' found
  181 + * ERROR_SYSTEM_CONFIG_EOF the config file is done
  182 + */
  183 + if (ret == ERROR_SYSTEM_CONFIG_INVALID) {
  184 + return ret;
  185 + }
  186 + if (ret == ERROR_SYSTEM_CONFIG_BLOCK_END) {
  187 + if (type != parse_block) {
  188 + srs_error("line %d: unexpected \"}\"", buffer->line);
  189 + return ret;
  190 + }
  191 + return ERROR_SUCCESS;
  192 + }
  193 + if (ret == ERROR_SYSTEM_CONFIG_EOF) {
  194 + if (type == parse_block) {
  195 + srs_error("line %d: unexpected end of file, expecting \"}\"", buffer->line);
  196 + return ret;
  197 + }
  198 + return ERROR_SUCCESS;
  199 + }
  200 +
  201 + if (args.empty()) {
  202 + srs_error("line %d: empty directive.", buffer->line);
  203 + return ret;
  204 + }
  205 +
  206 + // build directive tree.
  207 + SrsConfDirective* directive = new SrsConfDirective();
  208 +
  209 + directive->conf_line = buffer->line;
  210 + directive->name = args[0];
  211 + args.erase(args.begin());
  212 + directive->args.swap(args);
  213 +
  214 + directives.push_back(directive);
  215 +
  216 + if (ret == ERROR_SYSTEM_CONFIG_BLOCK_START) {
  217 + if ((ret = directive->parse_conf(buffer, parse_block)) != ERROR_SUCCESS) {
  218 + return ret;
  219 + }
  220 + }
  221 + }
  222 +
  223 + return ret;
  224 +}
  225 +
  226 +// see: ngx_conf_read_token
  227 +int SrsConfDirective::read_token(SrsFileBuffer* buffer, std::vector<std::string>& args)
  228 +{
  229 + int ret = ERROR_SUCCESS;
  230 +
  231 + char* pstart = buffer->pos;
  232 + int startline = buffer->line;
  233 +
  234 + bool sharp_comment = false;
  235 +
  236 + bool d_quoted = false;
  237 + bool s_quoted = false;
  238 +
  239 + bool need_space = false;
  240 + bool last_space = true;
  241 +
  242 + while (true) {
  243 + if ((ret = refill_buffer(buffer, d_quoted, s_quoted, startline, pstart)) != ERROR_SUCCESS) {
  244 + if (!args.empty() || !last_space) {
  245 + srs_error("line %d: unexpected end of file, expecting ; or \"}\"", buffer->line);
  246 + return ERROR_SYSTEM_CONFIG_INVALID;
  247 + }
  248 + return ret;
  249 + }
  250 +
  251 + char ch = *buffer->pos++;
  252 +
  253 + if (ch == LF) {
  254 + buffer->line++;
  255 + sharp_comment = false;
  256 + }
  257 +
  258 + if (sharp_comment) {
  259 + continue;
  260 + }
  261 +
  262 + if (need_space) {
  263 + if (is_common_space(ch)) {
  264 + last_space = true;
  265 + need_space = false;
  266 + continue;
  267 + }
  268 + if (ch == ';') {
  269 + return ERROR_SYSTEM_CONFIG_DIRECTIVE;
  270 + }
  271 + if (ch == '{') {
  272 + return ERROR_SYSTEM_CONFIG_BLOCK_START;
  273 + }
  274 + srs_error("line %d: unexpected '%c'", buffer->line, ch);
  275 + return ERROR_SYSTEM_CONFIG_INVALID;
  276 + }
  277 +
  278 + // last charecter is space.
  279 + if (last_space) {
  280 + if (is_common_space(ch)) {
  281 + continue;
  282 + }
  283 + pstart = buffer->pos - 1;
  284 + startline = buffer->line;
  285 + switch (ch) {
  286 + case ';':
  287 + if (args.size() == 0) {
  288 + srs_error("line %d: unexpected ';'", buffer->line);
  289 + return ERROR_SYSTEM_CONFIG_INVALID;
  290 + }
  291 + return ERROR_SYSTEM_CONFIG_DIRECTIVE;
  292 + case '{':
  293 + if (args.size() == 0) {
  294 + srs_error("line %d: unexpected '{'", buffer->line);
  295 + return ERROR_SYSTEM_CONFIG_INVALID;
  296 + }
  297 + return ERROR_SYSTEM_CONFIG_BLOCK_START;
  298 + case '}':
  299 + if (args.size() != 0) {
  300 + srs_error("line %d: unexpected '}'", buffer->line);
  301 + return ERROR_SYSTEM_CONFIG_INVALID;
  302 + }
  303 + return ERROR_SYSTEM_CONFIG_BLOCK_END;
  304 + case '#':
  305 + sharp_comment = 1;
  306 + continue;
  307 + case '"':
  308 + pstart++;
  309 + d_quoted = true;
  310 + last_space = 0;
  311 + continue;
  312 + case '\'':
  313 + pstart++;
  314 + s_quoted = true;
  315 + last_space = 0;
  316 + continue;
  317 + default:
  318 + last_space = 0;
  319 + continue;
  320 + }
  321 + } else {
  322 + // last charecter is not space
  323 + bool found = false;
  324 + if (d_quoted) {
  325 + if (ch == '"') {
  326 + d_quoted = false;
  327 + need_space = true;
  328 + found = true;
  329 + }
  330 + } else if (s_quoted) {
  331 + if (ch == '\'') {
  332 + s_quoted = false;
  333 + need_space = true;
  334 + found = true;
  335 + }
  336 + } else if (is_common_space(ch) || ch == ';' || ch == '{') {
  337 + last_space = true;
  338 + found = 1;
  339 + }
  340 +
  341 + if (found) {
  342 + int len = buffer->pos - pstart;
  343 + char* word = new char[len];
  344 + memcpy(word, pstart, len);
  345 + word[len - 1] = 0;
  346 +
  347 + args.push_back(word);
  348 + srs_freepa(word);
  349 +
  350 + if (ch == ';') {
  351 + return ERROR_SYSTEM_CONFIG_DIRECTIVE;
  352 + }
  353 + if (ch == '{') {
  354 + return ERROR_SYSTEM_CONFIG_BLOCK_START;
  355 + }
  356 + }
  357 + }
  358 + }
  359 +
  360 + return ret;
  361 +}
  362 +
  363 +int SrsConfDirective::refill_buffer(SrsFileBuffer* buffer, bool d_quoted, bool s_quoted, int startline, char*& pstart)
  364 +{
  365 + int ret = ERROR_SUCCESS;
  366 +
  367 + if (buffer->pos < buffer->last) {
  368 + return ret;
  369 + }
  370 +
  371 + int size = FILE_SIZE(buffer->fd) - FILE_OFFSET(buffer->fd);
  372 +
  373 + if (size <= 0) {
  374 + return ERROR_SYSTEM_CONFIG_EOF;
  375 + }
  376 +
  377 + int len = buffer->pos - buffer->start;
  378 + if (len >= CONF_BUFFER_SIZE) {
  379 + buffer->line = startline;
  380 +
  381 + if (!d_quoted && !s_quoted) {
  382 + srs_error("line %d: too long parameter \"%*s...\" started",
  383 + buffer->line, 10, buffer->start);
  384 +
  385 + } else {
  386 + srs_error("line %d: too long parameter, "
  387 + "probably missing terminating '%c' character", buffer->line, d_quoted? '"':'\'');
  388 + }
  389 + return ERROR_SYSTEM_CONFIG_INVALID;
  390 + }
  391 +
  392 + if (len) {
  393 + memmove(buffer->start, pstart, len);
  394 + }
  395 +
  396 + size = srs_min(size, buffer->end - (buffer->start + len));
  397 + int n = read(buffer->fd, buffer->start + len, size);
  398 + if (n != size) {
  399 + srs_error("read file read error. expect %d, actual %d bytes.", size, n);
  400 + return ERROR_SYSTEM_CONFIG_INVALID;
  401 + }
  402 +
  403 + buffer->pos = buffer->start + len;
  404 + buffer->last = buffer->pos + n;
  405 + pstart = buffer->start;
  406 +
  407 + return ret;
  408 +}
  409 +
  410 +SrsConfig* config = new SrsConfig();
  411 +
  412 +SrsConfig::SrsConfig()
  413 +{
  414 + show_help = false;
  415 + show_version = false;
  416 +
  417 + root = new SrsConfDirective();
  418 + root->conf_line = 0;
  419 + root->name = "root";
  420 +}
  421 +
  422 +SrsConfig::~SrsConfig()
  423 +{
  424 + srs_freep(root);
  425 +}
  426 +
  427 +int SrsConfig::reload()
  428 +{
  429 + int ret = ERROR_SUCCESS;
  430 +
  431 + SrsConfig conf;
  432 + if ((ret = conf.parse_file(config_file.c_str())) != ERROR_SUCCESS) {
  433 + srs_error("config reloader parse file failed. ret=%d", ret);
  434 + return ret;
  435 + }
  436 + srs_info("config reloader parse file success.");
  437 +
  438 + // store current root to old_root,
  439 + // and reap the root from conf to current root.
  440 + SrsConfDirective* old_root = root;
  441 + SrsAutoFree(SrsConfDirective, old_root, false);
  442 +
  443 + root = conf.root;
  444 + conf.root = NULL;
  445 +
  446 + // merge config.
  447 + std::vector<SrsReloadHandler*>::iterator it;
  448 +
  449 + // merge config: listen
  450 + if (!srs_directive_equals(root->get("listen"), old_root->get("listen"))) {
  451 + for (it = subscribes.begin(); it != subscribes.end(); ++it) {
  452 + SrsReloadHandler* subscribe = *it;
  453 + if ((ret = subscribe->on_reload_listen()) != ERROR_SUCCESS) {
  454 + srs_error("notify subscribes reload listen failed. ret=%d", ret);
  455 + return ret;
  456 + }
  457 + }
  458 + srs_trace("reload listen success.");
  459 + }
  460 + // merge config: pithy_print
  461 + if (!srs_directive_equals(root->get("pithy_print"), old_root->get("pithy_print"))) {
  462 + for (it = subscribes.begin(); it != subscribes.end(); ++it) {
  463 + SrsReloadHandler* subscribe = *it;
  464 + if ((ret = subscribe->on_reload_pithy_print()) != ERROR_SUCCESS) {
  465 + srs_error("notify subscribes pithy_print listen failed. ret=%d", ret);
  466 + return ret;
  467 + }
  468 + }
  469 + srs_trace("reload pithy_print success.");
  470 + }
  471 +
  472 + return ret;
  473 +}
  474 +
  475 +void SrsConfig::subscribe(SrsReloadHandler* handler)
  476 +{
  477 + std::vector<SrsReloadHandler*>::iterator it;
  478 +
  479 + it = std::find(subscribes.begin(), subscribes.end(), handler);
  480 + if (it != subscribes.end()) {
  481 + return;
  482 + }
  483 +
  484 + subscribes.push_back(handler);
  485 +}
  486 +
  487 +void SrsConfig::unsubscribe(SrsReloadHandler* handler)
  488 +{
  489 + std::vector<SrsReloadHandler*>::iterator it;
  490 +
  491 + it = std::find(subscribes.begin(), subscribes.end(), handler);
  492 + if (it == subscribes.end()) {
  493 + return;
  494 + }
  495 +
  496 + subscribes.erase(it);
  497 +}
  498 +
  499 +// see: ngx_get_options
  500 +int SrsConfig::parse_options(int argc, char** argv)
  501 +{
  502 + int ret = ERROR_SUCCESS;
  503 +
  504 + for (int i = 1; i < argc; i++) {
  505 + if ((ret = parse_argv(i, argv)) != ERROR_SUCCESS) {
  506 + return ret;
  507 + }
  508 + }
  509 +
  510 + if (show_help) {
  511 + print_help(argv);
  512 + }
  513 +
  514 + if (show_version) {
  515 + printf("%s\n", RTMP_SIG_SRS_VERSION);
  516 + }
  517 +
  518 + if (show_help || show_version) {
  519 + exit(0);
  520 + }
  521 +
  522 + if (config_file.empty()) {
  523 + ret = ERROR_SYSTEM_CONFIG_INVALID;
  524 + srs_error("config file not specified, see help: %s -h, ret=%d", argv[0], ret);
  525 + return ret;
  526 + }
  527 +
  528 + return parse_file(config_file.c_str());
  529 +}
  530 +
  531 +SrsConfDirective* SrsConfig::get_vhost(std::string vhost)
  532 +{
  533 + srs_assert(root);
  534 +
  535 + for (int i = 0; i < (int)root->directives.size(); i++) {
  536 + SrsConfDirective* conf = root->at(i);
  537 +
  538 + if (conf->name != "vhost") {
  539 + continue;
  540 + }
  541 +
  542 + if (conf->arg0() == vhost) {
  543 + return conf;
  544 + }
  545 + }
  546 +
  547 + if (vhost != RTMP_VHOST_DEFAULT) {
  548 + return get_vhost(RTMP_VHOST_DEFAULT);
  549 + }
  550 +
  551 + return NULL;
  552 +}
  553 +
  554 +SrsConfDirective* SrsConfig::get_gop_cache(std::string vhost)
  555 +{
  556 + SrsConfDirective* conf = get_vhost(vhost);
  557 +
  558 + if (!conf) {
  559 + return NULL;
  560 + }
  561 +
  562 + return conf->get("gop_cache");
  563 +}
  564 +
  565 +SrsConfDirective* SrsConfig::get_hls(std::string vhost)
  566 +{
  567 + SrsConfDirective* conf = get_vhost(vhost);
  568 +
  569 + if (!conf) {
  570 + return NULL;
  571 + }
  572 +
  573 + return conf->get("hls");
  574 +}
  575 +
  576 +SrsConfDirective* SrsConfig::get_hls_path(std::string vhost)
  577 +{
  578 + SrsConfDirective* conf = get_vhost(vhost);
  579 +
  580 + if (!conf) {
  581 + return NULL;
  582 + }
  583 +
  584 + return conf->get("hls_path");
  585 +}
  586 +
  587 +SrsConfDirective* SrsConfig::get_refer(std::string vhost)
  588 +{
  589 + SrsConfDirective* conf = get_vhost(vhost);
  590 +
  591 + if (!conf) {
  592 + return NULL;
  593 + }
  594 +
  595 + return conf->get("refer");
  596 +}
  597 +
  598 +SrsConfDirective* SrsConfig::get_refer_play(std::string vhost)
  599 +{
  600 + SrsConfDirective* conf = get_vhost(vhost);
  601 +
  602 + if (!conf) {
  603 + return NULL;
  604 + }
  605 +
  606 + return conf->get("refer_play");
  607 +}
  608 +
  609 +SrsConfDirective* SrsConfig::get_refer_publish(std::string vhost)
  610 +{
  611 + SrsConfDirective* conf = get_vhost(vhost);
  612 +
  613 + if (!conf) {
  614 + return NULL;
  615 + }
  616 +
  617 + return conf->get("refer_publish");
  618 +}
  619 +
  620 +SrsConfDirective* SrsConfig::get_listen()
  621 +{
  622 + return root->get("listen");
  623 +}
  624 +
  625 +SrsConfDirective* SrsConfig::get_chunk_size()
  626 +{
  627 + return root->get("chunk_size");
  628 +}
  629 +
  630 +SrsConfDirective* SrsConfig::get_pithy_print_publish()
  631 +{
  632 + SrsConfDirective* pithy = root->get("pithy_print");
  633 + if (!pithy) {
  634 + return NULL;
  635 + }
  636 +
  637 + return pithy->get("publish");
  638 +}
  639 +
  640 +SrsConfDirective* SrsConfig::get_pithy_print_play()
  641 +{
  642 + SrsConfDirective* pithy = root->get("pithy_print");
  643 + if (!pithy) {
  644 + return NULL;
  645 + }
  646 +
  647 + return pithy->get("play");
  648 +}
  649 +
  650 +int SrsConfig::parse_file(const char* filename)
  651 +{
  652 + int ret = ERROR_SUCCESS;
  653 +
  654 + config_file = filename;
  655 +
  656 + if (config_file.empty()) {
  657 + return ERROR_SYSTEM_CONFIG_INVALID;
  658 + }
  659 +
  660 + if ((ret = root->parse(config_file.c_str())) != ERROR_SUCCESS) {
  661 + return ret;
  662 + }
  663 +
  664 + SrsConfDirective* conf = NULL;
  665 + if ((conf = get_listen()) == NULL || conf->args.size() == 0) {
  666 + ret = ERROR_SYSTEM_CONFIG_INVALID;
  667 + srs_error("line %d: conf error, "
  668 + "directive \"listen\" is empty, ret=%d", (conf? conf->conf_line:0), ret);
  669 + return ret;
  670 + }
  671 +
  672 + return ret;
  673 +}
  674 +
  675 +int SrsConfig::parse_argv(int& i, char** argv)
  676 +{
  677 + int ret = ERROR_SUCCESS;
  678 +
  679 + char* p = argv[i];
  680 +
  681 + if (*p++ != '-') {
  682 + ret = ERROR_SYSTEM_CONFIG_INVALID;
  683 + srs_error("invalid options(index=%d, value=%s), "
  684 + "must starts with -, see help: %s -h, ret=%d", i, argv[i], argv[0], ret);
  685 + return ret;
  686 + }
  687 +
  688 + while (*p) {
  689 + switch (*p++) {
  690 + case '?':
  691 + case 'h':
  692 + show_help = true;
  693 + break;
  694 + case 'v':
  695 + case 'V':
  696 + show_version = true;
  697 + break;
  698 + case 'c':
  699 + if (*p) {
  700 + config_file = p;
  701 + return ret;
  702 + }
  703 + if (argv[++i]) {
  704 + config_file = argv[i];
  705 + return ret;
  706 + }
  707 + ret = ERROR_SYSTEM_CONFIG_INVALID;
  708 + srs_error("option \"-c\" requires parameter, ret=%d", ret);
  709 + return ret;
  710 + default:
  711 + ret = ERROR_SYSTEM_CONFIG_INVALID;
  712 + srs_error("invalid option: \"%c\", see help: %s -h, ret=%d", *(p - 1), argv[0], ret);
  713 + return ret;
  714 + }
  715 + }
  716 +
  717 + return ret;
  718 +}
  719 +
  720 +void SrsConfig::print_help(char** argv)
  721 +{
  722 + printf(RTMP_SIG_SRS_NAME" "RTMP_SIG_SRS_VERSION
  723 + " Copyright (c) 2013 winlin\n"
  724 + "Usage: %s [-h?vV] [-c <filename>]\n"
  725 + "\n"
  726 + "Options:\n"
  727 + " -?-h : show help\n"
  728 + " -v-V : show version and exit\n"
  729 + " -c filename : set configuration file\n"
  730 + "\n"
  731 + RTMP_SIG_SRS_WEB"\n"
  732 + RTMP_SIG_SRS_URL"\n"
  733 + "Email: "RTMP_SIG_SRS_EMAIL"\n",
  734 + argv[0]);
  735 +}
  736 +
  737 +bool srs_directive_equals(SrsConfDirective* a, SrsConfDirective* b)
  738 +{
  739 + if (!a || !b) {
  740 + return false;
  741 + }
  742 +
  743 + if (a->name != b->name) {
  744 + return false;
  745 + }
  746 +
  747 + if (a->args.size() != b->args.size()) {
  748 + return false;
  749 + }
  750 +
  751 + for (int i = 0; i < (int)a->args.size(); i++) {
  752 + if (a->args.at(i) != b->args.at(i)) {
  753 + return false;
  754 + }
  755 + }
  756 +
  757 + if (a->directives.size() != b->directives.size()) {
  758 + return false;
  759 + }
  760 +
  761 + for (int i = 0; i < (int)a->directives.size(); i++) {
  762 + SrsConfDirective* a0 = a->at(i);
  763 + SrsConfDirective* b0 = b->at(i);
  764 +
  765 + if (!srs_directive_equals(a0, b0)) {
  766 + return false;
  767 + }
  768 + }
  769 +
  770 + return true;
  771 +}
  772 +
1 -/*  
2 -The MIT License (MIT)  
3 -  
4 -Copyright (c) 2013 winlin  
5 -  
6 -Permission is hereby granted, free of charge, to any person obtaining a copy of  
7 -this software and associated documentation files (the "Software"), to deal in  
8 -the Software without restriction, including without limitation the rights to  
9 -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of  
10 -the Software, and to permit persons to whom the Software is furnished to do so,  
11 -subject to the following conditions:  
12 -  
13 -The above copyright notice and this permission notice shall be included in all  
14 -copies or substantial portions of the Software.  
15 -  
16 -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR  
17 -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS  
18 -FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR  
19 -COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER  
20 -IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN  
21 -CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.  
22 -*/  
23 -  
24 -#ifndef SRS_CORE_CONIFG_HPP  
25 -#define SRS_CORE_CONIFG_HPP  
26 -  
27 -/*  
28 -#include <srs_core_config.hpp>  
29 -*/  
30 -#include <srs_core.hpp>  
31 -  
32 -#include <vector>  
33 -#include <string>  
34 -  
35 -#include <srs_core_reload.hpp>  
36 -  
37 -// default vhost for rtmp  
38 -#define RTMP_VHOST_DEFAULT "__defaultVhost__"  
39 -  
40 -// conf node: enabled.  
41 -#define RTMP_VHOST_ENABLED "enabled"  
42 -  
43 -class SrsFileBuffer  
44 -{  
45 -public:  
46 - int fd;  
47 - int line;  
48 - // start of buffer.  
49 - char* start;  
50 - // end of buffer.  
51 - char* end;  
52 - // current consumed position.  
53 - char* pos;  
54 - // last available position.  
55 - char* last;  
56 -  
57 - SrsFileBuffer();  
58 - virtual ~SrsFileBuffer();  
59 - virtual int open(const char* filename);  
60 -};  
61 -  
62 -class SrsConfDirective  
63 -{  
64 -public:  
65 - int conf_line;  
66 - std::string name;  
67 - std::vector<std::string> args;  
68 - std::vector<SrsConfDirective*> directives;  
69 -public:  
70 - SrsConfDirective();  
71 - virtual ~SrsConfDirective();  
72 - std::string arg0();  
73 - std::string arg1();  
74 - std::string arg2();  
75 - SrsConfDirective* at(int index);  
76 - SrsConfDirective* get(std::string _name);  
77 -public:  
78 - virtual int parse(const char* filename);  
79 -public:  
80 - enum SrsDirectiveType{parse_file, parse_block};  
81 - virtual int parse_conf(SrsFileBuffer* buffer, SrsDirectiveType type);  
82 - virtual int read_token(SrsFileBuffer* buffer, std::vector<std::string>& args);  
83 - virtual int refill_buffer(SrsFileBuffer* buffer, bool d_quoted, bool s_quoted, int startline, char*& pstart);  
84 -};  
85 -  
86 -/**  
87 -* the config parser.  
88 -* for the config supports reload, so never keep the reference cross st-thread,  
89 -* that is, never save the SrsConfDirective* get by any api of config,  
90 -* for it maybe free in the reload st-thread cycle.  
91 -* you can keep it before st-thread switch, or simply never keep it.  
92 -*/  
93 -class SrsConfig  
94 -{  
95 -private:  
96 - bool show_help;  
97 - bool show_version;  
98 - std::string config_file;  
99 - SrsConfDirective* root;  
100 - std::vector<SrsReloadHandler*> subscribes;  
101 -public:  
102 - SrsConfig();  
103 - virtual ~SrsConfig();  
104 -public:  
105 - virtual int reload();  
106 - virtual void subscribe(SrsReloadHandler* handler);  
107 - virtual void unsubscribe(SrsReloadHandler* handler);  
108 -public:  
109 - virtual int parse_options(int argc, char** argv);  
110 - virtual SrsConfDirective* get_vhost(std::string vhost);  
111 - virtual SrsConfDirective* get_gop_cache(std::string vhost);  
112 - virtual SrsConfDirective* get_hls(std::string vhost);  
113 - virtual SrsConfDirective* get_refer(std::string vhost);  
114 - virtual SrsConfDirective* get_refer_play(std::string vhost);  
115 - virtual SrsConfDirective* get_refer_publish(std::string vhost);  
116 - virtual SrsConfDirective* get_listen();  
117 - virtual SrsConfDirective* get_chunk_size();  
118 - virtual SrsConfDirective* get_pithy_print_publish();  
119 - virtual SrsConfDirective* get_pithy_print_play();  
120 -private:  
121 - virtual int parse_file(const char* filename);  
122 - virtual int parse_argv(int& i, char** argv);  
123 - virtual void print_help(char** argv);  
124 -};  
125 -  
126 -/**  
127 -* deep compare directive.  
128 -*/  
129 -bool srs_directive_equals(SrsConfDirective* a, SrsConfDirective* b);  
130 -  
131 -// global config  
132 -extern SrsConfig* config;  
133 - 1 +/*
  2 +The MIT License (MIT)
  3 +
  4 +Copyright (c) 2013 winlin
  5 +
  6 +Permission is hereby granted, free of charge, to any person obtaining a copy of
  7 +this software and associated documentation files (the "Software"), to deal in
  8 +the Software without restriction, including without limitation the rights to
  9 +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
  10 +the Software, and to permit persons to whom the Software is furnished to do so,
  11 +subject to the following conditions:
  12 +
  13 +The above copyright notice and this permission notice shall be included in all
  14 +copies or substantial portions of the Software.
  15 +
  16 +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  17 +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
  18 +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
  19 +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
  20 +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  21 +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  22 +*/
  23 +
  24 +#ifndef SRS_CORE_CONIFG_HPP
  25 +#define SRS_CORE_CONIFG_HPP
  26 +
  27 +/*
  28 +#include <srs_core_config.hpp>
  29 +*/
  30 +#include <srs_core.hpp>
  31 +
  32 +#include <vector>
  33 +#include <string>
  34 +
  35 +#include <srs_core_reload.hpp>
  36 +
  37 +// default vhost for rtmp
  38 +#define RTMP_VHOST_DEFAULT "__defaultVhost__"
  39 +
  40 +// conf node: enabled.
  41 +#define RTMP_VHOST_ENABLED "enabled"
  42 +
  43 +class SrsFileBuffer
  44 +{
  45 +public:
  46 + int fd;
  47 + int line;
  48 + // start of buffer.
  49 + char* start;
  50 + // end of buffer.
  51 + char* end;
  52 + // current consumed position.
  53 + char* pos;
  54 + // last available position.
  55 + char* last;
  56 +
  57 + SrsFileBuffer();
  58 + virtual ~SrsFileBuffer();
  59 + virtual int open(const char* filename);
  60 +};
  61 +
  62 +class SrsConfDirective
  63 +{
  64 +public:
  65 + int conf_line;
  66 + std::string name;
  67 + std::vector<std::string> args;
  68 + std::vector<SrsConfDirective*> directives;
  69 +public:
  70 + SrsConfDirective();
  71 + virtual ~SrsConfDirective();
  72 + std::string arg0();
  73 + std::string arg1();
  74 + std::string arg2();
  75 + SrsConfDirective* at(int index);
  76 + SrsConfDirective* get(std::string _name);
  77 +public:
  78 + virtual int parse(const char* filename);
  79 +public:
  80 + enum SrsDirectiveType{parse_file, parse_block};
  81 + virtual int parse_conf(SrsFileBuffer* buffer, SrsDirectiveType type);
  82 + virtual int read_token(SrsFileBuffer* buffer, std::vector<std::string>& args);
  83 + virtual int refill_buffer(SrsFileBuffer* buffer, bool d_quoted, bool s_quoted, int startline, char*& pstart);
  84 +};
  85 +
  86 +/**
  87 +* the config parser.
  88 +* for the config supports reload, so never keep the reference cross st-thread,
  89 +* that is, never save the SrsConfDirective* get by any api of config,
  90 +* for it maybe free in the reload st-thread cycle.
  91 +* you can keep it before st-thread switch, or simply never keep it.
  92 +*/
  93 +class SrsConfig
  94 +{
  95 +private:
  96 + bool show_help;
  97 + bool show_version;
  98 + std::string config_file;
  99 + SrsConfDirective* root;
  100 + std::vector<SrsReloadHandler*> subscribes;
  101 +public:
  102 + SrsConfig();
  103 + virtual ~SrsConfig();
  104 +public:
  105 + virtual int reload();
  106 + virtual void subscribe(SrsReloadHandler* handler);
  107 + virtual void unsubscribe(SrsReloadHandler* handler);
  108 +public:
  109 + virtual int parse_options(int argc, char** argv);
  110 + virtual SrsConfDirective* get_vhost(std::string vhost);
  111 + virtual SrsConfDirective* get_gop_cache(std::string vhost);
  112 + virtual SrsConfDirective* get_hls(std::string vhost);
  113 + virtual SrsConfDirective* get_hls_path(std::string vhost);
  114 + virtual SrsConfDirective* get_refer(std::string vhost);
  115 + virtual SrsConfDirective* get_refer_play(std::string vhost);
  116 + virtual SrsConfDirective* get_refer_publish(std::string vhost);
  117 + virtual SrsConfDirective* get_listen();
  118 + virtual SrsConfDirective* get_chunk_size();
  119 + virtual SrsConfDirective* get_pithy_print_publish();
  120 + virtual SrsConfDirective* get_pithy_print_play();
  121 +private:
  122 + virtual int parse_file(const char* filename);
  123 + virtual int parse_argv(int& i, char** argv);
  124 + virtual void print_help(char** argv);
  125 +};
  126 +
  127 +/**
  128 +* deep compare directive.
  129 +*/
  130 +bool srs_directive_equals(SrsConfDirective* a, SrsConfDirective* b);
  131 +
  132 +// global config
  133 +extern SrsConfig* config;
  134 +
134 #endif 135 #endif
  1 +/*
  2 +The MIT License (MIT)
  3 +
  4 +Copyright (c) 2013 winlin
  5 +
  6 +Permission is hereby granted, free of charge, to any person obtaining a copy of
  7 +this software and associated documentation files (the "Software"), to deal in
  8 +the Software without restriction, including without limitation the rights to
  9 +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
  10 +the Software, and to permit persons to whom the Software is furnished to do so,
  11 +subject to the following conditions:
  12 +
  13 +The above copyright notice and this permission notice shall be included in all
  14 +copies or substantial portions of the Software.
  15 +
  16 +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  17 +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
  18 +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
  19 +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
  20 +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  21 +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  22 +*/
  23 +
  24 +#include <srs_core_hls.hpp>
  25 +
  1 +/*
  2 +The MIT License (MIT)
  3 +
  4 +Copyright (c) 2013 winlin
  5 +
  6 +Permission is hereby granted, free of charge, to any person obtaining a copy of
  7 +this software and associated documentation files (the "Software"), to deal in
  8 +the Software without restriction, including without limitation the rights to
  9 +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
  10 +the Software, and to permit persons to whom the Software is furnished to do so,
  11 +subject to the following conditions:
  12 +
  13 +The above copyright notice and this permission notice shall be included in all
  14 +copies or substantial portions of the Software.
  15 +
  16 +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  17 +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
  18 +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
  19 +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
  20 +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  21 +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  22 +*/
  23 +
  24 +#ifndef SRS_CORE_HLS_HPP
  25 +#define SRS_CORE_HLS_HPP
  26 +
  27 +/*
  28 +#include <srs_core_hls.hpp>
  29 +*/
  30 +#include <srs_core.hpp>
  31 +
  32 +#endif
@@ -22,6 +22,8 @@ file @@ -22,6 +22,8 @@ file
22 ..\core\srs_core_client.cpp, 22 ..\core\srs_core_client.cpp,
23 ..\core\srs_core_source.hpp, 23 ..\core\srs_core_source.hpp,
24 ..\core\srs_core_source.cpp, 24 ..\core\srs_core_source.cpp,
  25 + ..\core\srs_core_hls.hpp,
  26 + ..\core\srs_core_hls.cpp,
25 ..\core\srs_core_codec.hpp, 27 ..\core\srs_core_codec.hpp,
26 ..\core\srs_core_codec.cpp, 28 ..\core\srs_core_codec.cpp,
27 ..\core\srs_core_rtmp.hpp, 29 ..\core\srs_core_rtmp.hpp,