diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
new file mode 100644
index 000000000..574217ba5
--- /dev/null
+++ b/.github/workflows/release.yml
@@ -0,0 +1,75 @@
+name: "Release"
+
+on:
+ push:
+ tags:
+ - v3*
+
+jobs:
+ k8s:
+ name: actions-release-k8s
+ runs-on: ubuntu-20.04
+
+ steps:
+ - name: Checkout repository
+ uses: actions/checkout@v2
+
+ # The github.ref is, for example, refs/tags/v3.0.145 or refs/tags/v3.0-r8
+ # Generate variables like:
+ # SRS_TAG=v3.0.145
+ # SRS_TAG=v3.0-r8
+ # SRS_MAJOR=3
+ # @see https://docs.github.com/en/actions/reference/workflow-commands-for-github-actions#setting-an-environment-variable
+ - name: Generate varaiables
+ shell: bash
+ run: |
+ SRS_TAG=$(echo ${{ github.ref }}| awk -F '/' '{print $3}')
+ echo "SRS_TAG=$SRS_TAG" >> $GITHUB_ENV
+ SRS_MAJOR=$(echo $SRS_TAG| cut -c 2)
+ echo "SRS_MAJOR=$SRS_MAJOR" >> $GITHUB_ENV
+
+ - name: Build SRS
+ shell: bash
+ run: |
+ echo "Release ossrs/srs:$SRS_TAG"
+ docker build --tag ossrs/srs:$SRS_TAG -f trunk/Dockerfile .
+
+ - name: Login docker hub
+ uses: docker/login-action@v1
+ with:
+ username: "${{ secrets.DOCKER_USERNAME }}"
+ password: "${{ secrets.DOCKER_PASSWORD }}"
+ - name: Push to docker hub
+ shell: bash
+ run: |
+ docker push ossrs/srs:$SRS_TAG
+ docker tag ossrs/srs:$SRS_TAG ossrs/srs:$SRS_MAJOR
+ docker push ossrs/srs:$SRS_MAJOR
+
+ - name: Login Aliyun docker hub
+ uses: aliyun/acr-login@v1
+ with:
+ login-server: https://registry.cn-hangzhou.aliyuncs.com
+ username: "${{ secrets.ACR_USERNAME }}"
+ password: "${{ secrets.ACR_PASSWORD }}"
+ - name: Push to Aliyun docker hub
+ shell: bash
+ run: |
+ docker tag ossrs/srs:$SRS_TAG registry.cn-hangzhou.aliyuncs.com/ossrs/srs:$SRS_TAG
+ docker push registry.cn-hangzhou.aliyuncs.com/ossrs/srs:$SRS_TAG
+ docker tag ossrs/srs:$SRS_TAG registry.cn-hangzhou.aliyuncs.com/ossrs/srs:$SRS_MAJOR
+ docker push registry.cn-hangzhou.aliyuncs.com/ossrs/srs:$SRS_MAJOR
+
+ - name: Setup KUBCONFIG for Aliyun ACK
+ shell: bash
+ run: |-
+ KUBECONFIG=$RUNNER_TEMP/kubeconfig_$(date +%s)
+ echo "${{ secrets.KUBCONFIG }}" > $KUBECONFIG
+ echo "KUBECONFIG=$KUBECONFIG" >> $GITHUB_ENV
+
+ - name: Release SRS 3.0 to Aliyun ACK
+ shell: bash
+ if: ${{ startsWith(github.ref, 'refs/tags/v3') }}
+ run: |-
+ kubectl set image deploy/srs3-deploy srs=registry.cn-hangzhou.aliyuncs.com/ossrs/srs:$SRS_TAG
+ kubectl describe deploy/srs3-deploy
\ No newline at end of file
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
new file mode 100644
index 000000000..291ee14f4
--- /dev/null
+++ b/.github/workflows/test.yml
@@ -0,0 +1,47 @@
+name: "Test"
+
+on: [push, pull_request]
+
+jobs:
+ utest:
+ name: actions-test-utest
+ runs-on: ubuntu-20.04
+
+ steps:
+ - name: Checkout repository
+ uses: actions/checkout@v2
+
+ ################################################################
+ # Tests
+ - name: Build test image
+ run: docker build --tag srs:test -f trunk/Dockerfile.test .
+ # For utest
+ - name: Run SRS utest
+ run: docker run --rm srs:test bash -c 'make && ./objs/srs_utest'
+ coverage:
+ name: actions-test-coverage
+ runs-on: ubuntu-20.04
+
+ steps:
+ - name: Checkout repository
+ uses: actions/checkout@v2
+
+ ################################################################
+ # Tests
+ - name: Build coverage image
+ run: docker build --tag srs:cov -f trunk/Dockerfile.cov .
+ # For coverage
+ - name: Run SRS covergae
+ if: ${{ startsWith(github.ref, 'refs/heads/') || startsWith(github.ref, 'refs/pull/') }}
+ run: |
+ # The hash of commit.
+ SRS_SHA=${{ github.sha }}
+ # Note that the root of SRS, must contains .git, for report fixing.
+ SRS_PROJECT=/srs
+ # The github.ref is, for example, refs/heads/3.0release
+ SRS_BRANCH=$(echo ${{ github.ref }}| awk -F 'refs/heads/' '{print $2}'| awk -F '/' '{print $1}')
+ # The github.ref is, for example, refs/pull/2536/merge
+ SRS_PR=$(echo ${{ github.ref }}| awk -F 'refs/pull/' '{print $2}'| awk -F '/' '{print $1}')
+ echo "For ref=${{ github.ref }}, sha=${{ github.sha }}, SRS_BRANCH=$SRS_BRANCH, SRS_PR=$SRS_PR, SRS_SHA=$SRS_SHA, SRS_PROJECT=$SRS_PROJECT"
+ docker run --rm --env SRS_BRANCH=$SRS_BRANCH --env SRS_PR=$SRS_PR --env SRS_SHA=$SRS_SHA --env SRS_PROJECT=$SRS_PROJECT \
+ srs:cov bash -c 'make && ./objs/srs_utest && bash auto/coverage.sh'
\ No newline at end of file
diff --git a/README.md b/README.md
index 311e5920b..39d262cf4 100755
--- a/README.md
+++ b/README.md
@@ -1,31 +1,32 @@
# SRS(Simple Realtime Server)

