first commit

master
Evan, Chen 2021-07-07 18:46:39 +08:00
commit 3c34909cb5
52 changed files with 40625 additions and 0 deletions

12
Dockerfile Normal file
View File

@ -0,0 +1,12 @@
FROM gcc:5.4
RUN apt update && apt install -y zip
COPY st-load-master src
WORKDIR /src
RUN ./configure
RUN make
WORKDIR /src/objs
ENV PATH="/src/objs:${PATH}"

22
README.md Normal file
View File

@ -0,0 +1,22 @@
# rtmp-stress
> clone from https://github.com/rzrobert/st-load-master
## Build
```shell
docker build -t rtmp-stress .
```
## Use
```shell
# start
docker run -d --name stress rtmp-stress sb_rtmp_load_fast -c 50 -r rtmp://kumoly.io/mosu/live
# see the logs
docker logs -f stress
# stop
docker rm -f stress
```

28
st-load-master/.gitignore vendored Executable file
View File

@ -0,0 +1,28 @@
# Compiled Object files
*.slo
*.lo
*.o
*.obj
# Precompiled Headers
*.gch
*.pch
# Compiled Dynamic libraries
*.so
*.dylib
*.dll
# Fortran module files
*.mod
# Compiled Static libraries
*.lai
*.la
*.a
*.lib
# Executables
*.exe
*.out
*.app

BIN
st-load-master/3rdparty/http-parser-2.1.zip vendored Executable file

Binary file not shown.

View File

@ -0,0 +1,21 @@
Only in .: 1.st.arm.patch
diff -r -c ./md.h ../st-1.9-patch-arm/md.h
*** ./md.h 2009-10-02 02:46:43.000000000 +0800
--- ../st-1.9-patch-arm/md.h 2014-03-16 20:49:03.845344804 +0800
***************
*** 422,428 ****
#define MD_STACK_GROWS_DOWN
#if defined(__GLIBC__) && __GLIBC__ >= 2
! #define MD_GET_SP(_t) (_t)->context[0].__jmpbuf[20]
#else
#error "ARM/Linux pre-glibc2 not supported yet"
#endif /* defined(__GLIBC__) && __GLIBC__ >= 2 */
--- 422,428 ----
#define MD_STACK_GROWS_DOWN
#if defined(__GLIBC__) && __GLIBC__ >= 2
! #define MD_GET_SP(_t) (_t)->context[0].__jmpbuf[8]
#else
#error "ARM/Linux pre-glibc2 not supported yet"
#endif /* defined(__GLIBC__) && __GLIBC__ >= 2 */

BIN
st-load-master/3rdparty/st-1.9.zip vendored Executable file

Binary file not shown.

21
st-load-master/LICENSE Executable file
View File

@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2013-2015 srs-org
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

127
st-load-master/README.md Executable file
View File

