diff --git a/trunk/3rdparty/st-srs/Makefile b/trunk/3rdparty/st-srs/Makefile index cf4d519461..71f96ba4ed 100644 --- a/trunk/3rdparty/st-srs/Makefile +++ b/trunk/3rdparty/st-srs/Makefile @@ -282,6 +282,10 @@ endif # # make EXTRA_CFLAGS=-UMD_HAVE_EPOLL # +# or to enable sendmmsg(2) support: +# +# make EXTRA_CFLAGS="-DMD_HAVE_SENDMMSG -D_GNU_SOURCE" +# # or to enable stats for ST: # # make EXTRA_CFLAGS=-DDEBUG_STATS diff --git a/trunk/3rdparty/st-srs/README.md b/trunk/3rdparty/st-srs/README.md index 8a5eba94fe..aa8ad70bc8 100644 --- a/trunk/3rdparty/st-srs/README.md +++ b/trunk/3rdparty/st-srs/README.md @@ -66,7 +66,7 @@ The branch [srs](https://github.com/ossrs/state-threads/tree/srs) will be patche - [x] Support macro `MD_ST_NO_ASM` to disable ASM, [#8](https://github.com/ossrs/state-threads/issues/8). - [x] Merge patch [srs#1282](https://github.com/ossrs/srs/issues/1282#issuecomment-445539513) to support aarch64, [#9](https://github.com/ossrs/state-threads/issues/9). - [x] Support OSX for Apple Darwin, macOS, [#11](https://github.com/ossrs/state-threads/issues/11). -- [ ] Support sendmmsg for UDP, [#12](https://github.com/ossrs/state-threads/issues/12). +- [x] Support sendmmsg for UDP, [#12](https://github.com/ossrs/state-threads/issues/12). - [x] Refine performance for sleep or epoll_wait(0), [#17](https://github.com/ossrs/state-threads/issues/17). - [ ] Improve the performance of timer. [9fe8cfe5b](https://github.com/ossrs/state-threads/commit/9fe8cfe5b1c9741a2e671a46215184f267fba400), [7879c2b](https://github.com/ossrs/state-threads/commit/7879c2b), [387cddb](https://github.com/ossrs/state-threads/commit/387cddb) diff --git a/trunk/3rdparty/st-srs/io.c b/trunk/3rdparty/st-srs/io.c index 788a1046f9..da91840915 100644 --- a/trunk/3rdparty/st-srs/io.c +++ b/trunk/3rdparty/st-srs/io.c @@ -68,6 +68,8 @@ unsigned long long _st_stat_recvmsg = 0; unsigned long long _st_stat_recvmsg_eagain = 0; unsigned long long _st_stat_sendmsg = 0; unsigned long long _st_stat_sendmsg_eagain = 0; +unsigned long long _st_stat_sendmmsg = 0; +unsigned long long _st_stat_sendmmsg_eagain = 0; #endif #if EAGAIN != EWOULDBLOCK @@ -831,6 +833,69 @@ int st_sendmsg(_st_netfd_t *fd, const struct msghdr *msg, int flags, st_utime_t return n; } +int st_sendmmsg(st_netfd_t fd, struct st_mmsghdr *msgvec, unsigned int vlen, int flags, st_utime_t timeout) +{ +#if defined(MD_HAVE_SENDMMSG) && defined(_GNU_SOURCE) + int n; + int left; + struct mmsghdr *p; + + #if defined(DEBUG) && defined(DEBUG_STATS) + ++_st_stat_sendmmsg; + #endif + + left = (int)vlen; + while (left > 0) { + p = (struct mmsghdr*)msgvec + (vlen - left); + + if ((n = sendmmsg(fd->osfd, p, left, flags)) < 0) { + if (errno == EINTR) + continue; + if (!_IO_NOT_READY_ERROR) + break; + + #if defined(DEBUG) && defined(DEBUG_STATS) + ++_st_stat_sendmmsg_eagain; + #endif + + /* Wait until the socket becomes writable */ + if (st_netfd_poll(fd, POLLOUT, timeout) < 0) + break; + } + + left -= n; + } + + // An error is returned only if no datagrams could be sent. + if (left == (int)vlen) { + return n; + } + return (int)vlen - left; +#else + struct st_mmsghdr *p; + int i, n; + + // @see http://man7.org/linux/man-pages/man2/sendmmsg.2.html + for (i = 0; i < (int)vlen; ++i) { + p = msgvec + i; + n = st_sendmsg(fd, &p->msg_hdr, flags, timeout); + if (n < 0) { + // An error is returned only if no datagrams could be sent. + if (i == 0) { + return n; + } + return i + 1; + } + + p->msg_len = n; + } + + // Returns the number of messages sent from msgvec; if this is less than vlen, the caller can retry with a + // further sendmmsg() call to send the remaining messages. + return vlen; +#endif +} + /* * To open FIFOs or other special files. diff --git a/trunk/3rdparty/st-srs/public.h b/trunk/3rdparty/st-srs/public.h index df7c5c967d..c911912b82 100644 --- a/trunk/3rdparty/st-srs/public.h +++ b/trunk/3rdparty/st-srs/public.h @@ -153,6 +153,14 @@ extern int st_sendto(st_netfd_t fd, const void *msg, int len, const struct socka extern int st_recvmsg(st_netfd_t fd, struct msghdr *msg, int flags, st_utime_t timeout); extern int st_sendmsg(st_netfd_t fd, const struct msghdr *msg, int flags, st_utime_t timeout); +// @see http://man7.org/linux/man-pages/man2/sendmmsg.2.html +#include +struct st_mmsghdr { + struct msghdr msg_hdr; /* Message header */ + unsigned int msg_len; /* Number of bytes transmitted */ +}; +extern int st_sendmmsg(st_netfd_t fd, struct st_mmsghdr *msgvec, unsigned int vlen, int flags, st_utime_t timeout); + extern st_netfd_t st_open(const char *path, int oflags, mode_t mode); #ifdef DEBUG diff --git a/trunk/auto/depends.sh b/trunk/auto/depends.sh index c58f81d536..cda4091ea8 100755 --- a/trunk/auto/depends.sh +++ b/trunk/auto/depends.sh @@ -348,6 +348,14 @@ fi if [[ $SRS_OSX == YES ]]; then _ST_MAKE=darwin-debug && _ST_EXTRA_CFLAGS="-DMD_HAVE_KQUEUE" && _ST_LD=${SRS_TOOL_CC} && _ST_OBJ="DARWIN_`uname -r`_DBG" fi +# For UDP sendmmsg, disable it if not suppported. +if [[ $SRS_SENDMMSG == YES ]]; then + echo "Build ST with UDP sendmmsg support." + _ST_EXTRA_CFLAGS="$_ST_EXTRA_CFLAGS -DMD_HAVE_SENDMMSG -D_GNU_SOURCE" +else + echo "Build ST without UDP sendmmsg support." + _ST_EXTRA_CFLAGS="$_ST_EXTRA_CFLAGS -UMD_HAVE_SENDMMSG -U_GNU_SOURCE" +fi # Whether enable debug stats. if [[ $SRS_DEBUG_STATS == YES ]]; then _ST_EXTRA_CFLAGS="$_ST_EXTRA_CFLAGS -DDEBUG_STATS" diff --git a/trunk/auto/options.sh b/trunk/auto/options.sh index 82d2c5256e..ca7d6dac81 100755 --- a/trunk/auto/options.sh +++ b/trunk/auto/options.sh @@ -128,6 +128,7 @@ SRS_EXTRA_FLAGS= # Performance optimize. SRS_NASM=YES SRS_SRTP_ASM=YES +SRS_SENDMMSG=NO SRS_DEBUG=NO SRS_DEBUG_STATS=NO @@ -176,6 +177,7 @@ Performance: @see https://blog.csdn.net/win_lin/article/details/5 --nasm=on|off Whether build FFMPEG for RTC with nasm. Default: $(value2switch $SRS_NASM) --srtp-nasm=on|off Whether build SRTP with ASM(openssl-asm), requires RTC and openssl-1.0.*. Default: $(value2switch $SRS_SRTP_ASM) + --sendmmsg=on|off Whether enable UDP sendmmsg. Default: $(value2switch $SRS_SENDMMSG). @see http://man7.org/linux/man-pages/man2/sendmmsg.2.html Toolchain options: @see https://github.com/ossrs/srs/issues/1547#issuecomment-576078411 --static=on|off Whether add '-static' to link options. Default: $(value2switch $SRS_STATIC) @@ -228,6 +230,8 @@ function parse_user_option() { --x86-64) SRS_X86_X64=YES ;; --osx) SRS_OSX=YES ;; + --sendmmsg) if [[ $value == off ]]; then SRS_SENDMMSG=NO; else SRS_SENDMMSG=YES; fi ;; + --without-srtp-nasm) SRS_SRTP_ASM=NO ;; --with-srtp-nasm) SRS_SRTP_ASM=YES ;; --srtp-nasm) if [[ $value == off ]]; then SRS_SRTP_ASM=NO; else SRS_SRTP_ASM=YES; fi ;; @@ -519,6 +523,11 @@ function apply_detail_options() { echo "Use openssl-1.0 for SRTP-ASM." SRS_SSL_1_0=YES fi + + if [[ $SRS_OSX == YES && $SRS_SENDMMSG == YES ]]; then + echo "Disable sendmmsg for OSX" + SRS_SENDMMSG=NO + fi } apply_detail_options @@ -553,6 +562,7 @@ function regenerate_options() { SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --ffmpeg-fit=$(value2switch $SRS_FFMPEG_FIT)" SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --nasm=$(value2switch $SRS_NASM)" SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --srtp-nasm=$(value2switch $SRS_SRTP_ASM)" + SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --sendmmsg=$(value2switch $SRS_SENDMMSG)" SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --clean=$(value2switch $SRS_CLEAN)" SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --gperf=$(value2switch $SRS_GPERF)" SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --gmc=$(value2switch $SRS_GPERF_MC)" diff --git a/trunk/src/app/srs_app_hybrid.cpp b/trunk/src/app/srs_app_hybrid.cpp index 29ceca211d..a862cf1ed5 100644 --- a/trunk/src/app/srs_app_hybrid.cpp +++ b/trunk/src/app/srs_app_hybrid.cpp @@ -66,10 +66,14 @@ extern unsigned long long _st_stat_recvmsg; extern unsigned long long _st_stat_recvmsg_eagain; extern unsigned long long _st_stat_sendmsg; extern unsigned long long _st_stat_sendmsg_eagain; +extern unsigned long long _st_stat_sendmmsg; +extern unsigned long long _st_stat_sendmmsg_eagain; SrsPps* _srs_pps_recvmsg = new SrsPps(); SrsPps* _srs_pps_recvmsg_eagain = new SrsPps(); SrsPps* _srs_pps_sendmsg = new SrsPps(); SrsPps* _srs_pps_sendmsg_eagain = new SrsPps(); +SrsPps* _srs_pps_sendmmsg = new SrsPps(); +SrsPps* _srs_pps_sendmmsg_eagain = new SrsPps(); extern unsigned long long _st_stat_epoll; extern unsigned long long _st_stat_epoll_zero; @@ -327,8 +331,9 @@ srs_error_t SrsHybridServer::notify(int event, srs_utime_t interval, srs_utime_t #if defined(SRS_DEBUG) && defined(SRS_DEBUG_STATS) _srs_pps_recvmsg->update(_st_stat_recvmsg); _srs_pps_recvmsg_eagain->update(_st_stat_recvmsg_eagain); _srs_pps_sendmsg->update(_st_stat_sendmsg); _srs_pps_sendmsg_eagain->update(_st_stat_sendmsg_eagain); - if (_srs_pps_recvmsg->r10s() || _srs_pps_recvmsg_eagain->r10s() || _srs_pps_sendmsg->r10s() || _srs_pps_sendmsg_eagain->r10s()) { - snprintf(buf, sizeof(buf), ", msg=%d,%d,%d,%d", _srs_pps_recvmsg->r10s(), _srs_pps_recvmsg_eagain->r10s(), _srs_pps_sendmsg->r10s(), _srs_pps_sendmsg_eagain->r10s()); + _srs_pps_sendmmsg->update(_st_stat_sendmmsg); _srs_pps_sendmmsg_eagain->update(_st_stat_sendmmsg_eagain); + if (_srs_pps_recvmsg->r10s() || _srs_pps_recvmsg_eagain->r10s() || _srs_pps_sendmsg->r10s() || _srs_pps_sendmsg_eagain->r10s() || _srs_pps_sendmmsg->r10s() || _srs_pps_sendmmsg_eagain->r10s()) { + snprintf(buf, sizeof(buf), ", msg=%d,%d,%d,%d,%d,%d", _srs_pps_recvmsg->r10s(), _srs_pps_recvmsg_eagain->r10s(), _srs_pps_sendmsg->r10s(), _srs_pps_sendmsg_eagain->r10s(), _srs_pps_sendmmsg->r10s(), _srs_pps_sendmmsg_eagain->r10s()); msg_desc = buf; } #endif diff --git a/trunk/src/protocol/srs_service_st.cpp b/trunk/src/protocol/srs_service_st.cpp index a0fa42de9c..784c7e140c 100644 --- a/trunk/src/protocol/srs_service_st.cpp +++ b/trunk/src/protocol/srs_service_st.cpp @@ -446,6 +446,11 @@ int srs_sendmsg(srs_netfd_t stfd, const struct msghdr *msg, int flags, srs_utime return st_sendmsg((st_netfd_t)stfd, msg, flags, (st_utime_t)timeout); } +int srs_sendmmsg(srs_netfd_t stfd, struct srs_mmsghdr *msgvec, unsigned int vlen, int flags, srs_utime_t timeout) +{ + return st_sendmmsg((st_netfd_t)stfd, (struct st_mmsghdr*)msgvec, vlen, flags, (st_utime_t)timeout); +} + srs_netfd_t srs_accept(srs_netfd_t stfd, struct sockaddr *addr, int *addrlen, srs_utime_t timeout) { return (srs_netfd_t)st_accept((st_netfd_t)stfd, addr, addrlen, (st_utime_t)timeout); diff --git a/trunk/src/protocol/srs_service_st.hpp b/trunk/src/protocol/srs_service_st.hpp index 76ec4b8d6f..1de96003e6 100644 --- a/trunk/src/protocol/srs_service_st.hpp +++ b/trunk/src/protocol/srs_service_st.hpp @@ -99,6 +99,14 @@ extern int srs_sendto(srs_netfd_t stfd, void *buf, int len, const struct sockadd extern int srs_recvmsg(srs_netfd_t stfd, struct msghdr *msg, int flags, srs_utime_t timeout); extern int srs_sendmsg(srs_netfd_t stfd, const struct msghdr *msg, int flags, srs_utime_t timeout); +// @see http://man7.org/linux/man-pages/man2/sendmmsg.2.html +#include +struct srs_mmsghdr { + struct msghdr msg_hdr; /* Message header */ + unsigned int msg_len; /* Number of bytes transmitted */ +}; +extern int srs_sendmmsg(srs_netfd_t stfd, struct srs_mmsghdr *msgvec, unsigned int vlen, int flags, srs_utime_t timeout); + extern srs_netfd_t srs_accept(srs_netfd_t stfd, struct sockaddr *addr, int *addrlen, srs_utime_t timeout); extern ssize_t srs_read(srs_netfd_t stfd, void *buf, size_t nbyte, srs_utime_t timeout);