-[](https://circleci.com/gh/ossrs/srs/tree/3.0release)
+[](https://github.com/ossrs/srs/actions?query=workflow%3ATest+branch%3A3.0release)
+[](https://github.com/ossrs/srs/actions?query=workflow%3ARelease)
[](https://codecov.io/gh/ossrs/srs/branch/3.0release)
[](https://github.com/ossrs/srs/wiki/v1_CN_Contact#wechat)
-SRS/3.0,[OuXuli][release3],是一个简单高效的实时视频服务器,支持RTMP/WebRTC/HLS/HTTP-FLV/SRT/GB28181。
+SRS/3.0,[OuXuli][release3],是一个简单高效的实时视频服务器,支持RTMP/HLS/HTTP-FLV。
-SRS is a simple, high efficiency and realtime video server, supports RTMP/WebRTC/HLS/HTTP-FLV/SRT/GB28181.
+SRS is a simple, high efficiency and realtime video server, supports RTMP/HLS/HTTP-FLV.
> Remark: Although SRS is licenced under [MIT][LICENSE], but there are some depended libraries which are distributed using their own licenses, please read [License Mixing][LicenseMixing].
## Usage
-Recommend running SRS by [docker][docker-srs3], images is [here](https://hub.docker.com/r/ossrs/srs/tags) or [there](https://cr.console.aliyun.com/repository/cn-hangzhou/ossrs/srs/images):
+Build SRS from source, please read **Wiki: Gettting Started( [EN](https://github.com/ossrs/srs/wiki/v3_EN_Home#getting-started) / [CN](https://github.com/ossrs/srs/wiki/v3_CN_Home#getting-started) )**:
-```bash
-docker run --rm -p 1935:1935 -p 1985:1985 -p 8080:8080 ossrs/srs:3
+```
+git clone -b 3.0release https://gitee.com/ossrs/srs.git &&
+cd srs/trunk && ./configure && make && ./objs/srs -c conf/srs.conf
```
Open [http://localhost:8080/](http://localhost:8080/) to check it, then publish
-[stream](https://github.com/ossrs/srs/blob/3.0release/trunk/doc/source.200kbps.768x320.flv) by:
+by [FFmpeg](https://ffmpeg.org/download.html) or [OBS](https://obsproject.com/download) as:
```bash
-docker run --rm --network=host ossrs/srs:encoder ffmpeg -re -i ./doc/source.200kbps.768x320.flv \
- -c copy -f flv -y rtmp://localhost/live/livestream
+ffmpeg -re -i ./doc/source.flv -c copy -f flv -y rtmp://localhost/live/livestream
```
Play the following streams by [players](https://ossrs.net):
@@ -34,29 +35,17 @@ Play the following streams by [players](https://ossrs.net):
* H5(HTTP-FLV): [http://localhost:8080/live/livestream.flv](http://localhost:8080/players/srs_player.html?autostart=true&stream=livestream.flv&port=8080&schema=http)
* H5(HLS): [http://localhost:8080/live/livestream.m3u8](http://localhost:8080/players/srs_player.html?autostart=true&stream=livestream.m3u8&port=8080&schema=http)
-It's also very easy to build from source:
-
-```
-git clone -b 3.0release https://gitee.com/winlinvip/srs.oschina.git srs &&
-cd srs/trunk && git remote set-url origin https://github.com/ossrs/srs.git &&
-./configure && make && ./objs/srs -c conf/srs.conf
-```
-
-> Note: We use [mirrors(gitee)](#mirrors) here, but it's also ok to `git clone https://github.com/ossrs/srs.git`
-
-> Remark: Recommend to use Centos7 64bits, please read wiki([CN][v3_CN_Build],[EN][v3_EN_Build]), or use [docker][docker-dev].
-
From here, please read wikis:
-* [SRS 3.0 English Wiki][v3_EN_Home], please read Wiki first.
-* [SRS 3.0 中文Wiki][v3_CN_Home],不读Wiki一定扑街,不读文档请不要提Issue,不读文档请不要提问题,任何文档中明确说过的疑问都不会解答。
+* [Getting Started](https://github.com/ossrs/srs/wiki/v3_EN_Home#getting-started), please read Wiki first.
+* [中文文档:起步](https://github.com/ossrs/srs/wiki/v3_CN_Home#getting-started),不读Wiki一定扑街,不读文档请不要提Issue,不读文档请不要提问题,任何文档中明确说过的疑问都不会解答。
Fast index for Wikis:
-* Overview? ([CN][v3_EN_Home], [EN][v3_CN_Home])
+* Overview? ([CN][v3_CN_Home], [EN][v3_EN_Home])
* How to deliver RTMP streaming?([CN][v1_CN_SampleRTMP], [EN][v1_EN_SampleRTMP])
* How to build RTMP Edge-Cluster?([CN][v3_CN_SampleRTMPCluster], [EN][v3_EN_SampleRTMPCluster])
* How to build RTMP Origin-Cluster?([CN][v3_CN_SampleOriginCluster], [EN][v3_EN_SampleOriginCluster])
@@ -141,6 +130,13 @@ Other important wiki:
## V3 changes
+* v3.0, 2021-10-08, Fix [#2606](https://github.com/ossrs/srs/issues/2606): Memory leak for RTMP client, pick from 4.0. v3.0.170
+* v3.0, 2021-08-14, [3.0 release8(3.0.168)](https://github.com/ossrs/srs/releases/tag/v3.0-r8) released. 124469 lines.
+* v3.0, 2021-07-04, [3.0 release7(3.0.164)](https://github.com/ossrs/srs/releases/tag/v3.0-r7) released. 123463 lines.
+* v3.0, 2021-07-04, For [#2424](https://github.com/ossrs/srs/issues/2424), use srandom/random to generate. 3.0.164
+* v3.0, 2021-06-26, [3.0 release6(3.0.163)](https://github.com/ossrs/srs/releases/tag/v3.0-r6) released. 123011 lines.
+* v3.0, 2021-06-26, For [#2424](https://github.com/ossrs/srs/issues/2424), query the latest available version. 3.0.163
+* v3.0, 2021-05-12, Fix [#2311][bug #2311], Copy the request for stat client. 3.0.162
* v3.0, 2021-04-28, [3.0 release5(3.0.161)][r3.0r5] released. 122750 lines.
* v3.0, 2021-04-28, Upgrade players. 3.0.161
* v3.0, 2021-04-24, [3.0 release4(3.0.160)][r3.0r4] released. 122750 lines.
@@ -343,6 +339,11 @@ Other important wiki:
## V2 changes
+* v2.0, 2021-08-14, [2.0 release11(2.0.276)](https://github.com/ossrs/srs/releases/tag/v2.0-r11) released. 89013 lines.
+* v2.0, 2021-07-04, [2.0 release10(2.0.274)](https://github.com/ossrs/srs/releases/tag/v2.0-r10) released. 87575 lines.
+* v2.0, 2021-07-04, For [#2424](https://github.com/ossrs/srs/issues/2424), use srandom/random to generate. 2.0.274
+* v2.0, 2021-06-26, [2.0 release9(2.0.273)](https://github.com/ossrs/srs/releases/tag/v2.0-r9) released. 87552 lines.
+* v2.0, 2021-06-25, For [#2424](https://github.com/ossrs/srs/issues/2424), query the latest available version. 2.0.273
* v2.0, 2020-01-25, [2.0 release8(2.0.272)][r2.0r8] released. 87292 lines.
* v2.0, 2020-01-08, Merge [#1554][bug #1554], support logrotate copytruncate. 2.0.272
* v2.0, 2020-01-05, Merge [#1551][bug #1551], fix memory leak in RTSP stack. 2.0.270
@@ -781,6 +782,9 @@ Other important wiki:
## Releases
+* 2021-08-14, [Release v3.0-r8](https://github.com/ossrs/srs/releases/tag/v3.0-r8), 3.0 release8, 3.0.168, 124469 lines.
+* 2021-07-04, [Release v3.0-r7](https://github.com/ossrs/srs/releases/tag/v3.0-r7), 3.0 release7, 3.0.167, 123463 lines.
+* 2021-06-26, [Release v3.0-r6](https://github.com/ossrs/srs/releases/tag/v3.0-r6), 3.0 release6, 3.0.163, 123011 lines.
* 2021-04-28, [Release v3.0-r5][r3.0r5], 3.0 release5, 3.0.161, 122750 lines.
* 2021-04-24, [Release v3.0-r4][r3.0r4], 3.0 release4, 3.0.160, 122750 lines.
* 2021-01-02, [Release v3.0-r3][r3.0r3], 3.0 release3, 3.0.156, 122736 lines.
@@ -1153,10 +1157,10 @@ A big THANK YOU goes to:
## Mirrors
-OSChina: [https://gitee.com/winlinvip/srs.oschina][oschina], the GIT usage([CN][v1_CN_Git], [EN][v1_EN_Git])
+Gitee: [https://gitee.com/ossrs/srs][gitee], the GIT usage([CN][v1_CN_Git], [EN][v1_EN_Git])
```
-git clone https://gitee.com/winlinvip/srs.oschina.git srs &&
+git clone https://gitee.com/ossrs/srs.git &&
cd srs && git remote set-url origin https://github.com/ossrs/srs.git && git pull
```
@@ -1177,12 +1181,12 @@ git clone https://github.com/ossrs/srs.git
| Branch | Cost | Size | CMD |
| --- | --- | --- | --- |
-| 3.0release | 2m19.931s | 262MB | git clone -b 3.0release https://gitee.com/winlinvip/srs.oschina.git |
-| 3.0release | 0m56.515s | 95MB | git clone -b 3.0release --depth=1 https://gitee.com/winlinvip/srs.oschina.git |
-| develop | 2m22.430s | 234MB | git clone -b develop https://gitee.com/winlinvip/srs.oschina.git |
-| develop | 0m46.421s | 42MB | git clone -b develop --depth=1 https://gitee.com/winlinvip/srs.oschina.git |
-| min | 2m22.865s | 217MB | git clone -b min https://gitee.com/winlinvip/srs.oschina.git |
-| min | 0m36.472s | 11MB | git clone -b min --depth=1 https://gitee.com/winlinvip/srs.oschina.git |
+| 3.0release | 2m19.931s | 262MB | git clone -b 3.0release https://gitee.com/ossrs/srs.git |
+| 3.0release | 0m56.515s | 95MB | git clone -b 3.0release --depth=1 https://gitee.com/ossrs/srs.git |
+| develop | 2m22.430s | 234MB | git clone -b develop https://gitee.com/ossrs/srs.git |
+| develop | 0m46.421s | 42MB | git clone -b develop --depth=1 https://gitee.com/ossrs/srs.git |
+| min | 2m22.865s | 217MB | git clone -b min https://gitee.com/ossrs/srs.git |
+| min | 0m36.472s | 11MB | git clone -b min --depth=1 https://gitee.com/ossrs/srs.git |
## System Requirements
@@ -1233,7 +1237,7 @@ Winlin
[libx264]: http://www.videolan.org/
[srs]: https://github.com/ossrs/srs
[csdn]: https://code.csdn.net/winlinvip/srs-csdn
-[oschina]: https://gitee.com/winlinvip/srs.oschina
+[gitee]: https://gitee.com/ossrs/srs
[srs-dolphin]: https://github.com/ossrs/srs-dolphin
[oryx]: https://github.com/ossrs/go-oryx
[srs-bench]: https://github.com/ossrs/srs-bench
@@ -1719,6 +1723,7 @@ Winlin
[bug #1987]: https://github.com/ossrs/srs/issues/1987
[bug #1548]: https://github.com/ossrs/srs/issues/1548
[bug #1694]: https://github.com/ossrs/srs/issues/1694
+[bug #2311]: https://github.com/ossrs/srs/issues/2311
[bug #yyyyyyyyyyyyy]: https://github.com/ossrs/srs/issues/yyyyyyyyyyyyy
[exo #828]: https://github.com/google/ExoPlayer/pull/828
@@ -1792,7 +1797,7 @@ Winlin
[more0]: http://winlinvip.github.io/srs.release/releases/
[more1]: http://ossrs.net/srs.release/releases/
-[LICENSE]: https://github.com/ossrs/srs/blob/develop/LICENSE
+[LICENSE]: https://github.com/ossrs/srs/blob/3.0release/LICENSE
[LicenseMixing]: https://github.com/ossrs/srs/wiki/LicenseMixing
[srs_CN]: https://github.com/ossrs/srs/wiki/v3_CN_Home
diff --git a/trunk/.gitignore b/trunk/.gitignore
index 7d0164b16..5ab388b11 100644
--- a/trunk/.gitignore
+++ b/trunk/.gitignore
@@ -13,6 +13,7 @@
/ide/srs_xcode/srs_xcode.xcodeproj/xcuserdata/
/research/aac/
/research/api-server/static-dir/mse
+/research/api-server/static-dir/crossdomain.xml
/research/bat/
/research/big/
/research/bitch/
diff --git a/trunk/Dockerfile b/trunk/Dockerfile
new file mode 100644
index 000000000..7a3e32d34
--- /dev/null
+++ b/trunk/Dockerfile
@@ -0,0 +1,36 @@
+FROM ossrs/srs:dev AS build
+
+# Install depends tools.
+RUN yum install -y gcc make gcc-c++ patch unzip perl git
+
+# Build and install SRS.
+COPY . /srs
+WORKDIR /srs/trunk
+RUN ./configure --jobs=2 && make -j2 && make install
+
+# All config files for SRS.
+RUN cp -R conf /usr/local/srs/conf
+# The default index.html and srs-console.
+RUN cp research/api-server/static-dir/index.html /usr/local/srs/objs/nginx/html/
+RUN cp research/api-server/static-dir/favicon.ico /usr/local/srs/objs/nginx/html/
+RUN cp research/players/crossdomain.xml /usr/local/srs/objs/nginx/html/
+RUN cp -R research/console /usr/local/srs/objs/nginx/html/
+RUN cp -R research/players /usr/local/srs/objs/nginx/html/
+#RUN cp -R 3rdparty/signaling/www/demos /usr/local/srs/objs/nginx/html/
+
+############################################################
+# dist
+############################################################
+FROM centos:7 AS dist
+
+# Expose ports for live streaming
+EXPOSE 1935 1985 8080
+
+# FFMPEG 4.1
+COPY --from=build /usr/local/bin/ffmpeg /usr/local/srs/objs/ffmpeg/bin/ffmpeg
+# SRS binary, config files and srs-console.
+COPY --from=build /usr/local/srs /usr/local/srs
+
+# Default workdir and command.
+WORKDIR /usr/local/srs
+CMD ["./objs/srs", "-c", "conf/srs.conf"]
diff --git a/trunk/Dockerfile.cov b/trunk/Dockerfile.cov
new file mode 100644
index 000000000..a898cb969
--- /dev/null
+++ b/trunk/Dockerfile.cov
@@ -0,0 +1,9 @@
+FROM ossrs/srs:dev
+
+# Install depends tools.
+RUN yum install -y gcc make gcc-c++ patch unzip perl git
+
+# Build and install SRS.
+COPY . /srs
+WORKDIR /srs/trunk
+RUN ./configure --with-utest --gcov --jobs=2 && make -j2
diff --git a/trunk/Dockerfile.test b/trunk/Dockerfile.test
new file mode 100644
index 000000000..de1eb633e
--- /dev/null
+++ b/trunk/Dockerfile.test
@@ -0,0 +1,9 @@
+FROM ossrs/srs:dev
+
+# Install depends tools.
+RUN yum install -y gcc make gcc-c++ patch unzip perl git
+
+# Build and install SRS.
+COPY . /srs
+WORKDIR /srs/trunk
+RUN ./configure --with-utest --jobs=2 && make -j2
diff --git a/trunk/auto/auto_headers.sh b/trunk/auto/auto_headers.sh
index 25564d1d2..3983433a9 100755
--- a/trunk/auto/auto_headers.sh
+++ b/trunk/auto/auto_headers.sh
@@ -11,6 +11,7 @@ echo "#ifndef SRS_AUTO_HEADER_HPP" >> $SRS_AUTO_HEADERS_H
echo "#define SRS_AUTO_HEADER_HPP" >> $SRS_AUTO_HEADERS_H
echo "" >> $SRS_AUTO_HEADERS_H
+echo "#define SRS_AUTO_PACKAGER \"${SRS_AUTO_PACKAGER}\"" >> $SRS_AUTO_HEADERS_H
echo "#define SRS_AUTO_BUILD_TS \"`date +%s`\"" >> $SRS_AUTO_HEADERS_H
echo "#define SRS_AUTO_BUILD_DATE \"`date \"+%Y-%m-%d %H:%M:%S\"`\"" >> $SRS_AUTO_HEADERS_H
echo "#define SRS_AUTO_UNAME \"`uname -a`\"" >> $SRS_AUTO_HEADERS_H
diff --git a/trunk/auto/coverage.sh b/trunk/auto/coverage.sh
index 55cb7ce46..25f7041d5 100644
--- a/trunk/auto/coverage.sh
+++ b/trunk/auto/coverage.sh
@@ -1,36 +1,35 @@
#!/bin/bash
# In .circleci/config.yml, generate *.gcno with
-# ./configure --gcov --without-research --without-librtmp && make
+# ./configure --gcov --with-utest --without-research --without-librtmp && make
# and generate *.gcda by
# ./objs/srs_utest
# Workdir is objs/cover.
workdir=`pwd`/objs/cover
-# Tool git is required to map the right path.
-git --version >/dev/null 2>&1
-ret=$?; if [[ $ret -ne 0 ]]; then echo "Tool git is required, ret=$ret"; exit $ret; fi
-
# Create trunk under workdir.
mkdir -p $workdir && cd $workdir
ret=$?; if [[ $ret -ne 0 ]]; then echo "Enter workdir failed, ret=$ret"; exit $ret; fi
-# Collect all *.gcno and *.gcda to objs/cover.
-cd $workdir && (rm -rf src && cp -R ../../src . && cp -R ../src/* src/)
-ret=$?; if [[ $ret -ne 0 ]]; then echo "Collect *.gcno and *.gcda failed, ret=$ret"; exit $ret; fi
-
-# Generate *.gcov for coverage.
-cd $workdir &&
-for file in `find src -name "*.cpp"|grep -v utest`; do
- gcov $file -o `dirname $file`
- ret=$?; if [[ $ret -ne 0 ]]; then echo "Collect $file failed, ret=$ret"; exit $ret; fi
-done
-
-# Cook the gcov files.
-cd $workdir &&
-find . -name "*.gcov"|grep -v srs|xargs rm -f
-ret=$?; if [[ $ret -ne 0 ]]; then echo "Cook gcov files failed, ret=$ret"; exit $ret; fi
+CODECOV_ARGS=""
+if [[ $SRS_PROJECT != '' ]]; then
+ # -R root dir Used when not in git/hg project to identify project root directory
+ # -p dir Project root directory. Also used when preparing gcov
+ CODECOV_ARGS="$CODECOV_ARGS -R $SRS_PROJECT -p $SRS_PROJECT"
+fi
+if [[ $SRS_BRANCH != '' ]]; then
+ # -B branch Specify the branch name
+ CODECOV_ARGS="$CODECOV_ARGS -B $SRS_BRANCH"
+fi
+if [[ $SRS_SHA != '' ]]; then
+ # -C sha Specify the commit sha
+ CODECOV_ARGS="$CODECOV_ARGS -C $SRS_SHA"
+fi
+if [[ $SRS_PR != '' ]]; then
+ # -P pr Specify the pull request number
+ CODECOV_ARGS="$CODECOV_ARGS -P $SRS_PR"
+fi
# Upload report with *.gcov
# Remark: The file codecov.yml is not neccessary. It literally depends on git.
@@ -41,5 +40,6 @@ ret=$?; if [[ $ret -ne 0 ]]; then echo "Cook gcov files failed, ret=$ret"; exit
# https://circleci.com/gh/ossrs/srs/tree/3.0release
cd $workdir &&
export CODECOV_TOKEN="493bba46-c468-4e73-8b45-8cdd8ff62d96" &&
-bash <(curl -s https://codecov.io/bash) &&
+bash <(curl -s https://codecov.io/bash) $CODECOV_ARGS &&
echo "Done" && exit 0
+
diff --git a/trunk/conf/full.conf b/trunk/conf/full.conf
index 74f62d4c6..8e8d15270 100644
--- a/trunk/conf/full.conf
+++ b/trunk/conf/full.conf
@@ -105,6 +105,11 @@ inotify_auto_reload off;
# default: on
auto_reload_for_docker on;
+# Query the latest available version of SRS, write a log to notice user to upgrade.
+# @see https://github.com/ossrs/srs/issues/2424
+# Default: on
+query_latest_version on;
+
#############################################################################################
# heartbeat/stats sections
#############################################################################################
diff --git a/trunk/configure b/trunk/configure
index d1196dd36..916e1ba99 100755
--- a/trunk/configure
+++ b/trunk/configure
@@ -228,7 +228,7 @@ if [ $SRS_EXPORT_LIBRTMP_PROJECT = NO ]; then
"srs_app_heartbeat" "srs_app_empty" "srs_app_http_client" "srs_app_http_static"
"srs_app_recv_thread" "srs_app_security" "srs_app_statistic" "srs_app_hds"
"srs_app_mpegts_udp" "srs_app_rtsp" "srs_app_listener" "srs_app_async_call"
- "srs_app_caster_flv" "srs_app_process" "srs_app_ng_exec"
+ "srs_app_caster_flv" "srs_app_latest_version" "srs_app_uuid" "srs_app_process" "srs_app_ng_exec"
"srs_app_hourglass" "srs_app_dash" "srs_app_fragment" "srs_app_dvr"
"srs_app_coworkers")
DEFINES=""
diff --git a/trunk/doc/source.flv b/trunk/doc/source.flv
new file mode 120000
index 000000000..32d9ecfc2
--- /dev/null
+++ b/trunk/doc/source.flv
@@ -0,0 +1 @@
+source.200kbps.768x320.flv
\ No newline at end of file
diff --git a/trunk/research/api-server/static-dir/crossdomain.xml b/trunk/research/api-server/static-dir/crossdomain.xml
deleted file mode 100644
index ae9108482..000000000
--- a/trunk/research/api-server/static-dir/crossdomain.xml
+++ /dev/null
@@ -1,3 +0,0 @@
-
-
-
diff --git a/trunk/src/app/srs_app_config.cpp b/trunk/src/app/srs_app_config.cpp
index 56fefb336..9ff560d3c 100644
--- a/trunk/src/app/srs_app_config.cpp
+++ b/trunk/src/app/srs_app_config.cpp
@@ -4056,6 +4056,18 @@ bool SrsConfig::get_asprocess()
return SRS_CONF_PERFER_FALSE(conf->arg0());
}
+bool SrsConfig::whether_query_latest_version()
+{
+ static bool DEFAULT = true;
+
+ SrsConfDirective* conf = root->get("query_latest_version");
+ if (!conf) {
+ return DEFAULT;
+ }
+
+ return SRS_CONF_PERFER_TRUE(conf->arg0());
+}
+
bool SrsConfig::empty_ip_ok()
{
static bool DEFAULT = true;
diff --git a/trunk/src/app/srs_app_config.hpp b/trunk/src/app/srs_app_config.hpp
index d0e6f2928..0788e5a34 100644
--- a/trunk/src/app/srs_app_config.hpp
+++ b/trunk/src/app/srs_app_config.hpp
@@ -468,6 +468,8 @@ public:
virtual std::string get_work_dir();
// Whether use asprocess mode.
virtual bool get_asprocess();
+ // Whether query the latest available version of SRS.
+ virtual bool whether_query_latest_version();
// Whether empty client IP is ok.
virtual bool empty_ip_ok();
// Get the start wait in ms for gracefully quit.
diff --git a/trunk/src/app/srs_app_http_stream.cpp b/trunk/src/app/srs_app_http_stream.cpp
index d28335b5c..bd6fcfdee 100755
--- a/trunk/src/app/srs_app_http_stream.cpp
+++ b/trunk/src/app/srs_app_http_stream.cpp
@@ -75,7 +75,7 @@ SrsBufferCache::~SrsBufferCache()
srs_freep(req);
}
-srs_error_t SrsBufferCache::update(SrsSource* s, SrsRequest* r)
+srs_error_t SrsBufferCache::update_auth(SrsSource* s, SrsRequest* r)
{
srs_freep(req);
req = r->copy();
@@ -523,7 +523,7 @@ SrsLiveStream::~SrsLiveStream()
srs_freep(req);
}
-srs_error_t SrsLiveStream::update(SrsSource* s, SrsRequest* r)
+srs_error_t SrsLiveStream::update_auth(SrsSource* s, SrsRequest* r)
{
source = s;
@@ -938,9 +938,10 @@ srs_error_t SrsHttpStreamServer::http_mount(SrsSource* s, SrsRequest* r)
}
srs_trace("http: mount flv stream for sid=%s, mount=%s", sid.c_str(), mount.c_str());
} else {
+ // The entry exists, we reuse it and update the request of stream and cache.
entry = sflvs[sid];
- entry->stream->update(s, r);
- entry->cache->update(s, r);
+ entry->stream->update_auth(s, r);
+ entry->cache->update_auth(s, r);
}
if (entry->stream) {
diff --git a/trunk/src/app/srs_app_http_stream.hpp b/trunk/src/app/srs_app_http_stream.hpp
index a82e2a5a0..cd137fccc 100755
--- a/trunk/src/app/srs_app_http_stream.hpp
+++ b/trunk/src/app/srs_app_http_stream.hpp
@@ -46,7 +46,7 @@ private:
public:
SrsBufferCache(SrsSource* s, SrsRequest* r);
virtual ~SrsBufferCache();
- virtual srs_error_t update(SrsSource* s, SrsRequest* r);
+ virtual srs_error_t update_auth(SrsSource* s, SrsRequest* r);
public:
virtual srs_error_t start();
virtual srs_error_t dump_cache(SrsConsumer* consumer, SrsRtmpJitterAlgorithm jitter);
@@ -188,7 +188,7 @@ private:
public:
SrsLiveStream(SrsSource* s, SrsRequest* r, SrsBufferCache* c);
virtual ~SrsLiveStream();
- virtual srs_error_t update(SrsSource* s, SrsRequest* r);
+ virtual srs_error_t update_auth(SrsSource* s, SrsRequest* r);
public:
virtual srs_error_t serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* r);
private:
diff --git a/trunk/src/app/srs_app_ingest.cpp b/trunk/src/app/srs_app_ingest.cpp
index 44987f16c..4ca1db87c 100644
--- a/trunk/src/app/srs_app_ingest.cpp
+++ b/trunk/src/app/srs_app_ingest.cpp
@@ -484,7 +484,7 @@ void SrsIngester::show_ingest_log_message()
}
// random choose one ingester to report.
- int index = rand() % (int)ingesters.size();
+ int index = srs_random() % (int)ingesters.size();
SrsIngesterFFMPEG* ingester = ingesters.at(index);
// reportable
diff --git a/trunk/src/app/srs_app_latest_version.cpp b/trunk/src/app/srs_app_latest_version.cpp
new file mode 100644
index 000000000..66ac01561
--- /dev/null
+++ b/trunk/src/app/srs_app_latest_version.cpp
@@ -0,0 +1,187 @@
+/*
+The MIT License (MIT)
+
+Copyright (c) 2013-2015 SRS(ossrs)
+
+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
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+using namespace std;
+
+// Whether we are in docker, defined in main module.
+extern bool _srs_in_docker;
+
+void srs_build_features(stringstream& ss)
+{
+ ss << "&os=linux";
+
+ ss << "&docker=" << _srs_in_docker
+ << "&packager=" << SRS_AUTO_PACKAGER;
+}
+
+SrsLatestVersion::SrsLatestVersion()
+{
+ trd_ = new SrsSTCoroutine("signal", this);
+}
+
+SrsLatestVersion::~SrsLatestVersion()
+{
+ srs_freep(trd_);
+}
+
+srs_error_t SrsLatestVersion::start()
+{
+ if (!_srs_config->whether_query_latest_version()) {
+ return srs_success;
+ }
+
+ if (true) {
+ uuid_t uuid;
+ uuid_generate_time(uuid);
+
+ char buf[32];
+ for (int i = 0; i < 16; i++) {
+ snprintf(buf + i * 2, sizeof(buf), "%02x", uuid[i]);
+ }
+ server_id_ = string(buf, sizeof(buf));
+ }
+
+ return trd_->start();
+}
+
+srs_error_t SrsLatestVersion::cycle()
+{
+ srs_error_t err = srs_success;
+
+ srs_utime_t first_random_wait = 0;
+ srs_random_generate((char*)&first_random_wait, 8);
+ first_random_wait = srs_utime_t(uint64_t((first_random_wait + srs_update_system_time() + getpid())) % (5 * 60)) * SRS_UTIME_SECONDS; // in s.
+
+ // Only report after 5+ minutes.
+ first_random_wait += 5 * 60 * SRS_UTIME_SECONDS;
+
+ srs_trace("Startup query id=%s, eip=%s, wait=%ds", server_id_.c_str(), srs_get_public_internet_address().c_str(), srsu2msi(first_random_wait)/1000);
+ srs_usleep(first_random_wait);
+
+ while (true) {
+ srs_utime_t starttime = srs_update_system_time();
+ if ((err = query_latest_version()) != srs_success) {
+ srs_warn("query err %s", srs_error_desc(err).c_str());
+ srs_freep(err); // Ignore any error.
+ }
+
+ srs_trace("Finish query id=%s, eip=%s, match=%s, stable=%s, cost=%dms", server_id_.c_str(), srs_get_public_internet_address().c_str(), match_version_.c_str(), stable_version_.c_str(), srsu2msi(srs_update_system_time() - starttime));
+ srs_usleep(3600 * SRS_UTIME_SECONDS); // Every an hour.
+ }
+
+ return err;
+}
+
+srs_error_t SrsLatestVersion::query_latest_version()
+{
+ srs_error_t err = srs_success;
+
+ // Generate uri and parse to object.
+ stringstream ss;
+ ss << "http://api.ossrs.net/service/v1/releases?"
+ << "version=v" << VERSION_MAJOR << "." << VERSION_MINOR << "." << VERSION_REVISION
+ << "&id=" << server_id_ << "&role=srs"
+ << "&eip=" << srs_get_public_internet_address()
+ << "&ts=" << srs_get_system_time()
+ << "&alive=" << srsu2ms(srs_get_system_time() - srs_get_system_startup_time()) / 1000;
+ srs_build_features(ss);
+
+ string url = ss.str();
+
+ SrsHttpUri uri;
+ if ((err = uri.initialize(url)) != srs_success) {
+ return srs_error_wrap(err, "http: post failed. url=%s", url.c_str());
+ }
+
+ // Start HTTP request and read response.
+ SrsHttpClient http;
+ if ((err = http.initialize(uri.get_host(), uri.get_port())) != srs_success) {
+ return err;
+ }
+
+ // Path with query.
+ string path = uri.get_path();
+ path += "?";
+ path += uri.get_query();
+
+ ISrsHttpMessage* msg = NULL;
+ if ((err = http.get(path, "", &msg)) != srs_success) {
+ return err;
+ }
+ SrsAutoFree(ISrsHttpMessage, msg);
+
+ string res;
+ int code = msg->status_code();
+ if ((err = msg->body_read_all(res)) != srs_success) {
+ return err;
+ }
+
+ // Check the response code and content.
+ if (code != SRS_CONSTS_HTTP_OK) {
+ return srs_error_new(ERROR_HTTP_STATUS_INVALID, "invalid response status=%d", code);
+ }
+
+ if (res.empty()) {
+ return srs_error_new(ERROR_HTTP_DATA_INVALID, "invalid empty response");
+ }
+
+ // Response in json object.
+ SrsJsonAny* jres = SrsJsonAny::loads((char*)res.c_str());
+ if (!jres || !jres->is_object()) {
+ return srs_error_new(ERROR_HTTP_DATA_INVALID, "invalid response %s", res.c_str());
+ }
+ SrsAutoFree(SrsJsonAny, jres);
+
+ SrsJsonObject* obj = jres->to_object();
+ SrsJsonAny* prop = NULL;
+
+ // Parse fields of response.
+ if ((prop = obj->ensure_property_string("match_version")) == NULL) {
+ return srs_error_new(ERROR_RESPONSE_CODE, "no match_version");
+ }
+ match_version_ = prop->to_str();
+
+ if ((prop = obj->ensure_property_string("stable_version")) == NULL) {
+ return srs_error_new(ERROR_RESPONSE_CODE, "no stable_version");
+ }
+ stable_version_ = prop->to_str();
+
+ return err;
+}
+
diff --git a/trunk/src/app/srs_app_latest_version.hpp b/trunk/src/app/srs_app_latest_version.hpp
new file mode 100644
index 000000000..50ade4290
--- /dev/null
+++ b/trunk/src/app/srs_app_latest_version.hpp
@@ -0,0 +1,58 @@
+/*
+The MIT License (MIT)
+
+Copyright (c) 2013-2015 SRS(ossrs)
+
+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 SRS_APP_LATEST_VERSION_HPP
+#define SRS_APP_LATEST_VERSION_HPP
+
+/*
+#include
+*/
+
+#include
+
+#include
+
+#include
+
+class SrsLatestVersion : public ISrsCoroutineHandler
+{
+private:
+ SrsCoroutine* trd_;
+ std::string server_id_;
+private:
+ std::string match_version_;
+ std::string stable_version_;
+public:
+ SrsLatestVersion();
+ virtual ~SrsLatestVersion();
+public:
+ virtual srs_error_t start();
+// interface ISrsEndlessThreadHandler.
+public:
+ virtual srs_error_t cycle();
+private:
+ srs_error_t query_latest_version();
+};
+
+#endif
+
diff --git a/trunk/src/app/srs_app_server.cpp b/trunk/src/app/srs_app_server.cpp
index 971b771c0..11fe8116d 100644
--- a/trunk/src/app/srs_app_server.cpp
+++ b/trunk/src/app/srs_app_server.cpp
@@ -54,6 +54,7 @@ using namespace std;
#include
#include
#include
+#include
// system interval in srs_utime_t,
// all resolution times should be times togother,
@@ -623,6 +624,7 @@ SrsServer::SrsServer()
pid_fd = -1;
signal_manager = new SrsSignalManager(this);
+ latest_version_ = new SrsLatestVersion();
conn_manager = new SrsCoroutineManager();
handler = NULL;
@@ -659,6 +661,7 @@ void SrsServer::destroy()
}
srs_freep(signal_manager);
+ srs_freep(latest_version_);
srs_freep(conn_manager);
}
@@ -787,7 +790,18 @@ srs_error_t SrsServer::initialize_st()
srs_error_t SrsServer::initialize_signal()
{
- return signal_manager->initialize();
+ srs_error_t err = srs_success;
+
+ if ((err = signal_manager->initialize()) != srs_success) {
+ return srs_error_wrap(err, "init signal manager");
+ }
+
+ // Start the version query coroutine.
+ if ((err = latest_version_->start()) != srs_success) {
+ return srs_error_wrap(err, "start version query");
+ }
+
+ return err;
}
srs_error_t SrsServer::acquire_pid_file()
diff --git a/trunk/src/app/srs_app_server.hpp b/trunk/src/app/srs_app_server.hpp
index baeb7f4c5..5893055eb 100644
--- a/trunk/src/app/srs_app_server.hpp
+++ b/trunk/src/app/srs_app_server.hpp
@@ -51,6 +51,7 @@ class SrsUdpListener;
class SrsTcpListener;
class SrsAppCasterFlv;
class SrsCoroutineManager;
+class SrsLatestVersion;
// The listener type for server to identify the connection,
// that is, use different type to process the connection.
@@ -239,6 +240,8 @@ private:
std::vector listeners;
// Signal manager which convert gignal to io message.
SrsSignalManager* signal_manager;
+ // To query the latest available version of SRS.
+ SrsLatestVersion* latest_version_;
// Handle in server cycle.
ISrsServerCycle* handler;
// User send the signal, convert to variable.
diff --git a/trunk/src/app/srs_app_statistic.cpp b/trunk/src/app/srs_app_statistic.cpp
index e0f870a55..aa055d8b8 100644
--- a/trunk/src/app/srs_app_statistic.cpp
+++ b/trunk/src/app/srs_app_statistic.cpp
@@ -215,6 +215,7 @@ SrsStatisticClient::SrsStatisticClient()
SrsStatisticClient::~SrsStatisticClient()
{
+ srs_freep(req);
}
srs_error_t SrsStatisticClient::dumps(SrsJsonObject* obj)
@@ -425,10 +426,14 @@ srs_error_t SrsStatistic::on_client(std::string id, SrsRequest* req, SrsConnecti
// got client.
client->conn = conn;
- client->req = req;
client->type = type;
stream->nb_clients++;
vhost->nb_clients++;
+
+ // The req might be freed, in such as SrsLiveStream::update, so we must copy it.
+ // @see https://github.com/ossrs/srs/issues/2311
+ srs_freep(client->req);
+ client->req = req->copy();
return err;
}
diff --git a/trunk/src/app/srs_app_uuid.cpp b/trunk/src/app/srs_app_uuid.cpp
new file mode 100644
index 000000000..721efbf7b
--- /dev/null
+++ b/trunk/src/app/srs_app_uuid.cpp
@@ -0,0 +1,1320 @@
+//
+// libuuid BSD License @see https://sourceforge.net/projects/libuuid/
+//
+// SPDX-License-Identifier: BSD-3-Clause
+//
+
+#include
+
+#include
+#include
+#include
+#define HAVE_USLEEP
+////////////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////////////
+
+/*
+ * Fundamental C definitions.
+ */
+
+#ifndef UTIL_LINUX_C_H
+#define UTIL_LINUX_C_H
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include
+#include
+
+#ifdef HAVE_STDINT_H
+#include
+#else
+# ifdef HAVE_INTTYPES_H
+# include
+# endif
+#endif
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+#ifdef HAVE_ERR_H
+# include
+#endif
+
+#ifndef HAVE_USLEEP
+# include
+#endif
+
+/*
+ * Compiler specific stuff
+ */
+#ifndef __GNUC_PREREQ
+# if defined __GNUC__ && defined __GNUC_MINOR__
+# define __GNUC_PREREQ(maj, min) \
+ ((__GNUC__ << 16) + __GNUC_MINOR__ >= ((maj) << 16) + (min))
+# else
+# define __GNUC_PREREQ(maj, min) 0
+# endif
+#endif
+
+#ifdef __GNUC__
+
+/* &a[0] degrades to a pointer: a different type from an array */
+# define __must_be_array(a) \
+ UL_BUILD_BUG_ON_ZERO(__builtin_types_compatible_p(__typeof__(a), __typeof__(&a[0])))
+
+# define ignore_result(x) ({ \
+ __typeof__(x) __dummy __attribute__((__unused__)) = (x); (void) __dummy; \
+})
+
+#else /* !__GNUC__ */
+# define __must_be_array(a) 0
+# define __attribute__(_arg_)
+# define ignore_result(x) ((void) (x))
+#endif /* !__GNUC__ */
+
+/*
+ * Function attributes
+ */
+#ifndef __ul_alloc_size
+# if __GNUC_PREREQ (4, 3)
+# define __ul_alloc_size(s) __attribute__((alloc_size(s)))
+# else
+# define __ul_alloc_size(s)
+# endif
+#endif
+
+#ifndef __ul_calloc_size
+# if __GNUC_PREREQ (4, 3)
+# define __ul_calloc_size(n, s) __attribute__((alloc_size(n, s)))
+# else
+# define __ul_calloc_size(n, s)
+# endif
+#endif
+
+/* Force a compilation error if condition is true, but also produce a
+ * result (of value 0 and type size_t), so the expression can be used
+ * e.g. in a structure initializer (or where-ever else comma expressions
+ * aren't permitted).
+ */
+#define UL_BUILD_BUG_ON_ZERO(e) (sizeof(struct { int:-!!(e); }))
+#define BUILD_BUG_ON_NULL(e) ((void *)sizeof(struct { int:-!!(e); }))
+
+#ifndef ARRAY_SIZE
+# define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]) + __must_be_array(arr))
+#endif
+
+#ifndef PATH_MAX
+# define PATH_MAX 4096
+#endif
+
+#ifndef TRUE
+# define TRUE 1
+#endif
+
+#ifndef FALSE
+# define FALSE 0
+#endif
+
+#ifndef min
+# define min(x, y) ({ \
+ __typeof__(x) _min1 = (x); \
+ __typeof__(y) _min2 = (y); \
+ (void) (&_min1 == &_min2); \
+ _min1 < _min2 ? _min1 : _min2; })
+#endif
+
+#ifndef max
+# define max(x, y) ({ \
+ __typeof__(x) _max1 = (x); \
+ __typeof__(y) _max2 = (y); \
+ (void) (&_max1 == &_max2); \
+ _max1 > _max2 ? _max1 : _max2; })
+#endif
+
+#ifndef offsetof
+#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
+#endif
+
+#ifndef container_of
+#define container_of(ptr, type, member) ({ \
+ const __typeof__( ((type *)0)->member ) *__mptr = (ptr); \
+ (type *)( (char *)__mptr - offsetof(type,member) );})
+#endif
+
+#ifndef HAVE_PROGRAM_INVOCATION_SHORT_NAME
+# ifdef HAVE___PROGNAME
+extern char *__progname;
+# define program_invocation_short_name __progname
+# else
+# ifdef HAVE_GETEXECNAME
+# define program_invocation_short_name \
+ prog_inv_sh_nm_from_file(getexecname(), 0)
+# else
+# define program_invocation_short_name \
+ prog_inv_sh_nm_from_file((char*)__FILE__, 1)
+# endif
+static char prog_inv_sh_nm_buf[256];
+static inline char *
+prog_inv_sh_nm_from_file(char *f, char stripext)
+{
+ char *t;
+
+ if ((t = strrchr(f, '/')) != NULL)
+ t++;
+ else
+ t = f;
+
+ strncpy(prog_inv_sh_nm_buf, t, sizeof(prog_inv_sh_nm_buf) - 1);
+ prog_inv_sh_nm_buf[sizeof(prog_inv_sh_nm_buf) - 1] = '\0';
+
+ if (stripext && (t = strrchr(prog_inv_sh_nm_buf, '.')) != NULL)
+ *t = '\0';
+
+ return prog_inv_sh_nm_buf;
+}
+# endif
+#endif
+
+
+#ifndef HAVE_ERR_H
+static inline void
+errmsg(char doexit, int excode, char adderr, const char *fmt, ...)
+{
+ fprintf(stderr, "%s: ", program_invocation_short_name);
+ if (fmt != NULL) {
+ va_list argp;
+ va_start(argp, fmt);
+ vfprintf(stderr, fmt, argp);
+ va_end(argp);
+ if (adderr)
+ fprintf(stderr, ": ");
+ }
+ if (adderr)
+ fprintf(stderr, "%m");
+ fprintf(stderr, "\n");
+ if (doexit)
+ exit(excode);
+}
+
+#ifndef HAVE_ERR
+# define err(E, FMT...) errmsg(1, E, 1, FMT)
+#endif
+
+#ifndef HAVE_ERRX
+# define errx(E, FMT...) errmsg(1, E, 0, FMT)
+#endif
+
+#ifndef HAVE_WARN
+# define warn(FMT...) errmsg(0, 0, 1, FMT)
+#endif
+
+#ifndef HAVE_WARNX
+# define warnx(FMT...) errmsg(0, 0, 0, FMT)
+#endif
+#endif /* !HAVE_ERR_H */
+
+
+static inline __attribute__((const)) int is_power_of_2(unsigned long num)
+{
+ return (num != 0 && ((num & (num - 1)) == 0));
+}
+
+#ifndef HAVE_LOFF_T
+typedef int64_t loff_t;
+#endif
+
+#if !defined(HAVE_DIRFD) && (!defined(HAVE_DECL_DIRFD) || HAVE_DECL_DIRFD == 0) && defined(HAVE_DIR_DD_FD)
+#include
+#include
+static inline int dirfd(DIR *d)
+{
+ return d->dd_fd;
+}
+#endif
+
+/*
+ * Fallback defines for old versions of glibc
+ */
+#include
+
+#ifdef O_CLOEXEC
+#define UL_CLOEXECSTR "e"
+#else
+#define UL_CLOEXECSTR ""
+#endif
+
+#ifndef O_CLOEXEC
+#define O_CLOEXEC 0
+#endif
+
+
+#ifndef AI_ADDRCONFIG
+#define AI_ADDRCONFIG 0x0020
+#endif
+
+#ifndef IUTF8
+#define IUTF8 0040000
+#endif
+
+/*
+ * MAXHOSTNAMELEN replacement
+ */
+static inline size_t get_hostname_max(void)
+{
+#if HAVE_DECL__SC_HOST_NAME_MAX
+ long len = sysconf(_SC_HOST_NAME_MAX);
+
+ if (0 < len)
+ return len;
+#endif
+
+#ifdef MAXHOSTNAMELEN
+ return MAXHOSTNAMELEN;
+#elif HOST_NAME_MAX
+ return HOST_NAME_MAX;
+#endif
+ return 64;
+}
+
+#ifndef HAVE_USLEEP
+/*
+ * This function is marked obsolete in POSIX.1-2001 and removed in
+ * POSIX.1-2008. It is replaced with nanosleep().
+ */
+static inline int usleep(useconds_t usec)
+{
+ struct timespec waittime = {
+ .tv_sec = usec / 1000000L,
+ .tv_nsec = (usec % 1000000L) * 1000
+ };
+ return nanosleep(&waittime, NULL);
+}
+#endif
+
+/*
+ * Constant strings for usage() functions. For more info see
+ * Documentation/howto-usage-function.txt and disk-utils/delpart.c
+ */
+#define USAGE_HEADER _("\nUsage:\n")
+#define USAGE_OPTIONS _("\nOptions:\n")
+#define USAGE_SEPARATOR _("\n")
+#define USAGE_HELP _(" -h, --help display this help and exit\n")
+#define USAGE_VERSION _(" -V, --version output version information and exit\n")
+#define USAGE_MAN_TAIL(_man) _("\nFor more details see %s.\n"), _man
+
+#define UTIL_LINUX_VERSION _("%s from %s\n"), program_invocation_short_name, PACKAGE_STRING
+
+/*
+ * scanf modifiers for "strings allocation"
+ */
+#ifdef HAVE_SCANF_MS_MODIFIER
+#define UL_SCNsA "%ms"
+#elif defined(HAVE_SCANF_AS_MODIFIER)
+#define UL_SCNsA "%as"
+#endif
+
+/*
+ * seek stuff
+ */
+#ifndef SEEK_DATA
+# define SEEK_DATA 3
+#endif
+#ifndef SEEK_HOLE
+# define SEEK_HOLE 4
+#endif
+
+#endif /* UTIL_LINUX_C_H */
+
+/*
+ * Definitions used by the uuidd daemon
+ *
+ * Copyright (C) 2007 Theodore Ts'o.
+ *
+ * %Begin-Header%
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, and the entire permission notice in its entirety,
+ * including the disclaimer of warranties.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
+ * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+ * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ * %End-Header%
+ */
+
+#ifndef _UUID_UUIDD_H
+#define _UUID_UUIDD_H
+
+#define UUIDD_DIR _PATH_LOCALSTATEDIR "/uuidd"
+#define UUIDD_SOCKET_PATH UUIDD_DIR "/request"
+#define UUIDD_PIDFILE_PATH UUIDD_DIR "/uuidd.pid"
+#define UUIDD_PATH "/usr/sbin/uuidd"
+
+#define UUIDD_OP_GETPID 0
+#define UUIDD_OP_GET_MAXOP 1
+#define UUIDD_OP_TIME_UUID 2
+#define UUIDD_OP_RANDOM_UUID 3
+#define UUIDD_OP_BULK_TIME_UUID 4
+#define UUIDD_OP_BULK_RANDOM_UUID 5
+#define UUIDD_MAX_OP UUIDD_OP_BULK_RANDOM_UUID
+
+extern int __uuid_generate_time(uuid_t out, int *num);
+extern void __uuid_generate_random(uuid_t out, int *num);
+
+#endif /* _UUID_UUID_H */
+
+#ifndef UTIL_LINUX_RANDUTILS
+#define UTIL_LINUX_RANDUTILS
+
+#ifdef HAVE_SRANDOM
+#define srand(x) srandom(x)
+#define rand() random()
+#endif
+
+extern int random_get_fd(void);
+extern void random_get_bytes(void *buf, size_t nbytes);
+
+#endif
+
+/*
+ * uuid.h -- private header file for uuids
+ *
+ * Copyright (C) 1996, 1997 Theodore Ts'o.
+ *
+ * %Begin-Header%
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, and the entire permission notice in its entirety,
+ * including the disclaimer of warranties.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
+ * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+ * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ * %End-Header%
+ */
+
+#include
+#include
+
+//#include "uuid.h"
+
+#define LIBUUID_CLOCK_FILE "/var/lib/libuuid/clock.txt"
+
+/*
+ * Offset between 15-Oct-1582 and 1-Jan-70
+ */
+#define TIME_OFFSET_HIGH 0x01B21DD2
+#define TIME_OFFSET_LOW 0x13814000
+
+struct uuid {
+ uint32_t time_low;
+ uint16_t time_mid;
+ uint16_t time_hi_and_version;
+ uint16_t clock_seq;
+ uint8_t node[6];
+};
+
+
+/*
+ * prototypes
+ */
+void uuid_pack(const struct uuid *uu, uuid_t ptr);
+void uuid_unpack(const uuid_t in, struct uuid *uu);
+
+/*
+ * gen_uuid.c --- generate a DCE-compatible uuid
+ *
+ * Copyright (C) 1996, 1997, 1998, 1999 Theodore Ts'o.
+ *
+ * %Begin-Header%
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, and the entire permission notice in its entirety,
+ * including the disclaimer of warranties.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
+ * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+ * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ * %End-Header%
+ */
+
+/*
+ * Force inclusion of SVID stuff since we need it if we're compiling in
+ * gcc-wall wall mode
+ */
+#ifndef _SVID_SOURCE
+#define _SVID_SOURCE
+#endif
+
+#ifdef _WIN32
+#define _WIN32_WINNT 0x0500
+#include
+#define UUID MYUUID
+#endif
+#include
+#ifdef HAVE_UNISTD_H
+#include
+#endif
+#ifdef HAVE_STDLIB_H
+#include
+#endif
+#include
+#include
+#include
+#include
+#include
+#ifdef HAVE_SYS_TIME_H
+#include
+#endif
+#include
+#ifdef HAVE_SYS_FILE_H
+#include
+#endif
+#ifdef HAVE_SYS_IOCTL_H
+#include
+#endif
+#ifdef HAVE_SYS_SOCKET_H
+#include
+#endif
+#ifdef HAVE_SYS_UN_H
+#include
+#endif
+#ifdef HAVE_SYS_SOCKIO_H
+#include
+#endif
+#ifdef HAVE_NET_IF_H
+#include
+#endif
+#ifdef HAVE_NETINET_IN_H
+#include
+#endif
+#ifdef HAVE_NET_IF_DL_H
+#include
+#endif
+#if defined(__linux__) && defined(HAVE_SYS_SYSCALL_H)
+#include
+#endif
+
+//#include "all-io.h"
+//#include "uuidP.h"
+//#include "uuidd.h"
+//#include "randutils.h"
+//#include "c.h"
+
+#ifdef HAVE_TLS
+#define THREAD_LOCAL static __thread
+#else
+#define THREAD_LOCAL static
+#endif
+
+#ifndef LOCK_EX
+/* flock() replacement */
+#define LOCK_EX 1
+#define LOCK_SH 2
+#define LOCK_UN 3
+#define LOCK_NB 4
+
+static int flock(int fd, int op)
+{
+ int rc = 0;
+
+#if defined(F_SETLK) && defined(F_SETLKW)
+ struct flock fl = {0};
+
+ switch (op & (LOCK_EX|LOCK_SH|LOCK_UN)) {
+ case LOCK_EX:
+ fl.l_type = F_WRLCK;
+ break;
+
+ case LOCK_SH:
+ fl.l_type = F_RDLCK;
+ break;
+
+ case LOCK_UN:
+ fl.l_type = F_UNLCK;
+ break;
+
+ default:
+ errno = EINVAL;
+ return -1;
+ }
+
+ fl.l_whence = SEEK_SET;
+ rc = fcntl (fd, op & LOCK_NB ? F_SETLK : F_SETLKW, &fl);
+
+ if (rc && (errno == EAGAIN))
+ errno = EWOULDBLOCK;
+#endif /* defined(F_SETLK) && defined(F_SETLKW) */
+
+ return rc;
+}
+
+#endif /* LOCK_EX */
+
+#ifdef _WIN32
+static void gettimeofday (struct timeval *tv, void *dummy)
+{
+ FILETIME ftime;
+ uint64_t n;
+
+ GetSystemTimeAsFileTime (&ftime);
+ n = (((uint64_t) ftime.dwHighDateTime << 32)
+ + (uint64_t) ftime.dwLowDateTime);
+ if (n) {
+ n /= 10;
+ n -= ((369 * 365 + 89) * (uint64_t) 86400) * 1000000;
+ }
+
+ tv->tv_sec = n / 1000000;
+ tv->tv_usec = n % 1000000;
+}
+
+static int getuid (void)
+{
+ return 1;
+}
+#endif
+
+/*
+ * Get the ethernet hardware address, if we can find it...
+ *
+ * XXX for a windows version, probably should use GetAdaptersInfo:
+ * http://www.codeguru.com/cpp/i-n/network/networkinformation/article.php/c5451
+ * commenting out get_node_id just to get gen_uuid to compile under windows
+ * is not the right way to go!
+ */
+static int get_node_id(unsigned char *node_id)
+{
+#ifdef HAVE_NET_IF_H
+ int sd;
+ struct ifreq ifr, *ifrp;
+ struct ifconf ifc;
+ char buf[1024];
+ int n, i;
+ unsigned char *a;
+#ifdef HAVE_NET_IF_DL_H
+ struct sockaddr_dl *sdlp;
+#endif
+
+/*
+ * BSD 4.4 defines the size of an ifreq to be
+ * max(sizeof(ifreq), sizeof(ifreq.ifr_name)+ifreq.ifr_addr.sa_len
+ * However, under earlier systems, sa_len isn't present, so the size is
+ * just sizeof(struct ifreq)
+ */
+#ifdef HAVE_SA_LEN
+#define ifreq_size(i) max(sizeof(struct ifreq),\
+ sizeof((i).ifr_name)+(i).ifr_addr.sa_len)
+#else
+#define ifreq_size(i) sizeof(struct ifreq)
+#endif /* HAVE_SA_LEN */
+
+ sd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
+ if (sd < 0) {
+ return -1;
+ }
+ memset(buf, 0, sizeof(buf));
+ ifc.ifc_len = sizeof(buf);
+ ifc.ifc_buf = buf;
+ if (ioctl (sd, SIOCGIFCONF, (char *)&ifc) < 0) {
+ close(sd);
+ return -1;
+ }
+ n = ifc.ifc_len;
+ for (i = 0; i < n; i+= ifreq_size(*ifrp) ) {
+ ifrp = (struct ifreq *)((char *) ifc.ifc_buf+i);
+ strncpy(ifr.ifr_name, ifrp->ifr_name, IFNAMSIZ);
+#ifdef SIOCGIFHWADDR
+ if (ioctl(sd, SIOCGIFHWADDR, &ifr) < 0)
+ continue;
+ a = (unsigned char *) &ifr.ifr_hwaddr.sa_data;
+#else
+#ifdef SIOCGENADDR
+ if (ioctl(sd, SIOCGENADDR, &ifr) < 0)
+ continue;
+ a = (unsigned char *) ifr.ifr_enaddr;
+#else
+#ifdef HAVE_NET_IF_DL_H
+ sdlp = (struct sockaddr_dl *) &ifrp->ifr_addr;
+ if ((sdlp->sdl_family != AF_LINK) || (sdlp->sdl_alen != 6))
+ continue;
+ a = (unsigned char *) &sdlp->sdl_data[sdlp->sdl_nlen];
+#else
+ /*
+ * XXX we don't have a way of getting the hardware
+ * address
+ */
+ close(sd);
+ return 0;
+#endif /* HAVE_NET_IF_DL_H */
+#endif /* SIOCGENADDR */
+#endif /* SIOCGIFHWADDR */
+ if (!a[0] && !a[1] && !a[2] && !a[3] && !a[4] && !a[5])
+ continue;
+ if (node_id) {
+ memcpy(node_id, a, 6);
+ close(sd);
+ return 1;
+ }
+ }
+ close(sd);
+#endif
+ return 0;
+}
+
+/* Assume that the gettimeofday() has microsecond granularity */
+#define MAX_ADJUSTMENT 10
+
+/*
+ * Get clock from global sequence clock counter.
+ *
+ * Return -1 if the clock counter could not be opened/locked (in this case
+ * pseudorandom value is returned in @ret_clock_seq), otherwise return 0.
+ */
+static int get_clock(uint32_t *clock_high, uint32_t *clock_low,
+ uint16_t *ret_clock_seq, int *num)
+{
+ THREAD_LOCAL int adjustment = 0;
+ THREAD_LOCAL struct timeval last = {0, 0};
+ THREAD_LOCAL int state_fd = -2;
+ THREAD_LOCAL FILE *state_f;
+ THREAD_LOCAL uint16_t clock_seq;
+ struct timeval tv;
+ uint64_t clock_reg;
+ mode_t save_umask;
+ int len;
+ int ret = 0;
+
+ if (state_fd == -2) {
+ save_umask = umask(0);
+ state_fd = open(LIBUUID_CLOCK_FILE, O_RDWR|O_CREAT|O_CLOEXEC, 0660);
+ (void) umask(save_umask);
+ if (state_fd != -1) {
+ state_f = fdopen(state_fd, "r+" UL_CLOEXECSTR);
+ if (!state_f) {
+ close(state_fd);
+ state_fd = -1;
+ ret = -1;
+ }
+ }
+ else
+ ret = -1;
+ }
+ if (state_fd >= 0) {
+ rewind(state_f);
+ while (flock(state_fd, LOCK_EX) < 0) {
+ if ((errno == EAGAIN) || (errno == EINTR))
+ continue;
+ fclose(state_f);
+ close(state_fd);
+ state_fd = -1;
+ ret = -1;
+ break;
+ }
+ }
+ if (state_fd >= 0) {
+ unsigned int cl;
+ unsigned long tv1, tv2;
+ int a;
+
+ if (fscanf(state_f, "clock: %04x tv: %lu %lu adj: %d\n",
+ &cl, &tv1, &tv2, &a) == 4) {
+ clock_seq = cl & 0x3FFF;
+ last.tv_sec = tv1;
+ last.tv_usec = tv2;
+ adjustment = a;
+ }
+ }
+
+ if ((last.tv_sec == 0) && (last.tv_usec == 0)) {
+ random_get_bytes(&clock_seq, sizeof(clock_seq));
+ clock_seq &= 0x3FFF;
+ gettimeofday(&last, 0);
+ last.tv_sec--;
+ }
+
+ try_again:
+ gettimeofday(&tv, 0);
+ if ((tv.tv_sec < last.tv_sec) ||
+ ((tv.tv_sec == last.tv_sec) &&
+ (tv.tv_usec < last.tv_usec))) {
+ clock_seq = (clock_seq+1) & 0x3FFF;
+ adjustment = 0;
+ last = tv;
+ } else if ((tv.tv_sec == last.tv_sec) &&
+ (tv.tv_usec == last.tv_usec)) {
+ if (adjustment >= MAX_ADJUSTMENT)
+ goto try_again;
+ adjustment++;
+ } else {
+ adjustment = 0;
+ last = tv;
+ }
+
+ clock_reg = tv.tv_usec*10 + adjustment;
+ clock_reg += ((uint64_t) tv.tv_sec)*10000000;
+ clock_reg += (((uint64_t) 0x01B21DD2) << 32) + 0x13814000;
+
+ if (num && (*num > 1)) {
+ adjustment += *num - 1;
+ last.tv_usec += adjustment / 10;
+ adjustment = adjustment % 10;
+ last.tv_sec += last.tv_usec / 1000000;
+ last.tv_usec = last.tv_usec % 1000000;
+ }
+
+ if (state_fd >= 0) {
+ rewind(state_f);
+ len = fprintf(state_f,
+ "clock: %04x tv: %016lu %08lu adj: %08d\n",
+ clock_seq, last.tv_sec, last.tv_usec, adjustment);
+ fflush(state_f);
+ if (ftruncate(state_fd, len) < 0) {
+ fprintf(state_f, " \n");
+ fflush(state_f);
+ }
+ rewind(state_f);
+ flock(state_fd, LOCK_UN);
+ }
+
+ *clock_high = clock_reg >> 32;
+ *clock_low = clock_reg;
+ *ret_clock_seq = clock_seq;
+ return ret;
+}
+
+#if defined(HAVE_UUIDD) && defined(HAVE_SYS_UN_H)
+/*
+ * Try using the uuidd daemon to generate the UUID
+ *
+ * Returns 0 on success, non-zero on failure.
+ */
+static int get_uuid_via_daemon(int op, uuid_t out, int *num)
+{
+ char op_buf[64];
+ int op_len;
+ int s;
+ ssize_t ret;
+ int32_t reply_len = 0, expected = 16;
+ struct sockaddr_un srv_addr;
+
+ if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
+ return -1;
+
+ srv_addr.sun_family = AF_UNIX;
+ strcpy(srv_addr.sun_path, UUIDD_SOCKET_PATH);
+
+ if (connect(s, (const struct sockaddr *) &srv_addr,
+ sizeof(struct sockaddr_un)) < 0)
+ goto fail;
+
+ op_buf[0] = op;
+ op_len = 1;
+ if (op == UUIDD_OP_BULK_TIME_UUID) {
+ memcpy(op_buf+1, num, sizeof(*num));
+ op_len += sizeof(*num);
+ expected += sizeof(*num);
+ }
+
+ ret = write(s, op_buf, op_len);
+ if (ret < 1)
+ goto fail;
+
+ ret = read_all(s, (char *) &reply_len, sizeof(reply_len));
+ if (ret < 0)
+ goto fail;
+
+ if (reply_len != expected)
+ goto fail;
+
+ ret = read_all(s, op_buf, reply_len);
+
+ if (op == UUIDD_OP_BULK_TIME_UUID)
+ memcpy(op_buf+16, num, sizeof(int));
+
+ memcpy(out, op_buf, 16);
+
+ close(s);
+ return ((ret == expected) ? 0 : -1);
+
+fail:
+ close(s);
+ return -1;
+}
+
+#else /* !defined(HAVE_UUIDD) && defined(HAVE_SYS_UN_H) */
+static int get_uuid_via_daemon(int op, uuid_t out, int *num)
+{
+ return -1;
+}
+#endif
+
+int __uuid_generate_time(uuid_t out, int *num)
+{
+ static unsigned char node_id[6];
+ static int has_init = 0;
+ struct uuid uu;
+ uint32_t clock_mid;
+ int ret;
+
+ if (!has_init) {
+ if (get_node_id(node_id) <= 0) {
+ random_get_bytes(node_id, 6);
+ /*
+ * Set multicast bit, to prevent conflicts
+ * with IEEE 802 addresses obtained from
+ * network cards
+ */
+ node_id[0] |= 0x01;
+ }
+ has_init = 1;
+ }
+ ret = get_clock(&clock_mid, &uu.time_low, &uu.clock_seq, num);
+ uu.clock_seq |= 0x8000;
+ uu.time_mid = (uint16_t) clock_mid;
+ uu.time_hi_and_version = ((clock_mid >> 16) & 0x0FFF) | 0x1000;
+ memcpy(uu.node, node_id, 6);
+ uuid_pack(&uu, out);
+ return ret;
+}
+
+/*
+ * Generate time-based UUID and store it to @out
+ *
+ * Tries to guarantee uniqueness of the generated UUIDs by obtaining them from the uuidd daemon,
+ * or, if uuidd is not usable, by using the global clock state counter (see get_clock()).
+ * If neither of these is possible (e.g. because of insufficient permissions), it generates
+ * the UUID anyway, but returns -1. Otherwise, returns 0.
+ */
+static int uuid_generate_time_generic(uuid_t out) {
+#ifdef HAVE_TLS
+ THREAD_LOCAL int num = 0;
+ THREAD_LOCAL struct uuid uu;
+ THREAD_LOCAL time_t last_time = 0;
+ time_t now;
+
+ if (num > 0) {
+ now = time(0);
+ if (now > last_time+1)
+ num = 0;
+ }
+ if (num <= 0) {
+ num = 1000;
+ if (get_uuid_via_daemon(UUIDD_OP_BULK_TIME_UUID,
+ out, &num) == 0) {
+ last_time = time(0);
+ uuid_unpack(out, &uu);
+ num--;
+ return 0;
+ }
+ num = 0;
+ }
+ if (num > 0) {
+ uu.time_low++;
+ if (uu.time_low == 0) {
+ uu.time_mid++;
+ if (uu.time_mid == 0)
+ uu.time_hi_and_version++;
+ }
+ num--;
+ uuid_pack(&uu, out);
+ return 0;
+ }
+#else
+ if (get_uuid_via_daemon(UUIDD_OP_TIME_UUID, out, 0) == 0)
+ return 0;
+#endif
+
+ return __uuid_generate_time(out, 0);
+}
+
+/*
+ * Generate time-based UUID and store it to @out.
+ *
+ * Discards return value from uuid_generate_time_generic()
+ */
+void uuid_generate_time(uuid_t out)
+{
+ (void)uuid_generate_time_generic(out);
+}
+
+
+int uuid_generate_time_safe(uuid_t out)
+{
+ return uuid_generate_time_generic(out);
+}
+
+
+void __uuid_generate_random(uuid_t out, int *num)
+{
+ uuid_t buf;
+ struct uuid uu;
+ int i, n;
+
+ if (!num || !*num)
+ n = 1;
+ else
+ n = *num;
+
+ for (i = 0; i < n; i++) {
+ random_get_bytes(buf, sizeof(buf));
+ uuid_unpack(buf, &uu);
+
+ uu.clock_seq = (uu.clock_seq & 0x3FFF) | 0x8000;
+ uu.time_hi_and_version = (uu.time_hi_and_version & 0x0FFF)
+ | 0x4000;
+ uuid_pack(&uu, out);
+ out += sizeof(uuid_t);
+ }
+}
+
+void uuid_generate_random(uuid_t out)
+{
+ int num = 1;
+ /* No real reason to use the daemon for random uuid's -- yet */
+
+ __uuid_generate_random(out, &num);
+}
+
+/*
+ * Check whether good random source (/dev/random or /dev/urandom)
+ * is available.
+ */
+static int have_random_source(void)
+{
+ struct stat s;
+
+ return (!stat("/dev/random", &s) || !stat("/dev/urandom", &s));
+}
+
+
+/*
+ * This is the generic front-end to uuid_generate_random and
+ * uuid_generate_time. It uses uuid_generate_random only if
+ * /dev/urandom is available, since otherwise we won't have
+ * high-quality randomness.
+ */
+void uuid_generate(uuid_t out)
+{
+ if (have_random_source())
+ uuid_generate_random(out);
+ else
+ uuid_generate_time(out);
+}
+
+/*
+ * General purpose random utilities
+ *
+ * Based on libuuid code.
+ *
+ * This file may be redistributed under the terms of the
+ * GNU Lesser General Public License.
+ */
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+
+//#include "randutils.h"
+
+#ifdef HAVE_TLS
+#define THREAD_LOCAL static __thread
+#else
+#define THREAD_LOCAL static
+#endif
+
+#if defined(__linux__) && defined(__NR_gettid) && defined(HAVE_JRAND48)
+#define DO_JRAND_MIX
+THREAD_LOCAL unsigned short ul_jrand_seed[3];
+#endif
+
+int random_get_fd(void)
+{
+ int i, fd;
+ struct timeval tv;
+
+ gettimeofday(&tv, 0);
+ fd = open("/dev/urandom", O_RDONLY);
+ if (fd == -1)
+ fd = open("/dev/random", O_RDONLY | O_NONBLOCK);
+ if (fd >= 0) {
+ i = fcntl(fd, F_GETFD);
+ if (i >= 0)
+ fcntl(fd, F_SETFD, i | FD_CLOEXEC);
+ }
+ srand((getpid() << 16) ^ getuid() ^ tv.tv_sec ^ tv.tv_usec);
+
+#ifdef DO_JRAND_MIX
+ ul_jrand_seed[0] = getpid() ^ (tv.tv_sec & 0xFFFF);
+ ul_jrand_seed[1] = getppid() ^ (tv.tv_usec & 0xFFFF);
+ ul_jrand_seed[2] = (tv.tv_sec ^ tv.tv_usec) >> 16;
+#endif
+ /* Crank the random number generator a few times */
+ gettimeofday(&tv, 0);
+ for (i = (tv.tv_sec ^ tv.tv_usec) & 0x1F; i > 0; i--)
+ rand();
+ return fd;
+}
+
+
+/*
+ * Generate a stream of random nbytes into buf.
+ * Use /dev/urandom if possible, and if not,
+ * use glibc pseudo-random functions.
+ */
+void random_get_bytes(void *buf, size_t nbytes)
+{
+ size_t i, n = nbytes;
+ int fd = random_get_fd();
+ int lose_counter = 0;
+ unsigned char *cp = (unsigned char *) buf;
+
+ if (fd >= 0) {
+ while (n > 0) {
+ ssize_t x = read(fd, cp, n);
+ if (x <= 0) {
+ if (lose_counter++ > 16)
+ break;
+ continue;
+ }
+ n -= x;
+ cp += x;
+ lose_counter = 0;
+ }
+
+ close(fd);
+ }
+
+ /*
+ * We do this all the time, but this is the only source of
+ * randomness if /dev/random/urandom is out to lunch.
+ */
+ for (cp = (unsigned char *)buf, i = 0; i < nbytes; i++)
+ *cp++ ^= (rand() >> 7) & 0xFF;
+
+#ifdef DO_JRAND_MIX
+ {
+ unsigned short tmp_seed[3];
+
+ memcpy(tmp_seed, ul_jrand_seed, sizeof(tmp_seed));
+ ul_jrand_seed[2] = ul_jrand_seed[2] ^ syscall(__NR_gettid);
+ for (cp = buf, i = 0; i < nbytes; i++)
+ *cp++ ^= (jrand48(tmp_seed) >> 7) & 0xFF;
+ memcpy(ul_jrand_seed, tmp_seed,
+ sizeof(ul_jrand_seed)-sizeof(unsigned short));
+ }
+#endif
+
+ return;
+}
+
+#ifdef TEST_PROGRAM
+int main(int argc __attribute__ ((__unused__)),
+ char *argv[] __attribute__ ((__unused__)))
+{
+ unsigned int v, i;
+
+ /* generate and print 10 random numbers */
+ for (i = 0; i < 10; i++) {
+ random_get_bytes(&v, sizeof(v));
+ printf("%d\n", v);
+ }
+
+ return EXIT_SUCCESS;
+}
+#endif /* TEST_PROGRAM */
+
+/*
+ * Internal routine for packing UUIDs
+ *
+ * Copyright (C) 1996, 1997 Theodore Ts'o.
+ *
+ * %Begin-Header%
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, and the entire permission notice in its entirety,
+ * including the disclaimer of warranties.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
+ * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+ * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ * %End-Header%
+ */
+
+#include
+//#include "uuidP.h"
+
+void uuid_pack(const struct uuid *uu, uuid_t ptr)
+{
+ uint32_t tmp;
+ unsigned char *out = ptr;
+
+ tmp = uu->time_low;
+ out[3] = (unsigned char) tmp;
+ tmp >>= 8;
+ out[2] = (unsigned char) tmp;
+ tmp >>= 8;
+ out[1] = (unsigned char) tmp;
+ tmp >>= 8;
+ out[0] = (unsigned char) tmp;
+
+ tmp = uu->time_mid;
+ out[5] = (unsigned char) tmp;
+ tmp >>= 8;
+ out[4] = (unsigned char) tmp;
+
+ tmp = uu->time_hi_and_version;
+ out[7] = (unsigned char) tmp;
+ tmp >>= 8;
+ out[6] = (unsigned char) tmp;
+
+ tmp = uu->clock_seq;
+ out[9] = (unsigned char) tmp;
+ tmp >>= 8;
+ out[8] = (unsigned char) tmp;
+
+ memcpy(out+10, uu->node, 6);
+}
+
+/*
+ * Internal routine for unpacking UUID
+ *
+ * Copyright (C) 1996, 1997 Theodore Ts'o.
+ *
+ * %Begin-Header%
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, and the entire permission notice in its entirety,
+ * including the disclaimer of warranties.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
+ * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+ * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ * %End-Header%
+ */
+
+#include
+//#include "uuidP.h"
+
+void uuid_unpack(const uuid_t in, struct uuid *uu)
+{
+ const uint8_t *ptr = in;
+ uint32_t tmp;
+
+ tmp = *ptr++;
+ tmp = (tmp << 8) | *ptr++;
+ tmp = (tmp << 8) | *ptr++;
+ tmp = (tmp << 8) | *ptr++;
+ uu->time_low = tmp;
+
+ tmp = *ptr++;
+ tmp = (tmp << 8) | *ptr++;
+ uu->time_mid = tmp;
+
+ tmp = *ptr++;
+ tmp = (tmp << 8) | *ptr++;
+ uu->time_hi_and_version = tmp;
+
+ tmp = *ptr++;
+ tmp = (tmp << 8) | *ptr++;
+ uu->clock_seq = tmp;
+
+ memcpy(uu->node, ptr, 6);
+}
+
diff --git a/trunk/src/app/srs_app_uuid.hpp b/trunk/src/app/srs_app_uuid.hpp
new file mode 100644
index 000000000..689fa239e
--- /dev/null
+++ b/trunk/src/app/srs_app_uuid.hpp
@@ -0,0 +1,112 @@
+//
+// libuuid BSD License @see https://sourceforge.net/projects/libuuid/
+//
+// SPDX-License-Identifier: BSD-3-Clause
+//
+#include
+
+/*
+ * Public include file for the UUID library
+ *
+ * Copyright (C) 1996, 1997, 1998 Theodore Ts'o.
+ *
+ * %Begin-Header%
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, and the entire permission notice in its entirety,
+ * including the disclaimer of warranties.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
+ * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+ * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ * %End-Header%
+ */
+
+#ifndef _UUID_UUID_H
+#define _UUID_UUID_H
+
+#include
+#ifndef _WIN32
+#include
+#endif
+#include
+
+typedef unsigned char uuid_t[16];
+
+/* UUID Variant definitions */
+#define UUID_VARIANT_NCS 0
+#define UUID_VARIANT_DCE 1
+#define UUID_VARIANT_MICROSOFT 2
+#define UUID_VARIANT_OTHER 3
+
+/* UUID Type definitions */
+#define UUID_TYPE_DCE_TIME 1
+#define UUID_TYPE_DCE_RANDOM 4
+
+/* Allow UUID constants to be defined */
+#ifdef __GNUC__
+#define UUID_DEFINE(name,u0,u1,u2,u3,u4,u5,u6,u7,u8,u9,u10,u11,u12,u13,u14,u15) \
+ static const uuid_t name __attribute__ ((unused)) = {u0,u1,u2,u3,u4,u5,u6,u7,u8,u9,u10,u11,u12,u13,u14,u15}
+#else
+#define UUID_DEFINE(name,u0,u1,u2,u3,u4,u5,u6,u7,u8,u9,u10,u11,u12,u13,u14,u15) \
+ static const uuid_t name = {u0,u1,u2,u3,u4,u5,u6,u7,u8,u9,u10,u11,u12,u13,u14,u15}
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* clear.c */
+void uuid_clear(uuid_t uu);
+
+/* compare.c */
+int uuid_compare(const uuid_t uu1, const uuid_t uu2);
+
+/* copy.c */
+void uuid_copy(uuid_t dst, const uuid_t src);
+
+/* gen_uuid.c */
+void uuid_generate(uuid_t out);
+void uuid_generate_random(uuid_t out);
+void uuid_generate_time(uuid_t out);
+int uuid_generate_time_safe(uuid_t out);
+
+/* isnull.c */
+int uuid_is_null(const uuid_t uu);
+
+/* parse.c */
+int uuid_parse(const char *in, uuid_t uu);
+
+/* unparse.c */
+void uuid_unparse(const uuid_t uu, char *out);
+void uuid_unparse_lower(const uuid_t uu, char *out);
+void uuid_unparse_upper(const uuid_t uu, char *out);
+
+/* uuid_time.c */
+time_t uuid_time(const uuid_t uu, struct timeval *ret_tv);
+int uuid_type(const uuid_t uu);
+int uuid_variant(const uuid_t uu);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _UUID_UUID_H */
+
diff --git a/trunk/src/core/srs_core_version3.hpp b/trunk/src/core/srs_core_version3.hpp
index 0b1b470b1..d4156cec3 100644
--- a/trunk/src/core/srs_core_version3.hpp
+++ b/trunk/src/core/srs_core_version3.hpp
@@ -24,6 +24,6 @@
#ifndef SRS_CORE_VERSION3_HPP
#define SRS_CORE_VERSION3_HPP
-#define SRS_VERSION3_REVISION 161
+#define SRS_VERSION3_REVISION 170
#endif
diff --git a/trunk/src/kernel/srs_kernel_utility.cpp b/trunk/src/kernel/srs_kernel_utility.cpp
index cd5e27e7d..09060b720 100644
--- a/trunk/src/kernel/srs_kernel_utility.cpp
+++ b/trunk/src/kernel/srs_kernel_utility.cpp
@@ -119,7 +119,7 @@ srs_utime_t srs_get_system_startup_time()
if (_srs_system_time_startup_time <= 0) {
srs_update_system_time();
}
-
+
return _srs_system_time_startup_time;
}
diff --git a/trunk/src/protocol/srs_protocol_utility.cpp b/trunk/src/protocol/srs_protocol_utility.cpp
index 3937ddc29..5d00f5df3 100644
--- a/trunk/src/protocol/srs_protocol_utility.cpp
+++ b/trunk/src/protocol/srs_protocol_utility.cpp
@@ -150,18 +150,23 @@ void srs_parse_query_string(string q, map& query)
void srs_random_generate(char* bytes, int size)
{
- static bool _random_initialized = false;
- if (!_random_initialized) {
- srand(0);
- _random_initialized = true;
- }
-
for (int i = 0; i < size; i++) {
// the common value in [0x0f, 0xf0]
- bytes[i] = 0x0f + (rand() % (256 - 0x0f - 0x0f));
+ bytes[i] = 0x0f + (srs_random() % (256 - 0x0f - 0x0f));
}
}
+long srs_random()
+{
+ static bool _random_initialized = false;
+ if (!_random_initialized) {
+ _random_initialized = true;
+ srandom((unsigned int)srs_get_system_startup_time());
+ }
+
+ return random();
+}
+
string srs_generate_tc_url(string host, string vhost, string app, int port)
{
string tcUrl = "rtmp://";
diff --git a/trunk/src/protocol/srs_protocol_utility.hpp b/trunk/src/protocol/srs_protocol_utility.hpp
index 777ec1900..36ecbb07e 100644
--- a/trunk/src/protocol/srs_protocol_utility.hpp
+++ b/trunk/src/protocol/srs_protocol_utility.hpp
@@ -69,6 +69,8 @@ extern void srs_parse_query_string(std::string q, std::map