@ -0,0 +1,127 @@
SB(SRS Bench)
===========
hls/http/rtmp-play/rtmp-publish load test tool base on st(state-threads), support huge concurrency<br/>
## About
服务器负载测试工具SB(SRS Bench)
1. 模拟huge并发2G内存就可以开300k连接。基于states-threads的协程。
1. 支持HLS解析和测试下载ts片后等待一个切片长度模拟客户端。支持HLS点播和直播。执行程序`./objs/sb_hls_load`
1. 支持HTTP负载测试所有并发重复下载一个http文件。可将80Gbps带宽测试的72Gbps。执行程序`./objs/sb_http_load `
1. 支持RTMP流播放测试一个进程支持5k并发。执行程序`./objs/sb_rtmp_load`
1. 支持RTMP流推流测试一个进程支持500个并发。执行程序`./objs/sb_rtmp_publish`
1. RTMP协议使用高性能服务器SRS([SimpleRtmpServer](https://github.com/winlinvip/simple-rtmp-server))的协议栈。
注意:
1. HTTP/HLS依赖服务器Content-Length不支持chunked方式(chunked时会把所有内容当做body一直读)。
2. 所有程序都在Linux下运行模拟客户端运行。
3. 其他工具参考[srs-librtmp](https://github.com/winlinvip/simple-rtmp-server/wiki/v2_CN_SrsLibrtmp#srs-librtmp-examples)
## Usage
```
git clone https://github.com/winlinvip/st-load.git &&
cd st-load && ./configure && make &&
./objs/sb_rtmp_load -c 1 -r rtmp://127.0.0.1:1935/live/livestream
```
## Benchmarks
TestEnvironment: 24CPU, 80Gbps Network, 16GB Memory<br/>
Server: NGINX HLS<br/>
Result: 90% bandwith, 72Gbps
<pre>
[root@dell-server ~]# dstat
----total-cpu-usage---- -dsk/total- -net/total- ---paging-- ---system--
usr sys idl wai hiq siq| read writ| recv send | in out | int csw
1 1 95 0 0 3|4091B 369k| 0 0 | 0 0 | 100k 9545
3 8 66 0 0 23| 0 0 | 40MB 6114MB| 0 0 | 681k 46k
3 8 63 0 0 25| 0 100k| 41MB 6223MB| 0 0 | 692k 46k
3 8 64 0 0 25| 0 0 | 41MB 6190MB| 0 0 | 694k 45k
3 8 66 0 0 23| 0 0 | 40MB 6272MB| 0 0 | 694k 48k
3 8 64 0 0 25| 0 20k| 40MB 6161MB| 0 0 | 687k 46k
3 8 65 0 0 24| 0 0 | 40MB 6198MB| 0 0 | 687k 46k
3 8 66 0 0 23| 0 0 | 40MB 6231MB| 0 0 | 688k 47k
3 7 70 0 0 20| 0 68k| 40MB 6159MB| 0 0 | 675k 49k
3 9 62 0 0 26| 0 4096B| 42MB 6283MB| 0 0 | 702k 44k
4 8 62 0 0 25| 0 2472k| 40MB 6122MB| 0 0 | 698k 44k
3 8 67 0 0 22| 0 0 | 39MB 6066MB| 0 0 | 671k 46k
3 8 64 0 0 25| 0 0 | 41MB 6263MB| 0 0 | 695k 46k
3 8 64 0 0 25|4096B 132k| 41MB 6161MB| 0 0 | 687k 45k
3 11 60 0 0 26| 0 0 | 42MB 6822MB| 0 0 | 714k 36k
3 10 62 0 0 25| 0 0 | 40MB 6734MB| 0 0 | 703k 38k
3 11 60 0 0 26| 0 0 | 43MB 7019MB| 0 0 | 724k 38k
3 11 60 0 0 26| 0 24k| 45MB 7436MB| 0 0 | 746k 41k
3 11 60 0 0 27| 0 24k| 47MB 7736MB| 0 0 | 766k 42k
3 11 59 0 0 28| 0 0 | 52MB 8283MB| 0 0 | 806k 45k
2 10 61 0 0 27| 0 0 | 54MB 8359MB| 0 0 | 806k 47k
3 12 53 0 0 32| 0 16k| 58MB 8565MB| 0 0 | 850k 42k
2 10 62 0 0 26| 0 1212k| 51MB 8140MB| 0 0 | 783k 47k
2 10 64 0 0 24| 0 0 | 42MB 7033MB| 0 0 | 703k 40k
2 11 62 0 0 25| 0 0 | 43MB 7203MB| 0 0 | 703k 40k
2 12 57 0 0 29| 0 0 | 50MB 7970MB| 0 0 | 774k 40k
2 11 54 0 0 33| 0 0 | 72MB 8943MB| 0 0 | 912k 47k
3 13 65 0 0 20| 0 0 | 36MB 7247MB| 0 0 | 552k 29k
3 14 61 0 0 23| 0 1492k| 42MB 8091MB| 0 0 | 613k 32k
3 13 54 0 0 30| 0 0 | 57MB 9144MB| 0 0 | 760k 34k
2 10 55 0 0 32| 0 84k| 69MB 9292MB| 0 0 | 861k 38k
2 9 58 0 0 31| 0 92k| 71MB 9083MB| 0 0 | 860k 39k
2 9 56 0 0 33| 0 0 | 78MB 9098MB| 0 0 | 914k 39k
2 8 61 0 0 30| 0 0 | 73MB 8860MB| 0 0 | 876k 39k
</pre>
RTMP load test:<br/>
<pre>
top - 17:57:24 up 7:10, 7 users, load average: 0.20, 0.20, 0.09
Tasks: 154 total, 1 running, 153 sleeping, 0 stopped, 0 zombie
Cpu(s): 7.4%us, 7.2%sy, 0.0%ni, 78.8%id, 0.0%wa, 0.1%hi, 6.5%si, 0.0%st
Mem: 2055440k total, 1304528k used, 750912k free, 182336k buffers
Swap: 2064376k total, 0k used, 2064376k free, 613848k cached
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
13091 winlin 20 0 186m 110m 1404 S 29.6 5.5 1:55.35 ./objs/sb_rtmp_load -c 1000
12544 winlin 20 0 124m 22m 2080 S 20.3 1.1 1:51.51 ./objs/srs
----total-cpu-usage---- -dsk/total- ---net/lo-- ---paging-- ---system--
usr sys idl wai hiq siq| read writ| recv send| in out | int csw
7 7 82 0 0 4| 0 0 | 158M 158M| 0 0 |2962 353
6 5 83 0 0 6| 0 0 | 74M 74M| 0 0 |2849 291
7 6 81 0 0 6| 0 0 | 102M 102M| 0 0 |2966 360
7 8 79 0 0 6| 0 0 | 168M 168M| 0 0 |2889 321
7 7 79 0 0 7| 0 0 | 83M 83M| 0 0 |2862 364
5 6 83 0 0 6| 0 0 | 106M 106M| 0 0 |2967 296
5 6 83 0 0 6| 0 0 | 54M 54M| 0 0 |2907 355
6 6 84 0 0 4| 0 0 | 58M 58M| 0 0 |2986 353
6 6 83 0 0 4| 0 0 | 117M 117M| 0 0 |2863 326
7 6 82 0 0 5| 0 0 | 97M 97M| 0 0 |2954 321
5 7 78 2 0 8| 0 40k| 82M 82M| 0 0 |2909 357
5 5 84 0 0 6| 0 0 | 57M 57M| 0 0 |2937 307
8 8 78 0 0 6| 0 0 | 190M 190M| 0 0 |3024 413
5 7 82 0 0 7| 0 0 | 75M 75M| 0 0 |2940 310
8 8 80 0 0 4| 0 0 | 136M 136M| 0 0 |3000 436
8 8 74 0 0 10| 0 0 | 116M 116M| 0 0 |2816 356
7 8 78 0 0 6| 0 0 | 128M 128M| 0 0 |2972 424
6 8 80 0 0 7| 0 4096B| 123M 123M| 0 0 |2981 395
6 6 83 0 0 5| 0 0 | 50M 50M| 0 0 |2984 367
7 6 81 2 0 4| 0 92k| 49M 49M| 0 0 |3010 445
5 6 84 0 0 6| 0 0 | 22M 22M| 0 0 |2912 364
5 5 85 0 0 4| 0 0 | 34M 34M| 0 0 |3001 429
6 6 81 0 0 7| 0 0 | 45M 45M| 0 0 |2996 468
5 5 84 0 0 6| 0 0 | 18M 18M| 0 0 |2923 338
8 8 77 0 0 7| 0 0 | 158M 158M| 0 0 |2971 351
7 7 80 0 0 5| 0 0 | 167M 167M| 0 0 |2860 334
6 5 83 0 0 6| 0 60k| 61M 61M| 0 0 |2988 424
7 8 79 0 0 6| 0 0 | 140M 140M| 0 0 |2916 391
8 8 78 0 0 6| 0 0 | 172M 172M| 0 0 |2961 348
7 8 78 0 0 7| 0 0 | 127M 127M| 0 0 |2865 347
5 6 84 0 0 5| 0 0 | 73M 73M| 0 0 |2972 344
6 8 78 0 0 8| 0 0 | 115M 115M| 0 0 |2942 314
7 8 79 0 0 6| 0 0 | 147M 147M| 0 0 |2966 366
</pre>
2016-12-01
</pre>

92
st-load-master/auto/apps.sh Executable file
View File

@ -0,0 +1,92 @@
#!/bin/bash
# params:
# $GLOBAL_DIR_OBJS the objs directory. ie. objs
# $GLOBAL_FILE_MAKEFILE the makefile name. ie. Makefile
# $MAIN_ENTRANCES array, all main entrance, disable all except the $APP_MAIN itself
# $MODULE_OBJS array, the objects to compile the app.
# $BUILD_KEY a string indicates the build key for Makefile. ie. dump
# $APP_MAIN the object file that contains main function. ie. your_app_main
# $APP_NAME the app name to output. ie. your_app
# $ModuleLibFiles array, the 3rdpart library file to link with. ie. (objs/st-1.9/obj/libst.a objs/libx264/obj/libx264.a)
# $LINK_OPTIONS the linker options.
# $SO_PATH the libssl.so.10 and other so file path.
FILE=${GLOBAL_DIR_OBJS}/${GLOBAL_FILE_MAKEFILE}
APP_TARGET="${GLOBAL_DIR_OBJS}/${APP_NAME}"
echo "generate app ${APP_NAME} depends...";
echo "# build ${APP_TARGET}" >> ${FILE}
echo "${BUILD_KEY}: ${APP_TARGET}" >> ${FILE}
echo -n "${APP_TARGET}: " >> ${FILE}
for item in ${MODULE_OBJS[*]}; do
FILE_NAME=`basename $item`
FILE_NAME=${FILE_NAME%.*}
ignored=0
for disabled_item in ${MAIN_ENTRANCES[*]}; do
if [[ ${FILE_NAME} == ${disabled_item} && ${FILE_NAME} != ${APP_MAIN} ]]; then
ignored=1
continue;
fi
done
if [ ! -f ${item} ]; then
ignored=1
fi
if [ ${ignored} == 1 ]; then
continue;
fi
OBJ_FILE=${GLOBAL_DIR_OBJS}/$item
OBJ_FILE="${OBJ_FILE%.*}.o"
echo -n "${OBJ_FILE} " >> ${FILE}
done
echo "" >> ${FILE}
echo "generate app ${APP_NAME} link...";
echo -n " \$(LINK) ${PerformanceLink} -o ${APP_TARGET} " >> ${FILE}
for item in ${MODULE_OBJS[*]}; do
FILE_NAME=`basename $item`
FILE_NAME=${FILE_NAME%.*}
ignored=0
for disabled_item in ${MAIN_ENTRANCES[*]}; do
if [[ ${FILE_NAME} == ${disabled_item} && ${FILE_NAME} != ${APP_MAIN} ]]; then
ignored=1
continue;
fi
done
if [ ! -f ${item} ]; then
ignored=1
fi
if [ ${ignored} == 1 ]; then
continue;
fi
OBJ_FILE=${GLOBAL_DIR_OBJS}/$item
OBJ_FILE="${OBJ_FILE%.*}.o"
echo -n "${OBJ_FILE} " >> ${FILE}
done
# 3rdpart library static link.
for item in ${ModuleLibFiles[*]}; do
echo -n "$item " >> ${FILE}
done
# link options.
echo -n "${LINK_OPTIONS}" >> ${FILE}
echo "" >> ${FILE}
# set the so reference path.
if [[ ! -z ${SO_PATH} ]]; then
echo -n " @bash auto/set_so_rpath.sh ${SOPathTool} ${APP_TARGET} ${SO_PATH}" >> ${FILE}
echo "" >> ${FILE}
fi
echo -n "generate app ${APP_NAME} ok"; echo '!';

61
st-load-master/auto/modules.sh Executable file
View File

@ -0,0 +1,61 @@
# params:
# $GLOBAL_DIR_OBJS the objs directory. ie. objs
# $GLOBAL_FILE_MAKEFILE the makefile name. ie. Makefile
# $MODULE_DIR the module dir. ie. src/os/linux
# $MODULE_ID the id of module. ie. CORE
# $MODULE_DEPENDS array, the denpend MODULEs id. ie. (CORE OS)
# $ModuleLibIncs array, the depend 3rdpart library includes. ie. (objs/st-1.9/obj objs/libx264/obj)
# $MODULE_FILES array, the head/cpp files of modules. ie. (public log)
#
# returns:
# $MODULE_OBJS array, the objects of the modules.
FILE=${GLOBAL_DIR_OBJS}/${GLOBAL_FILE_MAKEFILE}
# INCS
INCS_NAME="${MODULE_ID}_INCS"
echo "# the ${MODULE_ID} module." >> ${FILE}
echo "${MODULE_ID}_MODULE_INCS = -I ${MODULE_DIR} " >> ${FILE}
echo -n "${INCS_NAME} = -I ${MODULE_DIR} " >> ${FILE}
for item in ${MODULE_DEPENDS[*]}; do
DEP_INCS_NAME="${item}_INCS"do
DEP_INCS_NAME="${item}_MODULE_INCS"
echo -n "\$(${DEP_INCS_NAME}) " >> ${FILE}
done
for item in ${ModuleLibIncs[*]}; do
echo -n "-I ${item} " >> ${FILE}
done
echo "" >> ${FILE}
# DEPS
DEPS_NAME="${MODULE_ID}_DEPS"
echo -n "${DEPS_NAME} = " >> ${FILE}
for item in ${MODULE_FILES[*]}; do
HEADER_FILE="${MODULE_DIR}/${item}.hpp"
if [ -f ${HEADER_FILE} ]; then
echo -n " ${HEADER_FILE}" >> ${FILE}
fi
done
for item in ${MODULE_DEPENDS[*]}; do
DEP_DEPS_NAME="${item}_DEPS"
echo -n " \$(${DEP_DEPS_NAME}) " >> ${FILE}
done
echo "" >> ${FILE}; echo "" >> ${FILE}
# OBJ
MODULE_OBJS=()
for item in ${MODULE_FILES[*]}; do
CPP_FILE="${MODULE_DIR}/${item}.cpp"
OBJ_FILE="${GLOBAL_DIR_OBJS}/${MODULE_DIR}/${item}.o"
MODULE_OBJS="${MODULE_OBJS[@]} ${CPP_FILE}"
if [ -f ${CPP_FILE} ]; then
echo "${OBJ_FILE}: \$(${DEPS_NAME}) ${CPP_FILE} " >> ${FILE}
echo " \$(GCC) -c \$(CXXFLAGS) \$(${INCS_NAME}) -o ${OBJ_FILE} ${CPP_FILE}" >> ${FILE}
fi
done
echo "" >> ${FILE}
# Makefile
echo " mkdir -p ${GLOBAL_DIR_OBJS}/${MODULE_DIR}" >> ${GLOBAL_FILE_MAKEFILE}
echo -n "generate module ${MODULE_ID} ok"; echo '!';

215
st-load-master/configure vendored Executable file
View File

@ -0,0 +1,215 @@
#!/bin/bash
GLOBAL_FILE_MAKEFILE="Makefile"
GLOBAL_DIR_OBJS="objs"
mkdir -p ${GLOBAL_DIR_OBJS}
#####################################################################################
# prepare the depends tools
#####################################################################################
OS_IS_OSX=NO
uname -s|grep Darwin >/dev/null 2>&1
ret=$?; if [[ 0 -eq $ret ]]; then
OS_IS_OSX=YES
fi
echo "Is OSX: ${OS_IS_OSX}"
# check the arm flag file, if flag changed, need to rebuild the st.
_ST_MAKE=linux-debug && _ST_EXTRA_CFLAGS="-DMALLOC_STACK -DMD_HAVE_EPOLL"
# for osx, use darwin for st, donot use epoll.
if [ $OS_IS_OSX = YES ]; then
_ST_MAKE=darwin-debug && _ST_EXTRA_CFLAGS="-DMD_HAVE_KQUEUE"
fi
# st-1.9
if [[ -f ${GLOBAL_DIR_OBJS}/st-1.9/obj/libst.a ]]; then
echo "st-1.9t is ok.";
else
echo "build st-1.9t";
(
rm -rf ${GLOBAL_DIR_OBJS}/st-1.9 && cd ${GLOBAL_DIR_OBJS} && unzip ../3rdparty/st-1.9.zip && cd st-1.9 &&
patch -p0 < ../../3rdparty/patches/1.st.arm.patch &&
make EXTRA_CFLAGS="${_ST_EXTRA_CFLAGS}" ${_ST_MAKE}
)
fi
# check status
ret=$?; if [[ $ret -ne 0 ]]; then echo "build st-1.9 failed, ret=$ret"; exit $ret; fi
if [ ! -f ${GLOBAL_DIR_OBJS}/st-1.9/obj/libst.a ]; then echo "build st-1.9 failed."; exit -1; fi
SED="sed -i"
if [ $OS_IS_OSX = YES ]; then SED="sed -i ''"; fi
# http-parser-2.1
if [[ -f ${GLOBAL_DIR_OBJS}/http-parser-2.1/http_parser.h && -f ${GLOBAL_DIR_OBJS}/http-parser-2.1/libhttp_parser.a ]]; then
echo "http-parser-2.1 is ok.";
else
echo "build http-parser-2.1";
(
rm -rf ${GLOBAL_DIR_OBJS}/http-parser-2.1 && cd ${GLOBAL_DIR_OBJS} && unzip ../3rdparty/http-parser-2.1.zip &&
cd http-parser-2.1 &&
$SED "s/CPPFLAGS_FAST +=.*$/CPPFLAGS_FAST = \$\(CPPFLAGS_DEBUG\)/g" Makefile &&
$SED "s/CFLAGS_FAST =.*$/CFLAGS_FAST = \$\(CFLAGS_DEBUG\)/g" Makefile &&
make package
)
fi
# check status
ret=$?; if [[ $ret -ne 0 ]]; then echo "build http-parser-2.1 failed, ret=$ret"; exit $ret; fi
if [[ ! -f ${GLOBAL_DIR_OBJS}/http-parser-2.1/http_parser.h ]]; then echo "build http-parser-2.1 failed"; exit -1; fi
if [[ ! -f ${GLOBAL_DIR_OBJS}/http-parser-2.1/libhttp_parser.a ]]; then echo "build http-parser-2.1 failed"; exit -1; fi
#####################################################################################
# generate Makefile.
#####################################################################################
echo "generate Makefile"
cat << END > ${GLOBAL_FILE_MAKEFILE}
.PHONY: default help clean http hls all _prepare_dir
default: all
help:
@echo "Usage: make <help>|<clean>|<http>|<hls>|<rtmp>|<all>"
@echo " help display this help menu"
@echo " clean cleanup project"
@echo " http build the http load test tool over st(state-threads)"
@echo " hls build the hls load test tool over st(state-threads)"
@echo " rtmp build the rtmp load test tool over st(state-threads)"
@echo " all build the http/hls load test tool over st(state-threads)"
clean:
(cd ${GLOBAL_DIR_OBJS}; rm -rf src sb_*_load)
http: _prepare_dir
@echo "build the http load test tool over st(state-threads)"
\$(MAKE) -f ${GLOBAL_DIR_OBJS}/${GLOBAL_FILE_MAKEFILE} sb_http_load
rtmp: _prepare_dir
@echo "build the http load test tool over st(state-threads)"
\$(MAKE) -f ${GLOBAL_DIR_OBJS}/${GLOBAL_FILE_MAKEFILE} sb_rtmp_load
\$(MAKE) -f ${GLOBAL_DIR_OBJS}/${GLOBAL_FILE_MAKEFILE} sb_rtmp_load_fast
\$(MAKE) -f ${GLOBAL_DIR_OBJS}/${GLOBAL_FILE_MAKEFILE} sb_rtmp_publish
hls: _prepare_dir
@echo "build the HLS load test tool over st(state-threads)"
\$(MAKE) -f ${GLOBAL_DIR_OBJS}/${GLOBAL_FILE_MAKEFILE} sb_hls_load
all: _prepare_dir
@echo "build the http/hls/rtmp load test tool over st(state-threads)"
\$(MAKE) -f ${GLOBAL_DIR_OBJS}/${GLOBAL_FILE_MAKEFILE} sb_http_load
\$(MAKE) -f ${GLOBAL_DIR_OBJS}/${GLOBAL_FILE_MAKEFILE} sb_hls_load
\$(MAKE) -f ${GLOBAL_DIR_OBJS}/${GLOBAL_FILE_MAKEFILE} sb_rtmp_load
\$(MAKE) -f ${GLOBAL_DIR_OBJS}/${GLOBAL_FILE_MAKEFILE} sb_rtmp_load_fast
\$(MAKE) -f ${GLOBAL_DIR_OBJS}/${GLOBAL_FILE_MAKEFILE} sb_rtmp_publish
@echo "build ok, you can:"
@echo " ./objs/sb_http_load"
@echo " ./objs/sb_hls_load"
@echo " ./objs/sb_rtmp_load"
@echo " ./objs/sb_rtmp_load_fast"
@echo " ./objs/sb_rtmp_publish"
# the ./configure will generate it.
_prepare_dir:
END
echo 'generate Makefile ok!'
# the performance analysis, uncomments the following when use gperf to analysis the performance. see third-party/readme.txt
#Performance="-pg"
#PerformanceLink="-pg"
# enable gdb debug
GDBDebug="-g -O0"
# the warning level.
WarnLevel="-Wall -Wextra"
# the compile standard.
CppStd="-std=c++98"
# other macros defined
UserMacros="-DSRS_HIJACK_IO -DSRS_DISABLE_LOG"
# the cxx flag generated.
CXXFLAGS="${CppStd} ${WarnLevel} ${GDBDebug} ${Performance} ${UserMacros}"
cat << END > ${GLOBAL_DIR_OBJS}/${GLOBAL_FILE_MAKEFILE}
CXXFLAGS = ${CXXFLAGS}
GCC = g++
LINK = \$(GCC)
AR = ar
.PHONY: default sb_http_load sb_hls_load sb_rtmp_load sb_rtmp_load_fast sb_rtmp_publish
default:
END
# Libraries
LibSTRoot="${GLOBAL_DIR_OBJS}/st-1.9/obj"
LibSTfile="${LibSTRoot}/libst.a"
LibHttpParserRoot="${GLOBAL_DIR_OBJS}/http-parser-2.1"
LibHttpParserfile="${LibHttpParserRoot}/libhttp_parser.a"
#Core Module
MODULE_ID="CORE"
MODULE_DEPENDS=()
ModuleLibIncs=(${LibHttpParserRoot})
MODULE_FILES=("htl_core_log" "htl_core_error" "htl_core_uri" "htl_core_aggregate_ret")
MODULE_DIR="src/core" . auto/modules.sh
CORE_OBJS="${MODULE_OBJS[@]}"
#OS Module
MODULE_ID="OS"
MODULE_DEPENDS=("CORE")
ModuleLibIncs=(${LibSTRoot})
MODULE_FILES=("htl_os_st")
MODULE_DIR="src/os" . auto/modules.sh
OS_OBJS="${MODULE_OBJS[@]}"
#APP Module
MODULE_ID="APP"
MODULE_DEPENDS=("CORE" "OS")
ModuleLibIncs=(${LibSTRoot} ${LibHttpParserRoot})
MODULE_FILES=("htl_app_hls_load" "htl_app_http_load" "htl_app_http_client" "htl_app_rtmp_play"
"htl_app_m3u8_parser" "htl_app_task_base" "htl_app_rtmp_load" "htl_app_rtmp_protocol"
"htl_app_rtmp_publish" "htl_app_srs_hijack")
MODULE_DIR="src/app" . auto/modules.sh
APP_OBJS="${MODULE_OBJS[@]}"
#Main Module
MODULE_ID="MAIN"
MODULE_DEPENDS=("CORE" "OS" "APP")
ModuleLibIncs=(${LibSTRoot} ${LibHttpParserRoot})
MODULE_FILES=("htl_main_hls_load" "htl_main_http_load" "htl_main_rtmp_load" "htl_main_rtmp_load_fast" "htl_main_utility" "htl_main_rtmp_publish")
MODULE_DIR="src/main" . auto/modules.sh
MAIN_OBJS="${MODULE_OBJS[@].o}"
# all main entrances
MAIN_ENTRANCES=("htl_main_hls_load" "htl_main_http_load" "htl_main_rtmp_load" "htl_main_rtmp_load_fast" "htl_main_rtmp_publish")
# http load test tool over st(state-threads)
ModuleLibFiles=(${LibSTfile} ${LibHttpParserfile})
MODULE_OBJS="${CORE_OBJS[@]} ${OS_OBJS[@]} ${APP_OBJS[@]} ${MAIN_OBJS[@]}"
BUILD_KEY="sb_http_load" APP_MAIN="htl_main_http_load" APP_NAME="sb_http_load" LINK_OPTIONS="-ldl" SO_PATH="" . auto/apps.sh
# rtmp play load test tool over st(state-threads)
ModuleLibFiles=(${LibSTfile} ${LibHttpParserfile})
MODULE_OBJS="${CORE_OBJS[@]} ${OS_OBJS[@]} ${APP_OBJS[@]} ${MAIN_OBJS[@]}"
BUILD_KEY="sb_rtmp_load" APP_MAIN="htl_main_rtmp_load" APP_NAME="sb_rtmp_load" LINK_OPTIONS="-ldl" SO_PATH="" . auto/apps.sh
# rtmp play load test tool over st(state-threads)
# Remark, the fast algorithm may not work for other RTMP server, it's ok for SRS/GO-SRS.
ModuleLibFiles=(${LibSTfile} ${LibHttpParserfile})
MODULE_OBJS="${CORE_OBJS[@]} ${OS_OBJS[@]} ${APP_OBJS[@]} ${MAIN_OBJS[@]}"
BUILD_KEY="sb_rtmp_load_fast" APP_MAIN="htl_main_rtmp_load_fast" APP_NAME="sb_rtmp_load_fast" LINK_OPTIONS="-ldl" SO_PATH="" . auto/apps.sh
# rtmp publish load test tool over st(state-threads)
ModuleLibFiles=(${LibSTfile} ${LibHttpParserfile})
MODULE_OBJS="${CORE_OBJS[@]} ${OS_OBJS[@]} ${APP_OBJS[@]} ${MAIN_OBJS[@]}"
BUILD_KEY="sb_rtmp_publish" APP_MAIN="htl_main_rtmp_publish" APP_NAME="sb_rtmp_publish" LINK_OPTIONS="-ldl" SO_PATH="" . auto/apps.sh
# hls load test tool over direct TCP.
ModuleLibFiles=(${LibSTfile} ${LibHttpParserfile})
MODULE_OBJS="${CORE_OBJS[@]} ${OS_OBJS[@]} ${APP_OBJS[@]} ${MAIN_OBJS[@]}"
BUILD_KEY="sb_hls_load" APP_MAIN="htl_main_hls_load" APP_NAME="sb_hls_load" LINK_OPTIONS="-ldl" SO_PATH="" . auto/apps.sh
echo 'configure ok! '
# next step.
echo "you can:"
echo "\" make \" to build the http/hls load test tools."
echo "\" make help \" to get the usage of make"

Binary file not shown.

View File

@ -0,0 +1,194 @@
/*
The MIT License (MIT)
Copyright (c) 2013-2015 winlin
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include <htl_stdinc.hpp>
#include <inttypes.h>
#include <stdlib.h>
#include <string>
#include <sstream>
#include <vector>
using namespace std;
#include <htl_core_log.hpp>
#include <htl_core_error.hpp>
#include <htl_core_aggregate_ret.hpp>
#include <htl_app_http_client.hpp>
#include <htl_app_hls_load.hpp>
#include <algorithm>
#define DEFAULT_TS_DURATION 10
StHlsTask::StHlsTask(){
target_duration = DEFAULT_TS_DURATION;
}
StHlsTask::~StHlsTask(){
}
int StHlsTask::Initialize(std::string http_url, bool vod, double startup, double delay, double error, int count){
int ret = ERROR_SUCCESS;
is_vod = vod;
if((ret = InitializeBase(http_url, startup, delay, error, count)) != ERROR_SUCCESS){
return ret;
}
return ret;
}
Uri* StHlsTask::GetUri(){
return &url;
}
int StHlsTask::ProcessTask(){
int ret = ERROR_SUCCESS;
Trace("start to process HLS task #%d, schema=%s, host=%s, port=%d, path=%s, startup=%.2f, delay=%.2f, error=%.2f, count=%d",
GetId(), url.GetSchema(), url.GetHost(), url.GetPort(), url.GetPath(), startup_seconds, delay_seconds, error_seconds, count);
StHttpClient client;
// if count is zero, infinity loop.
for(int i = 0; count == 0 || i < count; i++){
statistic->OnTaskStart(GetId(), url.GetUrl());
if((ret = ProcessM3u8(client)) != ERROR_SUCCESS){
statistic->OnTaskError(GetId(), 0);
Error("http client process m3u8 failed. ret=%d", ret);
st_usleep((st_utime_t)(error_seconds * 1000 * 1000));
continue;
}
Info("[HLS] %s download completed.", url.GetUrl());
}
return ret;
}
int StHlsTask::ProcessM3u8(StHttpClient& client){
int ret = ERROR_SUCCESS;
string m3u8;
if((ret = client.DownloadString(&url, &m3u8)) != ERROR_SUCCESS){
Error("http client get m3u8 failed. ret=%d", ret);
return ret;
}
Trace("[HLS] get m3u8 %s get success, length=%"PRId64, url.GetUrl(), (int64_t)m3u8.length());
vector<M3u8TS> ts_objects;
if((ret = HlsM3u8Parser::ParseM3u8Data(&url, m3u8, ts_objects, target_duration)) != ERROR_SUCCESS){
Error("http client parse m3u8 content failed. ret=%d", ret);
return ret;
}
if((ret = ProcessTS(client, ts_objects)) != ERROR_SUCCESS){
Error("http client download m3u8 ts file failed. ret=%d", ret);
return ret;
}
return ret;
}
int StHlsTask::ProcessTS(StHttpClient& client, vector<M3u8TS>& ts_objects){
int ret = ERROR_SUCCESS;
vector<M3u8TS>::iterator ite = ts_objects.begin();
// if live(not vod), remember the last download ts object.
// if vod(not live), always access from the frist ts.
if(!is_vod){
ite = find(ts_objects.begin(), ts_objects.end(), last_downloaded_ts);
// not found, reset to begin to process all.
if(ite == ts_objects.end()){
ite = ts_objects.begin();
}
// fount, skip it.
else{
ite++;
}
// no ts now, wait for a segment
if(ite == ts_objects.end()){
int sleep_ms = StUtility::BuildRandomMTime((target_duration > 0)? target_duration:DEFAULT_TS_DURATION);
Trace("[TS] no fresh ts, wait for a while. sleep %dms", sleep_ms);
st_usleep(sleep_ms * 1000);
return ret;
}
}
AggregateRet aggregate_ret;
// to process from the specified ite
for(; ite != ts_objects.end(); ++ite){
M3u8TS ts_object = *ite;
if(!is_vod){
last_downloaded_ts = ts_object;
}
Info("start to process ts %s", ts_object.ts_url.c_str());
aggregate_ret.Add(DownloadTS(client, ts_object));
}
return aggregate_ret.GetReturnValue();
}
int StHlsTask::DownloadTS(StHttpClient& client, M3u8TS& ts){
int ret = ERROR_SUCCESS;
HttpUrl url;
if((ret = url.Initialize(ts.ts_url)) != ERROR_SUCCESS){
Error("initialize ts url failed. ret=%d", ret);
return ret;
}
Info("[TS] url=%s, duration=%.2f, delay=%.2f", url.GetUrl(), ts.duration, delay_seconds);
statistic->OnSubTaskStart(GetId(), ts.ts_url);
if((ret = client.DownloadString(&url, NULL)) != ERROR_SUCCESS){
statistic->OnSubTaskError(GetId(), (int)ts.duration);
Error("http client download ts file %s failed. ret=%d", url.GetUrl(), ret);
return ret;
}
int sleep_ms = StUtility::BuildRandomMTime((delay_seconds >= 0)? delay_seconds:ts.duration);
Trace("[TS] url=%s download, duration=%.2f, delay=%.2f, size=%"PRId64", sleep %dms",
url.GetUrl(), ts.duration, delay_seconds, client.GetResponseHeader()->content_length, sleep_ms);
st_usleep(sleep_ms * 1000);
statistic->OnSubTaskEnd(GetId(), (int)ts.duration);
return ret;
}

View File

@ -0,0 +1,57 @@
/*
The MIT License (MIT)
Copyright (c) 2013-2015 winlin
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef _htl_app_hls_load_hpp
#define _htl_app_hls_load_hpp
/*
#include <htl_app_hls_load.hpp>
*/
#include <htl_app_http_client.hpp>
#include <htl_app_m3u8_parser.hpp>
#include <htl_app_task_base.hpp>
// for http task.
class StHlsTask : public StBaseTask
{
private:
HttpUrl url;
// the last downloaded ts url to prevent download multile times.
M3u8TS last_downloaded_ts;
int target_duration;
bool is_vod;
public:
StHlsTask();
virtual ~StHlsTask();
public:
virtual int Initialize(std::string http_url, bool vod, double startup, double delay, double error, int count);
protected:
virtual Uri* GetUri();
virtual int ProcessTask();
private:
virtual int ProcessM3u8(StHttpClient& client);
virtual int ProcessTS(StHttpClient& client, std::vector<M3u8TS>& ts_objects);
virtual int DownloadTS(StHttpClient& client, M3u8TS& ts);
};
#endif

View File

@ -0,0 +1,269 @@
/*
The MIT License (MIT)
Copyright (c) 2013-2015 winlin
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include <htl_stdinc.hpp>
#include <inttypes.h>
#include <assert.h>
#include <string>
#include <sstream>
using namespace std;
#include <htl_core_error.hpp>
#include <htl_core_log.hpp>
#include <htl_app_http_client.hpp>
StHttpClient::StHttpClient(){
socket = new StSocket();
connected_url = NULL;
}
StHttpClient::~StHttpClient(){
delete socket;
socket = NULL;
delete connected_url;
connected_url = NULL;
}
int StHttpClient::DownloadString(HttpUrl* url, std::string* response){
int ret = ERROR_SUCCESS;
if((ret = CheckUrl(url)) != ERROR_SUCCESS){
Error("http client check url failed. ret=%d", ret);
return ret;
}
if((ret = Connect(url)) != ERROR_SUCCESS){
Error("http client connect url failed. ret=%d", ret);
return ret;
}
// send GET request to read content
// GET %s HTTP/1.1\r\nHost: %s\r\n\r\n
stringstream ss;
ss << "GET " << url->GetPath() << " "
<< "HTTP/1.1\r\n"
<< "Host: " << url->GetHost() << "\r\n"
<< "Connection: Keep-Alive" << "\r\n"
<< "User-Agent: " << ProductHTTPName << "\r\n"
<< "\r\n";
ssize_t nwrite;
if((ret = socket->Write(ss.str().c_str(), ss.str().length(), &nwrite)) != ERROR_SUCCESS){
Error("write to server failed. ret=%d", ret);
return ret;
}
if((ret = ParseResponse(url, response)) != ERROR_SUCCESS){
Error("http client parse response failed. ret=%d", ret);
return ret;
}
return ret;
}
http_parser* StHttpClient::GetResponseHeader(){
return &http_header;
}
int StHttpClient::on_headers_complete(http_parser* parser){
StHttpClient* obj = (StHttpClient*)parser->data;
obj->OnHeaderCompleted(parser);
// see http_parser.c:1570, return 1 to skip body.
return 1;
}
void StHttpClient::OnHeaderCompleted(http_parser* parser){
// save the parser status when header parse completed.
memcpy(&http_header, parser, sizeof(http_header));
}
int StHttpClient::ParseResponse(HttpUrl* url, string* response){
int ret = ERROR_SUCCESS;
int body_received = 0;
if((ret = ParseResponseHeader(response, body_received)) != ERROR_SUCCESS){
Error("parse response header failed. ret=%d", ret);
return ret;
}
if((ret = ParseResponseBody(url, response, body_received)) != ERROR_SUCCESS){
Error("parse response body failed. ret=%d", ret);
return ret;
}
Info("url %s download, body size=%"PRId64, url->GetUrl(), http_header.content_length);
return ret;
}
int StHttpClient::ParseResponseBody(HttpUrl* url, string* response, int body_received){
int ret = ERROR_SUCCESS;
assert(url != NULL);
uint64_t body_left = http_header.content_length - body_received;
if(response != NULL){
char buf[HTTP_BODY_BUFFER];
return ParseResponseBodyData(url, response, (size_t)body_left, (const void*)buf, (size_t)HTTP_BODY_BUFFER);
}
else{
// if ignore response, use shared fast memory.
static char buf[HTTP_BODY_BUFFER];
return ParseResponseBodyData(url, response, (size_t)body_left, (const void*)buf, (size_t)HTTP_BODY_BUFFER);
}
return ret;
}
int StHttpClient::ParseResponseBodyData(HttpUrl* url, string* response, size_t body_left, const void* buf, size_t size){
int ret = ERROR_SUCCESS;
assert(url != NULL);
while(body_left > 0){
ssize_t nread;
if((ret = socket->Read(buf, (size < body_left)? size:body_left, &nread)) != ERROR_SUCCESS){
Error("read header from server failed. ret=%d", ret);
return ret;
}
if(response != NULL && nread > 0){
response->append((char*)buf, nread);
}
body_left -= nread;
Info("read url(%s) content partial %"PRId64"/%"PRId64"",
url->GetUrl(), http_header.content_length - body_left, http_header.content_length);
}
return ret;
}
int StHttpClient::ParseResponseHeader(string* response, int& body_received){
int ret = ERROR_SUCCESS;
http_parser_settings settings;
memset(&settings, 0, sizeof(settings));
settings.on_headers_complete = on_headers_complete;
http_parser parser;
http_parser_init(&parser, HTTP_RESPONSE);
// callback object ptr.
parser.data = (void*)this;
// reset response header.
memset(&http_header, 0, sizeof(http_header));
// parser header.
char buf[HTTP_HEADER_BUFFER];
for(;;){
ssize_t nread;
if((ret = socket->Read((const void*)buf, (size_t)sizeof(buf), &nread)) != ERROR_SUCCESS){
Error("read body from server failed. ret=%d", ret);
return ret;
}
ssize_t nparsed = http_parser_execute(&parser, &settings, buf, nread);
Info("read_size=%d, nparsed=%d", (int)nread, (int)nparsed);
// check header size.
if(http_header.nread != 0){
body_received = nread - nparsed;
Info("http header parsed, size=%d, content-length=%"PRId64", body-received=%d",
http_header.nread, http_header.content_length, body_received);
if(response != NULL && body_received > 0){
response->append(buf + nparsed, body_received);
}
return ret;
}
if(nparsed != nread){
ret = ERROR_HP_PARSE_RESPONSE;
Error("parse response error, parsed(%d)!=read(%d), ret=%d", (int)nparsed, (int)nread, ret);
return ret;
}
}
return ret;
}
int StHttpClient::Connect(HttpUrl* url){
int ret = ERROR_SUCCESS;
if(socket->Status() == SocketConnected){
return ret;
}
string ip;
if((ret = StUtility::DnsResolve(url->GetHost(), ip)) != ERROR_SUCCESS){
Error("dns resolve failed. ret=%d", ret);
return ret;
}
if((ret = socket->Connect(ip.c_str(), url->GetPort())) != ERROR_SUCCESS){
Error("connect to server failed. ret=%d", ret);
return ret;
}
Info("socket connected on url %s", url->GetUrl());
return ret;
}
int StHttpClient::CheckUrl(HttpUrl* url){
int ret = ERROR_SUCCESS;
if(connected_url == NULL){
connected_url = url->Copy();
if((ret = StUtility::DnsResolve(connected_url->GetHost(), connected_ip)) != ERROR_SUCCESS){
return ret;
}
}
string ip;
if((ret = StUtility::DnsResolve(url->GetHost(), ip)) != ERROR_SUCCESS){
return ret;
}
if(ip != connected_ip || connected_url->GetPort() != url->GetPort()){
ret = ERROR_HP_EP_CHNAGED;
Error("invalid url=%s, endpoint change from %s:%d to %s:%d",
url->GetUrl(), connected_ip.c_str(), connected_url->GetPort(), ip.c_str(), url->GetPort());
return ret;
}
return ret;
}

View File

@ -0,0 +1,70 @@
/*
The MIT License (MIT)
Copyright (c) 2013-2015 winlin
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef _htl_app_http_client_hpp
#define _htl_app_http_client_hpp
/*
#include <htl_app_http_client.hpp>
*/
#include <string>
#include <htl_core_uri.hpp>
#include <htl_os_st.hpp>
class StHttpClient
{
private:
std::string connected_ip;
HttpUrl* connected_url;
StSocket* socket;
private:
http_parser http_header;
public:
StHttpClient();
virtual ~StHttpClient();
public:
/**
* download the content specified by url using HTTP GET method.
* @response the string pointer which store the content. ignore content if set to NULL.
*/
virtual int DownloadString(HttpUrl* url, std::string* response);
public:
/**
* when get response and parse header completed, return the header.
* if not parsed, header set to zero.
*/
virtual http_parser* GetResponseHeader();
private:
static int on_headers_complete(http_parser* parser);
virtual void OnHeaderCompleted(http_parser* parser);
private:
virtual int ParseResponse(HttpUrl* url, string* response);
virtual int ParseResponseBody(HttpUrl* url, string* response, int body_received);
virtual int ParseResponseBodyData(HttpUrl* url, string* response, size_t body_left, const void* buf, size_t size);
virtual int ParseResponseHeader(string* response, int& body_received);
virtual int Connect(HttpUrl* url);
virtual int CheckUrl(HttpUrl* url);
};
#endif

View File

@ -0,0 +1,88 @@
/*
The MIT License (MIT)
Copyright (c) 2013-2015 winlin
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include <htl_stdinc.hpp>
#include <inttypes.h>
#include <stdlib.h>
#include <string>
#include <sstream>
using namespace std;
#include <htl_core_error.hpp>
#include <htl_core_log.hpp>
#include <htl_app_http_client.hpp>
#include <htl_app_http_load.hpp>
StHttpTask::StHttpTask(){
}
StHttpTask::~StHttpTask(){
}
int StHttpTask::Initialize(std::string http_url, double startup, double delay, double error, int count){
int ret = ERROR_SUCCESS;
if((ret = InitializeBase(http_url, startup, delay, error, count)) != ERROR_SUCCESS){
return ret;
}
return ret;
}
Uri* StHttpTask::GetUri(){
return &url;
}
int StHttpTask::ProcessTask(){
int ret = ERROR_SUCCESS;
Trace("start to process HTTP task #%d, schema=%s, host=%s, port=%d, path=%s, startup=%.2f, delay=%.2f, error=%.2f, count=%d",
GetId(), url.GetSchema(), url.GetHost(), url.GetPort(), url.GetPath(), startup_seconds, delay_seconds, error_seconds, count);
StHttpClient client;
// if count is zero, infinity loop.
for(int i = 0; count == 0 || i < count; i++){
statistic->OnTaskStart(GetId(), url.GetUrl());
if((ret = client.DownloadString(&url, NULL)) != ERROR_SUCCESS){
statistic->OnTaskError(GetId(), 0);
Error("http client get url failed. ret=%d", ret);
st_usleep((st_utime_t)(error_seconds * 1000 * 1000));
continue;
}
int sleep_ms = StUtility::BuildRandomMTime((delay_seconds >= 0)? delay_seconds:0);
Info("[HTTP] %s download, size=%"PRId64", sleep %dms", url.GetUrl(), client.GetResponseHeader()->content_length, sleep_ms);
st_usleep(sleep_ms * 1000);
statistic->OnTaskEnd(GetId(), 0);
}
return ret;
}

View File

@ -0,0 +1,47 @@
/*
The MIT License (MIT)
Copyright (c) 2013-2015 winlin
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef _htl_app_http_load_hpp
#define _htl_app_http_load_hpp
/*
#include <htl_app_http_load.hpp>
*/
#include <htl_app_task_base.hpp>
// for http task.
class StHttpTask : public StBaseTask
{
private:
HttpUrl url;
public:
StHttpTask();
virtual ~StHttpTask();
public:
virtual int Initialize(std::string http_url, double startup, double delay, double error, int count);
protected:
virtual Uri* GetUri();
virtual int ProcessTask();
};
#endif

View File

@ -0,0 +1,185 @@
/*
The MIT License (MIT)
Copyright (c) 2013-2015 winlin
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include <htl_stdinc.hpp>
#include <inttypes.h>
#include <stdlib.h>
#include <string>
#include <sstream>
#include <vector>
using namespace std;
#include <htl_core_error.hpp>
#include <htl_core_log.hpp>
#include <htl_app_http_client.hpp>
#include <htl_app_m3u8_parser.hpp>
class String
{
private:
string value;
public:
String(string str = ""){
value = str;
}
public:
String& set_str(string str){
value = str;
return *this;
}
int length(){
return (int)value.length();
}
bool startswith(string key, String* left = NULL){
size_t pos = value.find(key);
if(pos == 0 && left != NULL){
left->set_str(value.substr(pos + key.length()));
left->strip();
}
return pos == 0;
}
bool endswith(string key, String* left = NULL){
size_t pos = value.rfind(key);
if(pos == value.length() - key.length() && left != NULL){
left->set_str(value.substr(pos));
left->strip();
}
return pos == value.length() - key.length();
}
String& strip(){
if (value.empty()) {
return *this;
}
// macro to test whether char is a space.
#define __IS_SPACE(ch) (ch == '\n' || ch == '\r' || ch == ' ')
// find the start and end which is not space.
char* bytes = (char*)value.data();
// find the end not space
char* end = NULL;
for (end = bytes + value.length() - 1; end > bytes && __IS_SPACE(end[0]); end--) {
}
// find the start not space
char* start = NULL;
for (start = bytes; start < end && __IS_SPACE(start[0]); start++) {
}
// get the data to trim.
value = value.substr(start - bytes, end - start + 1);
return *this;
}
string getline(){
size_t pos = string::npos;
if((pos = value.find("\n")) != string::npos){
return value.substr(0, pos);
}
return value;
}
String& remove(int size){
if(size >= (int)value.length()){
value = "";
return *this;
}
value = value.substr(size);
return *this;
}
const char* c_str(){
return value.c_str();
}
};
HlsM3u8Parser::HlsM3u8Parser(){
}
HlsM3u8Parser::~HlsM3u8Parser(){
}
int HlsM3u8Parser::ParseM3u8Data(HttpUrl* url, string m3u8, vector<M3u8TS>& ts_objects, int& target_duration){
int ret = ERROR_SUCCESS;
String data(m3u8);
// http://tools.ietf.org/html/draft-pantos-http-live-streaming-08#section-3.3.1
// An Extended M3U file is distinguished from a basic M3U file by its
// first line, which MUST be the tag #EXTM3U.
if(!data.startswith("#EXTM3U")){
ret = ERROR_HLS_INVALID;
Error("invalid hls, #EXTM3U not found. ret=%d", ret);
return ret;
}
String value;
M3u8TS ts_object;
while(data.length() > 0){
String line;
data.remove(line.set_str(data.strip().getline()).strip().length()).strip();
// http://tools.ietf.org/html/draft-pantos-http-live-streaming-08#section-3.4.2
// #EXT-X-TARGETDURATION:<s>
// where s is an integer indicating the target duration in seconds.
if(line.startswith("#EXT-X-TARGETDURATION:", &value)){
target_duration = atoi(value.c_str());
ts_object.duration = target_duration;
continue;
}
// http://tools.ietf.org/html/draft-pantos-http-live-streaming-08#section-3.3.2
// #EXTINF:<duration>,<title>
// "duration" is an integer or floating-point number in decimal
// positional notation that specifies the duration of the media segment
// in seconds. Durations that are reported as integers SHOULD be
// rounded to the nearest integer. Durations MUST be integers if the
// protocol version of the Playlist file is less than 3. The remainder
// of the line following the comma is an optional human-readable
// informative title of the media segment.
// ignore others util EXTINF
if(line.startswith("#EXTINF:", &value)){
ts_object.duration = atof(value.c_str());
continue;
}
if(!line.startswith("#")){
ts_object.ts_url = url->Resolve(line.c_str());
ts_objects.push_back(ts_object);
continue;
}
}
return ret;
}

View File

@ -0,0 +1,54 @@
/*
The MIT License (MIT)
Copyright (c) 2013-2015 winlin
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef _htl_app_m3u8_parser_hpp
#define _htl_app_m3u8_parser_hpp
/*
#include <htl_app_m3u8_parser.hpp>
*/
#include <string>
#include <vector>
#include <htl_core_uri.hpp>
struct M3u8TS
{
std::string ts_url;
double duration;
bool operator== (const M3u8TS& b)const{
return ts_url == b.ts_url;
}
};
class HlsM3u8Parser
{
public:
HlsM3u8Parser();
virtual ~HlsM3u8Parser();
public:
static int ParseM3u8Data(HttpUrl* url, std::string m3u8, std::vector<M3u8TS>& ts_objects, int& target_duration);
};
#endif

View File

@ -0,0 +1,191 @@
/*
The MIT License (MIT)
Copyright (c) 2013-2015 winlin
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include <htl_stdinc.hpp>
#include <inttypes.h>
#include <stdlib.h>
#include <string>
#include <sstream>
using namespace std;
#include <htl_core_error.hpp>
#include <htl_core_log.hpp>
#include <htl_app_rtmp_play.hpp>
#include <htl_app_rtmp_publish.hpp>
#include <htl_app_rtmp_load.hpp>
StRtmpTask::StRtmpTask(){
}
StRtmpTask::~StRtmpTask(){
}
int StRtmpTask::Initialize(string http_url, double startup, double delay, double error, int count){
int ret = ERROR_SUCCESS;
if((ret = InitializeBase(http_url, startup, delay, error, count)) != ERROR_SUCCESS){
return ret;
}
return ret;
}
Uri* StRtmpTask::GetUri(){
return &url;
}
int StRtmpTask::ProcessTask(){
int ret = ERROR_SUCCESS;
Trace("start to process RTMP play task #%d, schema=%s, host=%s, port=%d, tcUrl=%s, stream=%s, startup=%.2f, delay=%.2f, error=%.2f, count=%d",
GetId(), url.GetSchema(), url.GetHost(), url.GetPort(), url.GetTcUrl(), url.GetStream(), startup_seconds, delay_seconds, error_seconds, count);
StRtmpPlayClient client;
// if count is zero, infinity loop.
for(int i = 0; count == 0 || i < count; i++){
statistic->OnTaskStart(GetId(), url.GetUrl());
if((ret = client.Dump(&url)) != ERROR_SUCCESS){
statistic->OnTaskError(GetId(), 0);
Error("rtmp client dump url failed. ret=%d", ret);
st_usleep((st_utime_t)(error_seconds * 1000 * 1000));
continue;
}
int sleep_ms = StUtility::BuildRandomMTime((delay_seconds >= 0)? delay_seconds:0);
Trace("[RTMP] %s dump success, sleep %dms", url.GetUrl(), sleep_ms);
st_usleep(sleep_ms * 1000);
statistic->OnTaskEnd(GetId(), 0);
}
return ret;
}
StRtmpTaskFast::StRtmpTaskFast(){
}
StRtmpTaskFast::~StRtmpTaskFast(){
}
int StRtmpTaskFast::Initialize(string http_url, double startup, double delay, double error, int count){
int ret = ERROR_SUCCESS;
if((ret = InitializeBase(http_url, startup, delay, error, count)) != ERROR_SUCCESS){
return ret;
}
return ret;
}
Uri* StRtmpTaskFast::GetUri(){
return &url;
}
int StRtmpTaskFast::ProcessTask(){
int ret = ERROR_SUCCESS;
Trace("start to process RTMP play fast task #%d, schema=%s, host=%s, port=%d, tcUrl=%s, stream=%s, startup=%.2f, delay=%.2f, error=%.2f, count=%d",
GetId(), url.GetSchema(), url.GetHost(), url.GetPort(), url.GetTcUrl(), url.GetStream(), startup_seconds, delay_seconds, error_seconds, count);
StRtmpPlayClientFast client;
// if count is zero, infinity loop.
for(int i = 0; count == 0 || i < count; i++){
statistic->OnTaskStart(GetId(), url.GetUrl());
if((ret = client.Dump(&url)) != ERROR_SUCCESS){
statistic->OnTaskError(GetId(), 0);
Error("rtmp client dump url failed. ret=%d", ret);
st_usleep((st_utime_t)(error_seconds * 1000 * 1000));
continue;
}
int sleep_ms = StUtility::BuildRandomMTime((delay_seconds >= 0)? delay_seconds:0);
Trace("[RTMP] %s dump success, sleep %dms", url.GetUrl(), sleep_ms);
st_usleep(sleep_ms * 1000);
statistic->OnTaskEnd(GetId(), 0);
}
return ret;
}
StRtmpPublishTask::StRtmpPublishTask(){
}
StRtmpPublishTask::~StRtmpPublishTask(){
}
int StRtmpPublishTask::Initialize(string input, string http_url, double startup, double delay, double error, int count){
int ret = ERROR_SUCCESS;
input_flv_file = input;
if((ret = InitializeBase(http_url, startup, delay, error, count)) != ERROR_SUCCESS){
return ret;
}
return ret;
}
Uri* StRtmpPublishTask::GetUri(){
return &url;
}
int StRtmpPublishTask::ProcessTask(){
int ret = ERROR_SUCCESS;
Trace("start to process RTMP publish task #%d, schema=%s, host=%s, port=%d, tcUrl=%s, stream=%s, startup=%.2f, delay=%.2f, error=%.2f, count=%d",
GetId(), url.GetSchema(), url.GetHost(), url.GetPort(), url.GetTcUrl(), url.GetStream(), startup_seconds, delay_seconds, error_seconds, count);
StRtmpPublishClient client;
// if count is zero, infinity loop.
for(int i = 0; count == 0 || i < count; i++){
statistic->OnTaskStart(GetId(), url.GetUrl());
if((ret = client.Publish(input_flv_file, &url)) != ERROR_SUCCESS){
statistic->OnTaskError(GetId(), 0);
Error("rtmp client publish url failed. ret=%d", ret);
st_usleep((st_utime_t)(error_seconds * 1000 * 1000));
continue;
}
int sleep_ms = StUtility::BuildRandomMTime((delay_seconds >= 0)? delay_seconds:0);
Trace("[RTMP] %s publish success, sleep %dms", url.GetUrl(), sleep_ms);
st_usleep(sleep_ms * 1000);
statistic->OnTaskEnd(GetId(), 0);
}
return ret;
}

View File

@ -0,0 +1,80 @@
/*
The MIT License (MIT)
Copyright (c) 2013-2015 winlin
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef _htl_app_rtmp_load_hpp
#define _htl_app_rtmp_load_hpp
/*
#include <htl_app_rtmp_load.hpp>
*/
#include <htl_app_task_base.hpp>
// for rtmp task.
class StRtmpTask : public StBaseTask
{
private:
RtmpUrl url;
public:
StRtmpTask();
virtual ~StRtmpTask();
public:
virtual int Initialize(std::string http_url, double startup, double delay, double error, int count);
protected:
virtual Uri* GetUri();
virtual int ProcessTask();
};
// for rtmp task with fast algorihtm.
// donot recv in RTMP, but directly in TCP.
class StRtmpTaskFast : public StBaseTask
{
private:
RtmpUrl url;
public:
StRtmpTaskFast();
virtual ~StRtmpTaskFast();
public:
virtual int Initialize(std::string http_url, double startup, double delay, double error, int count);
protected:
virtual Uri* GetUri();
virtual int ProcessTask();
};
// for rtmp publish load task.
class StRtmpPublishTask : public StBaseTask
{
private:
std::string input_flv_file;
RtmpUrl url;
public:
StRtmpPublishTask();
virtual ~StRtmpPublishTask();
public:
virtual int Initialize(std::string input,
std::string http_url, double startup, double delay, double error, int count);
protected:
virtual Uri* GetUri();
virtual int ProcessTask();
};
#endif

View File

@ -0,0 +1,177 @@
/*
The MIT License (MIT)
Copyright (c) 2013-2015 winlin
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include <htl_stdinc.hpp>
#include <inttypes.h>
#include <assert.h>
#include <string>
#include <sstream>
using namespace std;
#include <htl_core_error.hpp>
#include <htl_core_log.hpp>
#include <htl_app_rtmp_play.hpp>
#include <htl_app_rtmp_protocol.hpp>
#include <htl_app_srs_hijack.hpp>
#define SOCK_READ_BUFFER 4096
#define SOCK_READV_NB 1024
#define SOCK_MERGED_READ_MS 800
StRtmpPlayClient::StRtmpPlayClient(){
stream_id = 0;
srs = NULL;
}
StRtmpPlayClient::~StRtmpPlayClient(){
srs_rtmp_destroy(srs);
}
int StRtmpPlayClient::Dump(RtmpUrl* url){
int ret = ERROR_SUCCESS;
if((ret = Connect(url)) != ERROR_SUCCESS){
Error("rtmp client connect server failed. ret=%d", ret);
return ret;
}
if((ret = Handshake()) != ERROR_SUCCESS){
Error("rtmp client handshake failed. ret=%d", ret);
return ret;
}
Info("rtmp client handshake success");
if((ret = ConnectApp()) != ERROR_SUCCESS){
Error("rtmp client connect tcUrl failed. ret=%d", ret);
return ret;
}
Info("rtmp client connect tcUrl(%s) success", url->GetTcUrl());
if((ret = PlayStram()) != ERROR_SUCCESS){
Error("rtmp client play stream failed. ret=%d", ret);
return ret;
}
Info("rtmp client play stream(%s) success", url->GetUrl());
if((ret = DumpAV()) != ERROR_SUCCESS){
Error("rtmp client dump av failed. ret=%d", ret);
return ret;
}
Info("rtmp client dump av success");
return ret;
}
int StRtmpPlayClient::Connect(RtmpUrl* url){
int ret = ERROR_SUCCESS;
srs_rtmp_destroy(srs);
srs = srs_rtmp_create(url->GetUrl());
if ((ret = srs_rtmp_dns_resolve(srs)) != ERROR_SUCCESS){
Error("dns resolve failed. ret=%d", ret);
return ret;
}
if ((ret = srs_rtmp_connect_server(srs)) != ERROR_SUCCESS){
Error("connect to server failed. ret=%d", ret);
return ret;
}
Info("socket connected on url %s", url->GetUrl());
return ret;
}
int StRtmpPlayClient::Handshake(){
return srs_rtmp_do_simple_handshake(srs);
}
int StRtmpPlayClient::ConnectApp(){
return srs_rtmp_connect_app(srs);
}
int StRtmpPlayClient::PlayStram(){
return srs_rtmp_play_stream(srs);
}
int StRtmpPlayClient::DumpAV(){
int ret = ERROR_SUCCESS;
// recv response
while(true){
char type;
u_int32_t timestamp;
char* data;
int size;
if ((ret = srs_rtmp_read_packet(srs, &type, &timestamp, &data, &size)) != ERROR_SUCCESS){
return ret;
}
Info("get message type=%d, size=%d", type, size);
delete data;
}
return ret;
}
StRtmpPlayClientFast::StRtmpPlayClientFast(){
}
StRtmpPlayClientFast::~StRtmpPlayClientFast(){
}
int StRtmpPlayClientFast::DumpAV(){
int ret = ERROR_SUCCESS;
StSocket* skt = srs_hijack_get(srs);
// use buffered iovs to read tcp data.
char buf[SOCK_READ_BUFFER];
iovec iovs[SOCK_READV_NB];
for (int i = 0; i < SOCK_READV_NB; i++) {
iovec& iov = iovs[i];
iov.iov_base = buf;
iov.iov_len = SOCK_READ_BUFFER;
}
// recv response
while(true){
ssize_t size = 0;
if ((ret = skt->Readv(iovs, SOCK_READV_NB, &size)) != ERROR_SUCCESS) {
return ret;
}
Info("get message size=%d", size);
// merged read.
st_usleep(SOCK_MERGED_READ_MS * 1000);
}
return ret;
}

View File

@ -0,0 +1,64 @@
/*
The MIT License (MIT)
Copyright (c) 2013-2015 winlin
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef _htl_app_rtmp_play_hpp
#define _htl_app_rtmp_play_hpp
/*
#include <htl_app_rtmp_play.hpp>
*/
#include <string>
#include <htl_core_uri.hpp>
#include <htl_os_st.hpp>
#include <htl_app_rtmp_protocol.hpp>
class StRtmpPlayClient
{
protected:
srs_rtmp_t srs;
int stream_id;
public:
StRtmpPlayClient();
virtual ~StRtmpPlayClient();
public:
virtual int Dump(RtmpUrl* url);
protected:
virtual int Connect(RtmpUrl* url);
virtual int Handshake();
virtual int ConnectApp();
virtual int PlayStram();
virtual int DumpAV();
};
class StRtmpPlayClientFast : public StRtmpPlayClient
{
public:
StRtmpPlayClientFast();
virtual ~StRtmpPlayClientFast();
protected:
virtual int DumpAV();
};
#endif

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,230 @@
/*
The MIT License (MIT)
Copyright (c) 2013-2015 winlin
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include <htl_stdinc.hpp>
#include <inttypes.h>
#include <assert.h>
#include <string>
#include <sstream>
using namespace std;
#include <htl_core_error.hpp>
#include <htl_core_log.hpp>
#include <htl_app_rtmp_publish.hpp>
#include <htl_app_rtmp_protocol.hpp>
StRtmpPublishClient::StRtmpPublishClient(){
stream_id = 0;
srs = NULL;
}
StRtmpPublishClient::~StRtmpPublishClient(){
srs_rtmp_destroy(srs);
}
int StRtmpPublishClient::Publish(string input, RtmpUrl* url){
int ret = ERROR_SUCCESS;
if((ret = Connect(url)) != ERROR_SUCCESS){
Error("rtmp client connect server failed. ret=%d", ret);
return ret;
}
if((ret = Handshake()) != ERROR_SUCCESS){
Error("rtmp client handshake failed. ret=%d", ret);
return ret;
}
Info("rtmp client handshake success");
if((ret = ConnectApp()) != ERROR_SUCCESS){
Error("rtmp client connect tcUrl failed. ret=%d", ret);
return ret;
}
Info("rtmp client connect tcUrl(%s) success", url->GetTcUrl());
if((ret = PublishStram()) != ERROR_SUCCESS){
Error("rtmp client publish stream failed. ret=%d", ret);
return ret;
}
Info("rtmp client publish stream(%s) success", url->GetUrl());
srs_flv_t flv = srs_flv_open_read(input.c_str());
if (!flv) {
ret = ERROR_RTMP_OPEN_FLV;
Error("open flv file %s failed. ret=%d", input.c_str(), ret);
return ret;
}
int64_t timebase = 0;
while (true) {
int32_t starttime = -1;
int32_t endtime = -1;
// publish the whole av of flv file
ret = PublishAV(flv, timebase, &starttime, &endtime);
// restart when flv EOF
if (srs_flv_is_eof(ret)) {
srs_flv_lseek(flv, 0);
timebase += endtime - starttime;
Info("republish for flv EOF, timebase=%"PRId64", start=%d, end=%d, ret=%d",
timebase, starttime, endtime, ret);
continue;
}
}
srs_flv_close(flv);
if(ret != ERROR_SUCCESS){
Error("rtmp client dump av failed. ret=%d", ret);
return ret;
}
Info("rtmp client dump av success");
return ret;
}
int StRtmpPublishClient::Connect(RtmpUrl* url){
int ret = ERROR_SUCCESS;
srs_rtmp_destroy(srs);
srs = srs_rtmp_create(url->GetUrl());
if ((ret = srs_rtmp_dns_resolve(srs)) != ERROR_SUCCESS){
Error("dns resolve failed. ret=%d", ret);
return ret;
}
if ((ret = srs_rtmp_connect_server(srs)) != ERROR_SUCCESS){
Error("connect to server failed. ret=%d", ret);
return ret;
}
Info("socket connected on url %s", url->GetUrl());
return ret;
}
int StRtmpPublishClient::Handshake(){
return srs_rtmp_do_simple_handshake(srs);
}
int StRtmpPublishClient::ConnectApp(){
return srs_rtmp_connect_app(srs);
}
int StRtmpPublishClient::PublishStram(){
return srs_rtmp_publish_stream(srs);
}
int StRtmpPublishClient::PublishAV(srs_flv_t flv,
int64_t timebase, int32_t* starttime, int32_t* endtime
){
int ret = ERROR_SUCCESS;
char header[9];
if ((ret = srs_flv_read_header(flv, header)) != ERROR_SUCCESS) {
Error("read flv header failed. ret=%d", ret);
return ret;
}
// open flv and publish to server.
u_int32_t re = 0;
while(true){
char type;
u_int32_t timestamp;
int32_t size;
if ((ret = srs_flv_read_tag_header(flv, &type, &size, &timestamp)) != ERROR_SUCCESS) {
return ret;
}
// update the start and end time.
if (*starttime < 0) {
*starttime = timestamp;
}
*endtime = timestamp;
char* data = new char[size];
if ((ret = srs_flv_read_tag_data(flv, data, size)) != ERROR_SUCCESS) {
delete data;
return ret;
}
// modify the duration to -1
if (type == SRS_RTMP_TYPE_SCRIPT) {
int nparsed = 0;
srs_amf0_t onMetaData = srs_amf0_parse(data, size, &nparsed);
srs_amf0_t metadata = srs_amf0_parse(data + nparsed, size - nparsed, &nparsed);
if (srs_amf0_is_ecma_array(metadata)) {
srs_amf0_t obj = srs_amf0_ecma_array_to_object(metadata);
srs_amf0_free(metadata);
metadata = obj;
}
if (srs_amf0_object_property(metadata, "duration")) {
srs_amf0_object_property_set(metadata, "duration", srs_amf0_create_number(-1));
// serialize to bytes.
int nb_onMetaData = srs_amf0_size(onMetaData);
int nb_metadata = srs_amf0_size(metadata);
size = nb_onMetaData + nb_metadata;
delete[] data;
data = new char[size];
ret = srs_amf0_serialize(onMetaData, data, nb_onMetaData);
if (ret == ERROR_SUCCESS) {
ret = srs_amf0_serialize(metadata, data + nb_onMetaData, nb_metadata);
}
srs_amf0_free(onMetaData);
srs_amf0_free(metadata);
if (ret != ERROR_SUCCESS) {
delete data;
return ret;
}
}
}
u_int32_t dts = (u_int32_t)(timebase + timestamp);
if ((ret = srs_rtmp_write_packet(srs, type, dts, data, size)) != ERROR_SUCCESS) {
return ret;
}
Info("send message type=%d, size=%d, time=%d, dts=%d",
type, size, timestamp, dts);
if (re <= 0) {
re = timestamp;
}
if (timestamp - re > 300) {
st_usleep((timestamp - re) * 1000);
re = timestamp;
}
}
return ret;
}

View File

@ -0,0 +1,57 @@
/*
The MIT License (MIT)
Copyright (c) 2013-2015 winlin
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef _htl_app_rtmp_publish_hpp
#define _htl_app_rtmp_publish_hpp
/*
#include <htl_app_rtmp_publish.hpp>
*/
#include <string>
#include <htl_core_uri.hpp>
#include <htl_os_st.hpp>
#include <htl_app_rtmp_protocol.hpp>
class StRtmpPublishClient
{
private:
srs_rtmp_t srs;
int stream_id;
public:
StRtmpPublishClient();
virtual ~StRtmpPublishClient();
public:
virtual int Publish(std::string input, RtmpUrl* url);
private:
virtual int Connect(RtmpUrl* url);
virtual int Handshake();
virtual int ConnectApp();
virtual int PublishStram();
virtual int PublishAV(srs_flv_t flv,
int64_t timebase, int32_t* starttime, int32_t* endtime
);
};
#endif

View File

@ -0,0 +1,118 @@
/*
The MIT License (MIT)
Copyright (c) 2013-2015 winlin
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include <htl_stdinc.hpp>
#include <htl_app_srs_hijack.hpp>
#include <htl_os_st.hpp>
#include <htl_core_error.hpp>
#include <htl_app_rtmp_protocol.hpp>
#ifndef SRS_HIJACK_IO
#error "must hijack the srs-librtmp"
#endif
StSocket* srs_hijack_get(srs_rtmp_t rtmp)
{
srs_hijack_io_t ctx = srs_hijack_io_get(rtmp);
return (StSocket*)ctx;
}
srs_hijack_io_t srs_hijack_io_create()
{
return new StSocket();
}
void srs_hijack_io_destroy(srs_hijack_io_t ctx)
{
StSocket* skt = (StSocket*)ctx;
delete skt;
}
int srs_hijack_io_create_socket(srs_hijack_io_t /*ctx*/)
{
return ERROR_SUCCESS;
}
int srs_hijack_io_connect(srs_hijack_io_t ctx, const char* server_ip, int port)
{
StSocket* skt = (StSocket*)ctx;
return skt->Connect(server_ip, port);
}
int srs_hijack_io_read(srs_hijack_io_t ctx, void* buf, size_t size, ssize_t* nread)
{
StSocket* skt = (StSocket*)ctx;
return skt->Read(buf, size, nread);
}
void srs_hijack_io_set_recv_timeout(srs_hijack_io_t /*ctx*/, int64_t /*timeout_us*/)
{
}
int64_t srs_hijack_io_get_recv_timeout(srs_hijack_io_t /*ctx*/)
{
return ST_UTIME_NO_TIMEOUT;
}
int64_t srs_hijack_io_get_recv_bytes(srs_hijack_io_t /*ctx*/)
{
return 0;
}
void srs_hijack_io_set_send_timeout(srs_hijack_io_t /*ctx*/, int64_t /*timeout_us*/)
{
}
int64_t srs_hijack_io_get_send_timeout(srs_hijack_io_t /*ctx*/)
{
return ST_UTIME_NO_TIMEOUT;
}
int64_t srs_hijack_io_get_send_bytes(srs_hijack_io_t /*ctx*/)
{
return 0;
}
int srs_hijack_io_writev(srs_hijack_io_t ctx, const iovec *iov, int iov_size, ssize_t* nwrite)
{
StSocket* skt = (StSocket*)ctx;
return skt->Writev(iov, iov_size, nwrite);
}
bool srs_hijack_io_is_never_timeout(srs_hijack_io_t /*ctx*/, int64_t /*timeout_us*/)
{
return true;
}
int srs_hijack_io_read_fully(srs_hijack_io_t ctx, void* buf, size_t size, ssize_t* nread)
{
StSocket* skt = (StSocket*)ctx;
return skt->ReadFully(buf, size, nread);
}
int srs_hijack_io_write(srs_hijack_io_t ctx, void* buf, size_t size, ssize_t* nwrite)
{
StSocket* skt = (StSocket*)ctx;
return skt->Write(buf, size, nwrite);
}

View File

@ -0,0 +1,37 @@
/*
The MIT License (MIT)
Copyright (c) 2013-2015 winlin
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef _htl_app_srs_hijack_hpp
#define _htl_app_srs_hijack_hpp
/*
#include <htl_app_srs_hijack.hpp>
*/
#include <htl_app_rtmp_protocol.hpp>
class StSocket;
extern StSocket* srs_hijack_get(srs_rtmp_t rtmp);
#endif

View File

@ -0,0 +1,77 @@
/*
The MIT License (MIT)
Copyright (c) 2013-2015 winlin
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include <htl_stdinc.hpp>
#include <inttypes.h>
#include <stdlib.h>
#include <string>
#include <sstream>
using namespace std;
#include <htl_core_error.hpp>
#include <htl_core_log.hpp>
#include <htl_app_http_client.hpp>
#include <htl_app_task_base.hpp>
StBaseTask::StBaseTask(){
}
StBaseTask::~StBaseTask(){
}
int StBaseTask::InitializeBase(std::string http_url, double startup, double delay, double error, int count){
int ret = ERROR_SUCCESS;
if((ret = GetUri()->Initialize(http_url)) != ERROR_SUCCESS){
return ret;
}
Info("task url(%s) parsed, startup=%.2f, delay=%.2f, error=%.2f, count=%d", http_url.c_str(), startup, delay, error, count);
this->delay_seconds = delay;
this->startup_seconds = startup;
this->error_seconds = error;
this->count = count;
return ret;
}
int StBaseTask::Process(){
int ret = ERROR_SUCCESS;
if(startup_seconds > 0){
int sleep_ms = StUtility::BuildRandomMTime(startup_seconds);
Trace("start random sleep %dms", sleep_ms);
st_usleep(sleep_ms * 1000);
}
if((ret = ProcessTask()) != ERROR_SUCCESS){
return ret;
}
return ret;
}

View File

@ -0,0 +1,56 @@
/*
The MIT License (MIT)
Copyright (c) 2013-2015 winlin
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef _htl_app_task_base_hpp
#define _htl_app_task_base_hpp
/*
#include <htl_app_task_base.hpp>
*/
#include <string>
#include <http_parser.h>
#include <htl_core_uri.hpp>
#include <htl_os_st.hpp>
class StBaseTask : public StTask
{
protected:
double startup_seconds;
double delay_seconds;
double error_seconds;
int count;
public:
StBaseTask();
virtual ~StBaseTask();
protected:
virtual int InitializeBase(std::string http_url, double startup, double delay, double error, int count);
public:
virtual int Process();
protected:
virtual Uri* GetUri() = 0;
virtual int ProcessTask() = 0;
};
#endif

View File

@ -0,0 +1,56 @@
/*
The MIT License (MIT)
Copyright (c) 2013-2015 winlin
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include <htl_stdinc.hpp>
#include <vector>
using namespace std;
#include <htl_core_error.hpp>
#include <htl_core_aggregate_ret.hpp>
AggregateRet::AggregateRet(){
}
AggregateRet::~AggregateRet(){
}
void AggregateRet::Add(int ret){
rets.push_back(ret);
}
int AggregateRet::GetReturnValue(){
int ret = ERROR_SUCCESS;
for(vector<int>::iterator ite = rets.begin(); ite != rets.end(); ++ite){
int item_ret = *ite;
if((ret = item_ret) != ERROR_SUCCESS){
return ret;
}
}
return ret;
}

View File

@ -0,0 +1,50 @@
/*
The MIT License (MIT)
Copyright (c) 2013-2015 winlin
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef _htl_core_aggregate_ret_hpp
#define _htl_core_aggregate_ret_hpp
/*
#include <htl_core_aggregate_ret.hpp>
*/
#include <vector>
class AggregateRet
{
private:
std::vector<int> rets;
public:
AggregateRet();
virtual ~AggregateRet();
public:
/**
* add return value to collection.
*/
virtual void Add(int ret);
/**
* get the summary of return value, if any failed, return it.
*/
virtual int GetReturnValue();
};
#endif

View File

@ -0,0 +1,26 @@
/*
The MIT License (MIT)
Copyright (c) 2013-2015 winlin
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include <htl_stdinc.hpp>

View File

@ -0,0 +1,72 @@
/*
The MIT License (MIT)
Copyright (c) 2013-2015 winlin
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef _htl_core_error_hpp
#define _htl_core_error_hpp
/*
#include <htl_core_error.hpp>
*/
#define ERROR_SUCCESS 0
#define ERROR_SOCKET 100
#define ERROR_OPEN_SOCKET 101
#define ERROR_CONNECT 102
#define ERROR_SEND 103
#define ERROR_READ 104
#define ERROR_CLOSE 105
#define ERROR_DNS_RESOLVE 106
#define ERROR_URL_INVALID 200
#define ERROR_HTTP_RESPONSE 201
#define ERROR_HLS_INVALID 202
#define ERROR_NOT_SUPPORT 300
#define ERROR_ST_INITIALIZE 400
#define ERROR_ST_THREAD_CREATE 401
#define ERROR_HP_PARSE_URL 500
#define ERROR_HP_EP_CHNAGED 501
#define ERROR_HP_PARSE_RESPONSE 502
#define ERROR_RTMP_URL 600
#define ERROR_RTMP_OVERFLOW 601
#define ERROR_RTMP_MSG_TOO_BIG 602
#define ERROR_RTMP_INVALID_RESPONSE 603
#define ERROR_RTMP_OPEN_FLV 604
#define ProductVersion "1.0.14"
#define ProductHTTPName "SB(SRS Bench) HttpLoad/"ProductVersion
#define ProductHLSName "SB(SRS Bench) HlsLoad/"ProductVersion
#define ProductRtmpName "SB(SRS Bench) RtmpPlayLoad/"ProductVersion
#define ProductRtmpPublishName "SB(SRS Bench) RtmpPublishLoad/"ProductVersion
#define BuildPlatform "linux"
#define BugReportEmail "winlin@vip.126.com"
#define HTTP_HEADER_BUFFER 1024
#define HTTP_BODY_BUFFER 32*1024
#endif

View File

@ -0,0 +1,72 @@
/*
The MIT License (MIT)
Copyright (c) 2013-2015 winlin
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include <htl_stdinc.hpp>
#include <string.h>
#include <sys/time.h>
#include <htl_core_log.hpp>
DateTime::DateTime(){
memset(time_data, 0, DATE_LEN);
}
DateTime::~DateTime(){
}
const char* DateTime::FormatTime(){
// clock time
timeval tv;
if(gettimeofday(&tv, NULL) == -1){
return "";
}
// to calendar time
struct tm* tm;
if((tm = localtime(&tv.tv_sec)) == NULL){
return "";
}
// log header, the time/pid/level of log
// reserved 1bytes for the new line.
snprintf(time_data, DATE_LEN, "%d-%02d-%02d %02d:%02d:%02d.%03d",
1900 + tm->tm_year, 1 + tm->tm_mon, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec,
(int)(tv.tv_usec / 1000));
return time_data;
}
LogContext::LogContext(){
}
LogContext::~LogContext(){
}
int LogContext::GetId(){
return 0;
}
const char* LogContext::FormatTime(){
return time.FormatTime();
}

View File

@ -0,0 +1,94 @@
/*
The MIT License (MIT)
Copyright (c) 2013-2015 winlin
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef _htl_core_log_hpp
#define _htl_core_log_hpp
/*
#include <htl_core_log.hpp>
*/
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <string>
class DateTime
{
private:
// %d-%02d-%02d %02d:%02d:%02d.%03d
#define DATE_LEN 24
char time_data[DATE_LEN];
public:
DateTime();
virtual ~DateTime();
public:
virtual const char* FormatTime();
};
class LogContext
{
private:
DateTime time;
public:
LogContext();
virtual ~LogContext();
public:
virtual void SetId(int id) = 0;
virtual int GetId();
public:
virtual const char* FormatTime();
};
// user must implements the LogContext and define a global instance.
extern LogContext* context;
#if 1
#define Verbose(msg, ...) printf("[%s][%d][verbs] ", context->FormatTime(), context->GetId());printf(msg, ##__VA_ARGS__);printf("\n")
#define Info(msg, ...) printf("[%s][%d][infos] ", context->FormatTime(), context->GetId());printf(msg, ##__VA_ARGS__);printf("\n")
#define Trace(msg, ...) printf("[%s][%d][trace] ", context->FormatTime(), context->GetId());printf(msg, ##__VA_ARGS__);printf("\n")
#define Warn(msg, ...) printf("[%s][%d][warns] ", context->FormatTime(), context->GetId());printf(msg, ##__VA_ARGS__);printf(" errno=%d(%s)", errno, strerror(errno));printf("\n")
#define Error(msg, ...) printf("[%s][%d][error] ", context->FormatTime(), context->GetId());printf(msg, ##__VA_ARGS__);printf(" errno=%d(%s)", errno, strerror(errno));printf("\n")
#else
#define Verbose(msg, ...) printf("[%s][%d][verbs][%s] ", context->FormatTime(), context->GetId(), __FUNCTION__);printf(msg, ##__VA_ARGS__);printf("\n")
#define Info(msg, ...) printf("[%s][%d][infos][%s] ", context->FormatTime(), context->GetId(), __FUNCTION__);printf(msg, ##__VA_ARGS__);printf("\n")
#define Trace(msg, ...) printf("[%s][%d][trace][%s] ", context->FormatTime(), context->GetId(), __FUNCTION__);printf(msg, ##__VA_ARGS__);printf("\n")
#define Warn(msg, ...) printf("[%s][%d][warns][%s] ", context->FormatTime(), context->GetId(), __FUNCTION__);printf(msg, ##__VA_ARGS__);printf(" errno=%d(%s)", errno, strerror(errno));printf("\n")
#define Error(msg, ...) printf("[%s][%d][error][%s] ", context->FormatTime(), context->GetId(), __FUNCTION__);printf(msg, ##__VA_ARGS__);printf(" errno=%d(%s)", errno, strerror(errno));printf("\n")
#endif
#if 1
#undef Verbose
#define Verbose(msg, ...) (void)0
#endif
#if 1
#undef Info
#define Info(msg, ...) (void)0
#endif
// for summary/report thread, print to stderr.
#define LReport(msg, ...) fprintf(stderr, "[%s] ", context->FormatTime());fprintf(stderr, msg, ##__VA_ARGS__);fprintf(stderr, "\n")
#endif

View File

@ -0,0 +1,220 @@
/*
The MIT License (MIT)
Copyright (c) 2013-2015 winlin
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include <htl_stdinc.hpp>
#include <stdlib.h>
#include <string>
#include <sstream>
using namespace std;
#include <htl_core_log.hpp>
#include <htl_core_error.hpp>
#include <htl_core_uri.hpp>
Uri::Uri(){
}
Uri::~Uri(){
}
ProtocolUrl::ProtocolUrl(){
}
ProtocolUrl::~ProtocolUrl(){
}
int ProtocolUrl::Initialize(std::string http_url){
int ret = ERROR_SUCCESS;
url = http_url;
const char* purl = url.c_str();
if((ret = http_parser_parse_url(purl, url.length(), 0, &hp_u)) != 0){
int code = ret;
ret = ERROR_HP_PARSE_URL;
Error("parse url %s failed, code=%d, ret=%d", purl, code, ret);
return ret;
}
if(Get(UF_SCHEMA) != ""){
schema = Get(UF_SCHEMA);
}
host = Get(UF_HOST);
if(Get(UF_PORT) != ""){
port = atoi(Get(UF_PORT).c_str());
}
path = Get(UF_PATH);
return ret;
}
const char* ProtocolUrl::GetUrl(){
return url.c_str();
}
const char* ProtocolUrl::GetSchema(){
return schema.c_str();
}
const char* ProtocolUrl::GetHost(){
return host.c_str();
}
int ProtocolUrl::GetPort(){
return port;
}
string ProtocolUrl::Get(http_parser_url_fields field){
return HttpUrl::GetUriField(url, &hp_u, field);
}
string ProtocolUrl::GetUriField(string uri, http_parser_url* hp_u, http_parser_url_fields field){
if((hp_u->field_set & (1 << field)) == 0){
return "";
}
Verbose("uri field matched, off=%d, len=%d, value=%.*s",
hp_u->field_data[field].off, hp_u->field_data[field].len, hp_u->field_data[field].len,
uri.c_str() + hp_u->field_data[field].off);
return uri.substr(hp_u->field_data[field].off, hp_u->field_data[field].len);
}
HttpUrl::HttpUrl(){
port = 80;
}
HttpUrl::~HttpUrl(){
}
#define PROTOCOL_HTTP "http://"
#define PROTOCOL_HTTPS "https://"
string HttpUrl::Resolve(string origin_url){
string copy = origin_url;
size_t pos = string::npos;
string key = "./";
if((pos = origin_url.find(key)) == 0){
copy = origin_url.substr(key.length());
}
// uri
if(copy.find(PROTOCOL_HTTP) == 0 || copy.find(PROTOCOL_HTTPS) == 0){
return copy;
}
// abs or relative url
stringstream ss;
ss << schema << "://" << host;
if(port != 80){
ss << ":" << port;
}
// relative path
if(copy.find("/") != 0){
string dir = path;
if((pos = dir.rfind("/")) != string::npos){
dir = dir.substr(0, pos);
}
ss << dir << "/";
}
ss << copy;
return ss.str();
}
HttpUrl* HttpUrl::Copy(){
HttpUrl* copy = new HttpUrl();
copy->Initialize(url);
return copy;
}
const char* HttpUrl::GetPath(){
return path.c_str();
}
RtmpUrl::RtmpUrl(){
port = 1935;
}
RtmpUrl::~RtmpUrl(){
}
int RtmpUrl::Initialize(std::string http_url){
int ret = ERROR_SUCCESS;
if((ret = ProtocolUrl::Initialize(http_url)) != ERROR_SUCCESS){
return ret;
}
// TODO: support rewrite vhost in query.
vhost = host;
app = path.c_str() + 1;
size_t pos = string::npos;
if((pos = app.find("/")) == string::npos){
ret = ERROR_RTMP_URL;
Error("invalid rtmp url, no stream found, ret=%d", ret);
return ret;
}
stream = app.substr(pos + 1);
app = app.substr(0, pos);
stringstream ss;
ss << schema << "://" << vhost << ":" << port << "/" << app;
tcUrl = ss.str();
return ret;
}
const char* RtmpUrl::GetTcUrl(){
return tcUrl.c_str();
}
const char* RtmpUrl::GetVhost(){
return vhost.c_str();
}
const char* RtmpUrl::GetApp(){
return app.c_str();
}
const char* RtmpUrl::GetStream(){
return stream.c_str();
}

View File

@ -0,0 +1,105 @@
/*
The MIT License (MIT)
Copyright (c) 2013-2015 winlin
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef _htl_core_uri_hpp
#define _htl_core_uri_hpp
/*
#include <htl_core_uri.hpp>
*/
#include <string>
#include <http_parser.h>
class Uri
{
public:
Uri();
virtual ~Uri();
public:
virtual int Initialize(std::string http_url) = 0;
};
class ProtocolUrl : public Uri
{
protected:
std::string url;
http_parser_url hp_u;
protected:
std::string schema;
std::string host;
int port;
std::string path;
public:
ProtocolUrl();
virtual ~ProtocolUrl();
public:
virtual int Initialize(std::string http_url);
public:
virtual const char* GetUrl();
virtual const char* GetSchema();
virtual const char* GetHost();
virtual int GetPort();
protected:
virtual std::string Get(http_parser_url_fields field);
/**
* get the parsed url field.
* @return return empty string if not set.
*/
static std::string GetUriField(std::string uri, http_parser_url* hp_u, http_parser_url_fields field);
};
class HttpUrl : public ProtocolUrl
{
public:
HttpUrl();
virtual ~HttpUrl();
public:
virtual std::string Resolve(std::string origin_url);
virtual HttpUrl* Copy();
public:
virtual const char* GetPath();
};
class RtmpUrl : public ProtocolUrl
{
private:
std::string tcUrl;
std::string vhost;
std::string app;
std::string stream;
public:
RtmpUrl();
virtual ~RtmpUrl();
public:
virtual int Initialize(std::string http_url);
public:
virtual const char* GetTcUrl();
virtual const char* GetVhost();
virtual const char* GetApp();
virtual const char* GetStream();
};
#endif

View File

@ -0,0 +1,44 @@
/*
The MIT License (MIT)
Copyright (c) 2013-2015 winlin
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef _htl_stdinc_hpp
#define _htl_stdinc_hpp
/*
#include <htl_stdinc.hpp>
*/
// for 32bit os, 2G big file limit for unistd io,
// ie. read/write/lseek to use 64bits size for huge file.
#ifndef _FILE_OFFSET_BITS
#define _FILE_OFFSET_BITS 64
#endif
// for int64_t print using PRId64 format.
#ifndef __STDC_FORMAT_MACROS
#define __STDC_FORMAT_MACROS
#endif
#endif

View File

@ -0,0 +1,163 @@
/*
The MIT License (MIT)
Copyright (c) 2013-2015 winlin
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include <htl_stdinc.hpp>
#include <getopt.h>
#include <stdlib.h>
#include <string>
using namespace std;
// project lib
#include <htl_core_log.hpp>
#include <htl_core_error.hpp>
#include <htl_app_hls_load.hpp>
#include <htl_main_utility.hpp>
#define DefaultDelaySeconds -1
#define DefaultHttpUrl "http://127.0.0.1:3080/hls/hls.m3u8"
#define DefaultVod false
int discovery_options(int argc, char** argv,
bool& show_help, bool& show_version, string& url, bool& vod, int& threads,
double& startup, double& delay, double& error, double& report, int& count)
{
int ret = ERROR_SUCCESS;
static option long_options[] = {
SharedOptions()
{"vod", no_argument, 0, 'o'},
{0, 0, 0, 0}
};
int opt = 0;
int option_index = 0;
while((opt = getopt_long(argc, argv, "hvc:r:t:os:d:e:m:", long_options, &option_index)) != -1){
switch(opt){
case 'o':
vod = true;
break;
ProcessSharedOptions()
default:
show_help = true;
break;
}
}
// check values
if(url == ""){
show_help = true;
return ret;
}
return ret;
}
void help(char** argv){
printf("%s, Copyright (c) 2013-2015 winlin\n", ProductHTTPName);
printf(""
"Usage: %s <Options> <-u URL>\n"
"%s base on st(state-threads), support huge concurrency.\n"
"Options:\n"
ShowHelpPart1()
" -o, --vod Whether url is vod, loop the m3u8 file list. default is %s\n"
ShowHelpPart2()
"\n"
"\n"
"Examples:\n"
"1. start a client\n"
" %s -c 1 -r %s\n"
"2. start 1000 clients\n"
" %s -c 1000 -r %s\n"
"3. start 10000 clients\n"
" %s -c 10000 -r %s\n"
"4. start 100000 clients\n"
" %s -c 100000 -r %s\n"
"5. start 10000 vod clients\n"
" %s -c 10000 -o -r %s\n"
"\n"
"This program built for %s.\n"
"Report bugs to <%s>\n",
argv[0], argv[0],
DefaultThread, DefaultHttpUrl, DefaultCount, // part1
(DefaultVod? "true":"false"), // vod
(double)DefaultStartupSeconds, (double)DefaultDelaySeconds, // part2
DefaultErrorSeconds, DefaultReportSeconds, // part2
argv[0], DefaultHttpUrl, argv[0], DefaultHttpUrl, argv[0], DefaultHttpUrl, argv[0], DefaultHttpUrl,
argv[0], DefaultHttpUrl,
BuildPlatform, BugReportEmail);
exit(0);
}
int main(int argc, char** argv){
int ret = ERROR_SUCCESS;
bool show_help = false, show_version = false;
string url; bool vod = DefaultVod; int threads = DefaultThread;
double start = DefaultStartupSeconds, delay = DefaultDelaySeconds, error = DefaultErrorSeconds;
double report = DefaultReportSeconds; int count = DefaultCount;
if((ret = discovery_options(argc, argv, show_help, show_version, url, vod, threads, start, delay, error, report, count)) != ERROR_SUCCESS){
Error("discovery options failed. ret=%d", ret);
return ret;
}
Trace("params url=%s, vod=%d, threads=%d, start=%.2f, delay=%.2f, error=%.2f, report=%.2f, count=%d",
url.c_str(), vod, threads, start, delay, error, report, count);
if(show_help){
help(argv);
}
if(show_version){
version();
}
StFarm farm;
if((ret = farm.Initialize(report)) != ERROR_SUCCESS){
Error("initialize the farm failed. ret=%d", ret);
return ret;
}
for(int i = 0; i < threads; i++){
StHlsTask* task = new StHlsTask();
if((ret = task->Initialize(url, vod, start, delay, error, count)) != ERROR_SUCCESS){
Error("initialize task failed, url=%s, ret=%d", url.c_str(), ret);
return ret;
}
if((ret = farm.Spawn(task)) != ERROR_SUCCESS){
Error("st farm spwan task failed, ret=%d", ret);
return ret;
}
}
farm.WaitAll();
return 0;
}

View File

@ -0,0 +1,152 @@
/*
The MIT License (MIT)
Copyright (c) 2013-2015 winlin
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include <htl_stdinc.hpp>
#include <getopt.h>
#include <stdlib.h>
#include <string>
using namespace std;
// project lib
#include <htl_core_log.hpp>
#include <htl_core_error.hpp>
#include <htl_app_http_load.hpp>
#include <htl_main_utility.hpp>
#define DefaultDelaySeconds 0.0
#define DefaultHttpUrl "http://127.0.0.1:3080/hls/segm130813144315787-522881.ts"
int discovery_options(int argc, char** argv,
bool& show_help, bool& show_version, string& url, int& threads,
double& startup, double& delay, double& error, double& report, int& count
){
int ret = ERROR_SUCCESS;
static option long_options[] = {
SharedOptions()
{0, 0, 0, 0}
};
int opt = 0;
int option_index = 0;
while((opt = getopt_long(argc, argv, "hvc:r:t:s:d:e:m:", long_options, &option_index)) != -1){
switch(opt){
ProcessSharedOptions()
default:
show_help = true;
break;
}
}
// check values
if(url == ""){
show_help = true;
return ret;
}
return ret;
}
void help(char** argv){
printf("%s, Copyright (c) 2013-2015 winlin\n", ProductHTTPName);
printf(""
"Usage: %s <Options> <-u URL>\n"
"%s base on st(state-threads), support huge concurrency.\n"
"Options:\n"
ShowHelpPart1()
ShowHelpPart2()
"\n"
"Examples:\n"
"1. start a client\n"
" %s -c 1 -r %s\n"
"2. start 1000 clients\n"
" %s -c 1000 -r %s\n"
"3. start 10000 clients\n"
" %s -c 10000 -r %s\n"
"4. start 100000 clients\n"
" %s -c 100000 -r %s\n"
"\n"
"This program built for %s.\n"
"Report bugs to <%s>\n",
argv[0], argv[0],
DefaultThread, DefaultHttpUrl, DefaultCount, // part1
(double)DefaultStartupSeconds, DefaultDelaySeconds, // part2
DefaultErrorSeconds, DefaultReportSeconds, // part2
argv[0], DefaultHttpUrl, argv[0], DefaultHttpUrl, argv[0], DefaultHttpUrl, argv[0], DefaultHttpUrl,
BuildPlatform, BugReportEmail);
exit(0);
}
int main(int argc, char** argv){
int ret = ERROR_SUCCESS;
bool show_help = false, show_version = false;
string url; int threads = DefaultThread;
double start = DefaultStartupSeconds, delay = DefaultDelaySeconds, error = DefaultErrorSeconds;
double report = DefaultReportSeconds; int count = DefaultCount;
if((ret = discovery_options(argc, argv, show_help, show_version, url, threads, start, delay, error, report, count)) != ERROR_SUCCESS){
Error("discovery options failed. ret=%d", ret);
return ret;
}
Trace("params url=%s, threads=%d, start=%.2f, delay=%.2f, error=%.2f, report=%.2f, count=%d",
url.c_str(), threads, start, delay, error, report, count);
if(show_help){
help(argv);
}
if(show_version){
version();
}
StFarm farm;
if((ret = farm.Initialize(report)) != ERROR_SUCCESS){
Error("initialize the farm failed. ret=%d", ret);
return ret;
}
for(int i = 0; i < threads; i++){
StHttpTask* task = new StHttpTask();
if((ret = task->Initialize(url, start, delay, error, count)) != ERROR_SUCCESS){
Error("initialize task failed, url=%s, ret=%d", url.c_str(), ret);
return ret;
}
if((ret = farm.Spawn(task)) != ERROR_SUCCESS){
Error("st farm spwan task failed, ret=%d", ret);
return ret;
}
}
farm.WaitAll();
return 0;
}

View File

@ -0,0 +1,155 @@
/*
The MIT License (MIT)
Copyright (c) 2013-2015 winlin
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include <htl_stdinc.hpp>
#include <getopt.h>
#include <stdlib.h>
#include <string>
using namespace std;
// project lib
#include <htl_core_log.hpp>
#include <htl_core_error.hpp>
#include <htl_app_rtmp_load.hpp>
#include <htl_app_rtmp_protocol.hpp>
#include <htl_main_utility.hpp>
#define DefaultDelaySeconds 1.0
#define DefaultRtmpUrl "rtmp://127.0.0.1:1935/live/livestream"
int discovery_options(int argc, char** argv,
bool& show_help, bool& show_version, string& url, int& threads,
double& startup, double& delay, double& error, double& report, int& count
){
int ret = ERROR_SUCCESS;
static option long_options[] = {
SharedOptions()
{0, 0, 0, 0}
};
int opt = 0;
int option_index = 0;
while((opt = getopt_long(argc, argv, "hvc:r:t:s:d:e:m:", long_options, &option_index)) != -1){
switch(opt){
ProcessSharedOptions()
default:
show_help = true;
break;
}
}
// check values
if(url == ""){
show_help = true;
return ret;
}
return ret;
}
void help(char** argv){
printf("%s, Copyright (c) 2013-2015 winlin\n", ProductRtmpName);
printf("srs.librtmp %d.%d.%d (https://github.com/winlinvip/srs.librtmp)\n\n",
srs_version_major(), srs_version_minor(), srs_version_revision());
printf(""
"Usage: %s <Options> <-u URL>\n"
"%s base on st(state-threads), support huge concurrency.\n"
"Options:\n"
ShowHelpPart1()
ShowHelpPart2()
"\n"
"Examples:\n"
"1. start a client\n"
" %s -c 1 -r %s\n"
"2. start 1000 clients\n"
" %s -c 1000 -r %s\n"
"3. start 10000 clients\n"
" %s -c 10000 -r %s\n"
"4. start 100000 clients\n"
" %s -c 100000 -r %s\n"
"\n"
"This program built for %s.\n"
"Report bugs to <%s>\n",
argv[0], argv[0],
DefaultThread, DefaultRtmpUrl, DefaultCount, // part1
(double)DefaultStartupSeconds, DefaultDelaySeconds, // part2
DefaultErrorSeconds, DefaultReportSeconds, // part2
argv[0], DefaultRtmpUrl, argv[0], DefaultRtmpUrl, argv[0], DefaultRtmpUrl, argv[0], DefaultRtmpUrl,
BuildPlatform, BugReportEmail);
exit(0);
}
int main(int argc, char** argv){
int ret = ERROR_SUCCESS;
bool show_help = false, show_version = false;
string url; int threads = DefaultThread;
double start = DefaultStartupSeconds, delay = DefaultDelaySeconds, error = DefaultErrorSeconds;
double report = DefaultReportSeconds; int count = DefaultCount;
if((ret = discovery_options(argc, argv, show_help, show_version, url, threads, start, delay, error, report, count)) != ERROR_SUCCESS){
Error("discovery options failed. ret=%d", ret);
return ret;
}
Trace("params url=%s, threads=%d, start=%.2f, delay=%.2f, error=%.2f, report=%.2f, count=%d",
url.c_str(), threads, start, delay, error, report, count);
if(show_help){
help(argv);
}
if(show_version){
version();
}
StFarm farm;
if((ret = farm.Initialize(report)) != ERROR_SUCCESS){
Error("initialize the farm failed. ret=%d", ret);
return ret;
}
for(int i = 0; i < threads; i++){
StRtmpTask* task = new StRtmpTask();
if((ret = task->Initialize(url, start, delay, error, count)) != ERROR_SUCCESS){
Error("initialize task failed, url=%s, ret=%d", url.c_str(), ret);
return ret;
}
if((ret = farm.Spawn(task)) != ERROR_SUCCESS){
Error("st farm spwan task failed, ret=%d", ret);
return ret;
}
}
farm.WaitAll();
return 0;
}

View File

@ -0,0 +1,160 @@
/*
The MIT License (MIT)
Copyright (c) 2013-2015 winlin
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include <htl_stdinc.hpp>
#include <getopt.h>
#include <stdlib.h>
#include <string>
using namespace std;
// project lib
#include <htl_core_log.hpp>
#include <htl_core_error.hpp>
#include <htl_app_rtmp_load.hpp>
#include <htl_app_rtmp_protocol.hpp>
#include <htl_main_utility.hpp>
#define DefaultDelaySeconds 1.0
#define DefaultRtmpUrl "rtmp://127.0.0.1:1935/live/livestream"
int discovery_options(int argc, char** argv,
bool& show_help, bool& show_version, string& url, int& threads,
double& startup, double& delay, double& error, double& report, int& count
){
int ret = ERROR_SUCCESS;
static option long_options[] = {
SharedOptions()
{0, 0, 0, 0}
};
int opt = 0;
int option_index = 0;
while((opt = getopt_long(argc, argv, "hvc:r:t:s:d:e:m:", long_options, &option_index)) != -1){
switch(opt){
ProcessSharedOptions()
default:
show_help = true;
break;
}
}
// check values
if(url == ""){
show_help = true;
return ret;
}
return ret;
}
void help(char** argv){
printf("%s, Copyright (c) 2013-2015 winlin\n", ProductRtmpName);
printf("srs.librtmp %d.%d.%d (https://github.com/winlinvip/srs.librtmp)\n\n",
srs_version_major(), srs_version_minor(), srs_version_revision());
printf(""
"Usage: %s <Options> <-u URL>\n"
"%s base on st(state-threads), support huge concurrency.\n"
"Options:\n"
ShowHelpPart1()
ShowHelpPart2()
"\n"
"Examples:\n"
"1. start a client\n"
" %s -c 1 -r %s\n"
"2. start 1000 clients\n"
" %s -c 1000 -r %s\n"
"3. start 10000 clients\n"
" %s -c 10000 -r %s\n"
"4. start 100000 clients\n"
" %s -c 100000 -r %s\n"
"\n"
"This program built for %s.\n"
"Report bugs to <%s>\n",
argv[0], argv[0],
DefaultThread, DefaultRtmpUrl, DefaultCount, // part1
(double)DefaultStartupSeconds, DefaultDelaySeconds, // part2
DefaultErrorSeconds, DefaultReportSeconds, // part2
argv[0], DefaultRtmpUrl, argv[0], DefaultRtmpUrl, argv[0], DefaultRtmpUrl, argv[0], DefaultRtmpUrl,
BuildPlatform, BugReportEmail);
exit(0);
}
int main(int argc, char** argv){
int ret = ERROR_SUCCESS;
printf("WARNING!!!\n"
"WARNING!!! we use FAST algorithm to read tcp data directly, \n"
"WARNING!!! may not work for some RTMP server, it's ok for SRS/GO-SRS.\n"
"WARNING!!!\n\n");
bool show_help = false, show_version = false;
string url; int threads = DefaultThread;
double start = DefaultStartupSeconds, delay = DefaultDelaySeconds, error = DefaultErrorSeconds;
double report = DefaultReportSeconds; int count = DefaultCount;
if((ret = discovery_options(argc, argv, show_help, show_version, url, threads, start, delay, error, report, count)) != ERROR_SUCCESS){
Error("discovery options failed. ret=%d", ret);
return ret;
}
Trace("params url=%s, threads=%d, start=%.2f, delay=%.2f, error=%.2f, report=%.2f, count=%d",
url.c_str(), threads, start, delay, error, report, count);
if(show_help){
help(argv);
}
if(show_version){
version();
}
StFarm farm;
if((ret = farm.Initialize(report)) != ERROR_SUCCESS){
Error("initialize the farm failed. ret=%d", ret);
return ret;
}
for(int i = 0; i < threads; i++){
StRtmpTaskFast* task = new StRtmpTaskFast();
if((ret = task->Initialize(url, start, delay, error, count)) != ERROR_SUCCESS){
Error("initialize task failed, url=%s, ret=%d", url.c_str(), ret);
return ret;
}
if((ret = farm.Spawn(task)) != ERROR_SUCCESS){
Error("st farm spwan task failed, ret=%d", ret);
return ret;
}
}
farm.WaitAll();
return 0;
}

View File

@ -0,0 +1,178 @@
/*
The MIT License (MIT)
Copyright (c) 2013-2015 winlin
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include <htl_stdinc.hpp>
#include <getopt.h>
#include <stdlib.h>
#include <string>
using namespace std;
// project lib
#include <htl_core_log.hpp>
#include <htl_core_error.hpp>
#include <htl_app_rtmp_load.hpp>
#include <htl_app_rtmp_protocol.hpp>
#include <htl_main_utility.hpp>
#define DefaultDelaySeconds 1.0
#define DefaultRtmpUrlSingle "rtmp://127.0.0.1:1935/live/livestream"
#define DefaultRtmpUrl "rtmp://127.0.0.1:1935/live/livestream_{i}"
#define DefaultInputFlv "doc/source.200kbps.768x320.flv"
int discovery_options(int argc, char** argv,
bool& show_help, bool& show_version, string& url, int& threads,
double& startup, double& delay, double& error, double& report, int& count,
string& input
){
int ret = ERROR_SUCCESS;
static option long_options[] = {
SharedOptions()
{"input", no_argument, 0, 'i'},
{0, 0, 0, 0}
};
int opt = 0;
int option_index = 0;
while((opt = getopt_long(argc, argv, "hvc:r:t:s:d:e:m:i:", long_options, &option_index)) != -1){
switch(opt){
ProcessSharedOptions()
case 'i':
input = optarg;
break;
default:
show_help = true;
break;
}
}
// check values
if(url == "" || input == ""){
show_help = true;
return ret;
}
return ret;
}
void help(char** argv){
printf("%s, Copyright (c) 2013-2015 winlin\n", ProductRtmpPublishName);
printf("srs.librtmp %d.%d.%d (https://github.com/winlinvip/srs.librtmp)\n\n",
srs_version_major(), srs_version_minor(), srs_version_revision());
printf(""
"Usage: %s <Options> <-u URL>\n"
"%s base on st(state-threads), support huge concurrency.\n"
"Options:\n"
ShowHelpPart1()
ShowHelpPart2()
"\n"
"Examples:\n"
"1. start a client\n"
" %s -i %s -c 1 -r %s\n"
"2. start 1000 clients\n"
" %s -i %s -c 1000 -r %s\n"
"3. start 10000 clients\n"
" %s -i %s -c 10000 -r %s\n"
"4. start 100000 clients\n"
" %s -i %s -c 100000 -r %s\n"
"\n"
"This program built for %s.\n"
"Report bugs to <%s>\n",
argv[0], argv[0],
DefaultThread, DefaultRtmpUrl, DefaultCount, // part1
(double)DefaultStartupSeconds, DefaultDelaySeconds, // part2
DefaultErrorSeconds, DefaultReportSeconds, // part2
argv[0], DefaultInputFlv, DefaultRtmpUrlSingle,
argv[0], DefaultInputFlv, DefaultRtmpUrl,
argv[0], DefaultInputFlv, DefaultRtmpUrl,
argv[0], DefaultInputFlv, DefaultRtmpUrl,
BuildPlatform, BugReportEmail);
exit(0);
}
int main(int argc, char** argv){
int ret = ERROR_SUCCESS;
bool show_help = false, show_version = false;
string url; int threads = DefaultThread;
double start = DefaultStartupSeconds, delay = DefaultDelaySeconds, error = DefaultErrorSeconds;
double report = DefaultReportSeconds; int count = DefaultCount;
string input;
if((ret = discovery_options(argc, argv, show_help, show_version, url, threads, start, delay, error, report, count, input)) != ERROR_SUCCESS){
Error("discovery options failed. ret=%d", ret);
return ret;
}
if(show_help){
help(argv);
}
if(show_version){
version();
}
Trace("params url=%s, threads=%d, start=%.2f, delay=%.2f, error=%.2f, report=%.2f, count=%d",
url.c_str(), threads, start, delay, error, report, count);
StFarm farm;
if((ret = farm.Initialize(report)) != ERROR_SUCCESS){
Error("initialize the farm failed. ret=%d", ret);
return ret;
}
for(int i = 0; i < threads; i++){
StRtmpPublishTask* task = new StRtmpPublishTask();
char index[16];
snprintf(index, sizeof(index), "%d", i);
std::string _index = index;
std::string rtmp_url = url;
size_t pos = std::string::npos;
if ((pos = rtmp_url.find("{i}")) != std::string::npos) {
rtmp_url = rtmp_url.replace(pos, pos + 3, _index);
}
if((ret = task->Initialize(input, rtmp_url, start, delay, error, count)) != ERROR_SUCCESS){
Error("initialize task failed, input=%s, url=%s, ret=%d", input.c_str(), rtmp_url.c_str(), ret);
return ret;
}
if((ret = farm.Spawn(task)) != ERROR_SUCCESS){
Error("st farm spwan task failed, ret=%d", ret);
return ret;
}
}
farm.WaitAll();
return 0;
}

View File

@ -0,0 +1,26 @@
/*
The MIT License (MIT)
Copyright (c) 2013-2015 winlin
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include <htl_stdinc.hpp>

View File

@ -0,0 +1,109 @@
/*
The MIT License (MIT)
Copyright (c) 2013-2015 winlin
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef _htl_main_utility_hpp
#define _htl_main_utility_hpp
/*
#include <htl_main_utility.hpp>
*/
// global instance for graceful log.
LogContext* context = new StLogContext();
#define DefaultThread 1
#define DefaultStartupSeconds 5.0
#define DefaultErrorSeconds 3.0
#define DefaultReportSeconds 30.0
#define DefaultCount 0
#define SharedOptions()\
{"clients", required_argument, 0, 'c'}, \
{"url", required_argument, 0, 'r'}, \
{"repeat", required_argument, 0, 't'}, \
\
{"startup", required_argument, 0, 's'}, \
{"delay", required_argument, 0, 'd'}, \
{"error", required_argument, 0, 'e'}, \
{"summary", required_argument, 0, 'm'}, \
\
{"help", no_argument, 0, 'h'}, \
{"version", no_argument, 0, 'v'},
#define ProcessSharedOptions()\
case 'h': \
show_help = true; \
break; \
case 'v': \
show_version = true; \
break; \
case 'c': \
threads = atoi(optarg); \
break; \
case 'r': \
url = optarg; \
break; \
case 't': \
count = atoi(optarg); \
break; \
case 's': \
startup = atof(optarg); \
break; \
case 'd': \
delay = atof(optarg); \
break; \
case 'e': \
error = atof(optarg); \
break; \
case 'm': \
report = atof(optarg); \
break;
#define ShowHelpPart1()\
" -c CLIENTS, --clients CLIENTS The concurrency client to start to request. defaut: %d\n" \
" -r URL, --url URL The load test url for each client to download/process. \n" \
" -t REPEAT, --repeat REPEAT The repeat is the number for each client to download the url. \n" \
" ie. %s\n" \
" default: %d. 0 means infinity.\n"
#define ShowHelpPart2()\
" -s STARTUP, --start STARTUP The start is the ramdom sleep when thread startup in seconds. \n" \
" defaut: %.2f. 0 means no delay.\n" \
" -d DELAY, --delay DELAY The delay is the ramdom sleep when success in seconds. \n" \
" default: %.2f. 0 means no delay. -1 means to use HLS EXTINF duration(HLS only).\n" \
" -e ERROR, --error ERROR The error is the sleep when error in seconds. \n" \
" defaut: %.2f. 0 means no delay. \n" \
" -m SUMMARY, --summary SUMMARY The summary is the sleep when report in seconds. \n" \
" etasks is error_tasks, statks is sub_tasks, estatks is error_sub_tasks.\n" \
" duration is the running time in seconds, tduration is the avarage duation of tasks.\n" \
" nread/nwrite in Mbps, duration/tduration in seconds.\n" \
" defaut: %.2f. 0 means no delay. \n" \
" -v, --version Print the version and exit.\n" \
" -h, --help Print this help message and exit.\n"
void version(){
printf(ProductVersion);
exit(0);
}
#endif

View File

@ -0,0 +1,513 @@
/*
The MIT License (MIT)
Copyright (c) 2013-2015 winlin
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include <htl_stdinc.hpp>
// system
#include <unistd.h>
#include <errno.h>
#include <stdlib.h>
#include <sys/time.h>
#include <inttypes.h>
// socket
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
// dns
#include <netdb.h>
#include <string>
using namespace std;
#include <htl_core_error.hpp>
#include <htl_core_log.hpp>
#include <htl_os_st.hpp>
StStatistic::StStatistic(){
starttime = StUtility::GetCurrentTime();
task_duration = 0;
threads = alive = 0;
nread = nwrite = 0;
tasks = err_tasks = sub_tasks = err_sub_tasks = 0;
}
StStatistic::~StStatistic(){
}
void StStatistic::OnRead(int /*tid*/, ssize_t nread_bytes){
this->nread += nread_bytes;
}
void StStatistic::OnWrite(int /*tid*/, ssize_t nwrite_bytes){
this->nwrite += nwrite_bytes;
}
void StStatistic::OnThreadRun(int /*tid*/){
threads++;
}
void StStatistic::OnThreadQuit(int /*tid*/){
threads--;
}
void StStatistic::OnTaskStart(int /*tid*/, std::string /*task_url*/){
alive++;
tasks++;
}
void StStatistic::OnTaskError(int /*tid*/, int duration_seconds){
alive--;
err_tasks++;
this->task_duration += duration_seconds * 1000;
}
void StStatistic::OnTaskEnd(int /*tid*/, int duration_seconds){
alive--;
this->task_duration += duration_seconds * 1000;
}
void StStatistic::OnSubTaskStart(int /*tid*/, std::string /*sub_task_url*/){
sub_tasks++;
}
void StStatistic::OnSubTaskError(int /*tid*/, int duration_seconds){
err_sub_tasks++;
this->task_duration += duration_seconds * 1000;
}
void StStatistic::OnSubTaskEnd(int /*tid*/, int duration_seconds){
this->task_duration += duration_seconds * 1000;
}
void StStatistic::DoReport(double sleep_ms){
for(;;){
int64_t duration = StUtility::GetCurrentTime() - starttime;
double read_mbps = 0, write_mbps = 0;
if(duration > 0){
read_mbps = nread * 8.0 / duration / 1000;
write_mbps = nwrite * 8.0 / duration / 1000;
}
double avarage_duration = task_duration/1000.0;
if(tasks > 0){
avarage_duration /= tasks;
}
LReport("[report] [%d] threads:%d alive:%d duration:%.0f tduration:%.0f nread:%.2f nwrite:%.2f "
"tasks:%"PRId64" etasks:%"PRId64" stasks:%"PRId64" estasks:%"PRId64,
getpid(), threads, alive, duration/1000.0, avarage_duration, read_mbps, write_mbps,
tasks, err_tasks, sub_tasks, err_sub_tasks);
st_usleep((st_utime_t)(sleep_ms * 1000));
}
}
StStatistic* statistic = new StStatistic();
StTask::StTask(){
static int _id = 0;
id = ++_id;
}
StTask::~StTask(){
}
int StTask::GetId(){
return id;
}
StFarm::StFarm(){
}
StFarm::~StFarm(){
}
int StFarm::Initialize(double report){
int ret = ERROR_SUCCESS;
report_seconds = report;
// use linux epoll.
if(st_set_eventsys(ST_EVENTSYS_ALT) == -1){
ret = ERROR_ST_INITIALIZE;
Error("st_set_eventsys use linux epoll failed. ret=%d", ret);
return ret;
}
if(st_init() != 0){
ret = ERROR_ST_INITIALIZE;
Error("st_init failed. ret=%d", ret);
return ret;
}
StUtility::InitRandom();
return ret;
}
int StFarm::Spawn(StTask* task){
int ret = ERROR_SUCCESS;
if(st_thread_create(st_thread_function, task, 0, 0) == NULL){
ret = ERROR_ST_THREAD_CREATE;
Error("crate st_thread failed, ret=%d", ret);
return ret;
}
Trace("create thread for task #%d success", task->GetId());
return ret;
}
int StFarm::WaitAll(){
int ret = ERROR_SUCCESS;
// main thread turn to a report therad.
statistic->DoReport(report_seconds * 1000);
st_thread_exit(NULL);
return ret;
}
void* StFarm::st_thread_function(void* args){
StTask* task = (StTask*)args;
context->SetId(task->GetId());
statistic->OnThreadRun(task->GetId());
int ret = task->Process();
statistic->OnThreadQuit(task->GetId());
if(ret != ERROR_SUCCESS){
Warn("st task terminate with ret=%d", ret);
}
else{
Trace("st task terminate with ret=%d", ret);
}
delete task;
return NULL;
}
StSocket::StSocket(){
sock_nfd = NULL;
status = SocketInit;
}
StSocket::~StSocket(){
Close();
}
st_netfd_t StSocket::GetStfd(){
return sock_nfd;
}
SocketStatus StSocket::Status(){
return status;
}
int StSocket::Connect(const char* ip, int port){
int ret = ERROR_SUCCESS;
Close();
int sock = socket(AF_INET, SOCK_STREAM, 0);
if(sock == -1){
ret = ERROR_SOCKET;
Error("create socket error. ret=%d", ret);
return ret;
}
int reuse_socket = 1;
if(setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &reuse_socket, sizeof(int)) == -1){
ret = ERROR_SOCKET;
Error("setsockopt reuse-addr error. ret=%d", ret);
return ret;
}
int keepalive_socket = 1;
if(setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, &keepalive_socket, sizeof(int)) == -1){
ret = ERROR_SOCKET;
Error("setsockopt keep-alive error. ret=%d", ret);
return ret;
}
sock_nfd = st_netfd_open_socket(sock);
if(sock_nfd == NULL){
ret = ERROR_OPEN_SOCKET;
Error("st_netfd_open_socket failed. ret=%d", ret);
return ret;
}
Info("create socket(%d) success", sock);
// connect to server
sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
addr.sin_addr.s_addr = inet_addr(ip);
if(st_connect(sock_nfd, (const struct sockaddr*)&addr, sizeof(sockaddr_in), ST_UTIME_NO_TIMEOUT) == -1){
ret = ERROR_CONNECT;
Error("connect to server(%s:%d) error. ret=%d", ip, port, ret);
return ret;
}
Info("connec to server %s at port %d success", ip, port);
status = SocketConnected;
return ret;
}
int StSocket::Read(const void* buf, size_t size, ssize_t* nread){
int ret = ERROR_SUCCESS;
ssize_t got = st_read(sock_nfd, (void*)buf, size, ST_UTIME_NO_TIMEOUT);
// On success a non-negative integer indicating the number of bytes actually read is returned
// (a value of 0 means the network connection is closed or end of file is reached).
if(got <= 0){
if(got == 0){
errno = ECONNRESET;
}
ret = ERROR_READ;
status = SocketDisconnected;
}
if(got > 0){
statistic->OnRead(context->GetId(), got);
}
if (nread) {
*nread = got;
}
return ret;
}
int StSocket::Readv(const iovec *iov, int iov_size, ssize_t* nread){
int ret = ERROR_SUCCESS;
ssize_t got = st_readv(sock_nfd, iov, iov_size, ST_UTIME_NO_TIMEOUT);
// On success a non-negative integer indicating the number of bytes actually read is returned
// (a value of 0 means the network connection is closed or end of file is reached).
if(got <= 0){
if(got == 0){
errno = ECONNRESET;
}
ret = ERROR_READ;
status = SocketDisconnected;
}
if(got > 0){
statistic->OnRead(context->GetId(), got);
}
if (nread) {
*nread = got;
}
return ret;
}
int StSocket::ReadFully(const void* buf, size_t size, ssize_t* nread){
int ret = ERROR_SUCCESS;
ssize_t got = st_read_fully(sock_nfd, (void*)buf, size, ST_UTIME_NO_TIMEOUT);
// On success a non-negative integer indicating the number of bytes actually read is returned
// (a value less than nbyte means the network connection is closed or end of file is reached)
if(got != (ssize_t)size){
if(got >= 0){
errno = ECONNRESET;
}
ret = ERROR_READ;
status = SocketDisconnected;
}
if(got > 0){
statistic->OnRead(context->GetId(), got);
}
if (nread) {
*nread = got;
}
return ret;
}
int StSocket::Write(const void* buf, size_t size, ssize_t* nwrite){
int ret = ERROR_SUCCESS;
ssize_t writen = st_write(sock_nfd, (void*)buf, size, ST_UTIME_NO_TIMEOUT);
if(writen <= 0){
ret = ERROR_SEND;
status = SocketDisconnected;
}
if(writen > 0){
statistic->OnWrite(context->GetId(), writen);
}
if (nwrite) {
*nwrite = writen;
}
return ret;
}
int StSocket::Writev(const iovec *iov, int iov_size, ssize_t* nwrite){
int ret = ERROR_SUCCESS;
ssize_t writen = st_writev(sock_nfd, iov, iov_size, ST_UTIME_NO_TIMEOUT);
if(writen <= 0){
ret = ERROR_SEND;
status = SocketDisconnected;
}
if(writen > 0){
statistic->OnWrite(context->GetId(), writen);
}
if (nwrite) {
*nwrite = writen;
}
return ret;
}
int StSocket::Close(){
int ret = ERROR_SUCCESS;
if(sock_nfd == NULL){
return ret;
}
int fd = st_netfd_fileno(sock_nfd);
if(st_netfd_close(sock_nfd) != 0){
ret = ERROR_CLOSE;
}
sock_nfd = NULL;
status = SocketDisconnected;
::close(fd);
return ret;
}
int64_t StUtility::GetCurrentTime(){
timeval now;
int ret = gettimeofday(&now, NULL);
if(ret == -1){
Warn("gettimeofday error, ret=%d", ret);
}
// we must convert the tv_sec/tv_usec to int64_t.
return ((int64_t)now.tv_sec)*1000 + ((int64_t)now.tv_usec) / 1000;
}
void StUtility::InitRandom(){
timeval now;
if(gettimeofday(&now, NULL) == -1){
srand(0);
return;
}
srand(now.tv_sec * 1000000 + now.tv_usec);
}
st_utime_t StUtility::BuildRandomMTime(double sleep_seconds){
if(sleep_seconds <= 0){
return 0 * 1000;
}
// 80% consts value.
// 40% random value.
// to get more graceful random time to mocking HLS client.
st_utime_t sleep_ms = (int)(sleep_seconds * 1000 * 0.7) + rand() % (int)(sleep_seconds * 1000 * 0.4);
return sleep_ms;
}
int StUtility::DnsResolve(string host, string& ip){
int ret = ERROR_SUCCESS;
if(inet_addr(host.c_str()) != INADDR_NONE){
ip = host;
Info("dns resolve %s to %s", host.c_str(), ip.c_str());
return ret;
}
hostent* answer = gethostbyname(host.c_str());
if(answer == NULL){
ret = ERROR_DNS_RESOLVE;
Error("dns resolve host %s error. ret=%d", host.c_str(), ret);
return ret;
}
char ipv4[16];
memset(ipv4, 0, sizeof(ipv4));
for(int i = 0; i < answer->h_length; i++){
inet_ntop(AF_INET, answer->h_addr_list[i], ipv4, sizeof(ipv4));
Info("dns resolve host %s to %s.", host.c_str(), ipv4);
break;
}
ip = ipv4;
Info("dns resolve %s to %s", host.c_str(), ip.c_str());
return ret;
}
StLogContext::StLogContext(){
}
StLogContext::~StLogContext(){
}
void StLogContext::SetId(int id){
cache[st_thread_self()] = id;
}
int StLogContext::GetId(){
return cache[st_thread_self()];
}

View File

@ -0,0 +1,160 @@
/*
The MIT License (MIT)
Copyright (c) 2013-2015 winlin
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef _htl_os_st_hpp
#define _htl_os_st_hpp
/*
#include <htl_os_st.hpp>
*/
#include <map>
#include <string>
#include <st.h>
#include <htl_core_log.hpp>
// the statistic for each st-thread(task)
class StStatistic
{
private:
int threads, alive;
int64_t starttime, task_duration;
int64_t nread, nwrite;
int64_t tasks, err_tasks, sub_tasks, err_sub_tasks;
public:
StStatistic();
virtual ~StStatistic();
public:
virtual void OnRead(int tid, ssize_t nread_bytes);
virtual void OnWrite(int tid, ssize_t nwrite_bytes);
public:
// when task thread run.
virtual void OnThreadRun(int tid);
// when task thread quit.
virtual void OnThreadQuit(int tid);
// when task start request url, ie. get m3u8
virtual void OnTaskStart(int tid, std::string task_url);
// when task error.
virtual void OnTaskError(int tid, int duration_seconds);
// when task finish request url, ie. finish all ts in m3u8
virtual void OnTaskEnd(int tid, int duration_seconds);
// when sub task start, ie. get ts in m3u8
virtual void OnSubTaskStart(int tid, std::string sub_task_url);
// when sub task error.
virtual void OnSubTaskError(int tid, int duration_seconds);
// when sub task finish, ie. finish a ts.
virtual void OnSubTaskEnd(int tid, int duration_seconds);
public:
virtual void DoReport(double sleep_ms);
};
extern StStatistic* statistic;
// abstract task for st, which run in a st-thread.
class StTask
{
private:
int id;
public:
StTask();
virtual ~StTask();
public:
virtual int GetId();
public:
/**
* the framework will start a thread for the task,
* then invoke the Process function to do actual transaction.
*/
virtual int Process() = 0;
};
// the farm for all StTask, to spawn st-thread and process all task.
class StFarm
{
private:
double report_seconds;
public:
StFarm();
virtual ~StFarm();
public:
virtual int Initialize(double report);
virtual int Spawn(StTask* task);
virtual int WaitAll();
private:
static void* st_thread_function(void* args);
};
// the socket status
enum SocketStatus{
SocketInit,
SocketConnected,
SocketDisconnected,
};
// the socket base on st.
class StSocket
{
private:
SocketStatus status;
st_netfd_t sock_nfd;
public:
StSocket();
virtual ~StSocket();
public:
virtual st_netfd_t GetStfd();
virtual SocketStatus Status();
virtual int Connect(const char* ip, int port);
virtual int Read(const void* buf, size_t size, ssize_t* nread);
virtual int Readv(const iovec *iov, int iov_size, ssize_t* nread);
virtual int ReadFully(const void* buf, size_t size, ssize_t* nread);
virtual int Write(const void* buf, size_t size, ssize_t* nwrite);
virtual int Writev(const iovec *iov, int iov_size, ssize_t* nwrite);
virtual int Close();
};
// common utilities.
class StUtility
{
public:
static int64_t GetCurrentTime();
static void InitRandom();
static st_utime_t BuildRandomMTime(double sleep_seconds);
static int DnsResolve(std::string host, std::string& ip);
};
// st-thread based log context.
class StLogContext : public LogContext
{
private:
std::map<st_thread_t, int> cache;
public:
StLogContext();
virtual ~StLogContext();
public:
virtual void SetId(int id);
virtual int GetId();
};
#endif

View File

@ -0,0 +1,3 @@
#ifndef _st_load_icpp_init_stub
#define _st_load_icpp_init_stub
#endif

View File

@ -0,0 +1,52 @@
file
main readonly separator,
..\main\htl_main_hls_load.cpp,
..\main\htl_main_http_load.cpp,
..\main\htl_main_rtmp_load.cpp,
..\main\htl_main_rtmp_load_fast.cpp,
..\main\htl_main_rtmp_publish.cpp,
..\main\htl_main_utility.cpp,
..\main\htl_main_utility.hpp,
app readonly separator,
..\app\htl_app_hls_load.cpp,
..\app\htl_app_hls_load.hpp,
..\app\htl_app_http_load.cpp,
..\app\htl_app_http_load.hpp,
..\app\htl_app_m3u8_parser.cpp,
..\app\htl_app_m3u8_parser.hpp,
..\app\htl_app_rtmp_load.cpp,
..\app\htl_app_rtmp_load.hpp,
..\app\htl_app_rtmp_play.cpp,
..\app\htl_app_rtmp_play.hpp,
..\app\htl_app_rtmp_protocol.cpp,
..\app\htl_app_rtmp_protocol.hpp,
..\app\htl_app_rtmp_publish.cpp,
..\app\htl_app_rtmp_publish.hpp,
..\app\htl_app_srs_hijack.cpp,
..\app\htl_app_srs_hijack.hpp,
..\app\htl_app_task_base.cpp,
..\app\htl_app_task_base.hpp,
..\app\htl_app_http_client.cpp,
..\app\htl_app_http_client.hpp,
core readonly separator,
..\core\htl_stdinc.hpp,
..\core\htl_core_error.cpp,
..\core\htl_core_error.hpp,
..\core\htl_core_log.cpp,
..\core\htl_core_log.hpp,
..\core\htl_core_uri.cpp,
..\core\htl_core_uri.hpp,
..\core\htl_core_aggregate_ret.cpp,
..\core\htl_core_aggregate_ret.hpp,
os readonly separator,
..\os\htl_os_st.cpp,
..\os\htl_os_st.hpp,
st-1.9 readonly separator,
..\..\objs\st-1.9\obj\st.h,
http-parser readonly separator,
..\..\objs\http-parser-2.1\http_parser.h,
..\..\objs\http-parser-2.1\http_parser.c;
mainconfig
"main" = "MAIN";