mirror of
https://github.com/ossrs/srs.git
synced 2025-02-15 04:42:04 +00:00
Release v4.0.23
This commit is contained in:
commit
0bd3689766
52 changed files with 3356 additions and 4576 deletions
14
trunk/3rdparty/st-srs/README.md
vendored
14
trunk/3rdparty/st-srs/README.md
vendored
|
@ -31,6 +31,14 @@ The branch [srs](https://github.com/ossrs/state-threads/tree/srs) will be patche
|
|||
* API reference: http://ossrs.github.io/state-threads/docs/reference.html
|
||||
* Programming notes: http://ossrs.github.io/state-threads/docs/notes.html
|
||||
|
||||
## Analysis
|
||||
|
||||
* About setjmp and longjmp, read [setjmp](https://gitee.com/winlinvip/srs-wiki/raw/master/images/st-setjmp.jpg).
|
||||
* About the stack structure, read [stack](https://gitee.com/winlinvip/srs-wiki/raw/master/images/st-stack.jpg)
|
||||
* About asm code comments, read [#91d530e](https://github.com/ossrs/state-threads/commit/91d530e#diff-ed9428b14ff6afda0e9ab04cc91d4445R25).
|
||||
* About the scheduler, read [#13-scheduler](https://github.com/ossrs/state-threads/issues/13#issuecomment-616025527).
|
||||
* About the IO event system, read [#13-IO](https://github.com/ossrs/state-threads/issues/13#issuecomment-616096568).
|
||||
|
||||
## Usage
|
||||
|
||||
Get code:
|
||||
|
@ -87,10 +95,4 @@ Important cli options:
|
|||
1. `--track-origins=<yes|no> [default: no]`, Controls whether Memcheck tracks the origin of uninitialised values. By default, it does not, which means that although it can tell you that an uninitialised value is being used in a dangerous way, it cannot tell you where the uninitialised value came from. This often makes it difficult to track down the root problem.
|
||||
1. `--show-reachable=<yes|no> , --show-possibly-lost=<yes|no>`, to show the using memory.
|
||||
|
||||
## Analysis
|
||||
|
||||
1. About setjmp and longjmp, read [setjmp](https://gitee.com/winlinvip/srs-wiki/raw/master/images/st-setjmp.jpg).
|
||||
1. About the stack structure, read [stack](https://gitee.com/winlinvip/srs-wiki/raw/master/images/st-stack.jpg)
|
||||
1. About asm code comments, read [#91d530e](https://github.com/ossrs/state-threads/commit/91d530e#diff-ed9428b14ff6afda0e9ab04cc91d4445R25).
|
||||
|
||||
Winlin 2016
|
||||
|
|
|
@ -438,6 +438,10 @@ fi
|
|||
# cherrypy for http hooks callback, CherryPy-3.2.4
|
||||
#####################################################################################
|
||||
if [ $SRS_EXPORT_LIBRTMP_PROJECT = NO ]; then
|
||||
# Detect python or python2
|
||||
python --version >/dev/null 2>&1 && SYS_PYTHON=python;
|
||||
python2 --version >/dev/null 2>&1 && SYS_PYTHON=python2;
|
||||
# Install cherrypy for api server.
|
||||
if [[ -f ${SRS_OBJS}/${SRS_PLATFORM}/CherryPy-3.2.4/setup.py ]]; then
|
||||
echo "CherryPy-3.2.4 is ok.";
|
||||
else
|
||||
|
@ -445,7 +449,7 @@ if [ $SRS_EXPORT_LIBRTMP_PROJECT = NO ]; then
|
|||
(
|
||||
rm -rf ${SRS_OBJS}/CherryPy-3.2.4 && cd ${SRS_OBJS}/${SRS_PLATFORM} &&
|
||||
unzip -q ../../3rdparty/CherryPy-3.2.4.zip && cd CherryPy-3.2.4 &&
|
||||
python setup.py install --user --prefix=''
|
||||
$SYS_PYTHON setup.py install --user --prefix=''
|
||||
)
|
||||
fi
|
||||
# check status
|
||||
|
|
|
@ -656,10 +656,6 @@ function check_option_conflicts() {
|
|||
echo "Don't support building NGINX, please use docker https://github.com/ossrs/srs-docker"; exit -1;
|
||||
fi
|
||||
|
||||
if [[ $SRS_FFMPEG_TOOL == YES ]]; then
|
||||
echo "Don't support building FFMPEG, please use docker https://github.com/ossrs/srs-docker"; exit -1;
|
||||
fi
|
||||
|
||||
# For OSX, recommend to use DTrace, https://blog.csdn.net/win_lin/article/details/53503869
|
||||
if [[ $SRS_OSX == YES && $SRS_GPROF == YES ]]; then
|
||||
echo "Tool gprof for OSX is unavailable, please use dtrace, read https://blog.csdn.net/win_lin/article/details/53503869"
|
||||
|
|
|
@ -370,6 +370,9 @@ stream_caster {
|
|||
# Whether bundle media stream port.
|
||||
# default: on
|
||||
invite_port_fixed on;
|
||||
# interval to query equipment list from equipment or subordinate domain, unit(s)
|
||||
# default: 60
|
||||
query_catalog_interval 60;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -90,16 +90,18 @@ stream_caster {
|
|||
# 认为设备离线
|
||||
keepalive_timeout 120;
|
||||
|
||||
|
||||
# 注册之后是否自动给设备端发送invite
|
||||
# on: 是 off 不是,需要通过api控制
|
||||
auto_play on;
|
||||
|
||||
# 设备将流发送的端口,是否固定
|
||||
# on 发送流到多路复用端口 如9000
|
||||
# off 自动从rtp_mix_port - rtp_max_port 之间的值中
|
||||
# 选一个可以用的端口
|
||||
invite_port_fixed on;
|
||||
|
||||
# 向设备或下级域查询设备列表的间隔,单位(秒)
|
||||
# 默认60秒
|
||||
query_catalog_interval 60;
|
||||
}
|
||||
}
|
||||
vhost __defaultVhost__ {
|
||||
|
|
2
trunk/research/msg_zerocopy/.gitignore
vendored
Normal file
2
trunk/research/msg_zerocopy/.gitignore
vendored
Normal file
|
@ -0,0 +1,2 @@
|
|||
server
|
||||
client
|
16
trunk/research/msg_zerocopy/Makefile
Normal file
16
trunk/research/msg_zerocopy/Makefile
Normal file
|
@ -0,0 +1,16 @@
|
|||
|
||||
.PHONY: default clean
|
||||
|
||||
default: server client
|
||||
|
||||
server: server.cpp ../../objs/st/libst.a
|
||||
g++ -g -O0 -I../../objs/st/ $^ -o $@
|
||||
|
||||
client: client.cpp ../../objs/st/libst.a
|
||||
g++ -g -O0 -I../../objs/st/ $^ -o $@
|
||||
|
||||
../../objs/st/libst.a: ../../Makefile
|
||||
(cd ../../ && $(MAKE) st)
|
||||
|
||||
clean:
|
||||
rm -f server client ../../objs/st/libst.a
|
315
trunk/research/msg_zerocopy/client.cpp
Normal file
315
trunk/research/msg_zerocopy/client.cpp
Normal file
|
@ -0,0 +1,315 @@
|
|||
#include <st.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <getopt.h>
|
||||
|
||||
#include <linux/version.h>
|
||||
|
||||
// @see https://www.kernel.org/doc/html/latest/networking/msg_zerocopy.html#notification-reception
|
||||
#include <sys/epoll.h>
|
||||
|
||||
// @see https://github.com/torvalds/linux/blob/master/tools/testing/selftests/net/msg_zerocopy.c
|
||||
#include <linux/errqueue.h>
|
||||
#ifndef SO_EE_ORIGIN_ZEROCOPY
|
||||
#define SO_EE_ORIGIN_ZEROCOPY 5
|
||||
#endif
|
||||
|
||||
#ifndef SO_ZEROCOPY
|
||||
#define SO_ZEROCOPY 60
|
||||
#endif
|
||||
|
||||
#ifndef SO_EE_CODE_ZEROCOPY_COPIED
|
||||
#define SO_EE_CODE_ZEROCOPY_COPIED 1
|
||||
#endif
|
||||
|
||||
#ifndef MSG_ZEROCOPY
|
||||
#define MSG_ZEROCOPY 0x4000000
|
||||
#endif
|
||||
|
||||
#include <netinet/udp.h>
|
||||
// Define macro for UDP GSO.
|
||||
// @see https://github.com/torvalds/linux/blob/master/tools/testing/selftests/net/udpgso.c
|
||||
#ifndef UDP_SEGMENT
|
||||
#define UDP_SEGMENT 103
|
||||
#endif
|
||||
|
||||
void* receiver(void* arg)
|
||||
{
|
||||
st_netfd_t stfd = (st_netfd_t)arg;
|
||||
|
||||
for (;;) {
|
||||
sockaddr_in peer;
|
||||
memset(&peer, 0, sizeof(sockaddr_in));
|
||||
|
||||
char buf[1500];
|
||||
memset(buf, 0, sizeof(buf));
|
||||
|
||||
iovec iov;
|
||||
iov.iov_base = buf;
|
||||
iov.iov_len = sizeof(buf);
|
||||
|
||||
msghdr msg;
|
||||
memset(&msg, 0, sizeof(msghdr));
|
||||
msg.msg_name = (sockaddr_in*)&peer;
|
||||
msg.msg_namelen = sizeof(sockaddr_in);
|
||||
msg.msg_iov = &iov;
|
||||
msg.msg_iovlen = 1;
|
||||
|
||||
int r0 = st_recvmsg(stfd, &msg, 0, ST_UTIME_NO_TIMEOUT);
|
||||
assert(r0 > 0);
|
||||
printf("Pong %s:%d %d bytes, flags %#x, %s\n", inet_ntoa(peer.sin_addr), ntohs(peer.sin_port), r0,
|
||||
msg.msg_flags, msg.msg_iov->iov_base);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void parse_reception(st_netfd_t stfd, int nn_confirm)
|
||||
{
|
||||
int left = nn_confirm;
|
||||
while (left > 0) {
|
||||
msghdr msg;
|
||||
memset(&msg, 0, sizeof(msghdr));
|
||||
|
||||
// Reception from kernel, @see https://www.kernel.org/doc/html/latest/networking/msg_zerocopy.html#notification-reception
|
||||
// See do_recv_completion at https://github.com/torvalds/linux/blob/master/tools/testing/selftests/net/msg_zerocopy.c#L393
|
||||
char control[100];
|
||||
msg.msg_control = control;
|
||||
msg.msg_controllen = sizeof(control);
|
||||
// Note that the r0 is 0, the reception is in the control.
|
||||
int r0 = st_recvmsg(stfd, &msg, MSG_ERRQUEUE, ST_UTIME_NO_TIMEOUT);
|
||||
assert(r0 >= 0);
|
||||
assert(msg.msg_flags == MSG_ERRQUEUE);
|
||||
|
||||
// Notification parsing, @see https://www.kernel.org/doc/html/latest/networking/msg_zerocopy.html#notification-parsing
|
||||
cmsghdr* cm = CMSG_FIRSTHDR(&msg);
|
||||
assert(cm->cmsg_level == SOL_IP || cm->cmsg_type == IP_RECVERR);
|
||||
|
||||
sock_extended_err* serr = (sock_extended_err*)(void*)CMSG_DATA(cm);
|
||||
assert(serr->ee_errno == 0 && serr->ee_origin == SO_EE_ORIGIN_ZEROCOPY);
|
||||
|
||||
uint32_t hi = serr->ee_data;
|
||||
uint32_t lo = serr->ee_info;
|
||||
uint32_t range = hi - lo + 1;
|
||||
left -= range;
|
||||
printf("Reception %d bytes, flags %#x, cmsg(level %#x, type %#x), serr(errno %#x, origin %#x, code %#x), range %d [%d, %d]\n",
|
||||
msg.msg_controllen, msg.msg_flags, cm->cmsg_level, cm->cmsg_type, serr->ee_errno, serr->ee_origin, serr->ee_code, range, lo, hi);
|
||||
|
||||
// Defered Copies, @see https://www.kernel.org/doc/html/latest/networking/msg_zerocopy.html#deferred-copies
|
||||
if (serr->ee_code == SO_EE_CODE_ZEROCOPY_COPIED) {
|
||||
printf("Warning: Defered copies, should stop zerocopy\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void usage(int argc, char** argv)
|
||||
{
|
||||
printf("Usage: %s <options>\n", argv[0]);
|
||||
printf("Options:\n");
|
||||
printf(" --help Print this help and exit.\n");
|
||||
printf(" --host=string The host to send to.\n");
|
||||
printf(" --port=int The port to send to.\n");
|
||||
printf(" --pong=bool Whether response pong, true|false\n");
|
||||
printf(" --zerocopy=bool Whether use zerocopy to sendmsg, true|false\n");
|
||||
printf(" --copy=int The copies of message, 1 means sendmmsg(msg+msg)\n");
|
||||
printf(" --loop=int The number of loop to send out messages\n");
|
||||
printf(" --batch=bool Whether read reception by batch, true|false\n");
|
||||
printf(" --mix=bool Whether mix msg with zerocopy and those without, true|false\n");
|
||||
printf(" --size=int Each message size in bytes.\n");
|
||||
printf(" --gso=int The GSO size in bytes, 0 to disable it.\n");
|
||||
printf(" --iovs=int The number of iovs to send, at least 1.\n");
|
||||
printf(" --sndbuf=int The SO_SNDBUF size in bytes, 0 to ignore.\n");
|
||||
printf("For example:\n");
|
||||
printf(" %s --host=127.0.0.1 --port=8000 --pong=true --zerocopy=true --copy=0 --loop=1 --batch=true --mix=true --size=1400 --gso=0 --iovs=1 --sndbuf=0\n", argv[0]);
|
||||
}
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
option longopts[] = {
|
||||
{ "host", required_argument, NULL, 'o' },
|
||||
{ "port", required_argument, NULL, 'p' },
|
||||
{ "pong", required_argument, NULL, 'n' },
|
||||
{ "zerocopy", required_argument, NULL, 'z' },
|
||||
{ "copy", required_argument, NULL, 'c' },
|
||||
{ "loop", required_argument, NULL, 'l' },
|
||||
{ "batch", required_argument, NULL, 'b' },
|
||||
{ "mix", required_argument, NULL, 'm' },
|
||||
{ "size", required_argument, NULL, 's' },
|
||||
{ "gso", required_argument, NULL, 'g' },
|
||||
{ "iovs", required_argument, NULL, 'i' },
|
||||
{ "sndbuf", required_argument, NULL, 'u' },
|
||||
{ "help", no_argument, NULL, 'h' },
|
||||
{ NULL, 0, NULL, 0 }
|
||||
};
|
||||
|
||||
char* host = NULL; char ch;
|
||||
int port = 0; int nn_copies = 0; int loop = 1; int size = 1500; int gso = 0; int nn_iovs = 0; int sndbuf = 0;
|
||||
bool pong = false; bool zerocopy = false; bool batch = false; bool mix = false;
|
||||
while ((ch = getopt_long(argc, argv, "o:p:n:z:c:l:b:m:s:g:u:h", longopts, NULL)) != -1) {
|
||||
switch (ch) {
|
||||
case 'o': host = (char*)optarg; break;
|
||||
case 'p': port = atoi(optarg); break;
|
||||
case 'n': pong = !strcmp(optarg,"true"); break;
|
||||
case 'z': zerocopy = !strcmp(optarg,"true"); break;
|
||||
case 'c': nn_copies = atoi(optarg); break;
|
||||
case 'l': loop = atoi(optarg); break;
|
||||
case 'b': batch = !strcmp(optarg,"true"); break;
|
||||
case 'm': mix = !strcmp(optarg,"true"); break;
|
||||
case 's': size = atoi(optarg); break;
|
||||
case 'g': gso = atoi(optarg); break;
|
||||
case 'i': nn_iovs = atoi(optarg); break;
|
||||
case 'u': sndbuf = atoi(optarg); break;
|
||||
case 'h': usage(argc, argv); exit(0);
|
||||
default: usage(argc, argv); exit(-1);
|
||||
}
|
||||
}
|
||||
|
||||
printf("Server listen %s:%d, pong %d, zerocopy %d, copies %d, loop %d, batch %d, mix %d, size %d, gso %d, iovs %d, sndbuf %d\n",
|
||||
host, port, pong, zerocopy, nn_copies, loop, batch, mix, size, gso, nn_iovs, sndbuf);
|
||||
if (!host || !port || !nn_iovs) {
|
||||
usage(argc, argv);
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
assert(!st_set_eventsys(ST_EVENTSYS_ALT));
|
||||
assert(!st_init());
|
||||
|
||||
int fd = socket(PF_INET, SOCK_DGRAM, 0);
|
||||
assert(fd > 0);
|
||||
|
||||
// @see https://github.com/torvalds/linux/blob/master/tools/testing/selftests/net/msg_zerocopy.c
|
||||
if (zerocopy) {
|
||||
int one = 1;
|
||||
int r0 = setsockopt(fd, SOL_SOCKET, SO_ZEROCOPY, &one, sizeof(one));
|
||||
// MSG_ZEROCOPY for UDP was added in commit b5947e5d1e71 ("udp: msg_zerocopy") in Linux 5.0.
|
||||
// @see https://lore.kernel.org/netdev/CA+FuTSfBFqRViKfG5crEv8xLMgAkp3cZ+yeuELK5TVv61xT=Yw@mail.gmail.com/
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(5,0,0)
|
||||
if (r0 == -1) {
|
||||
printf("MSG_ZEROCOPY should be kernel 5.0+, kernel %#x, errno=%d\n", LINUX_VERSION_CODE, 524);
|
||||
exit(-1);
|
||||
}
|
||||
#endif
|
||||
assert(!r0);
|
||||
|
||||
printf("epoll events EPOLLERR=%#x, EPOLLHUP=%#x\n", EPOLLERR, EPOLLHUP);
|
||||
}
|
||||
|
||||
if (true) {
|
||||
int dv = 0;
|
||||
socklen_t len = sizeof(dv);
|
||||
int r0 = getsockopt(fd, SOL_SOCKET, SO_SNDBUF, &dv, &len);
|
||||
|
||||
int r1 = 0;
|
||||
if (sndbuf > 0) {
|
||||
r1 = setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &sndbuf, sizeof(sndbuf));
|
||||
}
|
||||
|
||||
int nv = 0;
|
||||
int r2 = getsockopt(fd, SOL_SOCKET, SO_SNDBUF, &nv, &len);
|
||||
printf("socket SO_SNDBUF default=%d, user=%d, now=%d, r0=%d, r1=%d, r2=%d\n", dv, sndbuf, nv, r0, r1, r2);
|
||||
}
|
||||
|
||||
st_netfd_t stfd = st_netfd_open_socket(fd);
|
||||
assert(stfd);
|
||||
printf("Client fd=%d\n", fd);
|
||||
|
||||
if (pong) {
|
||||
st_thread_t r0 = st_thread_create(receiver, stfd, 0, 0);
|
||||
assert(r0);
|
||||
}
|
||||
|
||||
sockaddr_in peer;
|
||||
memset(&peer, 0, sizeof(sockaddr_in));
|
||||
|
||||
peer.sin_family = AF_INET;
|
||||
peer.sin_port = htons(port);
|
||||
peer.sin_addr.s_addr = inet_addr(host);
|
||||
|
||||
char* buf = new char[size];
|
||||
memset(buf, 0, size);
|
||||
memcpy(buf, "Hello", size < 5? size : 5);
|
||||
|
||||
iovec iov;
|
||||
iov.iov_base = buf;
|
||||
iov.iov_len = size;
|
||||
|
||||
int nn_confirm = 0;
|
||||
for (int k = 0; k < loop; k++) {
|
||||
msghdr msg;
|
||||
memset(&msg, 0, sizeof(msghdr));
|
||||
msg.msg_name = (sockaddr_in*)&peer;
|
||||
msg.msg_namelen = sizeof(sockaddr_in);
|
||||
msg.msg_iov = new iovec[nn_iovs];
|
||||
msg.msg_iovlen = nn_iovs;
|
||||
|
||||
for (int i = 0; i < nn_iovs; i++) {
|
||||
iovec* p = msg.msg_iov + i;
|
||||
memcpy(p, &iov, sizeof(iovec));
|
||||
}
|
||||
|
||||
if (gso > 0) {
|
||||
msg.msg_controllen = CMSG_SPACE(sizeof(uint16_t));
|
||||
if (!msg.msg_control) {
|
||||
msg.msg_control = new char[msg.msg_controllen];
|
||||
}
|
||||
|
||||
cmsghdr* cm = CMSG_FIRSTHDR(&msg);
|
||||
cm->cmsg_level = SOL_UDP;
|
||||
cm->cmsg_type = UDP_SEGMENT;
|
||||
cm->cmsg_len = CMSG_LEN(sizeof(uint16_t));
|
||||
*((uint16_t*)CMSG_DATA(cm)) = gso;
|
||||
}
|
||||
|
||||
int r0;
|
||||
if (nn_copies == 0) {
|
||||
if (zerocopy) {
|
||||
r0 = st_sendmsg(stfd, &msg, MSG_ZEROCOPY, ST_UTIME_NO_TIMEOUT);
|
||||
} else {
|
||||
r0 = st_sendmsg(stfd, &msg, 0, ST_UTIME_NO_TIMEOUT);
|
||||
}
|
||||
} else {
|
||||
mmsghdr* hdrs = new mmsghdr[nn_copies + 1];
|
||||
for (int i = 0; i < nn_copies + 1; i++) {
|
||||
mmsghdr* p = hdrs + i;
|
||||
memcpy(&p->msg_hdr, &msg, sizeof(msghdr));
|
||||
p->msg_len = 0;
|
||||
}
|
||||
if (zerocopy) {
|
||||
r0 = st_sendmmsg(stfd, hdrs, nn_copies + 1, MSG_ZEROCOPY, ST_UTIME_NO_TIMEOUT);
|
||||
} else {
|
||||
r0 = st_sendmmsg(stfd, hdrs, nn_copies + 1, 0, ST_UTIME_NO_TIMEOUT);
|
||||
}
|
||||
}
|
||||
if (r0 > 0) {
|
||||
printf("Ping %s:%d %d bytes, control %d, copies=%d, r0=%d, %s\n", host, port, iov.iov_len * nn_iovs,
|
||||
msg.msg_controllen, nn_copies, r0, msg.msg_iov->iov_base);
|
||||
} else {
|
||||
printf("Ping %d bytes, error r0=%d, errno=%d\n", iov.iov_len * nn_iovs, r0, errno); exit(1);
|
||||
}
|
||||
|
||||
if (zerocopy && !batch) {
|
||||
parse_reception(stfd, r0);
|
||||
} else {
|
||||
nn_confirm += r0;
|
||||
}
|
||||
|
||||
if (mix) {
|
||||
r0 = st_sendmsg(stfd, &msg, 0, ST_UTIME_NO_TIMEOUT);
|
||||
assert(r0 > 0);
|
||||
printf("Mix %s:%d %d bytes, r0=%d, %s\n", host, port, iov.iov_len * nn_iovs, r0, msg.msg_iov->iov_base);
|
||||
}
|
||||
}
|
||||
|
||||
// @see https://www.kernel.org/doc/html/latest/networking/msg_zerocopy.html#notification-batching
|
||||
if (batch) {
|
||||
parse_reception(stfd, nn_confirm);
|
||||
}
|
||||
|
||||
st_sleep(-1);
|
||||
return 0;
|
||||
}
|
155
trunk/research/msg_zerocopy/server.cpp
Normal file
155
trunk/research/msg_zerocopy/server.cpp
Normal file
|
@ -0,0 +1,155 @@
|
|||
#include <st.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <getopt.h>
|
||||
|
||||
struct message {
|
||||
st_netfd_t stfd;
|
||||
sockaddr_in peer;
|
||||
int delay;
|
||||
};
|
||||
|
||||
void* sender(void* arg)
|
||||
{
|
||||
message* p = (message*)arg;
|
||||
|
||||
int delay = p->delay;
|
||||
if (delay > 0) {
|
||||
st_usleep(delay * 1000);
|
||||
}
|
||||
|
||||
msghdr msg;
|
||||
memset(&msg, 0, sizeof(msghdr));
|
||||
|
||||
sockaddr_in peer = p->peer;
|
||||
msg.msg_name = (sockaddr_in*)&peer;
|
||||
msg.msg_namelen = sizeof(sockaddr_in);
|
||||
|
||||
char buf[] = "World";
|
||||
|
||||
iovec iov;
|
||||
memset(&iov, 0, sizeof(iovec));
|
||||
iov.iov_base = buf;
|
||||
iov.iov_len = sizeof(buf);
|
||||
msg.msg_iov = &iov;
|
||||
msg.msg_iovlen = 1;
|
||||
|
||||
st_netfd_t stfd = p->stfd;
|
||||
int r0 = st_sendmsg(stfd, &msg, 0, ST_UTIME_NO_TIMEOUT);
|
||||
assert(r0 > 0);
|
||||
printf("Pong %s:%d %d bytes, flags %#x, %s\n", inet_ntoa(peer.sin_addr), ntohs(peer.sin_port), r0,
|
||||
msg.msg_flags, msg.msg_iov->iov_base);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void usage(int argc, char** argv)
|
||||
{
|
||||
printf("Usage: %s <options>\n", argv[0]);
|
||||
printf("Options:\n");
|
||||
printf(" --help Print this help and exit.\n");
|
||||
printf(" --host=string The host to send to.\n");
|
||||
printf(" --port=int The port to send to.\n");
|
||||
printf(" --pong=bool Whether response pong, true|false\n");
|
||||
printf(" --delay=int The delay in ms to response pong.\n");
|
||||
printf("For example:\n");
|
||||
printf(" %s --host=0.0.0.0 --port=8000 --pong --delay=100\n", argv[0]);
|
||||
}
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
option longopts[] = {
|
||||
{ "host", required_argument, NULL, 'o' },
|
||||
{ "port", required_argument, NULL, 'p' },
|
||||
{ "pong", required_argument, NULL, 'n' },
|
||||
{ "delay", required_argument, NULL, 'd' },
|
||||
{ "help", no_argument, NULL, 'h' },
|
||||
{ NULL, 0, NULL, 0 }
|
||||
};
|
||||
|
||||
char* host = NULL; char ch;
|
||||
int port = 0; int delay = 0; bool pong = false;
|
||||
while ((ch = getopt_long(argc, argv, "o:p:n:d:h", longopts, NULL)) != -1) {
|
||||
switch (ch) {
|
||||
case 'o': host = (char*)optarg; break;
|
||||
case 'p': port = atoi(optarg); break;
|
||||
case 'n': pong = !strcmp(optarg,"true"); break;
|
||||
case 'd': delay = atoi(optarg); break;
|
||||
case 'h': usage(argc, argv); exit(0);
|
||||
default: usage(argc, argv); exit(-1);
|
||||
}
|
||||
}
|
||||
|
||||
printf("Server listen %s:%d, pong %d, delay: %dms\n", host, port, pong, delay);
|
||||
if (!host || !port) {
|
||||
usage(argc, argv);
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
assert(!st_set_eventsys(ST_EVENTSYS_ALT));
|
||||
assert(!st_init());
|
||||
|
||||
int fd = socket(PF_INET, SOCK_DGRAM, 0);
|
||||
assert(fd > 0);
|
||||
|
||||
int n = 1;
|
||||
int r0 = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *)&n, sizeof(n));
|
||||
assert(!r0);
|
||||
|
||||
sockaddr_in addr;
|
||||
memset(&addr, 0, sizeof(sockaddr_in));
|
||||
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_port = htons(port);
|
||||
addr.sin_addr.s_addr = inet_addr(host);
|
||||
|
||||
r0 = bind(fd, (sockaddr *)&addr, sizeof(sockaddr_in));
|
||||
assert(!r0);
|
||||
|
||||
st_netfd_t stfd = st_netfd_open_socket(fd);
|
||||
assert(stfd);
|
||||
|
||||
printf("Listen at udp://%s:%d, fd=%d\n", host, port, fd);
|
||||
|
||||
msghdr msg;
|
||||
memset(&msg, 0, sizeof(msghdr));
|
||||
|
||||
sockaddr_in peer;
|
||||
memset(&peer, 0, sizeof(sockaddr_in));
|
||||
msg.msg_name = (sockaddr_in*)&peer;
|
||||
msg.msg_namelen = sizeof(sockaddr_in);
|
||||
|
||||
char buf[1500];
|
||||
memset(buf, 0, sizeof(buf));
|
||||
|
||||
iovec iov;
|
||||
memset(&iov, 0, sizeof(iovec));
|
||||
iov.iov_base = buf;
|
||||
iov.iov_len = sizeof(buf);
|
||||
msg.msg_iov = &iov;
|
||||
msg.msg_iovlen = 1;
|
||||
|
||||
int nn_msgs = 0;
|
||||
while (true) {
|
||||
r0 = st_recvmsg(stfd, &msg, 0, ST_UTIME_NO_TIMEOUT);
|
||||
assert(r0 > 0);
|
||||
printf("#%d, From %s:%d %d bytes, flags %#x, %s\n", nn_msgs++, inet_ntoa(peer.sin_addr), ntohs(peer.sin_port),
|
||||
r0, msg.msg_flags, msg.msg_iov->iov_base);
|
||||
|
||||
if (pong) {
|
||||
message* msg = new message();
|
||||
msg->stfd = stfd;
|
||||
msg->peer = peer;
|
||||
msg->delay = delay;
|
||||
st_thread_t r0 = st_thread_create(sender, msg, 0, 0);
|
||||
assert(r0);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -24,12 +24,14 @@
|
|||
<ul class="nav">
|
||||
<li><a id="nav_srs_player" href="srs_player.html">SRS播放器</a></li>
|
||||
<li class="active"><a id="nav_rtc_player" href="rtc_player.html">RTC播放器</a></li>
|
||||
<li><a id="nav_srs_publisher" href="srs_publisher.html">SRS编码器</a></li>
|
||||
<li><a id="nav_srs_chat" href="srs_chat.html">SRS会议</a></li>
|
||||
<li><a id="nav_srs_bwt" href="srs_bwt.html">SRS测网速</a></li>
|
||||
<!--<li><a id="nav_srs_publisher" href="srs_publisher.html">SRS编码器</a></li>-->
|
||||
<!--<li><a id="nav_srs_chat" href="srs_chat.html">SRS会议</a></li>-->
|
||||
<!--<li><a id="nav_srs_bwt" href="srs_bwt.html">SRS测网速</a></li>-->
|
||||
<!--<li><a id="nav_jwplayer6" href="jwplayer6.html">JWPlayer6播放器</a></li>-->
|
||||
<!--<li><a id="nav_osmf" href="osmf.html">AdobeOSMF播放器</a></li>-->
|
||||
<li><a id="nav_vlc" href="vlc.html">VLC播放器</a></li>
|
||||
<!--<li><a id="nav_vlc" href="vlc.html">VLC播放器</a></li>-->
|
||||
<li><a id="nav_gb28181" href="srs_gb28181.html">GB28181</a></li>
|
||||
<li><a href="https://github.com/ossrs/srs">源码</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
<!--<li><a id="nav_jwplayer6" href="jwplayer6.html">JWPlayer6播放器</a></li>-->
|
||||
<!--<li><a id="nav_osmf" href="osmf.html">AdobeOSMF播放器</a></li>-->
|
||||
<li><a id="nav_vlc" href="vlc.html">VLC播放器</a></li>
|
||||
<li><a id="nav_gb28181" href="srs_gb28181.html">SRS-GB28181</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
<!--<li><a id="nav_jwplayer6" href="jwplayer6.html">JWPlayer6播放器</a></li>-->
|
||||
<!--<li><a id="nav_osmf" href="osmf.html">AdobeOSMF播放器</a></li>-->
|
||||
<li><a id="nav_vlc" href="vlc.html">VLC播放器</a></li>
|
||||
<li><a id="nav_gb28181" href="srs_gb28181.html">SRS-GB28181</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
|
1244
trunk/research/players/srs_gb28181.html
Normal file
1244
trunk/research/players/srs_gb28181.html
Normal file
File diff suppressed because it is too large
Load diff
|
@ -34,12 +34,14 @@
|
|||
<ul class="nav">
|
||||
<li class="active"><a id="nav_srs_player" href="srs_player.html">SRS播放器</a></li>
|
||||
<li><a id="nav_rtc_player" href="rtc_player.html">RTC播放器</a></li>
|
||||
<li><a id="nav_srs_publisher" href="srs_publisher.html">SRS编码器</a></li>
|
||||
<li><a id="nav_srs_chat" href="srs_chat.html">SRS会议</a></li>
|
||||
<li><a id="nav_srs_bwt" href="srs_bwt.html">SRS测网速</a></li>
|
||||
<!--<li><a id="nav_srs_publisher" href="srs_publisher.html">SRS编码器</a></li>-->
|
||||
<!--<li><a id="nav_srs_chat" href="srs_chat.html">SRS会议</a></li>-->
|
||||
<!--<li><a id="nav_srs_bwt" href="srs_bwt.html">SRS测网速</a></li>-->
|
||||
<!--<li><a id="nav_jwplayer6" href="jwplayer6.html">JWPlayer6播放器</a></li>-->
|
||||
<!--<li><a id="nav_osmf" href="osmf.html">AdobeOSMF播放器</a></li>-->
|
||||
<li><a id="nav_vlc" href="vlc.html">VLC播放器</a></li>
|
||||
<!--li><a id="nav_vlc" href="vlc.html">VLC播放器</a></li>-->
|
||||
<li><a id="nav_gb28181" href="srs_gb28181.html">GB28181</a></li>
|
||||
<li><a href="https://github.com/ossrs/srs">源码</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
<!--<li><a id="nav_jwplayer6" href="jwplayer6.html">JWPlayer6播放器</a></li>-->
|
||||
<!--<li><a id="nav_osmf" href="osmf.html">AdobeOSMF播放器</a></li>-->
|
||||
<li><a id="nav_vlc" href="vlc.html">VLC播放器</a></li>
|
||||
<li><a id="nav_gb28181" href="srs_gb28181.html">SRS-GB28181</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
<!--<li><a id="nav_jwplayer6" href="jwplayer6.html">JWPlayer6播放器</a></li>-->
|
||||
<!--<li><a id="nav_osmf" href="osmf.html">AdobeOSMF播放器</a></li>-->
|
||||
<li><a id="nav_vlc" href="vlc.html">VLC播放器</a></li>
|
||||
<li><a id="nav_gb28181" href="srs_gb28181.html">SRS-GB28181</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
<!--<li><a id="nav_jwplayer6" href="jwplayer6.html">JWPlayer6播放器</a></li>-->
|
||||
<!--<li><a id="nav_osmf" href="osmf.html">AdobeOSMF播放器</a></li>-->
|
||||
<li class="active"><a id="nav_vlc" href="vlc.html">VLC播放器</a></li>
|
||||
<li><a id="nav_gb28181" href="srs_gb28181.html">SRS-GB28181</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -1,100 +0,0 @@
|
|||
# The contents of this file are subject to the Mozilla Public
|
||||
# License Version 1.1 (the "License"); you may not use this file
|
||||
# except in compliance with the License. You may obtain a copy of
|
||||
# the License at http://www.mozilla.org/MPL/
|
||||
#
|
||||
# Software distributed under the License is distributed on an "AS
|
||||
# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
||||
# implied. See the License for the specific language governing
|
||||
# rights and limitations under the License.
|
||||
#
|
||||
# The Original Code is the Netscape Portable Runtime library.
|
||||
#
|
||||
# The Initial Developer of the Original Code is Netscape
|
||||
# Communications Corporation. Portions created by Netscape are
|
||||
# Copyright (C) 1994-2000 Netscape Communications Corporation. All
|
||||
# Rights Reserved.
|
||||
#
|
||||
# Contributor(s): Silicon Graphics, Inc.
|
||||
#
|
||||
# Portions created by SGI are Copyright (C) 2000-2001 Silicon
|
||||
# Graphics, Inc. All Rights Reserved.
|
||||
#
|
||||
# Alternatively, the contents of this file may be used under the
|
||||
# terms of the GNU General Public License Version 2 or later (the
|
||||
# "GPL"), in which case the provisions of the GPL are applicable
|
||||
# instead of those above. If you wish to allow use of your
|
||||
# version of this file only under the terms of the GPL and not to
|
||||
# allow others to use your version of this file under the MPL,
|
||||
# indicate your decision by deleting the provisions above and
|
||||
# replace them with the notice and other provisions required by
|
||||
# the GPL. If you do not delete the provisions above, a recipient
|
||||
# may use your version of this file under either the MPL or the
|
||||
# GPL.
|
||||
|
||||
##########################
|
||||
# Target dir and cc:
|
||||
CC = cc
|
||||
TARGETDIR = objs
|
||||
|
||||
##########################
|
||||
# Supported OSes:
|
||||
OS = LINUX
|
||||
|
||||
ifneq ($(shell test -f /usr/include/sys/epoll.h && echo yes), yes)
|
||||
default:
|
||||
@echo "epoll not found"
|
||||
@exit 1
|
||||
endif
|
||||
|
||||
EXTRA_OBJS = $(TARGETDIR)/md.o
|
||||
|
||||
CFLAGS =
|
||||
OTHER_FLAGS += -Wall -g -O0
|
||||
DEFINES = -D$(OS) -DDEBUG -DMD_HAVE_EPOLL -DMALLOC_STACK
|
||||
|
||||
##########################
|
||||
# Other possible defines:
|
||||
# To use malloc(3) instead of mmap(2) for stack allocation:
|
||||
# DEFINES += -DMALLOC_STACK
|
||||
#
|
||||
# To provision more than the default 16 thread-specific-data keys
|
||||
# (but not too many!):
|
||||
# DEFINES += -DST_KEYS_MAX=<n>
|
||||
#
|
||||
# Note that you can also add these defines by specifying them as
|
||||
# make/gmake arguments (without editing this Makefile). For example:
|
||||
#
|
||||
# make EXTRA_CFLAGS=-UMD_HAVE_EPOLL <target>
|
||||
#
|
||||
##########################
|
||||
|
||||
CFLAGS += $(DEFINES) $(OTHER_FLAGS) $(EXTRA_CFLAGS)
|
||||
|
||||
OBJS = $(TARGETDIR)/sched.o \
|
||||
$(TARGETDIR)/stk.o \
|
||||
$(TARGETDIR)/sync.o \
|
||||
$(TARGETDIR)/key.o \
|
||||
$(TARGETDIR)/io.o \
|
||||
$(TARGETDIR)/event.o \
|
||||
$(TARGETDIR)/srs.o
|
||||
OBJS += $(EXTRA_OBJS)
|
||||
SRS = $(TARGETDIR)/srs
|
||||
|
||||
linux-debug: all
|
||||
all: $(TARGETDIR) $(SRS)
|
||||
|
||||
$(TARGETDIR):
|
||||
if [ ! -d $(TARGETDIR) ]; then mkdir $(TARGETDIR); fi
|
||||
|
||||
$(SRS): $(OBJS)
|
||||
$(CC) $(CFLAGS) -o $@ $(OBJS)
|
||||
|
||||
$(TARGETDIR)/md.o: md.S
|
||||
$(CC) $(CFLAGS) -c $< -o $@
|
||||
|
||||
$(TARGETDIR)/%.o: %.c common.h md.h Makefile
|
||||
$(CC) $(CFLAGS) -c $< -o $@
|
||||
|
||||
clean:
|
||||
rm -rf $(TARGETDIR)
|
|
@ -1,445 +0,0 @@
|
|||
/*
|
||||
* The contents of this file are subject to the Mozilla Public
|
||||
* License Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a copy of
|
||||
* the License at http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS
|
||||
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
||||
* implied. See the License for the specific language governing
|
||||
* rights and limitations under the License.
|
||||
*
|
||||
* The Original Code is the Netscape Portable Runtime library.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1994-2000 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s): Silicon Graphics, Inc.
|
||||
*
|
||||
* Portions created by SGI are Copyright (C) 2000-2001 Silicon
|
||||
* Graphics, Inc. All Rights Reserved.
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the
|
||||
* terms of the GNU General Public License Version 2 or later (the
|
||||
* "GPL"), in which case the provisions of the GPL are applicable
|
||||
* instead of those above. If you wish to allow use of your
|
||||
* version of this file only under the terms of the GPL and not to
|
||||
* allow others to use your version of this file under the MPL,
|
||||
* indicate your decision by deleting the provisions above and
|
||||
* replace them with the notice and other provisions required by
|
||||
* the GPL. If you do not delete the provisions above, a recipient
|
||||
* may use your version of this file under either the MPL or the
|
||||
* GPL.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file is derived directly from Netscape Communications Corporation,
|
||||
* and consists of extensive modifications made during the year(s) 1999-2000.
|
||||
*/
|
||||
|
||||
#ifndef __ST_COMMON_H__
|
||||
#define __ST_COMMON_H__
|
||||
|
||||
#include <stddef.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/time.h>
|
||||
#include <setjmp.h>
|
||||
|
||||
/* Enable assertions only if DEBUG is defined */
|
||||
#ifndef DEBUG
|
||||
#define NDEBUG
|
||||
#endif
|
||||
#include <assert.h>
|
||||
#define ST_ASSERT(expr) assert(expr)
|
||||
|
||||
#define ST_BEGIN_MACRO {
|
||||
#define ST_END_MACRO }
|
||||
|
||||
#ifdef DEBUG
|
||||
#define ST_HIDDEN /*nothing*/
|
||||
#else
|
||||
#define ST_HIDDEN static
|
||||
#endif
|
||||
|
||||
#include "public.h"
|
||||
#include "md.h"
|
||||
|
||||
/*****************************************
|
||||
* Circular linked list definitions
|
||||
*/
|
||||
|
||||
typedef struct _st_clist {
|
||||
struct _st_clist *next;
|
||||
struct _st_clist *prev;
|
||||
} _st_clist_t;
|
||||
|
||||
/* Insert element "_e" into the list, before "_l" */
|
||||
#define ST_INSERT_BEFORE(_e,_l) \
|
||||
ST_BEGIN_MACRO \
|
||||
(_e)->next = (_l); \
|
||||
(_e)->prev = (_l)->prev; \
|
||||
(_l)->prev->next = (_e); \
|
||||
(_l)->prev = (_e); \
|
||||
ST_END_MACRO
|
||||
|
||||
/* Insert element "_e" into the list, after "_l" */
|
||||
#define ST_INSERT_AFTER(_e,_l) \
|
||||
ST_BEGIN_MACRO \
|
||||
(_e)->next = (_l)->next; \
|
||||
(_e)->prev = (_l); \
|
||||
(_l)->next->prev = (_e); \
|
||||
(_l)->next = (_e); \
|
||||
ST_END_MACRO
|
||||
|
||||
/* Return the element following element "_e" */
|
||||
#define ST_NEXT_LINK(_e) ((_e)->next)
|
||||
|
||||
/* Append an element "_e" to the end of the list "_l" */
|
||||
#define ST_APPEND_LINK(_e,_l) ST_INSERT_BEFORE(_e,_l)
|
||||
|
||||
/* Insert an element "_e" at the head of the list "_l" */
|
||||
#define ST_INSERT_LINK(_e,_l) ST_INSERT_AFTER(_e,_l)
|
||||
|
||||
/* Return the head/tail of the list */
|
||||
#define ST_LIST_HEAD(_l) (_l)->next
|
||||
#define ST_LIST_TAIL(_l) (_l)->prev
|
||||
|
||||
/* Remove the element "_e" from it's circular list */
|
||||
#define ST_REMOVE_LINK(_e) \
|
||||
ST_BEGIN_MACRO \
|
||||
(_e)->prev->next = (_e)->next; \
|
||||
(_e)->next->prev = (_e)->prev; \
|
||||
ST_END_MACRO
|
||||
|
||||
/* Return non-zero if the given circular list "_l" is empty, */
|
||||
/* zero if the circular list is not empty */
|
||||
#define ST_CLIST_IS_EMPTY(_l) \
|
||||
((_l)->next == (_l))
|
||||
|
||||
/* Initialize a circular list */
|
||||
#define ST_INIT_CLIST(_l) \
|
||||
ST_BEGIN_MACRO \
|
||||
(_l)->next = (_l); \
|
||||
(_l)->prev = (_l); \
|
||||
ST_END_MACRO
|
||||
|
||||
#define ST_INIT_STATIC_CLIST(_l) \
|
||||
{(_l), (_l)}
|
||||
|
||||
|
||||
/*****************************************
|
||||
* Basic types definitions
|
||||
*/
|
||||
|
||||
typedef void (*_st_destructor_t)(void *);
|
||||
|
||||
typedef struct _st_stack {
|
||||
_st_clist_t links;
|
||||
char *vaddr; /* Base of stack's allocated memory */
|
||||
int vaddr_size; /* Size of stack's allocated memory */
|
||||
int stk_size; /* Size of usable portion of the stack */
|
||||
char *stk_bottom; /* Lowest address of stack's usable portion */
|
||||
char *stk_top; /* Highest address of stack's usable portion */
|
||||
void *sp; /* Stack pointer from C's point of view */
|
||||
} _st_stack_t;
|
||||
|
||||
|
||||
typedef struct _st_cond {
|
||||
_st_clist_t wait_q; /* Condition variable wait queue */
|
||||
} _st_cond_t;
|
||||
|
||||
|
||||
typedef struct _st_thread _st_thread_t;
|
||||
|
||||
struct _st_thread {
|
||||
int state; /* Thread's state */
|
||||
int flags; /* Thread's flags */
|
||||
|
||||
void *(*start)(void *arg); /* The start function of the thread */
|
||||
void *arg; /* Argument of the start function */
|
||||
void *retval; /* Return value of the start function */
|
||||
|
||||
_st_stack_t *stack; /* Info about thread's stack */
|
||||
|
||||
_st_clist_t links; /* For putting on run/sleep/zombie queue */
|
||||
_st_clist_t wait_links; /* For putting on mutex/condvar wait queue */
|
||||
#ifdef DEBUG
|
||||
_st_clist_t tlink; /* For putting on thread queue */
|
||||
#endif
|
||||
|
||||
st_utime_t due; /* Wakeup time when thread is sleeping */
|
||||
_st_thread_t *left; /* For putting in timeout heap */
|
||||
_st_thread_t *right; /* -- see docs/timeout_heap.txt for details */
|
||||
int heap_index;
|
||||
|
||||
void **private_data; /* Per thread private data */
|
||||
|
||||
_st_cond_t *term; /* Termination condition variable for join */
|
||||
|
||||
jmp_buf context; /* Thread's context */
|
||||
};
|
||||
|
||||
|
||||
typedef struct _st_mutex {
|
||||
_st_thread_t *owner; /* Current mutex owner */
|
||||
_st_clist_t wait_q; /* Mutex wait queue */
|
||||
} _st_mutex_t;
|
||||
|
||||
|
||||
typedef struct _st_pollq {
|
||||
_st_clist_t links; /* For putting on io queue */
|
||||
_st_thread_t *thread; /* Polling thread */
|
||||
struct pollfd *pds; /* Array of poll descriptors */
|
||||
int npds; /* Length of the array */
|
||||
int on_ioq; /* Is it on ioq? */
|
||||
} _st_pollq_t;
|
||||
|
||||
|
||||
typedef struct _st_eventsys_ops {
|
||||
const char *name; /* Name of this event system */
|
||||
int val; /* Type of this event system */
|
||||
int (*init)(void); /* Initialization */
|
||||
void (*dispatch)(void); /* Dispatch function */
|
||||
int (*pollset_add)(struct pollfd *, int); /* Add descriptor set */
|
||||
void (*pollset_del)(struct pollfd *, int); /* Delete descriptor set */
|
||||
int (*fd_new)(int); /* New descriptor allocated */
|
||||
int (*fd_close)(int); /* Descriptor closed */
|
||||
int (*fd_getlimit)(void); /* Descriptor hard limit */
|
||||
} _st_eventsys_t;
|
||||
|
||||
|
||||
typedef struct _st_vp {
|
||||
_st_thread_t *idle_thread; /* Idle thread for this vp */
|
||||
st_utime_t last_clock; /* The last time we went into vp_check_clock() */
|
||||
|
||||
_st_clist_t run_q; /* run queue for this vp */
|
||||
_st_clist_t io_q; /* io queue for this vp */
|
||||
_st_clist_t zombie_q; /* zombie queue for this vp */
|
||||
#ifdef DEBUG
|
||||
_st_clist_t thread_q; /* all threads of this vp */
|
||||
#endif
|
||||
int pagesize;
|
||||
|
||||
_st_thread_t *sleep_q; /* sleep queue for this vp */
|
||||
int sleepq_size; /* number of threads on sleep queue */
|
||||
|
||||
#ifdef ST_SWITCH_CB
|
||||
st_switch_cb_t switch_out_cb; /* called when a thread is switched out */
|
||||
st_switch_cb_t switch_in_cb; /* called when a thread is switched in */
|
||||
#endif
|
||||
} _st_vp_t;
|
||||
|
||||
|
||||
typedef struct _st_netfd {
|
||||
int osfd; /* Underlying OS file descriptor */
|
||||
int inuse; /* In-use flag */
|
||||
void *private_data; /* Per descriptor private data */
|
||||
_st_destructor_t destructor; /* Private data destructor function */
|
||||
void *aux_data; /* Auxiliary data for internal use */
|
||||
struct _st_netfd *next; /* For putting on the free list */
|
||||
} _st_netfd_t;
|
||||
|
||||
|
||||
/*****************************************
|
||||
* Current vp, thread, and event system
|
||||
*/
|
||||
|
||||
extern _st_vp_t _st_this_vp;
|
||||
extern _st_thread_t *_st_this_thread;
|
||||
extern _st_eventsys_t *_st_eventsys;
|
||||
|
||||
#define _ST_CURRENT_THREAD() (_st_this_thread)
|
||||
#define _ST_SET_CURRENT_THREAD(_thread) (_st_this_thread = (_thread))
|
||||
|
||||
#define _ST_LAST_CLOCK (_st_this_vp.last_clock)
|
||||
|
||||
#define _ST_RUNQ (_st_this_vp.run_q)
|
||||
#define _ST_IOQ (_st_this_vp.io_q)
|
||||
#define _ST_ZOMBIEQ (_st_this_vp.zombie_q)
|
||||
#ifdef DEBUG
|
||||
#define _ST_THREADQ (_st_this_vp.thread_q)
|
||||
#endif
|
||||
|
||||
#define _ST_PAGE_SIZE (_st_this_vp.pagesize)
|
||||
|
||||
#define _ST_SLEEPQ (_st_this_vp.sleep_q)
|
||||
#define _ST_SLEEPQ_SIZE (_st_this_vp.sleepq_size)
|
||||
|
||||
#define _ST_VP_IDLE() (*_st_eventsys->dispatch)()
|
||||
|
||||
|
||||
/*****************************************
|
||||
* vp queues operations
|
||||
*/
|
||||
|
||||
#define _ST_ADD_IOQ(_pq) ST_APPEND_LINK(&_pq.links, &_ST_IOQ)
|
||||
#define _ST_DEL_IOQ(_pq) ST_REMOVE_LINK(&_pq.links)
|
||||
|
||||
#define _ST_ADD_RUNQ(_thr) ST_APPEND_LINK(&(_thr)->links, &_ST_RUNQ)
|
||||
#define _ST_DEL_RUNQ(_thr) ST_REMOVE_LINK(&(_thr)->links)
|
||||
|
||||
#define _ST_ADD_SLEEPQ(_thr, _timeout) _st_add_sleep_q(_thr, _timeout)
|
||||
#define _ST_DEL_SLEEPQ(_thr) _st_del_sleep_q(_thr)
|
||||
|
||||
#define _ST_ADD_ZOMBIEQ(_thr) ST_APPEND_LINK(&(_thr)->links, &_ST_ZOMBIEQ)
|
||||
#define _ST_DEL_ZOMBIEQ(_thr) ST_REMOVE_LINK(&(_thr)->links)
|
||||
|
||||
#ifdef DEBUG
|
||||
#define _ST_ADD_THREADQ(_thr) ST_APPEND_LINK(&(_thr)->tlink, &_ST_THREADQ)
|
||||
#define _ST_DEL_THREADQ(_thr) ST_REMOVE_LINK(&(_thr)->tlink)
|
||||
#endif
|
||||
|
||||
|
||||
/*****************************************
|
||||
* Thread states and flags
|
||||
*/
|
||||
|
||||
#define _ST_ST_RUNNING 0
|
||||
#define _ST_ST_RUNNABLE 1
|
||||
#define _ST_ST_IO_WAIT 2
|
||||
#define _ST_ST_LOCK_WAIT 3
|
||||
#define _ST_ST_COND_WAIT 4
|
||||
#define _ST_ST_SLEEPING 5
|
||||
#define _ST_ST_ZOMBIE 6
|
||||
#define _ST_ST_SUSPENDED 7
|
||||
|
||||
#define _ST_FL_PRIMORDIAL 0x01
|
||||
#define _ST_FL_IDLE_THREAD 0x02
|
||||
#define _ST_FL_ON_SLEEPQ 0x04
|
||||
#define _ST_FL_INTERRUPT 0x08
|
||||
#define _ST_FL_TIMEDOUT 0x10
|
||||
|
||||
/*****************************************
|
||||
* Pointer conversion
|
||||
*/
|
||||
|
||||
#ifndef offsetof
|
||||
#define offsetof(type, identifier) ((size_t)&(((type *)0)->identifier))
|
||||
#endif
|
||||
|
||||
#define _ST_THREAD_PTR(_qp) \
|
||||
((_st_thread_t *)((char *)(_qp) - offsetof(_st_thread_t, links)))
|
||||
|
||||
#define _ST_THREAD_WAITQ_PTR(_qp) \
|
||||
((_st_thread_t *)((char *)(_qp) - offsetof(_st_thread_t, wait_links)))
|
||||
|
||||
#define _ST_THREAD_STACK_PTR(_qp) \
|
||||
((_st_stack_t *)((char*)(_qp) - offsetof(_st_stack_t, links)))
|
||||
|
||||
#define _ST_POLLQUEUE_PTR(_qp) \
|
||||
((_st_pollq_t *)((char *)(_qp) - offsetof(_st_pollq_t, links)))
|
||||
|
||||
#ifdef DEBUG
|
||||
#define _ST_THREAD_THREADQ_PTR(_qp) \
|
||||
((_st_thread_t *)((char *)(_qp) - offsetof(_st_thread_t, tlink)))
|
||||
#endif
|
||||
|
||||
|
||||
/*****************************************
|
||||
* Constants
|
||||
*/
|
||||
|
||||
#ifndef ST_UTIME_NO_TIMEOUT
|
||||
#define ST_UTIME_NO_TIMEOUT ((st_utime_t) -1LL)
|
||||
#endif
|
||||
|
||||
#define ST_DEFAULT_STACK_SIZE (64*1024)
|
||||
|
||||
#ifndef ST_KEYS_MAX
|
||||
#define ST_KEYS_MAX 16
|
||||
#endif
|
||||
|
||||
#ifndef ST_MIN_POLLFDS_SIZE
|
||||
#define ST_MIN_POLLFDS_SIZE 64
|
||||
#endif
|
||||
|
||||
|
||||
/*****************************************
|
||||
* Threads context switching
|
||||
*/
|
||||
|
||||
#ifdef DEBUG
|
||||
void _st_iterate_threads(void);
|
||||
#define ST_DEBUG_ITERATE_THREADS() _st_iterate_threads()
|
||||
#else
|
||||
#define ST_DEBUG_ITERATE_THREADS()
|
||||
#endif
|
||||
|
||||
#ifdef ST_SWITCH_CB
|
||||
#define ST_SWITCH_OUT_CB(_thread) \
|
||||
if (_st_this_vp.switch_out_cb != NULL && \
|
||||
_thread != _st_this_vp.idle_thread && \
|
||||
_thread->state != _ST_ST_ZOMBIE) { \
|
||||
_st_this_vp.switch_out_cb(); \
|
||||
}
|
||||
#define ST_SWITCH_IN_CB(_thread) \
|
||||
if (_st_this_vp.switch_in_cb != NULL && \
|
||||
_thread != _st_this_vp.idle_thread && \
|
||||
_thread->state != _ST_ST_ZOMBIE) { \
|
||||
_st_this_vp.switch_in_cb(); \
|
||||
}
|
||||
#else
|
||||
#define ST_SWITCH_OUT_CB(_thread)
|
||||
#define ST_SWITCH_IN_CB(_thread)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Switch away from the current thread context by saving its state and
|
||||
* calling the thread scheduler
|
||||
*/
|
||||
#define _ST_SWITCH_CONTEXT(_thread) \
|
||||
ST_BEGIN_MACRO \
|
||||
ST_SWITCH_OUT_CB(_thread); \
|
||||
if (!MD_SETJMP((_thread)->context)) { \
|
||||
_st_vp_schedule(); \
|
||||
} \
|
||||
ST_DEBUG_ITERATE_THREADS(); \
|
||||
ST_SWITCH_IN_CB(_thread); \
|
||||
ST_END_MACRO
|
||||
|
||||
/*
|
||||
* Restore a thread context that was saved by _ST_SWITCH_CONTEXT or
|
||||
* initialized by _ST_INIT_CONTEXT
|
||||
*/
|
||||
#define _ST_RESTORE_CONTEXT(_thread) \
|
||||
ST_BEGIN_MACRO \
|
||||
_ST_SET_CURRENT_THREAD(_thread); \
|
||||
MD_LONGJMP((_thread)->context, 1); \
|
||||
ST_END_MACRO
|
||||
|
||||
/*
|
||||
* Number of bytes reserved under the stack "bottom"
|
||||
*/
|
||||
#define _ST_STACK_PAD_SIZE MD_STACK_PAD_SIZE
|
||||
|
||||
|
||||
/*****************************************
|
||||
* Forward declarations
|
||||
*/
|
||||
|
||||
void _st_vp_schedule(void);
|
||||
void _st_vp_check_clock(void);
|
||||
void *_st_idle_thread_start(void *arg);
|
||||
void _st_thread_main(void);
|
||||
void _st_thread_cleanup(_st_thread_t *thread);
|
||||
void _st_add_sleep_q(_st_thread_t *thread, st_utime_t timeout);
|
||||
void _st_del_sleep_q(_st_thread_t *thread);
|
||||
_st_stack_t *_st_stack_new(int stack_size);
|
||||
void _st_stack_free(_st_stack_t *ts);
|
||||
int _st_io_init(void);
|
||||
|
||||
st_utime_t st_utime(void);
|
||||
_st_cond_t *st_cond_new(void);
|
||||
int st_cond_destroy(_st_cond_t *cvar);
|
||||
int st_cond_timedwait(_st_cond_t *cvar, st_utime_t timeout);
|
||||
int st_cond_signal(_st_cond_t *cvar);
|
||||
ssize_t st_read(_st_netfd_t *fd, void *buf, size_t nbyte, st_utime_t timeout);
|
||||
ssize_t st_write(_st_netfd_t *fd, const void *buf, size_t nbyte, st_utime_t timeout);
|
||||
int st_poll(struct pollfd *pds, int npds, st_utime_t timeout);
|
||||
_st_thread_t *st_thread_create(void *(*start)(void *arg), void *arg, int joinable, int stk_size);
|
||||
|
||||
#endif /* !__ST_COMMON_H__ */
|
||||
|
|
@ -1,483 +0,0 @@
|
|||
/*
|
||||
* The contents of this file are subject to the Mozilla Public
|
||||
* License Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a copy of
|
||||
* the License at http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS
|
||||
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
||||
* implied. See the License for the specific language governing
|
||||
* rights and limitations under the License.
|
||||
*
|
||||
* The Original Code is the Netscape Portable Runtime library.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1994-2000 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s): Silicon Graphics, Inc.
|
||||
* Yahoo! Inc.
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the
|
||||
* terms of the GNU General Public License Version 2 or later (the
|
||||
* "GPL"), in which case the provisions of the GPL are applicable
|
||||
* instead of those above. If you wish to allow use of your
|
||||
* version of this file only under the terms of the GPL and not to
|
||||
* allow others to use your version of this file under the MPL,
|
||||
* indicate your decision by deleting the provisions above and
|
||||
* replace them with the notice and other provisions required by
|
||||
* the GPL. If you do not delete the provisions above, a recipient
|
||||
* may use your version of this file under either the MPL or the
|
||||
* GPL.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <errno.h>
|
||||
#include "common.h"
|
||||
|
||||
#ifdef USE_POLL
|
||||
#error "Not support USE_POLL"
|
||||
#endif
|
||||
#ifdef MD_HAVE_KQUEUE
|
||||
#error "Not support MD_HAVE_KQUEUE"
|
||||
#endif
|
||||
#ifdef MD_HAVE_POLL
|
||||
#error "Not support MD_HAVE_POLL"
|
||||
#endif
|
||||
#ifndef MD_HAVE_EPOLL
|
||||
#error "Only support MD_HAVE_EPOLL"
|
||||
#endif
|
||||
|
||||
#include <sys/epoll.h>
|
||||
|
||||
typedef struct _epoll_fd_data {
|
||||
int rd_ref_cnt;
|
||||
int wr_ref_cnt;
|
||||
int ex_ref_cnt;
|
||||
int revents;
|
||||
} _epoll_fd_data_t;
|
||||
|
||||
static struct _st_epolldata {
|
||||
_epoll_fd_data_t *fd_data;
|
||||
struct epoll_event *evtlist;
|
||||
int fd_data_size;
|
||||
int evtlist_size;
|
||||
int evtlist_cnt;
|
||||
int fd_hint;
|
||||
int epfd;
|
||||
pid_t pid;
|
||||
} *_st_epoll_data;
|
||||
|
||||
#ifndef ST_EPOLL_EVTLIST_SIZE
|
||||
/* Not a limit, just a hint */
|
||||
#define ST_EPOLL_EVTLIST_SIZE 4096
|
||||
#endif
|
||||
|
||||
#define _ST_EPOLL_READ_CNT(fd) (_st_epoll_data->fd_data[fd].rd_ref_cnt)
|
||||
#define _ST_EPOLL_WRITE_CNT(fd) (_st_epoll_data->fd_data[fd].wr_ref_cnt)
|
||||
#define _ST_EPOLL_EXCEP_CNT(fd) (_st_epoll_data->fd_data[fd].ex_ref_cnt)
|
||||
#define _ST_EPOLL_REVENTS(fd) (_st_epoll_data->fd_data[fd].revents)
|
||||
|
||||
#define _ST_EPOLL_READ_BIT(fd) (_ST_EPOLL_READ_CNT(fd) ? EPOLLIN : 0)
|
||||
#define _ST_EPOLL_WRITE_BIT(fd) (_ST_EPOLL_WRITE_CNT(fd) ? EPOLLOUT : 0)
|
||||
#define _ST_EPOLL_EXCEP_BIT(fd) (_ST_EPOLL_EXCEP_CNT(fd) ? EPOLLPRI : 0)
|
||||
#define _ST_EPOLL_EVENTS(fd) \
|
||||
(_ST_EPOLL_READ_BIT(fd)|_ST_EPOLL_WRITE_BIT(fd)|_ST_EPOLL_EXCEP_BIT(fd))
|
||||
|
||||
_st_eventsys_t *_st_eventsys = NULL;
|
||||
|
||||
/*****************************************
|
||||
* epoll event system
|
||||
*/
|
||||
|
||||
ST_HIDDEN int _st_epoll_init(void)
|
||||
{
|
||||
int fdlim;
|
||||
int err = 0;
|
||||
int rv = 0;
|
||||
|
||||
_st_epoll_data = (struct _st_epolldata *) calloc(1, sizeof(*_st_epoll_data));
|
||||
if (!_st_epoll_data) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
fdlim = st_getfdlimit();
|
||||
_st_epoll_data->fd_hint = (fdlim > 0 && fdlim < ST_EPOLL_EVTLIST_SIZE) ? fdlim : ST_EPOLL_EVTLIST_SIZE;
|
||||
|
||||
if ((_st_epoll_data->epfd = epoll_create(_st_epoll_data->fd_hint)) < 0) {
|
||||
err = errno;
|
||||
rv = -1;
|
||||
goto cleanup_epoll;
|
||||
}
|
||||
fcntl(_st_epoll_data->epfd, F_SETFD, FD_CLOEXEC);
|
||||
_st_epoll_data->pid = getpid();
|
||||
|
||||
/* Allocate file descriptor data array */
|
||||
_st_epoll_data->fd_data_size = _st_epoll_data->fd_hint;
|
||||
_st_epoll_data->fd_data = (_epoll_fd_data_t *)calloc(_st_epoll_data->fd_data_size, sizeof(_epoll_fd_data_t));
|
||||
if (!_st_epoll_data->fd_data) {
|
||||
err = errno;
|
||||
rv = -1;
|
||||
goto cleanup_epoll;
|
||||
}
|
||||
|
||||
/* Allocate event lists */
|
||||
_st_epoll_data->evtlist_size = _st_epoll_data->fd_hint;
|
||||
_st_epoll_data->evtlist = (struct epoll_event *)malloc(_st_epoll_data->evtlist_size * sizeof(struct epoll_event));
|
||||
if (!_st_epoll_data->evtlist) {
|
||||
err = errno;
|
||||
rv = -1;
|
||||
}
|
||||
|
||||
cleanup_epoll:
|
||||
if (rv < 0) {
|
||||
if (_st_epoll_data->epfd >= 0) {
|
||||
close(_st_epoll_data->epfd);
|
||||
}
|
||||
free(_st_epoll_data->fd_data);
|
||||
free(_st_epoll_data->evtlist);
|
||||
free(_st_epoll_data);
|
||||
_st_epoll_data = NULL;
|
||||
errno = err;
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
ST_HIDDEN int _st_epoll_fd_data_expand(int maxfd)
|
||||
{
|
||||
_epoll_fd_data_t *ptr;
|
||||
int n = _st_epoll_data->fd_data_size;
|
||||
|
||||
while (maxfd >= n) {
|
||||
n <<= 1;
|
||||
}
|
||||
|
||||
ptr = (_epoll_fd_data_t *)realloc(_st_epoll_data->fd_data, n * sizeof(_epoll_fd_data_t));
|
||||
if (!ptr) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
memset(ptr + _st_epoll_data->fd_data_size, 0, (n - _st_epoll_data->fd_data_size) * sizeof(_epoll_fd_data_t));
|
||||
|
||||
_st_epoll_data->fd_data = ptr;
|
||||
_st_epoll_data->fd_data_size = n;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
ST_HIDDEN void _st_epoll_evtlist_expand(void)
|
||||
{
|
||||
struct epoll_event *ptr;
|
||||
int n = _st_epoll_data->evtlist_size;
|
||||
|
||||
while (_st_epoll_data->evtlist_cnt > n) {
|
||||
n <<= 1;
|
||||
}
|
||||
|
||||
ptr = (struct epoll_event *)realloc(_st_epoll_data->evtlist, n * sizeof(struct epoll_event));
|
||||
if (ptr) {
|
||||
_st_epoll_data->evtlist = ptr;
|
||||
_st_epoll_data->evtlist_size = n;
|
||||
}
|
||||
}
|
||||
|
||||
ST_HIDDEN void _st_epoll_pollset_del(struct pollfd *pds, int npds)
|
||||
{
|
||||
struct epoll_event ev;
|
||||
struct pollfd *pd;
|
||||
struct pollfd *epd = pds + npds;
|
||||
int old_events, events, op;
|
||||
|
||||
/*
|
||||
* It's more or less OK if deleting fails because a descriptor
|
||||
* will either be closed or deleted in dispatch function after
|
||||
* it fires.
|
||||
*/
|
||||
for (pd = pds; pd < epd; pd++) {
|
||||
old_events = _ST_EPOLL_EVENTS(pd->fd);
|
||||
|
||||
if (pd->events & POLLIN) {
|
||||
_ST_EPOLL_READ_CNT(pd->fd)--;
|
||||
}
|
||||
if (pd->events & POLLOUT) {
|
||||
_ST_EPOLL_WRITE_CNT(pd->fd)--;
|
||||
}
|
||||
if (pd->events & POLLPRI) {
|
||||
_ST_EPOLL_EXCEP_CNT(pd->fd)--;
|
||||
}
|
||||
|
||||
events = _ST_EPOLL_EVENTS(pd->fd);
|
||||
/*
|
||||
* The _ST_EPOLL_REVENTS check below is needed so we can use
|
||||
* this function inside dispatch(). Outside of dispatch()
|
||||
* _ST_EPOLL_REVENTS is always zero for all descriptors.
|
||||
*/
|
||||
if (events != old_events && _ST_EPOLL_REVENTS(pd->fd) == 0) {
|
||||
op = events ? EPOLL_CTL_MOD : EPOLL_CTL_DEL;
|
||||
ev.events = events;
|
||||
ev.data.fd = pd->fd;
|
||||
if (epoll_ctl(_st_epoll_data->epfd, op, pd->fd, &ev) == 0 && op == EPOLL_CTL_DEL) {
|
||||
_st_epoll_data->evtlist_cnt--;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ST_HIDDEN int _st_epoll_pollset_add(struct pollfd *pds, int npds)
|
||||
{
|
||||
struct epoll_event ev;
|
||||
int i, fd;
|
||||
int old_events, events, op;
|
||||
|
||||
/* Do as many checks as possible up front */
|
||||
for (i = 0; i < npds; i++) {
|
||||
fd = pds[i].fd;
|
||||
if (fd < 0 || !pds[i].events || (pds[i].events & ~(POLLIN | POLLOUT | POLLPRI))) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
if (fd >= _st_epoll_data->fd_data_size && _st_epoll_fd_data_expand(fd) < 0) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < npds; i++) {
|
||||
fd = pds[i].fd;
|
||||
old_events = _ST_EPOLL_EVENTS(fd);
|
||||
|
||||
if (pds[i].events & POLLIN) {
|
||||
_ST_EPOLL_READ_CNT(fd)++;
|
||||
}
|
||||
if (pds[i].events & POLLOUT) {
|
||||
_ST_EPOLL_WRITE_CNT(fd)++;
|
||||
}
|
||||
if (pds[i].events & POLLPRI) {
|
||||
_ST_EPOLL_EXCEP_CNT(fd)++;
|
||||
}
|
||||
|
||||
events = _ST_EPOLL_EVENTS(fd);
|
||||
if (events != old_events) {
|
||||
op = old_events ? EPOLL_CTL_MOD : EPOLL_CTL_ADD;
|
||||
ev.events = events;
|
||||
ev.data.fd = fd;
|
||||
if (epoll_ctl(_st_epoll_data->epfd, op, fd, &ev) < 0 && (op != EPOLL_CTL_ADD || errno != EEXIST)) {
|
||||
break;
|
||||
}
|
||||
if (op == EPOLL_CTL_ADD) {
|
||||
_st_epoll_data->evtlist_cnt++;
|
||||
if (_st_epoll_data->evtlist_cnt > _st_epoll_data->evtlist_size) {
|
||||
_st_epoll_evtlist_expand();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (i < npds) {
|
||||
/* Error */
|
||||
int err = errno;
|
||||
/* Unroll the state */
|
||||
_st_epoll_pollset_del(pds, i + 1);
|
||||
errno = err;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
ST_HIDDEN void _st_epoll_dispatch(void)
|
||||
{
|
||||
st_utime_t min_timeout;
|
||||
_st_clist_t *q;
|
||||
_st_pollq_t *pq;
|
||||
struct pollfd *pds, *epds;
|
||||
struct epoll_event ev;
|
||||
int timeout, nfd, i, osfd, notify;
|
||||
int events, op;
|
||||
short revents;
|
||||
|
||||
if (_ST_SLEEPQ == NULL) {
|
||||
timeout = -1;
|
||||
} else {
|
||||
min_timeout = (_ST_SLEEPQ->due <= _ST_LAST_CLOCK) ? 0 : (_ST_SLEEPQ->due - _ST_LAST_CLOCK);
|
||||
timeout = (int) (min_timeout / 1000);
|
||||
}
|
||||
|
||||
if (_st_epoll_data->pid != getpid()) {
|
||||
// WINLIN: remove it for bug introduced.
|
||||
// @see: https://github.com/ossrs/srs/issues/193
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
/* Check for I/O operations */
|
||||
nfd = epoll_wait(_st_epoll_data->epfd, _st_epoll_data->evtlist, _st_epoll_data->evtlist_size, timeout);
|
||||
|
||||
if (nfd > 0) {
|
||||
for (i = 0; i < nfd; i++) {
|
||||
osfd = _st_epoll_data->evtlist[i].data.fd;
|
||||
_ST_EPOLL_REVENTS(osfd) = _st_epoll_data->evtlist[i].events;
|
||||
if (_ST_EPOLL_REVENTS(osfd) & (EPOLLERR | EPOLLHUP)) {
|
||||
/* Also set I/O bits on error */
|
||||
_ST_EPOLL_REVENTS(osfd) |= _ST_EPOLL_EVENTS(osfd);
|
||||
}
|
||||
}
|
||||
|
||||
for (q = _ST_IOQ.next; q != &_ST_IOQ; q = q->next) {
|
||||
pq = _ST_POLLQUEUE_PTR(q);
|
||||
notify = 0;
|
||||
epds = pq->pds + pq->npds;
|
||||
|
||||
for (pds = pq->pds; pds < epds; pds++) {
|
||||
if (_ST_EPOLL_REVENTS(pds->fd) == 0) {
|
||||
pds->revents = 0;
|
||||
continue;
|
||||
}
|
||||
osfd = pds->fd;
|
||||
events = pds->events;
|
||||
revents = 0;
|
||||
if ((events & POLLIN) && (_ST_EPOLL_REVENTS(osfd) & EPOLLIN)) {
|
||||
revents |= POLLIN;
|
||||
}
|
||||
if ((events & POLLOUT) && (_ST_EPOLL_REVENTS(osfd) & EPOLLOUT)) {
|
||||
revents |= POLLOUT;
|
||||
}
|
||||
if ((events & POLLPRI) && (_ST_EPOLL_REVENTS(osfd) & EPOLLPRI)) {
|
||||
revents |= POLLPRI;
|
||||
}
|
||||
if (_ST_EPOLL_REVENTS(osfd) & EPOLLERR) {
|
||||
revents |= POLLERR;
|
||||
}
|
||||
if (_ST_EPOLL_REVENTS(osfd) & EPOLLHUP) {
|
||||
revents |= POLLHUP;
|
||||
}
|
||||
|
||||
pds->revents = revents;
|
||||
if (revents) {
|
||||
notify = 1;
|
||||
}
|
||||
}
|
||||
if (notify) {
|
||||
ST_REMOVE_LINK(&pq->links);
|
||||
pq->on_ioq = 0;
|
||||
/*
|
||||
* Here we will only delete/modify descriptors that
|
||||
* didn't fire (see comments in _st_epoll_pollset_del()).
|
||||
*/
|
||||
_st_epoll_pollset_del(pq->pds, pq->npds);
|
||||
|
||||
if (pq->thread->flags & _ST_FL_ON_SLEEPQ) {
|
||||
_ST_DEL_SLEEPQ(pq->thread);
|
||||
}
|
||||
pq->thread->state = _ST_ST_RUNNABLE;
|
||||
_ST_ADD_RUNQ(pq->thread);
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < nfd; i++) {
|
||||
/* Delete/modify descriptors that fired */
|
||||
osfd = _st_epoll_data->evtlist[i].data.fd;
|
||||
_ST_EPOLL_REVENTS(osfd) = 0;
|
||||
events = _ST_EPOLL_EVENTS(osfd);
|
||||
op = events ? EPOLL_CTL_MOD : EPOLL_CTL_DEL;
|
||||
ev.events = events;
|
||||
ev.data.fd = osfd;
|
||||
if (epoll_ctl(_st_epoll_data->epfd, op, osfd, &ev) == 0 && op == EPOLL_CTL_DEL) {
|
||||
_st_epoll_data->evtlist_cnt--;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ST_HIDDEN int _st_epoll_fd_new(int osfd)
|
||||
{
|
||||
if (osfd >= _st_epoll_data->fd_data_size && _st_epoll_fd_data_expand(osfd) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
ST_HIDDEN int _st_epoll_fd_close(int osfd)
|
||||
{
|
||||
if (_ST_EPOLL_READ_CNT(osfd) || _ST_EPOLL_WRITE_CNT(osfd) || _ST_EPOLL_EXCEP_CNT(osfd)) {
|
||||
errno = EBUSY;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
ST_HIDDEN int _st_epoll_fd_getlimit(void)
|
||||
{
|
||||
/* zero means no specific limit */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check if epoll functions are just stubs.
|
||||
*/
|
||||
ST_HIDDEN int _st_epoll_is_supported(void)
|
||||
{
|
||||
struct epoll_event ev;
|
||||
|
||||
ev.events = EPOLLIN;
|
||||
ev.data.ptr = NULL;
|
||||
/* Guaranteed to fail */
|
||||
epoll_ctl(-1, EPOLL_CTL_ADD, -1, &ev);
|
||||
|
||||
return (errno != ENOSYS);
|
||||
}
|
||||
|
||||
static _st_eventsys_t _st_epoll_eventsys = {
|
||||
"epoll",
|
||||
ST_EVENTSYS_ALT,
|
||||
_st_epoll_init,
|
||||
_st_epoll_dispatch,
|
||||
_st_epoll_pollset_add,
|
||||
_st_epoll_pollset_del,
|
||||
_st_epoll_fd_new,
|
||||
_st_epoll_fd_close,
|
||||
_st_epoll_fd_getlimit
|
||||
};
|
||||
|
||||
/*****************************************
|
||||
* Public functions
|
||||
*/
|
||||
|
||||
int st_set_eventsys(int eventsys)
|
||||
{
|
||||
if (_st_eventsys) {
|
||||
errno = EBUSY;
|
||||
return -1;
|
||||
}
|
||||
|
||||
switch (eventsys) {
|
||||
case ST_EVENTSYS_DEFAULT:
|
||||
case ST_EVENTSYS_ALT:
|
||||
default:
|
||||
if (_st_epoll_is_supported()) {
|
||||
_st_eventsys = &_st_epoll_eventsys;
|
||||
break;
|
||||
}
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int st_get_eventsys(void)
|
||||
{
|
||||
return _st_eventsys ? _st_eventsys->val : -1;
|
||||
}
|
||||
|
||||
const char *st_get_eventsys_name(void)
|
||||
{
|
||||
return _st_eventsys ? _st_eventsys->name : "";
|
||||
}
|
||||
|
|
@ -1,792 +0,0 @@
|
|||
/*
|
||||
* The contents of this file are subject to the Mozilla Public
|
||||
* License Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a copy of
|
||||
* the License at http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS
|
||||
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
||||
* implied. See the License for the specific language governing
|
||||
* rights and limitations under the License.
|
||||
*
|
||||
* The Original Code is the Netscape Portable Runtime library.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1994-2000 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s): Silicon Graphics, Inc.
|
||||
*
|
||||
* Portions created by SGI are Copyright (C) 2000-2001 Silicon
|
||||
* Graphics, Inc. All Rights Reserved.
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the
|
||||
* terms of the GNU General Public License Version 2 or later (the
|
||||
* "GPL"), in which case the provisions of the GPL are applicable
|
||||
* instead of those above. If you wish to allow use of your
|
||||
* version of this file only under the terms of the GPL and not to
|
||||
* allow others to use your version of this file under the MPL,
|
||||
* indicate your decision by deleting the provisions above and
|
||||
* replace them with the notice and other provisions required by
|
||||
* the GPL. If you do not delete the provisions above, a recipient
|
||||
* may use your version of this file under either the MPL or the
|
||||
* GPL.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file is derived directly from Netscape Communications Corporation,
|
||||
* and consists of extensive modifications made during the year(s) 1999-2000.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/uio.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/resource.h>
|
||||
#include <fcntl.h>
|
||||
#include <signal.h>
|
||||
#include <errno.h>
|
||||
#include "common.h"
|
||||
|
||||
#if EAGAIN != EWOULDBLOCK
|
||||
#define _IO_NOT_READY_ERROR ((errno == EAGAIN) || (errno == EWOULDBLOCK))
|
||||
#else
|
||||
#define _IO_NOT_READY_ERROR (errno == EAGAIN)
|
||||
#endif
|
||||
|
||||
#define _LOCAL_MAXIOV 16
|
||||
|
||||
/* File descriptor object free list */
|
||||
static _st_netfd_t *_st_netfd_freelist = NULL;
|
||||
/* Maximum number of file descriptors that the process can open */
|
||||
static int _st_osfd_limit = -1;
|
||||
|
||||
static void _st_netfd_free_aux_data(_st_netfd_t *fd);
|
||||
|
||||
int _st_io_init(void)
|
||||
{
|
||||
struct sigaction sigact;
|
||||
struct rlimit rlim;
|
||||
int fdlim;
|
||||
|
||||
/* Ignore SIGPIPE */
|
||||
sigact.sa_handler = SIG_IGN;
|
||||
sigemptyset(&sigact.sa_mask);
|
||||
sigact.sa_flags = 0;
|
||||
if (sigaction(SIGPIPE, &sigact, NULL) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Set maximum number of open file descriptors */
|
||||
if (getrlimit(RLIMIT_NOFILE, &rlim) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
fdlim = (*_st_eventsys->fd_getlimit)();
|
||||
if (fdlim > 0 && rlim.rlim_max > (rlim_t) fdlim) {
|
||||
rlim.rlim_max = fdlim;
|
||||
}
|
||||
rlim.rlim_cur = rlim.rlim_max;
|
||||
if (setrlimit(RLIMIT_NOFILE, &rlim) < 0) {
|
||||
return -1;
|
||||
}
|
||||
_st_osfd_limit = (int) rlim.rlim_max;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int st_getfdlimit(void)
|
||||
{
|
||||
return _st_osfd_limit;
|
||||
}
|
||||
|
||||
void st_netfd_free(_st_netfd_t *fd)
|
||||
{
|
||||
if (!fd->inuse) {
|
||||
return;
|
||||
}
|
||||
|
||||
fd->inuse = 0;
|
||||
if (fd->aux_data) {
|
||||
_st_netfd_free_aux_data(fd);
|
||||
}
|
||||
if (fd->private_data && fd->destructor) {
|
||||
(*(fd->destructor))(fd->private_data);
|
||||
}
|
||||
fd->private_data = NULL;
|
||||
fd->destructor = NULL;
|
||||
fd->next = _st_netfd_freelist;
|
||||
_st_netfd_freelist = fd;
|
||||
}
|
||||
|
||||
static _st_netfd_t *_st_netfd_new(int osfd, int nonblock, int is_socket)
|
||||
{
|
||||
_st_netfd_t *fd;
|
||||
int flags = 1;
|
||||
|
||||
if ((*_st_eventsys->fd_new)(osfd) < 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (_st_netfd_freelist) {
|
||||
fd = _st_netfd_freelist;
|
||||
_st_netfd_freelist = _st_netfd_freelist->next;
|
||||
} else {
|
||||
fd = calloc(1, sizeof(_st_netfd_t));
|
||||
if (!fd) {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
fd->osfd = osfd;
|
||||
fd->inuse = 1;
|
||||
fd->next = NULL;
|
||||
|
||||
if (nonblock) {
|
||||
/* Use just one system call */
|
||||
if (is_socket && ioctl(osfd, FIONBIO, &flags) != -1) {
|
||||
return fd;
|
||||
}
|
||||
/* Do it the Posix way */
|
||||
if ((flags = fcntl(osfd, F_GETFL, 0)) < 0 || fcntl(osfd, F_SETFL, flags | O_NONBLOCK) < 0) {
|
||||
st_netfd_free(fd);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
_st_netfd_t *st_netfd_open(int osfd)
|
||||
{
|
||||
return _st_netfd_new(osfd, 1, 0);
|
||||
}
|
||||
|
||||
_st_netfd_t *st_netfd_open_socket(int osfd)
|
||||
{
|
||||
return _st_netfd_new(osfd, 1, 1);
|
||||
}
|
||||
|
||||
int st_netfd_close(_st_netfd_t *fd)
|
||||
{
|
||||
if ((*_st_eventsys->fd_close)(fd->osfd) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
st_netfd_free(fd);
|
||||
return close(fd->osfd);
|
||||
}
|
||||
|
||||
int st_netfd_fileno(_st_netfd_t *fd)
|
||||
{
|
||||
return (fd->osfd);
|
||||
}
|
||||
|
||||
void st_netfd_setspecific(_st_netfd_t *fd, void *value, _st_destructor_t destructor)
|
||||
{
|
||||
if (value != fd->private_data) {
|
||||
/* Free up previously set non-NULL data value */
|
||||
if (fd->private_data && fd->destructor) {
|
||||
(*(fd->destructor))(fd->private_data);
|
||||
}
|
||||
}
|
||||
fd->private_data = value;
|
||||
fd->destructor = destructor;
|
||||
}
|
||||
|
||||
void *st_netfd_getspecific(_st_netfd_t *fd)
|
||||
{
|
||||
return (fd->private_data);
|
||||
}
|
||||
|
||||
/*
|
||||
* Wait for I/O on a single descriptor.
|
||||
*/
|
||||
int st_netfd_poll(_st_netfd_t *fd, int how, st_utime_t timeout)
|
||||
{
|
||||
struct pollfd pd;
|
||||
int n;
|
||||
|
||||
pd.fd = fd->osfd;
|
||||
pd.events = (short) how;
|
||||
pd.revents = 0;
|
||||
|
||||
if ((n = st_poll(&pd, 1, timeout)) < 0) {
|
||||
return -1;
|
||||
}
|
||||
if (n == 0) {
|
||||
/* Timed out */
|
||||
errno = ETIME;
|
||||
return -1;
|
||||
}
|
||||
if (pd.revents & POLLNVAL) {
|
||||
errno = EBADF;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef MD_ALWAYS_UNSERIALIZED_ACCEPT
|
||||
/* No-op */
|
||||
int st_netfd_serialize_accept(_st_netfd_t *fd)
|
||||
{
|
||||
fd->aux_data = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* No-op */
|
||||
static void _st_netfd_free_aux_data(_st_netfd_t *fd)
|
||||
{
|
||||
fd->aux_data = NULL;
|
||||
}
|
||||
|
||||
_st_netfd_t *st_accept(_st_netfd_t *fd, struct sockaddr *addr, int *addrlen, st_utime_t timeout)
|
||||
{
|
||||
int osfd, err;
|
||||
_st_netfd_t *newfd;
|
||||
|
||||
while ((osfd = accept(fd->osfd, addr, (socklen_t *)addrlen)) < 0) {
|
||||
if (errno == EINTR) {
|
||||
continue;
|
||||
}
|
||||
if (!_IO_NOT_READY_ERROR) {
|
||||
return NULL;
|
||||
}
|
||||
/* Wait until the socket becomes readable */
|
||||
if (st_netfd_poll(fd, POLLIN, timeout) < 0) {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* On some platforms the new socket created by accept() inherits */
|
||||
/* the nonblocking attribute of the listening socket */
|
||||
#if defined (MD_ACCEPT_NB_INHERITED)
|
||||
newfd = _st_netfd_new(osfd, 0, 1);
|
||||
#elif defined (MD_ACCEPT_NB_NOT_INHERITED)
|
||||
newfd = _st_netfd_new(osfd, 1, 1);
|
||||
#else
|
||||
#error Unknown OS
|
||||
#endif
|
||||
|
||||
if (!newfd) {
|
||||
err = errno;
|
||||
close(osfd);
|
||||
errno = err;
|
||||
}
|
||||
|
||||
return newfd;
|
||||
}
|
||||
|
||||
#else /* MD_ALWAYS_UNSERIALIZED_ACCEPT */
|
||||
/*
|
||||
* On some platforms accept() calls from different processes
|
||||
* on the same listen socket must be serialized.
|
||||
* The following code serializes accept()'s without process blocking.
|
||||
* A pipe is used as an inter-process semaphore.
|
||||
*/
|
||||
int st_netfd_serialize_accept(_st_netfd_t *fd)
|
||||
{
|
||||
_st_netfd_t **p;
|
||||
int osfd[2], err;
|
||||
|
||||
if (fd->aux_data) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
if ((p = (_st_netfd_t **)calloc(2, sizeof(_st_netfd_t *))) == NULL) {
|
||||
return -1;
|
||||
}
|
||||
if (pipe(osfd) < 0) {
|
||||
free(p);
|
||||
return -1;
|
||||
}
|
||||
if ((p[0] = st_netfd_open(osfd[0])) != NULL && (p[1] = st_netfd_open(osfd[1])) != NULL && write(osfd[1], " ", 1) == 1) {
|
||||
fd->aux_data = p;
|
||||
return 0;
|
||||
}
|
||||
/* Error */
|
||||
err = errno;
|
||||
if (p[0]) {
|
||||
st_netfd_free(p[0]);
|
||||
}
|
||||
if (p[1]) {
|
||||
st_netfd_free(p[1]);
|
||||
}
|
||||
close(osfd[0]);
|
||||
close(osfd[1]);
|
||||
free(p);
|
||||
errno = err;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void _st_netfd_free_aux_data(_st_netfd_t *fd)
|
||||
{
|
||||
_st_netfd_t **p = (_st_netfd_t **) fd->aux_data;
|
||||
|
||||
st_netfd_close(p[0]);
|
||||
st_netfd_close(p[1]);
|
||||
free(p);
|
||||
fd->aux_data = NULL;
|
||||
}
|
||||
|
||||
_st_netfd_t *st_accept(_st_netfd_t *fd, struct sockaddr *addr, int *addrlen, st_utime_t timeout)
|
||||
{
|
||||
int osfd, err;
|
||||
_st_netfd_t *newfd;
|
||||
_st_netfd_t **p = (_st_netfd_t **) fd->aux_data;
|
||||
ssize_t n;
|
||||
char c;
|
||||
|
||||
for ( ; ; ) {
|
||||
if (p == NULL) {
|
||||
osfd = accept(fd->osfd, addr, (socklen_t *)addrlen);
|
||||
} else {
|
||||
/* Get the lock */
|
||||
n = st_read(p[0], &c, 1, timeout);
|
||||
if (n < 0) {
|
||||
return NULL;
|
||||
}
|
||||
ST_ASSERT(n == 1);
|
||||
/* Got the lock */
|
||||
osfd = accept(fd->osfd, addr, (socklen_t *)addrlen);
|
||||
/* Unlock */
|
||||
err = errno;
|
||||
n = st_write(p[1], &c, 1, timeout);
|
||||
ST_ASSERT(n == 1);
|
||||
errno = err;
|
||||
}
|
||||
if (osfd >= 0) {
|
||||
break;
|
||||
}
|
||||
if (errno == EINTR) {
|
||||
continue;
|
||||
}
|
||||
if (!_IO_NOT_READY_ERROR) {
|
||||
return NULL;
|
||||
}
|
||||
/* Wait until the socket becomes readable */
|
||||
if (st_netfd_poll(fd, POLLIN, timeout) < 0) {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* On some platforms the new socket created by accept() inherits */
|
||||
/* the nonblocking attribute of the listening socket */
|
||||
#if defined (MD_ACCEPT_NB_INHERITED)
|
||||
newfd = _st_netfd_new(osfd, 0, 1);
|
||||
#elif defined (MD_ACCEPT_NB_NOT_INHERITED)
|
||||
newfd = _st_netfd_new(osfd, 1, 1);
|
||||
#else
|
||||
#error Unknown OS
|
||||
#endif
|
||||
|
||||
if (!newfd) {
|
||||
err = errno;
|
||||
close(osfd);
|
||||
errno = err;
|
||||
}
|
||||
|
||||
return newfd;
|
||||
}
|
||||
#endif /* MD_ALWAYS_UNSERIALIZED_ACCEPT */
|
||||
|
||||
int st_connect(_st_netfd_t *fd, const struct sockaddr *addr, int addrlen, st_utime_t timeout)
|
||||
{
|
||||
int n, err = 0;
|
||||
|
||||
while (connect(fd->osfd, addr, addrlen) < 0) {
|
||||
if (errno != EINTR) {
|
||||
/*
|
||||
* On some platforms, if connect() is interrupted (errno == EINTR)
|
||||
* after the kernel binds the socket, a subsequent connect()
|
||||
* attempt will fail with errno == EADDRINUSE. Ignore EADDRINUSE
|
||||
* iff connect() was previously interrupted. See Rich Stevens'
|
||||
* "UNIX Network Programming," Vol. 1, 2nd edition, p. 413
|
||||
* ("Interrupted connect").
|
||||
*/
|
||||
if (errno != EINPROGRESS && (errno != EADDRINUSE || err == 0)) {
|
||||
return -1;
|
||||
}
|
||||
/* Wait until the socket becomes writable */
|
||||
if (st_netfd_poll(fd, POLLOUT, timeout) < 0) {
|
||||
return -1;
|
||||
}
|
||||
/* Try to find out whether the connection setup succeeded or failed */
|
||||
n = sizeof(int);
|
||||
if (getsockopt(fd->osfd, SOL_SOCKET, SO_ERROR, (char *)&err, (socklen_t *)&n) < 0) {
|
||||
return -1;
|
||||
}
|
||||
if (err) {
|
||||
errno = err;
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
err = 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
ssize_t st_read(_st_netfd_t *fd, void *buf, size_t nbyte, st_utime_t timeout)
|
||||
{
|
||||
ssize_t n;
|
||||
|
||||
while ((n = read(fd->osfd, buf, nbyte)) < 0) {
|
||||
if (errno == EINTR) {
|
||||
continue;
|
||||
}
|
||||
if (!_IO_NOT_READY_ERROR) {
|
||||
return -1;
|
||||
}
|
||||
/* Wait until the socket becomes readable */
|
||||
if (st_netfd_poll(fd, POLLIN, timeout) < 0) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
int st_read_resid(_st_netfd_t *fd, void *buf, size_t *resid, st_utime_t timeout)
|
||||
{
|
||||
struct iovec iov, *riov;
|
||||
int riov_size, rv;
|
||||
|
||||
iov.iov_base = buf;
|
||||
iov.iov_len = *resid;
|
||||
riov = &iov;
|
||||
riov_size = 1;
|
||||
rv = st_readv_resid(fd, &riov, &riov_size, timeout);
|
||||
*resid = iov.iov_len;
|
||||
return rv;
|
||||
}
|
||||
|
||||
ssize_t st_readv(_st_netfd_t *fd, const struct iovec *iov, int iov_size, st_utime_t timeout)
|
||||
{
|
||||
ssize_t n;
|
||||
|
||||
while ((n = readv(fd->osfd, iov, iov_size)) < 0) {
|
||||
if (errno == EINTR) {
|
||||
continue;
|
||||
}
|
||||
if (!_IO_NOT_READY_ERROR) {
|
||||
return -1;
|
||||
}
|
||||
/* Wait until the socket becomes readable */
|
||||
if (st_netfd_poll(fd, POLLIN, timeout) < 0) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
int st_readv_resid(_st_netfd_t *fd, struct iovec **iov, int *iov_size, st_utime_t timeout)
|
||||
{
|
||||
ssize_t n;
|
||||
|
||||
while (*iov_size > 0) {
|
||||
if (*iov_size == 1) {
|
||||
n = read(fd->osfd, (*iov)->iov_base, (*iov)->iov_len);
|
||||
} else {
|
||||
n = readv(fd->osfd, *iov, *iov_size);
|
||||
}
|
||||
if (n < 0) {
|
||||
if (errno == EINTR) {
|
||||
continue;
|
||||
}
|
||||
if (!_IO_NOT_READY_ERROR) {
|
||||
return -1;
|
||||
}
|
||||
} else if (n == 0) {
|
||||
break;
|
||||
} else {
|
||||
while ((size_t) n >= (*iov)->iov_len) {
|
||||
n -= (*iov)->iov_len;
|
||||
(*iov)->iov_base = (char *) (*iov)->iov_base + (*iov)->iov_len;
|
||||
(*iov)->iov_len = 0;
|
||||
(*iov)++;
|
||||
(*iov_size)--;
|
||||
if (n == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (*iov_size == 0) {
|
||||
break;
|
||||
}
|
||||
(*iov)->iov_base = (char *) (*iov)->iov_base + n;
|
||||
(*iov)->iov_len -= n;
|
||||
}
|
||||
/* Wait until the socket becomes readable */
|
||||
if (st_netfd_poll(fd, POLLIN, timeout) < 0) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
ssize_t st_read_fully(_st_netfd_t *fd, void *buf, size_t nbyte, st_utime_t timeout)
|
||||
{
|
||||
size_t resid = nbyte;
|
||||
return st_read_resid(fd, buf, &resid, timeout) == 0 ? (ssize_t) (nbyte - resid) : -1;
|
||||
}
|
||||
|
||||
int st_write_resid(_st_netfd_t *fd, const void *buf, size_t *resid, st_utime_t timeout)
|
||||
{
|
||||
struct iovec iov, *riov;
|
||||
int riov_size, rv;
|
||||
|
||||
iov.iov_base = (void *) buf; /* we promise not to modify buf */
|
||||
iov.iov_len = *resid;
|
||||
riov = &iov;
|
||||
riov_size = 1;
|
||||
rv = st_writev_resid(fd, &riov, &riov_size, timeout);
|
||||
*resid = iov.iov_len;
|
||||
return rv;
|
||||
}
|
||||
|
||||
ssize_t st_write(_st_netfd_t *fd, const void *buf, size_t nbyte, st_utime_t timeout)
|
||||
{
|
||||
size_t resid = nbyte;
|
||||
return st_write_resid(fd, buf, &resid, timeout) == 0 ? (ssize_t) (nbyte - resid) : -1;
|
||||
}
|
||||
|
||||
ssize_t st_writev(_st_netfd_t *fd, const struct iovec *iov, int iov_size, st_utime_t timeout)
|
||||
{
|
||||
ssize_t n, rv;
|
||||
size_t nleft, nbyte;
|
||||
int index, iov_cnt;
|
||||
struct iovec *tmp_iov;
|
||||
struct iovec local_iov[_LOCAL_MAXIOV];
|
||||
|
||||
/* Calculate the total number of bytes to be sent */
|
||||
nbyte = 0;
|
||||
for (index = 0; index < iov_size; index++) {
|
||||
nbyte += iov[index].iov_len;
|
||||
}
|
||||
|
||||
rv = (ssize_t)nbyte;
|
||||
nleft = nbyte;
|
||||
tmp_iov = (struct iovec *) iov; /* we promise not to modify iov */
|
||||
iov_cnt = iov_size;
|
||||
|
||||
while (nleft > 0) {
|
||||
if (iov_cnt == 1) {
|
||||
if (st_write(fd, tmp_iov[0].iov_base, nleft, timeout) != (ssize_t) nleft) {
|
||||
rv = -1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if ((n = writev(fd->osfd, tmp_iov, iov_cnt)) < 0) {
|
||||
if (errno == EINTR) {
|
||||
continue;
|
||||
}
|
||||
if (!_IO_NOT_READY_ERROR) {
|
||||
rv = -1;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
if ((size_t) n == nleft) {
|
||||
break;
|
||||
}
|
||||
nleft -= n;
|
||||
/* Find the next unwritten vector */
|
||||
n = (ssize_t)(nbyte - nleft);
|
||||
for (index = 0; (size_t) n >= iov[index].iov_len; index++) {
|
||||
n -= iov[index].iov_len;
|
||||
}
|
||||
|
||||
if (tmp_iov == iov) {
|
||||
/* Must copy iov's around */
|
||||
if (iov_size - index <= _LOCAL_MAXIOV) {
|
||||
tmp_iov = local_iov;
|
||||
} else {
|
||||
tmp_iov = calloc(1, (iov_size - index) * sizeof(struct iovec));
|
||||
if (tmp_iov == NULL) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Fill in the first partial read */
|
||||
tmp_iov[0].iov_base = &(((char *)iov[index].iov_base)[n]);
|
||||
tmp_iov[0].iov_len = iov[index].iov_len - n;
|
||||
index++;
|
||||
/* Copy the remaining vectors */
|
||||
for (iov_cnt = 1; index < iov_size; iov_cnt++, index++) {
|
||||
tmp_iov[iov_cnt].iov_base = iov[index].iov_base;
|
||||
tmp_iov[iov_cnt].iov_len = iov[index].iov_len;
|
||||
}
|
||||
}
|
||||
/* Wait until the socket becomes writable */
|
||||
if (st_netfd_poll(fd, POLLOUT, timeout) < 0) {
|
||||
rv = -1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (tmp_iov != iov && tmp_iov != local_iov) {
|
||||
free(tmp_iov);
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
int st_writev_resid(_st_netfd_t *fd, struct iovec **iov, int *iov_size, st_utime_t timeout)
|
||||
{
|
||||
ssize_t n;
|
||||
|
||||
while (*iov_size > 0) {
|
||||
if (*iov_size == 1) {
|
||||
n = write(fd->osfd, (*iov)->iov_base, (*iov)->iov_len);
|
||||
} else {
|
||||
n = writev(fd->osfd, *iov, *iov_size);
|
||||
}
|
||||
if (n < 0) {
|
||||
if (errno == EINTR) {
|
||||
continue;
|
||||
}
|
||||
if (!_IO_NOT_READY_ERROR) {
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
while ((size_t) n >= (*iov)->iov_len) {
|
||||
n -= (*iov)->iov_len;
|
||||
(*iov)->iov_base = (char *) (*iov)->iov_base + (*iov)->iov_len;
|
||||
(*iov)->iov_len = 0;
|
||||
(*iov)++;
|
||||
(*iov_size)--;
|
||||
if (n == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (*iov_size == 0) {
|
||||
break;
|
||||
}
|
||||
(*iov)->iov_base = (char *) (*iov)->iov_base + n;
|
||||
(*iov)->iov_len -= n;
|
||||
}
|
||||
/* Wait until the socket becomes writable */
|
||||
if (st_netfd_poll(fd, POLLOUT, timeout) < 0) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Simple I/O functions for UDP.
|
||||
*/
|
||||
int st_recvfrom(_st_netfd_t *fd, void *buf, int len, struct sockaddr *from, int *fromlen, st_utime_t timeout)
|
||||
{
|
||||
int n;
|
||||
|
||||
while ((n = recvfrom(fd->osfd, buf, len, 0, from, (socklen_t *)fromlen)) < 0) {
|
||||
if (errno == EINTR) {
|
||||
continue;
|
||||
}
|
||||
if (!_IO_NOT_READY_ERROR) {
|
||||
return -1;
|
||||
}
|
||||
/* Wait until the socket becomes readable */
|
||||
if (st_netfd_poll(fd, POLLIN, timeout) < 0) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
int st_sendto(_st_netfd_t *fd, const void *msg, int len, const struct sockaddr *to, int tolen, st_utime_t timeout)
|
||||
{
|
||||
int n;
|
||||
|
||||
while ((n = sendto(fd->osfd, msg, len, 0, to, tolen)) < 0) {
|
||||
if (errno == EINTR) {
|
||||
continue;
|
||||
}
|
||||
if (!_IO_NOT_READY_ERROR) {
|
||||
return -1;
|
||||
}
|
||||
/* Wait until the socket becomes writable */
|
||||
if (st_netfd_poll(fd, POLLOUT, timeout) < 0) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
int st_recvmsg(_st_netfd_t *fd, struct msghdr *msg, int flags, st_utime_t timeout)
|
||||
{
|
||||
int n;
|
||||
|
||||
while ((n = recvmsg(fd->osfd, msg, flags)) < 0) {
|
||||
if (errno == EINTR) {
|
||||
continue;
|
||||
}
|
||||
if (!_IO_NOT_READY_ERROR) {
|
||||
return -1;
|
||||
}
|
||||
/* Wait until the socket becomes readable */
|
||||
if (st_netfd_poll(fd, POLLIN, timeout) < 0) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
int st_sendmsg(_st_netfd_t *fd, const struct msghdr *msg, int flags, st_utime_t timeout)
|
||||
{
|
||||
int n;
|
||||
|
||||
while ((n = sendmsg(fd->osfd, msg, flags)) < 0) {
|
||||
if (errno == EINTR) {
|
||||
continue;
|
||||
}
|
||||
if (!_IO_NOT_READY_ERROR) {
|
||||
return -1;
|
||||
}
|
||||
/* Wait until the socket becomes writable */
|
||||
if (st_netfd_poll(fd, POLLOUT, timeout) < 0) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
/*
|
||||
* To open FIFOs or other special files.
|
||||
*/
|
||||
_st_netfd_t *st_open(const char *path, int oflags, mode_t mode)
|
||||
{
|
||||
int osfd, err;
|
||||
_st_netfd_t *newfd;
|
||||
|
||||
while ((osfd = open(path, oflags | O_NONBLOCK, mode)) < 0) {
|
||||
if (errno != EINTR) {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
newfd = _st_netfd_new(osfd, 0, 0);
|
||||
if (!newfd) {
|
||||
err = errno;
|
||||
close(osfd);
|
||||
errno = err;
|
||||
}
|
||||
|
||||
return newfd;
|
||||
}
|
||||
|
|
@ -1,116 +0,0 @@
|
|||
/*
|
||||
* The contents of this file are subject to the Mozilla Public
|
||||
* License Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a copy of
|
||||
* the License at http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS
|
||||
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
||||
* implied. See the License for the specific language governing
|
||||
* rights and limitations under the License.
|
||||
*
|
||||
* The Original Code is the Netscape Portable Runtime library.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1994-2000 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s): Silicon Graphics, Inc.
|
||||
*
|
||||
* Portions created by SGI are Copyright (C) 2000-2001 Silicon
|
||||
* Graphics, Inc. All Rights Reserved.
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the
|
||||
* terms of the GNU General Public License Version 2 or later (the
|
||||
* "GPL"), in which case the provisions of the GPL are applicable
|
||||
* instead of those above. If you wish to allow use of your
|
||||
* version of this file only under the terms of the GPL and not to
|
||||
* allow others to use your version of this file under the MPL,
|
||||
* indicate your decision by deleting the provisions above and
|
||||
* replace them with the notice and other provisions required by
|
||||
* the GPL. If you do not delete the provisions above, a recipient
|
||||
* may use your version of this file under either the MPL or the
|
||||
* GPL.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file is derived directly from Netscape Communications Corporation,
|
||||
* and consists of extensive modifications made during the year(s) 1999-2000.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include "common.h"
|
||||
|
||||
/*
|
||||
* Destructor table for per-thread private data
|
||||
*/
|
||||
static _st_destructor_t _st_destructors[ST_KEYS_MAX];
|
||||
static int key_max = 0;
|
||||
|
||||
/*
|
||||
* Return a key to be used for thread specific data
|
||||
*/
|
||||
int st_key_create(int *keyp, _st_destructor_t destructor)
|
||||
{
|
||||
if (key_max >= ST_KEYS_MAX) {
|
||||
errno = EAGAIN;
|
||||
return -1;
|
||||
}
|
||||
|
||||
*keyp = key_max++;
|
||||
_st_destructors[*keyp] = destructor;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int st_key_getlimit(void)
|
||||
{
|
||||
return ST_KEYS_MAX;
|
||||
}
|
||||
|
||||
int st_thread_setspecific(int key, void *value)
|
||||
{
|
||||
_st_thread_t *me = _ST_CURRENT_THREAD();
|
||||
|
||||
if (key < 0 || key >= key_max) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (value != me->private_data[key]) {
|
||||
/* free up previously set non-NULL data value */
|
||||
if (me->private_data[key] && _st_destructors[key]) {
|
||||
(*_st_destructors[key])(me->private_data[key]);
|
||||
}
|
||||
me->private_data[key] = value;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void *st_thread_getspecific(int key)
|
||||
{
|
||||
if (key < 0 || key >= key_max) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return ((_ST_CURRENT_THREAD())->private_data[key]);
|
||||
}
|
||||
|
||||
/*
|
||||
* Free up all per-thread private data
|
||||
*/
|
||||
void _st_thread_cleanup(_st_thread_t *thread)
|
||||
{
|
||||
int key;
|
||||
|
||||
for (key = 0; key < key_max; key++) {
|
||||
if (thread->private_data[key] && _st_destructors[key]) {
|
||||
(*_st_destructors[key])(thread->private_data[key]);
|
||||
thread->private_data[key] = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,151 +0,0 @@
|
|||
/*
|
||||
* Portions created by SGI are Copyright (C) 2000 Silicon Graphics, Inc.
|
||||
* All Rights Reserved.
|
||||
*/
|
||||
|
||||
/****************************************************************/
|
||||
|
||||
#if defined(__i386__)
|
||||
|
||||
/*
|
||||
* Internal __jmp_buf layout
|
||||
*/
|
||||
#define JB_BX 0
|
||||
#define JB_SI 1
|
||||
#define JB_DI 2
|
||||
#define JB_BP 3
|
||||
#define JB_SP 4
|
||||
#define JB_PC 5
|
||||
|
||||
.file "md.S"
|
||||
.text
|
||||
|
||||
/* _st_md_cxt_save(__jmp_buf env) */
|
||||
.globl _st_md_cxt_save
|
||||
.type _st_md_cxt_save, @function
|
||||
.align 16
|
||||
_st_md_cxt_save:
|
||||
movl 4(%esp), %eax
|
||||
|
||||
/*
|
||||
* Save registers.
|
||||
*/
|
||||
movl %ebx, (JB_BX*4)(%eax)
|
||||
movl %esi, (JB_SI*4)(%eax)
|
||||
movl %edi, (JB_DI*4)(%eax)
|
||||
/* Save SP */
|
||||
leal 4(%esp), %ecx
|
||||
movl %ecx, (JB_SP*4)(%eax)
|
||||
/* Save PC we are returning to */
|
||||
movl 0(%esp), %ecx
|
||||
movl %ecx, (JB_PC*4)(%eax)
|
||||
/* Save caller frame pointer */
|
||||
movl %ebp, (JB_BP*4)(%eax)
|
||||
xorl %eax, %eax
|
||||
ret
|
||||
.size _st_md_cxt_save, .-_st_md_cxt_save
|
||||
|
||||
|
||||
/****************************************************************/
|
||||
|
||||
/* _st_md_cxt_restore(__jmp_buf env, int val) */
|
||||
.globl _st_md_cxt_restore
|
||||
.type _st_md_cxt_restore, @function
|
||||
.align 16
|
||||
_st_md_cxt_restore:
|
||||
/* First argument is jmp_buf */
|
||||
movl 4(%esp), %ecx
|
||||
/* Second argument is return value */
|
||||
movl 8(%esp), %eax
|
||||
/* Set the return address */
|
||||
movl (JB_PC*4)(%ecx), %edx
|
||||
/*
|
||||
* Restore registers.
|
||||
*/
|
||||
movl (JB_BX*4)(%ecx), %ebx
|
||||
movl (JB_SI*4)(%ecx), %esi
|
||||
movl (JB_DI*4)(%ecx), %edi
|
||||
movl (JB_BP*4)(%ecx), %ebp
|
||||
movl (JB_SP*4)(%ecx), %esp
|
||||
testl %eax, %eax
|
||||
jnz 1f
|
||||
incl %eax
|
||||
/* Jump to saved PC */
|
||||
1: jmp *%edx
|
||||
.size _st_md_cxt_restore, .-_st_md_cxt_restore
|
||||
|
||||
/****************************************************************/
|
||||
|
||||
#elif defined(__amd64__) || defined(__x86_64__)
|
||||
|
||||
/*
|
||||
* Internal __jmp_buf layout
|
||||
*/
|
||||
#define JB_RBX 0
|
||||
#define JB_RBP 1
|
||||
#define JB_R12 2
|
||||
#define JB_R13 3
|
||||
#define JB_R14 4
|
||||
#define JB_R15 5
|
||||
#define JB_RSP 6
|
||||
#define JB_PC 7
|
||||
|
||||
.file "md.S"
|
||||
.text
|
||||
|
||||
/* _st_md_cxt_save(__jmp_buf env) */
|
||||
.globl _st_md_cxt_save
|
||||
.type _st_md_cxt_save, @function
|
||||
.align 16
|
||||
_st_md_cxt_save:
|
||||
/*
|
||||
* Save registers.
|
||||
*/
|
||||
movq %rbx, (JB_RBX*8)(%rdi)
|
||||
movq %rbp, (JB_RBP*8)(%rdi)
|
||||
movq %r12, (JB_R12*8)(%rdi)
|
||||
movq %r13, (JB_R13*8)(%rdi)
|
||||
movq %r14, (JB_R14*8)(%rdi)
|
||||
movq %r15, (JB_R15*8)(%rdi)
|
||||
/* Save SP */
|
||||
leaq 8(%rsp), %rdx
|
||||
movq %rdx, (JB_RSP*8)(%rdi)
|
||||
/* Save PC we are returning to */
|
||||
movq (%rsp), %rax
|
||||
movq %rax, (JB_PC*8)(%rdi)
|
||||
xorq %rax, %rax
|
||||
ret
|
||||
.size _st_md_cxt_save, .-_st_md_cxt_save
|
||||
|
||||
|
||||
/****************************************************************/
|
||||
|
||||
/* _st_md_cxt_restore(__jmp_buf env, int val) */
|
||||
.globl _st_md_cxt_restore
|
||||
.type _st_md_cxt_restore, @function
|
||||
.align 16
|
||||
_st_md_cxt_restore:
|
||||
/*
|
||||
* Restore registers.
|
||||
*/
|
||||
movq (JB_RBX*8)(%rdi), %rbx
|
||||
movq (JB_RBP*8)(%rdi), %rbp
|
||||
movq (JB_R12*8)(%rdi), %r12
|
||||
movq (JB_R13*8)(%rdi), %r13
|
||||
movq (JB_R14*8)(%rdi), %r14
|
||||
movq (JB_R15*8)(%rdi), %r15
|
||||
/* Set return value */
|
||||
test %esi, %esi
|
||||
mov $01, %eax
|
||||
cmove %eax, %esi
|
||||
mov %esi, %eax
|
||||
movq (JB_PC*8)(%rdi), %rdx
|
||||
movq (JB_RSP*8)(%rdi), %rsp
|
||||
/* Jump to saved PC */
|
||||
jmpq *%rdx
|
||||
.size _st_md_cxt_restore, .-_st_md_cxt_restore
|
||||
|
||||
/****************************************************************/
|
||||
|
||||
#endif
|
||||
|
|
@ -1,193 +0,0 @@
|
|||
/*
|
||||
* The contents of this file are subject to the Mozilla Public
|
||||
* License Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a copy of
|
||||
* the License at http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS
|
||||
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
||||
* implied. See the License for the specific language governing
|
||||
* rights and limitations under the License.
|
||||
*
|
||||
* The Original Code is the Netscape Portable Runtime library.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1994-2000 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s): Silicon Graphics, Inc.
|
||||
*
|
||||
* Portions created by SGI are Copyright (C) 2000-2001 Silicon
|
||||
* Graphics, Inc. All Rights Reserved.
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the
|
||||
* terms of the GNU General Public License Version 2 or later (the
|
||||
* "GPL"), in which case the provisions of the GPL are applicable
|
||||
* instead of those above. If you wish to allow use of your
|
||||
* version of this file only under the terms of the GPL and not to
|
||||
* allow others to use your version of this file under the MPL,
|
||||
* indicate your decision by deleting the provisions above and
|
||||
* replace them with the notice and other provisions required by
|
||||
* the GPL. If you do not delete the provisions above, a recipient
|
||||
* may use your version of this file under either the MPL or the
|
||||
* GPL.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file is derived directly from Netscape Communications Corporation,
|
||||
* and consists of extensive modifications made during the year(s) 1999-2000.
|
||||
*/
|
||||
|
||||
#ifndef __ST_MD_H__
|
||||
#define __ST_MD_H__
|
||||
|
||||
#if defined(ETIMEDOUT) && !defined(ETIME)
|
||||
#define ETIME ETIMEDOUT
|
||||
#endif
|
||||
|
||||
#if defined(MAP_ANONYMOUS) && !defined(MAP_ANON)
|
||||
#define MAP_ANON MAP_ANONYMOUS
|
||||
#endif
|
||||
|
||||
#ifndef MAP_FAILED
|
||||
#define MAP_FAILED -1
|
||||
#endif
|
||||
|
||||
/*****************************************
|
||||
* Platform specifics
|
||||
*/
|
||||
#if defined (LINUX)
|
||||
/* linux ok, defined bellow */
|
||||
#elif defined (AIX)
|
||||
#error "AIX not supported"
|
||||
#elif defined (CYGWIN)
|
||||
#error "CYGWIN not supported"
|
||||
#elif defined (DARWIN)
|
||||
#error "DARWIN not supported"
|
||||
#elif defined (FREEBSD)
|
||||
#error "FREEBSD not supported"
|
||||
#elif defined (HPUX)
|
||||
#error "HPUX not supported"
|
||||
#elif defined (IRIX)
|
||||
#error "IRIX not supported"
|
||||
#elif defined (NETBSD)
|
||||
#error "NETBSD not supported"
|
||||
#elif defined (OPENBSD)
|
||||
#error "OPENBSD not supported"
|
||||
#elif defined (OSF1)
|
||||
#error "OSF1 not supported"
|
||||
#elif defined (SOLARIS)
|
||||
#error "SOLARIS not supported"
|
||||
#else
|
||||
#error "Unknown OS"
|
||||
#endif /* OS */
|
||||
|
||||
/* linux only, defined bellow */
|
||||
/*
|
||||
* These are properties of the linux kernel and are the same on every
|
||||
* flavor and architecture.
|
||||
*/
|
||||
#define MD_USE_BSD_ANON_MMAP
|
||||
#define MD_ACCEPT_NB_NOT_INHERITED
|
||||
#define MD_ALWAYS_UNSERIALIZED_ACCEPT
|
||||
/*
|
||||
* Modern GNU/Linux is Posix.1g compliant.
|
||||
*/
|
||||
#define MD_HAVE_SOCKLEN_T
|
||||
|
||||
/*
|
||||
* All architectures and flavors of linux have the gettimeofday
|
||||
* function but if you know of a faster way, use it.
|
||||
*/
|
||||
#define MD_GET_UTIME() \
|
||||
struct timeval tv; \
|
||||
(void) gettimeofday(&tv, NULL); \
|
||||
return (tv.tv_sec * 1000000LL + tv.tv_usec)
|
||||
|
||||
#if defined(__mips__)
|
||||
#define MD_STACK_GROWS_DOWN
|
||||
#else /* Not or mips */
|
||||
/*
|
||||
* On linux, there are a few styles of jmpbuf format. These vary based
|
||||
* on architecture/glibc combination.
|
||||
*
|
||||
* Most of the glibc based toggles were lifted from:
|
||||
* mozilla/nsprpub/pr/include/md/_linux.h
|
||||
*/
|
||||
/*
|
||||
* Starting with glibc 2.4, JB_SP definitions are not public anymore.
|
||||
* They, however, can still be found in glibc source tree in
|
||||
* architecture-specific "jmpbuf-offsets.h" files.
|
||||
* Most importantly, the content of jmp_buf is mangled by setjmp to make
|
||||
* it completely opaque (the mangling can be disabled by setting the
|
||||
* LD_POINTER_GUARD environment variable before application execution).
|
||||
* Therefore we will use built-in _st_md_cxt_save/_st_md_cxt_restore
|
||||
* functions as a setjmp/longjmp replacement wherever they are available
|
||||
* unless USE_LIBC_SETJMP is defined.
|
||||
*/
|
||||
#if defined(__i386__)
|
||||
#define MD_STACK_GROWS_DOWN
|
||||
#define MD_USE_BUILTIN_SETJMP
|
||||
|
||||
#if defined(__GLIBC__) && __GLIBC__ >= 2
|
||||
#ifndef JB_SP
|
||||
#define JB_SP 4
|
||||
#endif
|
||||
#define MD_GET_SP(_t) (_t)->context[0].__jmpbuf[JB_SP]
|
||||
#else
|
||||
/* not an error but certainly cause for caution */
|
||||
#error "Untested use of old glibc on i386"
|
||||
#define MD_GET_SP(_t) (_t)->context[0].__jmpbuf[0].__sp
|
||||
#endif
|
||||
#elif defined(__amd64__) || defined(__x86_64__)
|
||||
#define MD_STACK_GROWS_DOWN
|
||||
#define MD_USE_BUILTIN_SETJMP
|
||||
|
||||
#ifndef JB_RSP
|
||||
#define JB_RSP 6
|
||||
#endif
|
||||
#define MD_GET_SP(_t) (_t)->context[0].__jmpbuf[JB_RSP]
|
||||
#elif defined(__arm__)
|
||||
#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 */
|
||||
#else
|
||||
#error "Unknown CPU architecture"
|
||||
#endif /* Cases with common MD_INIT_CONTEXT and different SP locations */
|
||||
#endif /* Cases with different MD_INIT_CONTEXT */
|
||||
|
||||
#if defined(MD_USE_BUILTIN_SETJMP) && !defined(USE_LIBC_SETJMP)
|
||||
/* i386/x86_64 */
|
||||
#define MD_SETJMP(env) _st_md_cxt_save(env)
|
||||
#define MD_LONGJMP(env, val) _st_md_cxt_restore(env, val)
|
||||
|
||||
extern int _st_md_cxt_save(jmp_buf env);
|
||||
extern void _st_md_cxt_restore(jmp_buf env, int val);
|
||||
#else
|
||||
/* arm/mips */
|
||||
#define MD_SETJMP(env) setjmp(env)
|
||||
#define MD_LONGJMP(env, val) longjmp(env, val)
|
||||
#endif
|
||||
|
||||
/*****************************************
|
||||
* Other defines
|
||||
*/
|
||||
#ifndef MD_STACK_PAD_SIZE
|
||||
#define MD_STACK_PAD_SIZE 128
|
||||
#endif
|
||||
|
||||
#if !defined(MD_HAVE_SOCKLEN_T) && !defined(socklen_t)
|
||||
#define socklen_t int
|
||||
#endif
|
||||
|
||||
#ifndef MD_CAP_STACK
|
||||
#define MD_CAP_STACK(var_addr)
|
||||
#endif
|
||||
|
||||
#endif /* !__ST_MD_H__ */
|
||||
|
|
@ -1,164 +0,0 @@
|
|||
/*
|
||||
* The contents of this file are subject to the Mozilla Public
|
||||
* License Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a copy of
|
||||
* the License at http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS
|
||||
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
||||
* implied. See the License for the specific language governing
|
||||
* rights and limitations under the License.
|
||||
*
|
||||
* The Original Code is the Netscape Portable Runtime library.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1994-2000 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s): Silicon Graphics, Inc.
|
||||
*
|
||||
* Portions created by SGI are Copyright (C) 2000-2001 Silicon
|
||||
* Graphics, Inc. All Rights Reserved.
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the
|
||||
* terms of the GNU General Public License Version 2 or later (the
|
||||
* "GPL"), in which case the provisions of the GPL are applicable
|
||||
* instead of those above. If you wish to allow use of your
|
||||
* version of this file only under the terms of the GPL and not to
|
||||
* allow others to use your version of this file under the MPL,
|
||||
* indicate your decision by deleting the provisions above and
|
||||
* replace them with the notice and other provisions required by
|
||||
* the GPL. If you do not delete the provisions above, a recipient
|
||||
* may use your version of this file under either the MPL or the
|
||||
* GPL.
|
||||
*/
|
||||
|
||||
#ifndef __ST_THREAD_H__
|
||||
#define __ST_THREAD_H__
|
||||
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/uio.h>
|
||||
#include <time.h>
|
||||
#include <errno.h>
|
||||
#include <poll.h>
|
||||
|
||||
#define ST_VERSION "1.9"
|
||||
#define ST_VERSION_MAJOR 1
|
||||
#define ST_VERSION_MINOR 9
|
||||
|
||||
/* Undefine this to remove the context switch callback feature. */
|
||||
#define ST_SWITCH_CB
|
||||
|
||||
#ifndef ETIME
|
||||
#define ETIME ETIMEDOUT
|
||||
#endif
|
||||
|
||||
#ifndef ST_UTIME_NO_TIMEOUT
|
||||
#define ST_UTIME_NO_TIMEOUT ((st_utime_t) -1LL)
|
||||
#endif
|
||||
|
||||
#ifndef ST_UTIME_NO_WAIT
|
||||
#define ST_UTIME_NO_WAIT 0
|
||||
#endif
|
||||
|
||||
#define ST_EVENTSYS_DEFAULT 0
|
||||
#define ST_EVENTSYS_SELECT 1
|
||||
#define ST_EVENTSYS_POLL 2
|
||||
#define ST_EVENTSYS_ALT 3
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
typedef unsigned long long st_utime_t;
|
||||
typedef struct _st_thread * st_thread_t;
|
||||
typedef struct _st_cond * st_cond_t;
|
||||
typedef struct _st_mutex * st_mutex_t;
|
||||
typedef struct _st_netfd * st_netfd_t;
|
||||
#ifdef ST_SWITCH_CB
|
||||
typedef void (*st_switch_cb_t)(void);
|
||||
#endif
|
||||
|
||||
extern int st_init(void);
|
||||
extern int st_getfdlimit(void);
|
||||
|
||||
extern int st_set_eventsys(int eventsys);
|
||||
extern int st_get_eventsys(void);
|
||||
extern const char *st_get_eventsys_name(void);
|
||||
|
||||
#ifdef ST_SWITCH_CB
|
||||
extern st_switch_cb_t st_set_switch_in_cb(st_switch_cb_t cb);
|
||||
extern st_switch_cb_t st_set_switch_out_cb(st_switch_cb_t cb);
|
||||
#endif
|
||||
|
||||
extern st_thread_t st_thread_self(void);
|
||||
extern void st_thread_exit(void *retval);
|
||||
extern int st_thread_join(st_thread_t trd, void **retvalp);
|
||||
extern void st_thread_interrupt(st_thread_t trd);
|
||||
extern st_thread_t st_thread_create(void *(*start)(void *arg), void *arg, int joinable, int stack_size);
|
||||
extern int st_randomize_stacks(int on);
|
||||
extern int st_set_utime_function(st_utime_t (*func)(void));
|
||||
|
||||
extern st_utime_t st_utime(void);
|
||||
extern st_utime_t st_utime_last_clock(void);
|
||||
extern int st_timecache_set(int on);
|
||||
extern time_t st_time(void);
|
||||
extern int st_usleep(st_utime_t usecs);
|
||||
extern int st_sleep(int secs);
|
||||
extern st_cond_t st_cond_new(void);
|
||||
extern int st_cond_destroy(st_cond_t cvar);
|
||||
extern int st_cond_timedwait(st_cond_t cvar, st_utime_t timeout);
|
||||
extern int st_cond_wait(st_cond_t cvar);
|
||||
extern int st_cond_signal(st_cond_t cvar);
|
||||
extern int st_cond_broadcast(st_cond_t cvar);
|
||||
extern st_mutex_t st_mutex_new(void);
|
||||
extern int st_mutex_destroy(st_mutex_t lock);
|
||||
extern int st_mutex_lock(st_mutex_t lock);
|
||||
extern int st_mutex_unlock(st_mutex_t lock);
|
||||
extern int st_mutex_trylock(st_mutex_t lock);
|
||||
|
||||
extern int st_key_create(int *keyp, void (*destructor)(void *));
|
||||
extern int st_key_getlimit(void);
|
||||
extern int st_thread_setspecific(int key, void *value);
|
||||
extern void *st_thread_getspecific(int key);
|
||||
|
||||
extern st_netfd_t st_netfd_open(int osfd);
|
||||
extern st_netfd_t st_netfd_open_socket(int osfd);
|
||||
extern void st_netfd_free(st_netfd_t fd);
|
||||
extern int st_netfd_close(st_netfd_t fd);
|
||||
extern int st_netfd_fileno(st_netfd_t fd);
|
||||
extern void st_netfd_setspecific(st_netfd_t fd, void *value, void (*destructor)(void *));
|
||||
extern void *st_netfd_getspecific(st_netfd_t fd);
|
||||
extern int st_netfd_serialize_accept(st_netfd_t fd);
|
||||
extern int st_netfd_poll(st_netfd_t fd, int how, st_utime_t timeout);
|
||||
|
||||
extern int st_poll(struct pollfd *pds, int npds, st_utime_t timeout);
|
||||
extern st_netfd_t st_accept(st_netfd_t fd, struct sockaddr *addr, int *addrlen, st_utime_t timeout);
|
||||
extern int st_connect(st_netfd_t fd, const struct sockaddr *addr, int addrlen, st_utime_t timeout);
|
||||
extern ssize_t st_read(st_netfd_t fd, void *buf, size_t nbyte, st_utime_t timeout);
|
||||
extern ssize_t st_read_fully(st_netfd_t fd, void *buf, size_t nbyte, st_utime_t timeout);
|
||||
extern int st_read_resid(st_netfd_t fd, void *buf, size_t *resid, st_utime_t timeout);
|
||||
extern ssize_t st_readv(st_netfd_t fd, const struct iovec *iov, int iov_size, st_utime_t timeout);
|
||||
extern int st_readv_resid(st_netfd_t fd, struct iovec **iov, int *iov_size, st_utime_t timeout);
|
||||
extern ssize_t st_write(st_netfd_t fd, const void *buf, size_t nbyte, st_utime_t timeout);
|
||||
extern int st_write_resid(st_netfd_t fd, const void *buf, size_t *resid, st_utime_t timeout);
|
||||
extern ssize_t st_writev(st_netfd_t fd, const struct iovec *iov, int iov_size, st_utime_t timeout);
|
||||
extern int st_writev_resid(st_netfd_t fd, struct iovec **iov, int *iov_size, st_utime_t timeout);
|
||||
extern int st_recvfrom(st_netfd_t fd, void *buf, int len, struct sockaddr *from, int *fromlen, st_utime_t timeout);
|
||||
extern int st_sendto(st_netfd_t fd, const void *msg, int len, const struct sockaddr *to, int tolen, st_utime_t timeout);
|
||||
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);
|
||||
extern st_netfd_t st_open(const char *path, int oflags, mode_t mode);
|
||||
|
||||
#ifdef DEBUG
|
||||
extern void _st_show_thread_stack(st_thread_t thread, const char *messg);
|
||||
extern void _st_iterate_threads(void);
|
||||
#endif
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* !__ST_THREAD_H__ */
|
||||
|
|
@ -1,680 +0,0 @@
|
|||
/*
|
||||
* The contents of this file are subject to the Mozilla Public
|
||||
* License Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a copy of
|
||||
* the License at http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS
|
||||
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
||||
* implied. See the License for the specific language governing
|
||||
* rights and limitations under the License.
|
||||
*
|
||||
* The Original Code is the Netscape Portable Runtime library.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1994-2000 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s): Silicon Graphics, Inc.
|
||||
*
|
||||
* Portions created by SGI are Copyright (C) 2000-2001 Silicon
|
||||
* Graphics, Inc. All Rights Reserved.
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the
|
||||
* terms of the GNU General Public License Version 2 or later (the
|
||||
* "GPL"), in which case the provisions of the GPL are applicable
|
||||
* instead of those above. If you wish to allow use of your
|
||||
* version of this file only under the terms of the GPL and not to
|
||||
* allow others to use your version of this file under the MPL,
|
||||
* indicate your decision by deleting the provisions above and
|
||||
* replace them with the notice and other provisions required by
|
||||
* the GPL. If you do not delete the provisions above, a recipient
|
||||
* may use your version of this file under either the MPL or the
|
||||
* GPL.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file is derived directly from Netscape Communications Corporation,
|
||||
* and consists of extensive modifications made during the year(s) 1999-2000.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <errno.h>
|
||||
#include "common.h"
|
||||
|
||||
/* Global data */
|
||||
_st_vp_t _st_this_vp; /* This VP */
|
||||
_st_thread_t *_st_this_thread; /* Current thread */
|
||||
int _st_active_count = 0; /* Active thread count */
|
||||
|
||||
time_t _st_curr_time = 0; /* Current time as returned by time(2) */
|
||||
st_utime_t _st_last_tset; /* Last time it was fetched */
|
||||
|
||||
int st_poll(struct pollfd *pds, int npds, st_utime_t timeout)
|
||||
{
|
||||
struct pollfd *pd;
|
||||
struct pollfd *epd = pds + npds;
|
||||
_st_pollq_t pq;
|
||||
_st_thread_t *me = _ST_CURRENT_THREAD();
|
||||
int n;
|
||||
|
||||
if (me->flags & _ST_FL_INTERRUPT) {
|
||||
me->flags &= ~_ST_FL_INTERRUPT;
|
||||
errno = EINTR;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((*_st_eventsys->pollset_add)(pds, npds) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
pq.pds = pds;
|
||||
pq.npds = npds;
|
||||
pq.thread = me;
|
||||
pq.on_ioq = 1;
|
||||
_ST_ADD_IOQ(pq);
|
||||
if (timeout != ST_UTIME_NO_TIMEOUT) {
|
||||
_ST_ADD_SLEEPQ(me, timeout);
|
||||
}
|
||||
me->state = _ST_ST_IO_WAIT;
|
||||
|
||||
_ST_SWITCH_CONTEXT(me);
|
||||
|
||||
n = 0;
|
||||
if (pq.on_ioq) {
|
||||
/* If we timed out, the pollq might still be on the ioq. Remove it */
|
||||
_ST_DEL_IOQ(pq);
|
||||
(*_st_eventsys->pollset_del)(pds, npds);
|
||||
} else {
|
||||
/* Count the number of ready descriptors */
|
||||
for (pd = pds; pd < epd; pd++) {
|
||||
if (pd->revents) {
|
||||
n++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (me->flags & _ST_FL_INTERRUPT) {
|
||||
me->flags &= ~_ST_FL_INTERRUPT;
|
||||
errno = EINTR;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
void _st_vp_schedule(void)
|
||||
{
|
||||
_st_thread_t *trd;
|
||||
|
||||
if (_ST_RUNQ.next != &_ST_RUNQ) {
|
||||
/* Pull thread off of the run queue */
|
||||
trd = _ST_THREAD_PTR(_ST_RUNQ.next);
|
||||
_ST_DEL_RUNQ(trd);
|
||||
} else {
|
||||
/* If there are no threads to run, switch to the idle thread */
|
||||
trd = _st_this_vp.idle_thread;
|
||||
}
|
||||
ST_ASSERT(trd->state == _ST_ST_RUNNABLE);
|
||||
|
||||
/* Resume the thread */
|
||||
trd->state = _ST_ST_RUNNING;
|
||||
_ST_RESTORE_CONTEXT(trd);
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize this Virtual Processor
|
||||
*/
|
||||
int st_init(void)
|
||||
{
|
||||
_st_thread_t *trd;
|
||||
|
||||
if (_st_active_count) {
|
||||
/* Already initialized */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* We can ignore return value here */
|
||||
st_set_eventsys(ST_EVENTSYS_DEFAULT);
|
||||
|
||||
if (_st_io_init() < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
memset(&_st_this_vp, 0, sizeof(_st_vp_t));
|
||||
|
||||
ST_INIT_CLIST(&_ST_RUNQ);
|
||||
ST_INIT_CLIST(&_ST_IOQ);
|
||||
ST_INIT_CLIST(&_ST_ZOMBIEQ);
|
||||
#ifdef DEBUG
|
||||
ST_INIT_CLIST(&_ST_THREADQ);
|
||||
#endif
|
||||
|
||||
if ((*_st_eventsys->init)() < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
_st_this_vp.pagesize = getpagesize();
|
||||
_st_this_vp.last_clock = st_utime();
|
||||
|
||||
/*
|
||||
* Create idle thread
|
||||
*/
|
||||
_st_this_vp.idle_thread = st_thread_create(_st_idle_thread_start, NULL, 0, 0);
|
||||
if (!_st_this_vp.idle_thread) {
|
||||
return -1;
|
||||
}
|
||||
_st_this_vp.idle_thread->flags = _ST_FL_IDLE_THREAD;
|
||||
_st_active_count--;
|
||||
_ST_DEL_RUNQ(_st_this_vp.idle_thread);
|
||||
|
||||
/*
|
||||
* Initialize primordial thread
|
||||
*/
|
||||
trd = (_st_thread_t *) calloc(1, sizeof(_st_thread_t) +
|
||||
(ST_KEYS_MAX * sizeof(void *)));
|
||||
if (!trd) {
|
||||
return -1;
|
||||
}
|
||||
trd->private_data = (void **) (trd + 1);
|
||||
trd->state = _ST_ST_RUNNING;
|
||||
trd->flags = _ST_FL_PRIMORDIAL;
|
||||
_ST_SET_CURRENT_THREAD(trd);
|
||||
_st_active_count++;
|
||||
#ifdef DEBUG
|
||||
_ST_ADD_THREADQ(trd);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef ST_SWITCH_CB
|
||||
st_switch_cb_t st_set_switch_in_cb(st_switch_cb_t cb)
|
||||
{
|
||||
st_switch_cb_t ocb = _st_this_vp.switch_in_cb;
|
||||
_st_this_vp.switch_in_cb = cb;
|
||||
return ocb;
|
||||
}
|
||||
|
||||
st_switch_cb_t st_set_switch_out_cb(st_switch_cb_t cb)
|
||||
{
|
||||
st_switch_cb_t ocb = _st_this_vp.switch_out_cb;
|
||||
_st_this_vp.switch_out_cb = cb;
|
||||
return ocb;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Start function for the idle thread
|
||||
*/
|
||||
/* ARGSUSED */
|
||||
void *_st_idle_thread_start(void *arg)
|
||||
{
|
||||
_st_thread_t *me = _ST_CURRENT_THREAD();
|
||||
|
||||
while (_st_active_count > 0) {
|
||||
/* Idle vp till I/O is ready or the smallest timeout expired */
|
||||
_ST_VP_IDLE();
|
||||
|
||||
/* Check sleep queue for expired threads */
|
||||
_st_vp_check_clock();
|
||||
|
||||
me->state = _ST_ST_RUNNABLE;
|
||||
_ST_SWITCH_CONTEXT(me);
|
||||
}
|
||||
|
||||
/* No more threads */
|
||||
exit(0);
|
||||
|
||||
/* NOTREACHED */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void st_thread_exit(void *retval)
|
||||
{
|
||||
_st_thread_t *trd = _ST_CURRENT_THREAD();
|
||||
|
||||
trd->retval = retval;
|
||||
_st_thread_cleanup(trd);
|
||||
_st_active_count--;
|
||||
if (trd->term) {
|
||||
/* Put thread on the zombie queue */
|
||||
trd->state = _ST_ST_ZOMBIE;
|
||||
_ST_ADD_ZOMBIEQ(trd);
|
||||
|
||||
/* Notify on our termination condition variable */
|
||||
st_cond_signal(trd->term);
|
||||
|
||||
/* Switch context and come back later */
|
||||
_ST_SWITCH_CONTEXT(trd);
|
||||
|
||||
/* Continue the cleanup */
|
||||
st_cond_destroy(trd->term);
|
||||
trd->term = NULL;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
_ST_DEL_THREADQ(trd);
|
||||
#endif
|
||||
|
||||
if (!(trd->flags & _ST_FL_PRIMORDIAL)) {
|
||||
_st_stack_free(trd->stack);
|
||||
}
|
||||
|
||||
/* Find another thread to run */
|
||||
_ST_SWITCH_CONTEXT(trd);
|
||||
/* Not going to land here */
|
||||
}
|
||||
|
||||
int st_thread_join(_st_thread_t *trd, void **retvalp)
|
||||
{
|
||||
_st_cond_t *term = trd->term;
|
||||
|
||||
/* Can't join a non-joinable thread */
|
||||
if (term == NULL) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
if (_ST_CURRENT_THREAD() == trd) {
|
||||
errno = EDEADLK;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Multiple threads can't wait on the same joinable thread */
|
||||
if (term->wait_q.next != &term->wait_q) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
while (trd->state != _ST_ST_ZOMBIE) {
|
||||
if (st_cond_timedwait(term, ST_UTIME_NO_TIMEOUT) != 0) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (retvalp) {
|
||||
*retvalp = trd->retval;
|
||||
}
|
||||
|
||||
/*
|
||||
* Remove target thread from the zombie queue and make it runnable.
|
||||
* When it gets scheduled later, it will do the clean up.
|
||||
*/
|
||||
trd->state = _ST_ST_RUNNABLE;
|
||||
_ST_DEL_ZOMBIEQ(trd);
|
||||
_ST_ADD_RUNQ(trd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void _st_thread_main(void)
|
||||
{
|
||||
_st_thread_t *trd = _ST_CURRENT_THREAD();
|
||||
|
||||
/*
|
||||
* Cap the stack by zeroing out the saved return address register
|
||||
* value. This allows some debugging/profiling tools to know when
|
||||
* to stop unwinding the stack. It's a no-op on most platforms.
|
||||
*/
|
||||
MD_CAP_STACK(&trd);
|
||||
|
||||
/* Run thread main */
|
||||
trd->retval = (*trd->start)(trd->arg);
|
||||
|
||||
/* All done, time to go away */
|
||||
st_thread_exit(trd->retval);
|
||||
}
|
||||
|
||||
/*
|
||||
* Insert "thread" into the timeout heap, in the position
|
||||
* specified by thread->heap_index. See docs/timeout_heap.txt
|
||||
* for details about the timeout heap.
|
||||
*/
|
||||
static _st_thread_t **heap_insert(_st_thread_t *trd)
|
||||
{
|
||||
int target = trd->heap_index;
|
||||
int s = target;
|
||||
_st_thread_t **p = &_ST_SLEEPQ;
|
||||
int bits = 0;
|
||||
int bit;
|
||||
int index = 1;
|
||||
|
||||
while (s) {
|
||||
s >>= 1;
|
||||
bits++;
|
||||
}
|
||||
|
||||
for (bit = bits - 2; bit >= 0; bit--) {
|
||||
if (trd->due < (*p)->due) {
|
||||
_st_thread_t *t = *p;
|
||||
trd->left = t->left;
|
||||
trd->right = t->right;
|
||||
*p = trd;
|
||||
trd->heap_index = index;
|
||||
trd = t;
|
||||
}
|
||||
index <<= 1;
|
||||
if (target & (1 << bit)) {
|
||||
p = &((*p)->right);
|
||||
index |= 1;
|
||||
} else {
|
||||
p = &((*p)->left);
|
||||
}
|
||||
}
|
||||
|
||||
trd->heap_index = index;
|
||||
*p = trd;
|
||||
trd->left = trd->right = NULL;
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
/*
|
||||
* Delete "thread" from the timeout heap.
|
||||
*/
|
||||
static void heap_delete(_st_thread_t *trd)
|
||||
{
|
||||
_st_thread_t *t, **p;
|
||||
int bits = 0;
|
||||
int s, bit;
|
||||
|
||||
/* First find and unlink the last heap element */
|
||||
p = &_ST_SLEEPQ;
|
||||
s = _ST_SLEEPQ_SIZE;
|
||||
while (s) {
|
||||
s >>= 1;
|
||||
bits++;
|
||||
}
|
||||
|
||||
for (bit = bits - 2; bit >= 0; bit--) {
|
||||
if (_ST_SLEEPQ_SIZE & (1 << bit)) {
|
||||
p = &((*p)->right);
|
||||
} else {
|
||||
p = &((*p)->left);
|
||||
}
|
||||
}
|
||||
|
||||
t = *p;
|
||||
*p = NULL;
|
||||
--_ST_SLEEPQ_SIZE;
|
||||
if (t != trd) {
|
||||
/*
|
||||
* Insert the unlinked last element in place of the element we are deleting
|
||||
*/
|
||||
t->heap_index = trd->heap_index;
|
||||
p = heap_insert(t);
|
||||
t = *p;
|
||||
t->left = trd->left;
|
||||
t->right = trd->right;
|
||||
|
||||
/*
|
||||
* Reestablish the heap invariant.
|
||||
*/
|
||||
for (;;) {
|
||||
_st_thread_t *y; /* The younger child */
|
||||
int index_tmp;
|
||||
|
||||
if (t->left == NULL) {
|
||||
break;
|
||||
} else if (t->right == NULL) {
|
||||
y = t->left;
|
||||
} else if (t->left->due < t->right->due) {
|
||||
y = t->left;
|
||||
} else {
|
||||
y = t->right;
|
||||
}
|
||||
|
||||
if (t->due > y->due) {
|
||||
_st_thread_t *tl = y->left;
|
||||
_st_thread_t *tr = y->right;
|
||||
*p = y;
|
||||
if (y == t->left) {
|
||||
y->left = t;
|
||||
y->right = t->right;
|
||||
p = &y->left;
|
||||
} else {
|
||||
y->left = t->left;
|
||||
y->right = t;
|
||||
p = &y->right;
|
||||
}
|
||||
t->left = tl;
|
||||
t->right = tr;
|
||||
index_tmp = t->heap_index;
|
||||
t->heap_index = y->heap_index;
|
||||
y->heap_index = index_tmp;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
trd->left = trd->right = NULL;
|
||||
}
|
||||
|
||||
void _st_add_sleep_q(_st_thread_t *trd, st_utime_t timeout)
|
||||
{
|
||||
trd->due = _ST_LAST_CLOCK + timeout;
|
||||
trd->flags |= _ST_FL_ON_SLEEPQ;
|
||||
trd->heap_index = ++_ST_SLEEPQ_SIZE;
|
||||
heap_insert(trd);
|
||||
}
|
||||
|
||||
void _st_del_sleep_q(_st_thread_t *trd)
|
||||
{
|
||||
heap_delete(trd);
|
||||
trd->flags &= ~_ST_FL_ON_SLEEPQ;
|
||||
}
|
||||
|
||||
void _st_vp_check_clock(void)
|
||||
{
|
||||
_st_thread_t *trd;
|
||||
st_utime_t elapsed, now;
|
||||
|
||||
now = st_utime();
|
||||
elapsed = now - _ST_LAST_CLOCK;
|
||||
_ST_LAST_CLOCK = now;
|
||||
|
||||
if (_st_curr_time && now - _st_last_tset > 999000) {
|
||||
_st_curr_time = time(NULL);
|
||||
_st_last_tset = now;
|
||||
}
|
||||
|
||||
while (_ST_SLEEPQ != NULL) {
|
||||
trd = _ST_SLEEPQ;
|
||||
ST_ASSERT(trd->flags & _ST_FL_ON_SLEEPQ);
|
||||
if (trd->due > now) {
|
||||
break;
|
||||
}
|
||||
_ST_DEL_SLEEPQ(trd);
|
||||
|
||||
/* If thread is waiting on condition variable, set the time out flag */
|
||||
if (trd->state == _ST_ST_COND_WAIT) {
|
||||
trd->flags |= _ST_FL_TIMEDOUT;
|
||||
}
|
||||
|
||||
/* Make thread runnable */
|
||||
ST_ASSERT(!(trd->flags & _ST_FL_IDLE_THREAD));
|
||||
trd->state = _ST_ST_RUNNABLE;
|
||||
_ST_ADD_RUNQ(trd);
|
||||
}
|
||||
}
|
||||
|
||||
void st_thread_interrupt(_st_thread_t* trd)
|
||||
{
|
||||
/* If thread is already dead */
|
||||
if (trd->state == _ST_ST_ZOMBIE) {
|
||||
return;
|
||||
}
|
||||
|
||||
trd->flags |= _ST_FL_INTERRUPT;
|
||||
|
||||
if (trd->state == _ST_ST_RUNNING || trd->state == _ST_ST_RUNNABLE) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (trd->flags & _ST_FL_ON_SLEEPQ) {
|
||||
_ST_DEL_SLEEPQ(trd);
|
||||
}
|
||||
|
||||
/* Make thread runnable */
|
||||
trd->state = _ST_ST_RUNNABLE;
|
||||
_ST_ADD_RUNQ(trd);
|
||||
}
|
||||
|
||||
_st_thread_t *st_thread_create(void *(*start)(void *arg), void *arg, int joinable, int stk_size)
|
||||
{
|
||||
_st_thread_t *trd;
|
||||
_st_stack_t *stack;
|
||||
void **ptds;
|
||||
char *sp;
|
||||
|
||||
/* Adjust stack size */
|
||||
if (stk_size == 0) {
|
||||
stk_size = ST_DEFAULT_STACK_SIZE;
|
||||
}
|
||||
stk_size = ((stk_size + _ST_PAGE_SIZE - 1) / _ST_PAGE_SIZE) * _ST_PAGE_SIZE;
|
||||
stack = _st_stack_new(stk_size);
|
||||
if (!stack) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Allocate thread object and per-thread data off the stack */
|
||||
#if defined (MD_STACK_GROWS_DOWN)
|
||||
sp = stack->stk_top;
|
||||
/*
|
||||
* The stack segment is split in the middle. The upper half is used
|
||||
* as backing store for the register stack which grows upward.
|
||||
* The lower half is used for the traditional memory stack which
|
||||
* grows downward. Both stacks start in the middle and grow outward
|
||||
* from each other.
|
||||
*/
|
||||
/**
|
||||
The below comments is by winlin:
|
||||
The Stack public structure:
|
||||
+--------------------------------------------------------------+
|
||||
| stack |
|
||||
+--------------------------------------------------------------+
|
||||
bottom top
|
||||
The code bellow use the stack as:
|
||||
+-----------------+-----------------+-------------+------------+
|
||||
| stack of thread |pad+align(128B+) |thread(336B) | keys(128B) |
|
||||
+-----------------+-----------------+-------------+------------+
|
||||
bottom sp trd ptds top
|
||||
(context[0].__jmpbuf.sp) (private_data)
|
||||
*/
|
||||
sp = sp - (ST_KEYS_MAX * sizeof(void *));
|
||||
ptds = (void **) sp;
|
||||
sp = sp - sizeof(_st_thread_t);
|
||||
trd = (_st_thread_t *) sp;
|
||||
|
||||
/* Make stack 64-byte aligned */
|
||||
if ((unsigned long)sp & 0x3f) {
|
||||
sp = sp - ((unsigned long)sp & 0x3f);
|
||||
}
|
||||
stack->sp = sp - _ST_STACK_PAD_SIZE;
|
||||
#else
|
||||
#error "Only Supports Stack Grown Down"
|
||||
#endif
|
||||
|
||||
memset(trd, 0, sizeof(_st_thread_t));
|
||||
memset(ptds, 0, ST_KEYS_MAX * sizeof(void *));
|
||||
|
||||
/* Initialize thread */
|
||||
trd->private_data = ptds;
|
||||
trd->stack = stack;
|
||||
trd->start = start;
|
||||
trd->arg = arg;
|
||||
|
||||
// by winlin, expand macro MD_INIT_CONTEXT
|
||||
#if defined(__mips__)
|
||||
MD_SETJMP((trd)->context);
|
||||
trd->context[0].__jmpbuf[0].__pc = (__ptr_t) _st_thread_main;
|
||||
trd->context[0].__jmpbuf[0].__sp = stack->sp;
|
||||
#else
|
||||
if (MD_SETJMP((trd)->context)) {
|
||||
_st_thread_main();
|
||||
}
|
||||
MD_GET_SP(trd) = (long) (stack->sp);
|
||||
#endif
|
||||
|
||||
/* If thread is joinable, allocate a termination condition variable */
|
||||
if (joinable) {
|
||||
trd->term = st_cond_new();
|
||||
if (trd->term == NULL) {
|
||||
_st_stack_free(trd->stack);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* Make thread runnable */
|
||||
trd->state = _ST_ST_RUNNABLE;
|
||||
_st_active_count++;
|
||||
_ST_ADD_RUNQ(trd);
|
||||
#ifdef DEBUG
|
||||
_ST_ADD_THREADQ(trd);
|
||||
#endif
|
||||
|
||||
return trd;
|
||||
}
|
||||
|
||||
_st_thread_t *st_thread_self(void)
|
||||
{
|
||||
return _ST_CURRENT_THREAD();
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
/* ARGSUSED */
|
||||
void _st_show_thread_stack(_st_thread_t *trd, const char *messg)
|
||||
{
|
||||
}
|
||||
|
||||
/* To be set from debugger */
|
||||
int _st_iterate_threads_flag = 0;
|
||||
|
||||
void _st_iterate_threads(void)
|
||||
{
|
||||
static _st_thread_t *trd = NULL;
|
||||
static jmp_buf orig_jb, save_jb;
|
||||
_st_clist_t *q;
|
||||
|
||||
if (!_st_iterate_threads_flag) {
|
||||
if (trd) {
|
||||
memcpy(trd->context, save_jb, sizeof(jmp_buf));
|
||||
MD_LONGJMP(orig_jb, 1);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (trd) {
|
||||
memcpy(trd->context, save_jb, sizeof(jmp_buf));
|
||||
_st_show_thread_stack(trd, NULL);
|
||||
} else {
|
||||
if (MD_SETJMP(orig_jb)) {
|
||||
_st_iterate_threads_flag = 0;
|
||||
trd = NULL;
|
||||
_st_show_thread_stack(trd, "Iteration completed");
|
||||
return;
|
||||
}
|
||||
trd = _ST_CURRENT_THREAD();
|
||||
_st_show_thread_stack(trd, "Iteration started");
|
||||
}
|
||||
|
||||
q = trd->tlink.next;
|
||||
if (q == &_ST_THREADQ) {
|
||||
q = q->next;
|
||||
}
|
||||
ST_ASSERT(q != &_ST_THREADQ);
|
||||
trd = _ST_THREAD_THREADQ_PTR(q);
|
||||
if (trd == _ST_CURRENT_THREAD()) {
|
||||
MD_LONGJMP(orig_jb, 1);
|
||||
}
|
||||
memcpy(save_jb, trd->context, sizeof(jmp_buf));
|
||||
MD_LONGJMP(trd->context, 1);
|
||||
}
|
||||
#endif /* DEBUG */
|
||||
|
|
@ -1,497 +0,0 @@
|
|||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <signal.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include "public.h"
|
||||
|
||||
#define srs_trace(msg, ...) printf(msg, ##__VA_ARGS__);printf("\n")
|
||||
|
||||
int io_port = 1990;
|
||||
int sleep_ms = 100;
|
||||
|
||||
void stack_print(long int previous_sp, int level)
|
||||
{
|
||||
if (level <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
register long int rsp asm("sp");
|
||||
char buf[level * 1024];
|
||||
|
||||
stack_print(rsp, level - 1);
|
||||
|
||||
srs_trace("%d. psp=%#lx, sp=%#lx, size=%dB(%dB+%dKB)",
|
||||
level, previous_sp, rsp, (int)(previous_sp - rsp),
|
||||
(int)(previous_sp - rsp - sizeof(buf)), (int)(sizeof(buf) / 1024));
|
||||
}
|
||||
|
||||
int huge_stack_test()
|
||||
{
|
||||
srs_trace("===================================================");
|
||||
srs_trace("huge_stack test: start");
|
||||
|
||||
register long int rsp asm("sp");
|
||||
stack_print(rsp, 10);
|
||||
|
||||
srs_trace("huge_stack test: end");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sleep_test()
|
||||
{
|
||||
srs_trace("===================================================");
|
||||
srs_trace("sleep test: start");
|
||||
|
||||
srs_trace("1. sleep...");
|
||||
st_utime_t start = st_utime();
|
||||
st_usleep(sleep_ms * 1000);
|
||||
st_utime_t end = st_utime();
|
||||
|
||||
srs_trace("2. sleep ok, sleep=%dus, deviation=%dus",
|
||||
(int)(sleep_ms * 1000), (int)(end - start - sleep_ms * 1000));
|
||||
|
||||
srs_trace("sleep test: end");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void* sleep2_func0(void* arg)
|
||||
{
|
||||
int sleep_ms = 100;
|
||||
st_utime_t start = st_utime();
|
||||
st_usleep(sleep_ms * 1000);
|
||||
st_utime_t end = st_utime();
|
||||
|
||||
srs_trace("sleep ok, sleep=%dus, deviation=%dus",
|
||||
(int)(sleep_ms * 1000), (int)(end - start - sleep_ms * 1000));
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void* sleep2_func1(void* arg)
|
||||
{
|
||||
int sleep_ms = 250;
|
||||
st_utime_t start = st_utime();
|
||||
st_usleep(sleep_ms * 1000);
|
||||
st_utime_t end = st_utime();
|
||||
|
||||
srs_trace("sleep ok, sleep=%dus, deviation=%dus",
|
||||
(int)(sleep_ms * 1000), (int)(end - start - sleep_ms * 1000));
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int sleep2_test()
|
||||
{
|
||||
srs_trace("===================================================");
|
||||
srs_trace("sleep2 test: start");
|
||||
|
||||
st_thread_t trd0 = st_thread_create(sleep2_func0, NULL, 1, 0);
|
||||
st_thread_t trd1 = st_thread_create(sleep2_func1, NULL, 1, 0);
|
||||
st_thread_join(trd0, NULL);
|
||||
st_thread_join(trd1, NULL);
|
||||
|
||||
srs_trace("sleep test: end");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
st_mutex_t sleep_work_cond = NULL;
|
||||
void* sleep_deviation_func(void* arg)
|
||||
{
|
||||
st_mutex_lock(sleep_work_cond);
|
||||
srs_trace("2. work thread start.");
|
||||
|
||||
int64_t i;
|
||||
for (i = 0; i < 3000000000ULL; i++) {
|
||||
}
|
||||
|
||||
st_mutex_unlock(sleep_work_cond);
|
||||
srs_trace("3. work thread end.");
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int sleep_deviation_test()
|
||||
{
|
||||
srs_trace("===================================================");
|
||||
srs_trace("sleep deviation test: start");
|
||||
|
||||
sleep_work_cond = st_mutex_new();
|
||||
|
||||
st_thread_create(sleep_deviation_func, NULL, 0, 0);
|
||||
st_mutex_lock(sleep_work_cond);
|
||||
|
||||
srs_trace("1. sleep...");
|
||||
st_utime_t start = st_utime();
|
||||
|
||||
// other thread to do some complex work.
|
||||
st_mutex_unlock(sleep_work_cond);
|
||||
st_usleep(1000 * 1000);
|
||||
|
||||
st_utime_t end = st_utime();
|
||||
|
||||
srs_trace("4. sleep ok, sleep=%dus, deviation=%dus",
|
||||
(int)(sleep_ms * 1000), (int)(end - start - sleep_ms * 1000));
|
||||
|
||||
st_mutex_lock(sleep_work_cond);
|
||||
srs_trace("sleep deviation test: end");
|
||||
|
||||
st_mutex_destroy(sleep_work_cond);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void* thread_func(void* arg)
|
||||
{
|
||||
srs_trace("1. thread run");
|
||||
st_usleep(sleep_ms * 1000);
|
||||
srs_trace("2. thread completed");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int thread_test()
|
||||
{
|
||||
srs_trace("===================================================");
|
||||
srs_trace("thread test: start");
|
||||
|
||||
st_thread_t trd = st_thread_create(thread_func, NULL, 1, 0);
|
||||
if (trd == NULL) {
|
||||
srs_trace("st_thread_create failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
st_thread_join(trd, NULL);
|
||||
srs_trace("3. thread joined");
|
||||
|
||||
srs_trace("thread test: end");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
st_mutex_t sync_start = NULL;
|
||||
st_cond_t sync_cond = NULL;
|
||||
st_mutex_t sync_mutex = NULL;
|
||||
st_cond_t sync_end = NULL;
|
||||
|
||||
void* sync_master(void* arg)
|
||||
{
|
||||
// wait for main to sync_start this thread.
|
||||
st_mutex_lock(sync_start);
|
||||
st_mutex_unlock(sync_start);
|
||||
|
||||
st_usleep(sleep_ms * 1000);
|
||||
st_cond_signal(sync_cond);
|
||||
|
||||
st_mutex_lock(sync_mutex);
|
||||
srs_trace("2. st mutex is ok");
|
||||
st_mutex_unlock(sync_mutex);
|
||||
|
||||
st_usleep(sleep_ms * 1000);
|
||||
srs_trace("3. st thread is ok");
|
||||
st_cond_signal(sync_cond);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void* sync_slave(void* arg)
|
||||
{
|
||||
// lock mutex to control thread.
|
||||
st_mutex_lock(sync_mutex);
|
||||
|
||||
// wait for main to sync_start this thread.
|
||||
st_mutex_lock(sync_start);
|
||||
st_mutex_unlock(sync_start);
|
||||
|
||||
// wait thread to ready.
|
||||
st_cond_wait(sync_cond);
|
||||
srs_trace("1. st cond is ok");
|
||||
|
||||
// release mutex to control thread
|
||||
st_usleep(sleep_ms * 1000);
|
||||
st_mutex_unlock(sync_mutex);
|
||||
|
||||
// wait thread to exit.
|
||||
st_cond_wait(sync_cond);
|
||||
srs_trace("4. st is ok");
|
||||
|
||||
st_cond_signal(sync_end);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int sync_test()
|
||||
{
|
||||
srs_trace("===================================================");
|
||||
srs_trace("sync test: start");
|
||||
|
||||
if ((sync_start = st_mutex_new()) == NULL) {
|
||||
srs_trace("st_mutex_new sync_start failed");
|
||||
return -1;
|
||||
}
|
||||
st_mutex_lock(sync_start);
|
||||
|
||||
if ((sync_cond = st_cond_new()) == NULL) {
|
||||
srs_trace("st_cond_new cond failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((sync_end = st_cond_new()) == NULL) {
|
||||
srs_trace("st_cond_new end failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((sync_mutex = st_mutex_new()) == NULL) {
|
||||
srs_trace("st_mutex_new mutex failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!st_thread_create(sync_master, NULL, 0, 0)) {
|
||||
srs_trace("st_thread_create failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!st_thread_create(sync_slave, NULL, 0, 0)) {
|
||||
srs_trace("st_thread_create failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
// run all threads.
|
||||
st_mutex_unlock(sync_start);
|
||||
|
||||
st_cond_wait(sync_end);
|
||||
srs_trace("sync test: end");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void* io_client(void* arg)
|
||||
{
|
||||
|
||||
int fd;
|
||||
if ((fd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
|
||||
srs_trace("create linux socket error.");
|
||||
return NULL;
|
||||
}
|
||||
srs_trace("6. client create linux socket success. fd=%d", fd);
|
||||
|
||||
st_netfd_t stfd;
|
||||
if ((stfd = st_netfd_open_socket(fd)) == NULL){
|
||||
srs_trace("st_netfd_open_socket open socket failed.");
|
||||
return NULL;
|
||||
}
|
||||
srs_trace("7. client st open socket success. fd=%d", fd);
|
||||
|
||||
struct sockaddr_in addr;
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_port = htons(io_port);
|
||||
addr.sin_addr.s_addr = INADDR_ANY;
|
||||
if (st_connect(stfd, (const struct sockaddr*)&addr, sizeof(struct sockaddr_in), ST_UTIME_NO_TIMEOUT) == -1) {
|
||||
srs_trace("bind socket error.");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char buf[1024];
|
||||
if (st_read_fully(stfd, buf, sizeof(buf), ST_UTIME_NO_TIMEOUT) != sizeof(buf)) {
|
||||
srs_trace("st_read_fully failed");
|
||||
return NULL;
|
||||
}
|
||||
if (st_write(stfd, buf, sizeof(buf), ST_UTIME_NO_TIMEOUT) != sizeof(buf)) {
|
||||
srs_trace("st_write failed");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
st_netfd_close(stfd);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int io_test()
|
||||
{
|
||||
srs_trace("===================================================");
|
||||
srs_trace("io test: start, port=%d", io_port);
|
||||
|
||||
int fd;
|
||||
if ((fd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
|
||||
srs_trace("create linux socket error.");
|
||||
return -1;
|
||||
}
|
||||
srs_trace("1. server create linux socket success. fd=%d", fd);
|
||||
|
||||
int reuse_socket = 1;
|
||||
if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &reuse_socket, sizeof(int)) == -1) {
|
||||
srs_trace("setsockopt reuse-addr error.");
|
||||
return -1;
|
||||
}
|
||||
srs_trace("2. server setsockopt reuse-addr success. fd=%d", fd);
|
||||
|
||||
struct sockaddr_in addr;
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_port = htons(io_port);
|
||||
addr.sin_addr.s_addr = INADDR_ANY;
|
||||
if (bind(fd, (const struct sockaddr*)&addr, sizeof(struct sockaddr_in)) == -1) {
|
||||
srs_trace("bind socket error.");
|
||||
return -1;
|
||||
}
|
||||
srs_trace("3. server bind socket success. fd=%d", fd);
|
||||
|
||||
if (listen(fd, 10) == -1) {
|
||||
srs_trace("listen socket error.");
|
||||
return -1;
|
||||
}
|
||||
srs_trace("4. server listen socket success. fd=%d", fd);
|
||||
|
||||
st_netfd_t stfd;
|
||||
if ((stfd = st_netfd_open_socket(fd)) == NULL){
|
||||
srs_trace("st_netfd_open_socket open socket failed.");
|
||||
return -1;
|
||||
}
|
||||
srs_trace("5. server st open socket success. fd=%d", fd);
|
||||
|
||||
if (!st_thread_create(io_client, NULL, 0, 0)) {
|
||||
srs_trace("st_thread_create failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
st_netfd_t client_stfd = st_accept(stfd, NULL, NULL, ST_UTIME_NO_TIMEOUT);
|
||||
srs_trace("8. server get a client. fd=%d", st_netfd_fileno(client_stfd));
|
||||
|
||||
char buf[1024];
|
||||
if (st_write(client_stfd, buf, sizeof(buf), ST_UTIME_NO_TIMEOUT) != sizeof(buf)) {
|
||||
srs_trace("st_write failed");
|
||||
return -1;
|
||||
}
|
||||
if (st_read_fully(client_stfd, buf, sizeof(buf), ST_UTIME_NO_TIMEOUT) != sizeof(buf)) {
|
||||
srs_trace("st_read_fully failed");
|
||||
return -1;
|
||||
}
|
||||
srs_trace("9. server io completed.");
|
||||
|
||||
st_netfd_close(stfd);
|
||||
st_netfd_close(client_stfd);
|
||||
|
||||
srs_trace("io test: end");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pipe_test()
|
||||
{
|
||||
srs_trace("===================================================");
|
||||
srs_trace("pipe test: start");
|
||||
|
||||
int fds[2];
|
||||
if (pipe(fds) < 0) {
|
||||
srs_trace("pipe failed");
|
||||
return -1;
|
||||
}
|
||||
srs_trace("1. pipe ok, %d=>%d", fds[1], fds[0]);
|
||||
|
||||
st_netfd_t fdw;
|
||||
if ((fdw = st_netfd_open_socket(fds[1])) == NULL) {
|
||||
srs_trace("st_netfd_open_socket open socket failed.");
|
||||
return -1;
|
||||
}
|
||||
srs_trace("2. open write fd ok");
|
||||
|
||||
st_netfd_t fdr;
|
||||
if ((fdr = st_netfd_open_socket(fds[0])) == NULL) {
|
||||
srs_trace("st_netfd_open_socket open socket failed.");
|
||||
return -1;
|
||||
}
|
||||
srs_trace("3. open read fd ok");
|
||||
|
||||
char buf[1024];
|
||||
if (st_write(fdw, buf, sizeof(buf), ST_UTIME_NO_TIMEOUT) < 0) {
|
||||
srs_trace("st_write socket failed.");
|
||||
return -1;
|
||||
}
|
||||
srs_trace("4. write to pipe ok");
|
||||
|
||||
if (st_read(fdr, buf, sizeof(buf), ST_UTIME_NO_TIMEOUT) < 0) {
|
||||
srs_trace("st_read socket failed.");
|
||||
return -1;
|
||||
}
|
||||
srs_trace("5. read from pipe ok");
|
||||
|
||||
st_netfd_close(fdw);
|
||||
st_netfd_close(fdr);
|
||||
|
||||
srs_trace("pipe test: end");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
srs_trace("ETIME=%d", ETIME);
|
||||
|
||||
if (st_set_eventsys(ST_EVENTSYS_ALT) < 0) {
|
||||
srs_trace("st_set_eventsys failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (st_init() < 0) {
|
||||
srs_trace("st_init failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (sleep2_test() < 0) {
|
||||
srs_trace("sleep2_test failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (sleep_test() < 0) {
|
||||
srs_trace("sleep_test failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (sleep_deviation_test() < 0) {
|
||||
srs_trace("sleep_deviation_test failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (huge_stack_test() < 0) {
|
||||
srs_trace("huge_stack_test failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (thread_test() < 0) {
|
||||
srs_trace("thread_test failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (sync_test() < 0) {
|
||||
srs_trace("sync_test failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (io_test() < 0) {
|
||||
srs_trace("io_test failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (pipe_test() < 0) {
|
||||
srs_trace("pipe_test failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
// cleanup.
|
||||
srs_trace("wait for all thread completed");
|
||||
st_thread_exit(NULL);
|
||||
// the following never enter,
|
||||
// the above code will exit when all thread exit,
|
||||
// current is a primordial st-thread, when all thread exit,
|
||||
// the st idle thread will exit(0), see _st_idle_thread_start()
|
||||
srs_trace("all thread completed");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1,3 +0,0 @@
|
|||
#ifndef _st_icpp_init_stub
|
||||
#define _st_icpp_init_stub
|
||||
#endif
|
|
@ -1,18 +0,0 @@
|
|||
file
|
||||
main readonly separator,
|
||||
..\srs.c,
|
||||
st readonly separator,
|
||||
..\common.h,
|
||||
..\event.c,
|
||||
..\io.c,
|
||||
..\key.c,
|
||||
..\md.h,
|
||||
..\md.S,
|
||||
..\public.h,
|
||||
..\sched.c,
|
||||
..\stk.c,
|
||||
..\sync.c;
|
||||
|
||||
mainconfig
|
||||
"" = "MAIN";
|
||||
|
|
@ -1,169 +0,0 @@
|
|||
/*
|
||||
* The contents of this file are subject to the Mozilla Public
|
||||
* License Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a copy of
|
||||
* the License at http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS
|
||||
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
||||
* implied. See the License for the specific language governing
|
||||
* rights and limitations under the License.
|
||||
*
|
||||
* The Original Code is the Netscape Portable Runtime library.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1994-2000 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s): Silicon Graphics, Inc.
|
||||
*
|
||||
* Portions created by SGI are Copyright (C) 2000-2001 Silicon
|
||||
* Graphics, Inc. All Rights Reserved.
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the
|
||||
* terms of the GNU General Public License Version 2 or later (the
|
||||
* "GPL"), in which case the provisions of the GPL are applicable
|
||||
* instead of those above. If you wish to allow use of your
|
||||
* version of this file only under the terms of the GPL and not to
|
||||
* allow others to use your version of this file under the MPL,
|
||||
* indicate your decision by deleting the provisions above and
|
||||
* replace them with the notice and other provisions required by
|
||||
* the GPL. If you do not delete the provisions above, a recipient
|
||||
* may use your version of this file under either the MPL or the
|
||||
* GPL.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file is derived directly from Netscape Communications Corporation,
|
||||
* and consists of extensive modifications made during the year(s) 1999-2000.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/mman.h>
|
||||
#include "common.h"
|
||||
|
||||
/* How much space to leave between the stacks, at each end */
|
||||
#define REDZONE _ST_PAGE_SIZE
|
||||
|
||||
_st_clist_t _st_free_stacks = ST_INIT_STATIC_CLIST(&_st_free_stacks);
|
||||
int _st_num_free_stacks = 0;
|
||||
int _st_randomize_stacks = 0;
|
||||
|
||||
static char *_st_new_stk_segment(int size);
|
||||
|
||||
/**
|
||||
The below comments is by winlin:
|
||||
The stack memory struct:
|
||||
| REDZONE | stack | extra | REDZONE |
|
||||
+---------+------------------------+---------+---------+
|
||||
| 4k | | 4k/0 | 4k |
|
||||
+---------+------------------------+---------+---------+
|
||||
vaddr bottom top
|
||||
When _st_randomize_stacks is on, by st_randomize_stacks(),
|
||||
the bottom and top will random movided in the extra:
|
||||
long offset = (random() % extra) & ~0xf;
|
||||
ts->stk_bottom += offset;
|
||||
ts->stk_top += offset;
|
||||
Both REDZONE are protected by mprotect when DEBUG is on.
|
||||
*/
|
||||
_st_stack_t *_st_stack_new(int stack_size)
|
||||
{
|
||||
_st_clist_t *qp;
|
||||
_st_stack_t *ts;
|
||||
int extra;
|
||||
|
||||
// TODO: WINLIN: remove the stack reuse.
|
||||
for (qp = _st_free_stacks.next; qp != &_st_free_stacks; qp = qp->next) {
|
||||
ts = _ST_THREAD_STACK_PTR(qp);
|
||||
if (ts->stk_size >= stack_size) {
|
||||
/* Found a stack that is big enough */
|
||||
ST_REMOVE_LINK(&ts->links);
|
||||
_st_num_free_stacks--;
|
||||
ts->links.next = NULL;
|
||||
ts->links.prev = NULL;
|
||||
return ts;
|
||||
}
|
||||
}
|
||||
|
||||
/* Make a new thread stack object. */
|
||||
if ((ts = (_st_stack_t *)calloc(1, sizeof(_st_stack_t))) == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
extra = _st_randomize_stacks ? _ST_PAGE_SIZE : 0;
|
||||
ts->vaddr_size = stack_size + 2*REDZONE + extra;
|
||||
ts->vaddr = _st_new_stk_segment(ts->vaddr_size);
|
||||
if (!ts->vaddr) {
|
||||
free(ts);
|
||||
return NULL;
|
||||
}
|
||||
ts->stk_size = stack_size;
|
||||
ts->stk_bottom = ts->vaddr + REDZONE;
|
||||
ts->stk_top = ts->stk_bottom + stack_size;
|
||||
|
||||
#ifdef DEBUG
|
||||
mprotect(ts->vaddr, REDZONE, PROT_NONE);
|
||||
mprotect(ts->stk_top + extra, REDZONE, PROT_NONE);
|
||||
#endif
|
||||
|
||||
if (extra) {
|
||||
long offset = (random() % extra) & ~0xf;
|
||||
|
||||
ts->stk_bottom += offset;
|
||||
ts->stk_top += offset;
|
||||
}
|
||||
|
||||
return ts;
|
||||
}
|
||||
|
||||
/*
|
||||
* Free the stack for the current thread
|
||||
*/
|
||||
void _st_stack_free(_st_stack_t *ts)
|
||||
{
|
||||
if (!ts) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Put the stack on the free list */
|
||||
ST_APPEND_LINK(&ts->links, _st_free_stacks.prev);
|
||||
_st_num_free_stacks++;
|
||||
}
|
||||
|
||||
static char *_st_new_stk_segment(int size)
|
||||
{
|
||||
#ifdef MALLOC_STACK
|
||||
void *vaddr = malloc(size);
|
||||
#else
|
||||
#error "Only Supports Malloc Stack"
|
||||
#endif
|
||||
|
||||
return (char *)vaddr;
|
||||
}
|
||||
|
||||
/* Not used */
|
||||
#if 0
|
||||
void _st_delete_stk_segment(char *vaddr, int size)
|
||||
{
|
||||
#ifdef MALLOC_STACK
|
||||
free(vaddr);
|
||||
#else
|
||||
#error Unknown Stack Malloc
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
int st_randomize_stacks(int on)
|
||||
{
|
||||
int wason = _st_randomize_stacks;
|
||||
|
||||
_st_randomize_stacks = on;
|
||||
if (on) {
|
||||
srandom((unsigned int) st_utime());
|
||||
}
|
||||
|
||||
return wason;
|
||||
}
|
|
@ -1,352 +0,0 @@
|
|||
/*
|
||||
* The contents of this file are subject to the Mozilla Public
|
||||
* License Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a copy of
|
||||
* the License at http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS
|
||||
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
||||
* implied. See the License for the specific language governing
|
||||
* rights and limitations under the License.
|
||||
*
|
||||
* The Original Code is the Netscape Portable Runtime library.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1994-2000 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s): Silicon Graphics, Inc.
|
||||
*
|
||||
* Portions created by SGI are Copyright (C) 2000-2001 Silicon
|
||||
* Graphics, Inc. All Rights Reserved.
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the
|
||||
* terms of the GNU General Public License Version 2 or later (the
|
||||
* "GPL"), in which case the provisions of the GPL are applicable
|
||||
* instead of those above. If you wish to allow use of your
|
||||
* version of this file only under the terms of the GPL and not to
|
||||
* allow others to use your version of this file under the MPL,
|
||||
* indicate your decision by deleting the provisions above and
|
||||
* replace them with the notice and other provisions required by
|
||||
* the GPL. If you do not delete the provisions above, a recipient
|
||||
* may use your version of this file under either the MPL or the
|
||||
* GPL.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file is derived directly from Netscape Communications Corporation,
|
||||
* and consists of extensive modifications made during the year(s) 1999-2000.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
#include <errno.h>
|
||||
#include "common.h"
|
||||
|
||||
extern time_t _st_curr_time;
|
||||
extern st_utime_t _st_last_tset;
|
||||
extern int _st_active_count;
|
||||
|
||||
static st_utime_t (*_st_utime)(void) = NULL;
|
||||
|
||||
/*****************************************
|
||||
* Time functions
|
||||
*/
|
||||
|
||||
st_utime_t st_utime(void)
|
||||
{
|
||||
if (_st_utime == NULL) {
|
||||
#ifdef MD_GET_UTIME
|
||||
MD_GET_UTIME();
|
||||
#else
|
||||
#error Unknown OS
|
||||
#endif
|
||||
}
|
||||
|
||||
return (*_st_utime)();
|
||||
}
|
||||
|
||||
int st_set_utime_function(st_utime_t (*func)(void))
|
||||
{
|
||||
if (_st_active_count) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
_st_utime = func;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
st_utime_t st_utime_last_clock(void)
|
||||
{
|
||||
return _ST_LAST_CLOCK;
|
||||
}
|
||||
|
||||
int st_timecache_set(int on)
|
||||
{
|
||||
int wason = (_st_curr_time) ? 1 : 0;
|
||||
|
||||
if (on) {
|
||||
_st_curr_time = time(NULL);
|
||||
_st_last_tset = st_utime();
|
||||
} else {
|
||||
_st_curr_time = 0;
|
||||
}
|
||||
|
||||
return wason;
|
||||
}
|
||||
|
||||
time_t st_time(void)
|
||||
{
|
||||
if (_st_curr_time) {
|
||||
return _st_curr_time;
|
||||
}
|
||||
|
||||
return time(NULL);
|
||||
}
|
||||
|
||||
int st_usleep(st_utime_t usecs)
|
||||
{
|
||||
_st_thread_t *me = _ST_CURRENT_THREAD();
|
||||
|
||||
if (me->flags & _ST_FL_INTERRUPT) {
|
||||
me->flags &= ~_ST_FL_INTERRUPT;
|
||||
errno = EINTR;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (usecs != ST_UTIME_NO_TIMEOUT) {
|
||||
me->state = _ST_ST_SLEEPING;
|
||||
_ST_ADD_SLEEPQ(me, usecs);
|
||||
} else {
|
||||
me->state = _ST_ST_SUSPENDED;
|
||||
}
|
||||
|
||||
_ST_SWITCH_CONTEXT(me);
|
||||
|
||||
if (me->flags & _ST_FL_INTERRUPT) {
|
||||
me->flags &= ~_ST_FL_INTERRUPT;
|
||||
errno = EINTR;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int st_sleep(int secs)
|
||||
{
|
||||
return st_usleep((secs >= 0) ? secs * (st_utime_t) 1000000LL : ST_UTIME_NO_TIMEOUT);
|
||||
}
|
||||
|
||||
/*****************************************
|
||||
* Condition variable functions
|
||||
*/
|
||||
_st_cond_t *st_cond_new(void)
|
||||
{
|
||||
_st_cond_t *cvar;
|
||||
|
||||
cvar = (_st_cond_t *) calloc(1, sizeof(_st_cond_t));
|
||||
if (cvar) {
|
||||
ST_INIT_CLIST(&cvar->wait_q);
|
||||
}
|
||||
|
||||
return cvar;
|
||||
}
|
||||
|
||||
int st_cond_destroy(_st_cond_t *cvar)
|
||||
{
|
||||
if (cvar->wait_q.next != &cvar->wait_q) {
|
||||
errno = EBUSY;
|
||||
return -1;
|
||||
}
|
||||
|
||||
free(cvar);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int st_cond_timedwait(_st_cond_t *cvar, st_utime_t timeout)
|
||||
{
|
||||
_st_thread_t *me = _ST_CURRENT_THREAD();
|
||||
int rv;
|
||||
|
||||
if (me->flags & _ST_FL_INTERRUPT) {
|
||||
me->flags &= ~_ST_FL_INTERRUPT;
|
||||
errno = EINTR;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Put caller thread on the condition variable's wait queue */
|
||||
me->state = _ST_ST_COND_WAIT;
|
||||
ST_APPEND_LINK(&me->wait_links, &cvar->wait_q);
|
||||
|
||||
if (timeout != ST_UTIME_NO_TIMEOUT) {
|
||||
_ST_ADD_SLEEPQ(me, timeout);
|
||||
}
|
||||
|
||||
_ST_SWITCH_CONTEXT(me);
|
||||
|
||||
ST_REMOVE_LINK(&me->wait_links);
|
||||
rv = 0;
|
||||
|
||||
if (me->flags & _ST_FL_TIMEDOUT) {
|
||||
me->flags &= ~_ST_FL_TIMEDOUT;
|
||||
errno = ETIME;
|
||||
rv = -1;
|
||||
}
|
||||
if (me->flags & _ST_FL_INTERRUPT) {
|
||||
me->flags &= ~_ST_FL_INTERRUPT;
|
||||
errno = EINTR;
|
||||
rv = -1;
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
int st_cond_wait(_st_cond_t *cvar)
|
||||
{
|
||||
return st_cond_timedwait(cvar, ST_UTIME_NO_TIMEOUT);
|
||||
}
|
||||
|
||||
static int _st_cond_signal(_st_cond_t *cvar, int broadcast)
|
||||
{
|
||||
_st_thread_t *thread;
|
||||
_st_clist_t *q;
|
||||
|
||||
for (q = cvar->wait_q.next; q != &cvar->wait_q; q = q->next) {
|
||||
thread = _ST_THREAD_WAITQ_PTR(q);
|
||||
if (thread->state == _ST_ST_COND_WAIT) {
|
||||
if (thread->flags & _ST_FL_ON_SLEEPQ) {
|
||||
_ST_DEL_SLEEPQ(thread);
|
||||
}
|
||||
|
||||
/* Make thread runnable */
|
||||
thread->state = _ST_ST_RUNNABLE;
|
||||
_ST_ADD_RUNQ(thread);
|
||||
if (!broadcast) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int st_cond_signal(_st_cond_t *cvar)
|
||||
{
|
||||
return _st_cond_signal(cvar, 0);
|
||||
}
|
||||
|
||||
int st_cond_broadcast(_st_cond_t *cvar)
|
||||
{
|
||||
return _st_cond_signal(cvar, 1);
|
||||
}
|
||||
|
||||
/*****************************************
|
||||
* Mutex functions
|
||||
*/
|
||||
_st_mutex_t *st_mutex_new(void)
|
||||
{
|
||||
_st_mutex_t *lock;
|
||||
|
||||
lock = (_st_mutex_t *) calloc(1, sizeof(_st_mutex_t));
|
||||
if (lock) {
|
||||
ST_INIT_CLIST(&lock->wait_q);
|
||||
lock->owner = NULL;
|
||||
}
|
||||
|
||||
return lock;
|
||||
}
|
||||
|
||||
int st_mutex_destroy(_st_mutex_t *lock)
|
||||
{
|
||||
if (lock->owner != NULL || lock->wait_q.next != &lock->wait_q) {
|
||||
errno = EBUSY;
|
||||
return -1;
|
||||
}
|
||||
|
||||
free(lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int st_mutex_lock(_st_mutex_t *lock)
|
||||
{
|
||||
_st_thread_t *me = _ST_CURRENT_THREAD();
|
||||
|
||||
if (me->flags & _ST_FL_INTERRUPT) {
|
||||
me->flags &= ~_ST_FL_INTERRUPT;
|
||||
errno = EINTR;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (lock->owner == NULL) {
|
||||
/* Got the mutex */
|
||||
lock->owner = me;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (lock->owner == me) {
|
||||
errno = EDEADLK;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Put caller thread on the mutex's wait queue */
|
||||
me->state = _ST_ST_LOCK_WAIT;
|
||||
ST_APPEND_LINK(&me->wait_links, &lock->wait_q);
|
||||
|
||||
_ST_SWITCH_CONTEXT(me);
|
||||
|
||||
ST_REMOVE_LINK(&me->wait_links);
|
||||
|
||||
if ((me->flags & _ST_FL_INTERRUPT) && lock->owner != me) {
|
||||
me->flags &= ~_ST_FL_INTERRUPT;
|
||||
errno = EINTR;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int st_mutex_unlock(_st_mutex_t *lock)
|
||||
{
|
||||
_st_thread_t *thread;
|
||||
_st_clist_t *q;
|
||||
|
||||
if (lock->owner != _ST_CURRENT_THREAD()) {
|
||||
errno = EPERM;
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (q = lock->wait_q.next; q != &lock->wait_q; q = q->next) {
|
||||
thread = _ST_THREAD_WAITQ_PTR(q);
|
||||
if (thread->state == _ST_ST_LOCK_WAIT) {
|
||||
lock->owner = thread;
|
||||
/* Make thread runnable */
|
||||
thread->state = _ST_ST_RUNNABLE;
|
||||
_ST_ADD_RUNQ(thread);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* No threads waiting on this mutex */
|
||||
lock->owner = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int st_mutex_trylock(_st_mutex_t *lock)
|
||||
{
|
||||
if (lock->owner != NULL) {
|
||||
errno = EBUSY;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Got the mutex */
|
||||
lock->owner = _ST_CURRENT_THREAD();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -2195,8 +2195,34 @@ srs_error_t SrsConfig::global_to_json(SrsJsonObject* obj)
|
|||
sobj->set(sdir->name, sdir->dumps_arg0_to_str());
|
||||
} else if (sdir->name == "auto_create_channel") {
|
||||
sobj->set(sdir->name, sdir->dumps_arg0_to_str());
|
||||
}
|
||||
}
|
||||
} else if (sdir->name == "sip"){
|
||||
SrsJsonObject* ssobj = SrsJsonAny::object();
|
||||
sobj->set(sdir->name, ssobj);
|
||||
|
||||
for (int j = 0; j < (int)sdir->directives.size(); j++) {
|
||||
SrsConfDirective* ssdir = sdir->directives.at(j);
|
||||
if (ssdir->name == "enabled") {
|
||||
ssobj->set(ssdir->name, ssdir->dumps_arg0_to_boolean());
|
||||
} else if (ssdir->name == "listen") {
|
||||
ssobj->set(ssdir->name, ssdir->dumps_arg0_to_integer());
|
||||
} else if (ssdir->name == "serial") {
|
||||
ssobj->set(ssdir->name, ssdir->dumps_arg0_to_str());
|
||||
} else if (ssdir->name == "realm") {
|
||||
ssobj->set(ssdir->name, ssdir->dumps_arg0_to_str());
|
||||
} else if (ssdir->name == "ack_timeout") {
|
||||
ssobj->set(ssdir->name, ssdir->dumps_arg0_to_integer());
|
||||
} else if (ssdir->name == "keepalive_timeout") {
|
||||
ssobj->set(ssdir->name, ssdir->dumps_arg0_to_integer());
|
||||
} else if (ssdir->name == "auto_play") {
|
||||
ssobj->set(ssdir->name, ssdir->dumps_arg0_to_boolean());
|
||||
} else if (ssdir->name == "invite_port_fixed") {
|
||||
ssobj->set(ssdir->name, ssdir->dumps_arg0_to_boolean());
|
||||
} else if (ssdir->name == "query_catalog_interval") {
|
||||
ssobj->set(ssdir->name, ssdir->dumps_arg0_to_integer());
|
||||
}
|
||||
}
|
||||
}//end if
|
||||
}//end for
|
||||
obj->set(dir->name, sobj);
|
||||
} else {
|
||||
continue;
|
||||
|
@ -3730,7 +3756,8 @@ srs_error_t SrsConfig::check_normal_config()
|
|||
for (int j = 0; j < (int)conf->directives.size(); j++) {
|
||||
string m = conf->at(j)->name;
|
||||
if (m != "enabled" && m != "listen" && m != "ack_timeout" && m != "keepalive_timeout"
|
||||
&& m != "host" && m != "serial" && m != "realm" && m != "auto_play" && m != "invite_port_fixed") {
|
||||
&& m != "host" && m != "serial" && m != "realm" && m != "auto_play" && m != "invite_port_fixed"
|
||||
&& m != "query_catalog_interval") {
|
||||
return srs_error_new(ERROR_SYSTEM_CONFIG_INVALID, "illegal stream_caster.%s", m.c_str());
|
||||
}
|
||||
}
|
||||
|
@ -4630,6 +4657,28 @@ bool SrsConfig::get_stream_caster_gb28181_auto_create_channel(SrsConfDirective*
|
|||
return SRS_CONF_PERFER_FALSE(conf->arg0());
|
||||
}
|
||||
|
||||
srs_utime_t SrsConfig::get_stream_caster_gb28181_sip_query_catalog_interval(SrsConfDirective* conf)
|
||||
{
|
||||
static srs_utime_t DEFAULT = 60 * SRS_UTIME_SECONDS;
|
||||
|
||||
|
||||
if (!conf) {
|
||||
return DEFAULT;
|
||||
}
|
||||
|
||||
conf = conf->get("sip");
|
||||
if (!conf) {
|
||||
return DEFAULT;
|
||||
}
|
||||
|
||||
conf = conf->get("query_catalog_interval");
|
||||
if (!conf || conf->arg0().empty()) {
|
||||
return DEFAULT;
|
||||
}
|
||||
|
||||
return (srs_utime_t)(::atoi(conf->arg0().c_str()) * SRS_UTIME_SECONDS);
|
||||
}
|
||||
|
||||
int SrsConfig::get_rtc_server_enabled()
|
||||
{
|
||||
SrsConfDirective* conf = root->get("rtc_server");
|
||||
|
@ -4747,7 +4796,8 @@ int SrsConfig::get_rtc_server_sendmmsg()
|
|||
return DEFAULT;
|
||||
}
|
||||
|
||||
return ::atoi(conf->arg0().c_str());
|
||||
int v = ::atoi(conf->arg0().c_str());
|
||||
return srs_max(1, v);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
|
@ -517,6 +517,7 @@ public:
|
|||
virtual int get_stream_caster_gb28181_sip_listen(SrsConfDirective* conf);
|
||||
virtual bool get_stream_caster_gb28181_sip_invite_port_fixed(SrsConfDirective* conf);
|
||||
virtual bool get_stream_caster_gb28181_auto_create_channel(SrsConfDirective* conf);
|
||||
virtual srs_utime_t get_stream_caster_gb28181_sip_query_catalog_interval(SrsConfDirective* conf);
|
||||
|
||||
// rtc section
|
||||
public:
|
||||
|
@ -528,17 +529,14 @@ public:
|
|||
virtual int get_rtc_server_sendmmsg();
|
||||
virtual bool get_rtc_server_encrypt();
|
||||
virtual int get_rtc_server_reuseport();
|
||||
private:
|
||||
virtual int get_rtc_server_reuseport2();
|
||||
public:
|
||||
virtual bool get_rtc_server_merge_nalus();
|
||||
virtual bool get_rtc_server_gso();
|
||||
private:
|
||||
virtual bool get_rtc_server_gso2();
|
||||
public:
|
||||
virtual int get_rtc_server_padding();
|
||||
virtual bool get_rtc_server_perf_stat();
|
||||
virtual int get_rtc_server_queue_length();
|
||||
private:
|
||||
virtual int get_rtc_server_reuseport2();
|
||||
virtual bool get_rtc_server_gso2();
|
||||
|
||||
public:
|
||||
SrsConfDirective* get_rtc(std::string vhost);
|
||||
|
|
|
@ -103,7 +103,7 @@ srs_error_t SrsConnection::set_tcp_nodelay(bool v)
|
|||
|
||||
int iv = (v? 1:0);
|
||||
if ((r0 = setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &iv, nb_v)) != 0) {
|
||||
return srs_error_new(ERROR_SOCKET_NO_NODELAY, "setsockopt fd=%d, r0=%v", fd, r0);
|
||||
return srs_error_new(ERROR_SOCKET_NO_NODELAY, "setsockopt fd=%d, r0=%d", fd, r0);
|
||||
}
|
||||
if ((r0 = getsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &iv, &nb_v)) != 0) {
|
||||
return srs_error_new(ERROR_SOCKET_NO_NODELAY, "getsockopt fd=%d, r0=%d", fd, r0);
|
||||
|
@ -155,7 +155,7 @@ srs_error_t SrsConnection::set_socket_buffer(srs_utime_t buffer_v)
|
|||
|
||||
// set the socket send buffer when required larger buffer
|
||||
if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &iv, nb_v) < 0) {
|
||||
return srs_error_new(ERROR_SOCKET_SNDBUF, "setsockopt fd=%d, r0=%v", fd, r0);
|
||||
return srs_error_new(ERROR_SOCKET_SNDBUF, "setsockopt fd=%d, r0=%d", fd, r0);
|
||||
}
|
||||
if ((r0 = getsockopt(fd, SOL_SOCKET, SO_SNDBUF, &iv, &nb_v)) != 0) {
|
||||
return srs_error_new(ERROR_SOCKET_SNDBUF, "getsockopt fd=%d, r0=%d", fd, r0);
|
||||
|
|
|
@ -268,7 +268,7 @@ srs_error_t SrsGb28181PsRtpProcessor::on_udp_packet(const sockaddr* from, const
|
|||
}
|
||||
|
||||
if (pprint->can_print()) {
|
||||
srs_trace("<- " SRS_CONSTS_LOG_STREAM_CASTER " gb28181: client_id %s, peer(%s, %d) ps rtp packet %dB, age=%d, vt=%d/%u, sts=%u/%u/%#x, paylod=%dB",
|
||||
srs_trace("<- " SRS_CONSTS_LOG_GB28181_CASTER " gb28181: client_id %s, peer(%s, %d) ps rtp packet %dB, age=%d, vt=%d/%u, sts=%u/%u/%#x, paylod=%dB",
|
||||
channel_id.c_str(), address_string, peer_port, nb_buf, pprint->age(), pkt.version,
|
||||
pkt.payload_type, pkt.sequence_number, pkt.timestamp, pkt.ssrc,
|
||||
pkt.payload->length()
|
||||
|
@ -312,7 +312,12 @@ srs_error_t SrsGb28181PsRtpProcessor::on_udp_packet(const sockaddr* from, const
|
|||
channel.set_channel_id(tmp_id);
|
||||
channel.set_port_mode(RTP_PORT_MODE_FIXED);
|
||||
channel.set_ssrc(pkt.ssrc);
|
||||
_srs_gb28181->create_stream_channel(&channel);
|
||||
|
||||
srs_error_t err2 = srs_success;
|
||||
if ((err2 = _srs_gb28181->create_stream_channel(&channel)) != srs_success){
|
||||
srs_warn("gb28181: RtpProcessor create stream channel error %s", srs_error_desc(err2).c_str());
|
||||
srs_error_reset(err2);
|
||||
};
|
||||
|
||||
muxer = _srs_gb28181->fetch_rtmpmuxer(tmp_id);
|
||||
}
|
||||
|
@ -324,7 +329,7 @@ srs_error_t SrsGb28181PsRtpProcessor::on_udp_packet(const sockaddr* from, const
|
|||
muxer->set_channel_peer_ip(address_string);
|
||||
//not the first peer port's non processing
|
||||
if (muxer->channel_peer_port() != peer_port){
|
||||
srs_warn("<- " SRS_CONSTS_LOG_STREAM_CASTER " gb28181: client_id %s, ssrc=%#x, first peer_port=%d cur peer_port=%d",
|
||||
srs_warn("<- " SRS_CONSTS_LOG_GB28181_CASTER " gb28181: client_id %s, ssrc=%#x, first peer_port=%d cur peer_port=%d",
|
||||
muxer->get_channel_id().c_str(), pkt.ssrc, muxer->channel_peer_port(), peer_port);
|
||||
srs_freep(key->second);
|
||||
}else {
|
||||
|
@ -357,6 +362,7 @@ SrsPsStreamDemixer::SrsPsStreamDemixer(ISrsPsStreamHander *h, std::string id, bo
|
|||
audio_enable = a;
|
||||
wait_first_keyframe = k;
|
||||
channel_id = id;
|
||||
first_keyframe_flag = false;
|
||||
}
|
||||
|
||||
SrsPsStreamDemixer::~SrsPsStreamDemixer()
|
||||
|
@ -404,7 +410,6 @@ int64_t SrsPsStreamDemixer::parse_ps_timestamp(const uint8_t* p)
|
|||
srs_error_t SrsPsStreamDemixer::on_ps_stream(char* ps_data, int ps_size, uint32_t timestamp, uint32_t ssrc)
|
||||
{
|
||||
srs_error_t err = srs_success;
|
||||
|
||||
int complete_len = 0;
|
||||
int incomplete_len = ps_size;
|
||||
char *next_ps_pack = ps_data;
|
||||
|
@ -589,8 +594,10 @@ srs_error_t SrsPsStreamDemixer::on_ps_stream(char* ps_data, int ps_size, uint32_
|
|||
//ts=1000 seq=4 mark=true payload= audio
|
||||
incomplete_len = ps_size - complete_len;
|
||||
complete_len = complete_len + incomplete_len;
|
||||
|
||||
}
|
||||
|
||||
first_keyframe_flag = false;
|
||||
srs_trace("gb28181: client_id %s, unkonw ps data (%#x/%u) %02x %02x %02x %02x\n",
|
||||
channel_id.c_str(), ssrc, timestamp,
|
||||
next_ps_pack[0], next_ps_pack[1], next_ps_pack[2], next_ps_pack[3]);
|
||||
|
@ -599,7 +606,7 @@ srs_error_t SrsPsStreamDemixer::on_ps_stream(char* ps_data, int ps_size, uint32_
|
|||
}
|
||||
|
||||
if (complete_len != ps_size){
|
||||
srs_trace("gb28181: client_id %s decode ps packet error (%#x/%u)! ps_size=%d complete=%d \n",
|
||||
srs_trace("gb28181: client_id %s decode ps packet error (%#x/%u)! ps_size=%d complete=%d \n",
|
||||
channel_id.c_str(), ssrc, timestamp, ps_size, complete_len);
|
||||
}else if (hander && video_stream.length() && can_send_ps_av_packet()) {
|
||||
if ((err = hander->on_rtp_video(&video_stream, video_pts)) != srs_success) {
|
||||
|
@ -646,6 +653,7 @@ SrsGb28181Config::SrsGb28181Config(SrsConfDirective* c)
|
|||
sip_ack_timeout = _srs_config->get_stream_caster_gb28181_ack_timeout(c);
|
||||
sip_keepalive_timeout = _srs_config->get_stream_caster_gb28181_keepalive_timeout(c);
|
||||
sip_invite_port_fixed = _srs_config->get_stream_caster_gb28181_sip_invite_port_fixed(c);
|
||||
sip_query_catalog_interval = _srs_config->get_stream_caster_gb28181_sip_query_catalog_interval(c);
|
||||
}
|
||||
|
||||
SrsGb28181Config::~SrsGb28181Config()
|
||||
|
@ -653,7 +661,6 @@ SrsGb28181Config::~SrsGb28181Config()
|
|||
|
||||
}
|
||||
|
||||
|
||||
//SrsGb28181RtmpMuxer gb28181 rtmp muxer, process ps stream to rtmp
|
||||
SrsGb28181RtmpMuxer::SrsGb28181RtmpMuxer(SrsGb28181Manger* c, std::string id, bool a, bool k)
|
||||
{
|
||||
|
@ -675,7 +682,8 @@ SrsGb28181RtmpMuxer::SrsGb28181RtmpMuxer(SrsGb28181Manger* c, std::string id, bo
|
|||
wait_ps_queue = srs_cond_new();
|
||||
|
||||
stream_idle_timeout = -1;
|
||||
recv_stream_time = 0;
|
||||
recv_rtp_stream_time = 0;
|
||||
send_rtmp_stream_time = 0;
|
||||
|
||||
_rtmp_url = "";
|
||||
|
||||
|
@ -768,7 +776,7 @@ std::string SrsGb28181RtmpMuxer::rtmp_url()
|
|||
|
||||
srs_utime_t SrsGb28181RtmpMuxer::get_recv_stream_time()
|
||||
{
|
||||
return recv_stream_time;
|
||||
return recv_rtp_stream_time;
|
||||
}
|
||||
|
||||
|
||||
|
@ -785,7 +793,8 @@ void SrsGb28181RtmpMuxer::destroy()
|
|||
srs_error_t SrsGb28181RtmpMuxer::do_cycle()
|
||||
{
|
||||
srs_error_t err = srs_success;
|
||||
recv_stream_time = srs_get_system_time();
|
||||
recv_rtp_stream_time = srs_get_system_time();
|
||||
send_rtmp_stream_time = srs_get_system_time();
|
||||
|
||||
//consume ps stream, and check status
|
||||
while (true) {
|
||||
|
@ -819,7 +828,7 @@ srs_error_t SrsGb28181RtmpMuxer::do_cycle()
|
|||
}
|
||||
|
||||
srs_utime_t now = srs_get_system_time();
|
||||
srs_utime_t duration = now - recv_stream_time;
|
||||
srs_utime_t duration = now - recv_rtp_stream_time;
|
||||
|
||||
//if no RTP data is received within 2 seconds,
|
||||
//the peer-port and peer-ip will be cleared and
|
||||
|
@ -831,13 +840,28 @@ srs_error_t SrsGb28181RtmpMuxer::do_cycle()
|
|||
channel->set_rtp_peer_port(0);
|
||||
channel->set_rtp_peer_ip("");
|
||||
}
|
||||
|
||||
|
||||
SrsGb28181Config config = gb28181_manger->get_gb28181_config();
|
||||
if (duration > config.rtp_idle_timeout){
|
||||
srs_trace("gb28181: client id=%s, stream idle timeout, stop!!!", channel_id.c_str());
|
||||
break;
|
||||
}
|
||||
|
||||
//RTMP connection is about to timeout without receiving any data.,
|
||||
//waiting for the next time there is data automatically connected
|
||||
//it is related to the following two parameter settings of the rtmp server
|
||||
//the publish 1st packet timeout in srs_utime_t
|
||||
//publish_1stpkt_timeout default 20000ms
|
||||
//the publish normal packet timeout in srs_utime_t
|
||||
//publish_normal_timeout default 5000ms
|
||||
duration = now - send_rtmp_stream_time;
|
||||
bool will_timeout = duration > (5 * SRS_UTIME_SECONDS);
|
||||
if (will_timeout && sdk){
|
||||
srs_warn("gb28181: client id=%s RTMP connection is about to time out without receiving any data",
|
||||
channel_id.c_str());
|
||||
rtmp_close();
|
||||
}
|
||||
|
||||
if (ps_queue.empty()){
|
||||
srs_cond_timedwait(wait_ps_queue, 200 * SRS_UTIME_MILLISECONDS);
|
||||
}else {
|
||||
|
@ -862,7 +886,7 @@ void SrsGb28181RtmpMuxer::ps_packet_enqueue(SrsPsRtpPacket *pkt)
|
|||
{
|
||||
srs_assert(pkt);
|
||||
|
||||
recv_stream_time = srs_get_system_time();
|
||||
recv_rtp_stream_time = srs_get_system_time();
|
||||
|
||||
//prevent consumers from being unable to process data
|
||||
//and accumulating in the queue
|
||||
|
@ -923,7 +947,7 @@ srs_error_t SrsGb28181RtmpMuxer::on_rtp_video(SrsSimpleStream *stream, int64_t f
|
|||
uint32_t pts = (uint32_t)(fpts / 90);
|
||||
srs_info("gb28181rtmpmuxer: on_rtp_video dts=%u", dts);
|
||||
|
||||
recv_stream_time = srs_get_system_time();
|
||||
|
||||
|
||||
SrsBuffer *avs = new SrsBuffer(stream->bytes(), stream->length());
|
||||
SrsAutoFree(SrsBuffer, avs);
|
||||
|
@ -1010,8 +1034,6 @@ srs_error_t SrsGb28181RtmpMuxer::on_rtp_audio(SrsSimpleStream* stream, int64_t f
|
|||
return srs_error_wrap(err, "jitter");
|
||||
}
|
||||
|
||||
recv_stream_time = srs_get_system_time();
|
||||
|
||||
uint32_t dts = (uint32_t)(fdts / 90);
|
||||
|
||||
// send each frame.
|
||||
|
@ -1167,6 +1189,8 @@ srs_error_t SrsGb28181RtmpMuxer::rtmp_write_packet(char type, uint32_t timestamp
|
|||
|
||||
SrsSharedPtrMessage* msg = NULL;
|
||||
|
||||
send_rtmp_stream_time = srs_get_system_time();
|
||||
|
||||
if ((err = srs_rtmp_create_msg(type, timestamp, data, size, sdk->sid(), &msg)) != srs_success) {
|
||||
return srs_error_wrap(err, "create message");
|
||||
}
|
||||
|
@ -1197,8 +1221,9 @@ srs_error_t SrsGb28181RtmpMuxer::connect()
|
|||
srs_utime_t cto = SRS_CONSTS_RTMP_TIMEOUT;
|
||||
srs_utime_t sto = SRS_CONSTS_RTMP_PULSE;
|
||||
sdk = new SrsSimpleRtmpClient(url, cto, sto);
|
||||
|
||||
|
||||
srs_trace("gb28181: rtmp connect url=%s", url.c_str());
|
||||
|
||||
if ((err = sdk->connect()) != srs_success) {
|
||||
close();
|
||||
return srs_error_wrap(err, "connect %s failed, cto=%dms, sto=%dms.", url.c_str(), srsu2msi(cto), srsu2msi(sto));
|
||||
|
@ -1368,8 +1393,8 @@ uint32_t SrsGb28181Manger::generate_ssrc(std::string id)
|
|||
{
|
||||
srand(uint(time(0)));
|
||||
// TODO: SSRC rules can be customized,
|
||||
//gb28281 live ssrc max value 0999999999(3B9AC9FF)
|
||||
//gb28281 vod ssrc max value 1999999999(773593FF)
|
||||
//gb28181 live ssrc max value 0999999999(3B9AC9FF)
|
||||
//gb28181 vod ssrc max value 1999999999(773593FF)
|
||||
uint8_t index = uint8_t(rand() % (0x0F - 0x01 + 1) + 0x01);
|
||||
uint32_t ssrc = 0x2FFFF00 & (hash_code(id) << 8) | index;
|
||||
//uint32_t ssrc = 0x00FFFFFF & (hash_code(id));
|
||||
|
@ -1527,8 +1552,9 @@ void SrsGb28181Manger::stop_rtp_listen(std::string id)
|
|||
}
|
||||
|
||||
//api
|
||||
uint32_t SrsGb28181Manger::create_stream_channel(SrsGb28181StreamChannel *channel)
|
||||
srs_error_t SrsGb28181Manger::create_stream_channel(SrsGb28181StreamChannel *channel)
|
||||
{
|
||||
srs_error_t err = srs_success;
|
||||
srs_assert(channel);
|
||||
|
||||
std::string id = channel->get_channel_id();
|
||||
|
@ -1539,15 +1565,14 @@ uint32_t SrsGb28181Manger::create_stream_channel(SrsGb28181StreamChannel *channe
|
|||
SrsGb28181StreamChannel s = muxer->get_channel();
|
||||
channel->copy(&s);
|
||||
//return ERROR_GB28181_SESSION_IS_EXIST;
|
||||
return ERROR_SUCCESS;
|
||||
return err;
|
||||
}
|
||||
|
||||
//create on rtmp muxer, gb28181 stream to rtmp
|
||||
srs_error_t err = srs_success;
|
||||
|
||||
if ((err = fetch_or_create_rtmpmuxer(id, &muxer)) != srs_success){
|
||||
srs_warn("gb28181: create rtmp muxer error, %s", srs_error_desc(err).c_str());
|
||||
srs_freep(err);
|
||||
return ERROR_GB28181_CREATER_RTMPMUXER_FAILED;
|
||||
return err;
|
||||
}
|
||||
|
||||
//Start RTP listening port, receive gb28181 stream,
|
||||
|
@ -1564,21 +1589,19 @@ uint32_t SrsGb28181Manger::create_stream_channel(SrsGb28181StreamChannel *channe
|
|||
if (port_mode == RTP_PORT_MODE_RANDOM){
|
||||
alloc_port(&rtp_port);
|
||||
if (rtp_port <= 0){
|
||||
return ERROR_GB28181_RTP_PORT_FULL;
|
||||
return srs_error_new(ERROR_GB28181_RTP_PORT_FULL, "gb28181: rtp port full");
|
||||
}
|
||||
srs_error_t err = srs_success;
|
||||
|
||||
if ((err = start_ps_rtp_listen(id, rtp_port)) != srs_success){
|
||||
srs_warn("gb28181: start ps rtp listen error, %s", srs_error_desc(err).c_str());
|
||||
srs_freep(err);
|
||||
free_port(rtp_port, rtp_port + 1);
|
||||
return ERROR_GB28181_CREATER_RTMPMUXER_FAILED;
|
||||
return err;
|
||||
}
|
||||
}
|
||||
else if(port_mode == RTP_PORT_MODE_FIXED) {
|
||||
rtp_port = config->rtp_mux_port;
|
||||
}
|
||||
else{
|
||||
return ERROR_GB28181_PORT_MODE_INVALID;
|
||||
return srs_error_new(ERROR_GB28181_PORT_MODE_INVALID, "gb28181: port mode invalid");
|
||||
}
|
||||
|
||||
uint32_t ssrc = channel->get_ssrc();
|
||||
|
@ -1653,32 +1676,36 @@ uint32_t SrsGb28181Manger::create_stream_channel(SrsGb28181StreamChannel *channe
|
|||
|
||||
muxer->copy_channel(channel);
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
return err;
|
||||
}
|
||||
|
||||
uint32_t SrsGb28181Manger::delete_stream_channel(std::string id)
|
||||
srs_error_t SrsGb28181Manger::delete_stream_channel(std::string id)
|
||||
{
|
||||
srs_error_t err = srs_success;
|
||||
|
||||
//notify the device to stop streaming
|
||||
//if an internal sip service controlled channel
|
||||
notify_sip_bye(id);
|
||||
notify_sip_bye(id, id);
|
||||
|
||||
SrsGb28181RtmpMuxer *muxer = fetch_rtmpmuxer(id);
|
||||
if (muxer){
|
||||
stop_rtp_listen(id);
|
||||
muxer->stop();
|
||||
return ERROR_SUCCESS;
|
||||
return err;
|
||||
}else {
|
||||
return ERROR_GB28181_SESSION_IS_NOTEXIST;
|
||||
return srs_error_new(ERROR_GB28181_SESSION_IS_NOTEXIST, "stream channel is not exists");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
uint32_t SrsGb28181Manger::queue_stream_channel(std::string id, SrsJsonArray* arr)
|
||||
srs_error_t SrsGb28181Manger::query_stream_channel(std::string id, SrsJsonArray* arr)
|
||||
{
|
||||
srs_error_t err = srs_success;
|
||||
|
||||
if (!id.empty()){
|
||||
SrsGb28181RtmpMuxer *muxer = fetch_rtmpmuxer(id);
|
||||
if (!muxer){
|
||||
return ERROR_GB28181_SESSION_IS_NOTEXIST;
|
||||
return srs_error_new(ERROR_GB28181_SESSION_IS_NOTEXIST, "stream channel not exists");
|
||||
}
|
||||
SrsJsonObject* obj = SrsJsonAny::object();
|
||||
arr->append(obj);
|
||||
|
@ -1693,27 +1720,30 @@ uint32_t SrsGb28181Manger::queue_stream_channel(std::string id, SrsJsonArray* ar
|
|||
}
|
||||
}
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
return err;
|
||||
}
|
||||
|
||||
uint32_t SrsGb28181Manger::notify_sip_invite(std::string id, std::string ip, int port, uint32_t ssrc)
|
||||
srs_error_t SrsGb28181Manger::notify_sip_invite(std::string id, std::string ip, int port, uint32_t ssrc, std::string chid)
|
||||
{
|
||||
srs_error_t err = srs_success;
|
||||
|
||||
if (!sip_service){
|
||||
return ERROR_GB28181_SIP_NOT_RUN;
|
||||
return srs_error_new(ERROR_GB28181_SIP_NOT_RUN, "sip not run");
|
||||
}
|
||||
|
||||
//if RTMP Muxer does not exist, you need to create
|
||||
SrsGb28181RtmpMuxer *muxer = fetch_rtmpmuxer(id);
|
||||
std::string key = id+"@"+chid;
|
||||
SrsGb28181RtmpMuxer *muxer = fetch_rtmpmuxer(key);
|
||||
|
||||
if (!muxer){
|
||||
//if there is an invalid parameter, the channel will be created automatically
|
||||
if (ip.empty() || port == 0 || ssrc == 0){
|
||||
//channel not exist
|
||||
SrsGb28181StreamChannel channel;
|
||||
channel.set_channel_id(id);
|
||||
int code = create_stream_channel(&channel);
|
||||
if (code != ERROR_SUCCESS){
|
||||
return code;
|
||||
channel.set_channel_id(key);
|
||||
err = create_stream_channel(&channel);
|
||||
if (err != srs_success){
|
||||
return err;
|
||||
}
|
||||
|
||||
ip = channel.get_ip();
|
||||
|
@ -1730,30 +1760,36 @@ uint32_t SrsGb28181Manger::notify_sip_invite(std::string id, std::string ip, int
|
|||
|
||||
SrsSipRequest req;
|
||||
req.sip_auth_id = id;
|
||||
return sip_service->send_invite(&req, ip, port, ssrc);
|
||||
|
||||
return sip_service->send_invite(&req, ip, port, ssrc, chid);
|
||||
}
|
||||
|
||||
uint32_t SrsGb28181Manger::notify_sip_bye(std::string id)
|
||||
srs_error_t SrsGb28181Manger::notify_sip_bye(std::string id, std::string chid)
|
||||
{
|
||||
if (!sip_service){
|
||||
return ERROR_GB28181_SIP_NOT_RUN;
|
||||
}
|
||||
|
||||
SrsGb28181RtmpMuxer *muxer = fetch_rtmpmuxer(id);
|
||||
if (muxer){
|
||||
muxer->rtmp_close();
|
||||
return srs_error_new(ERROR_GB28181_SIP_NOT_RUN, "sip not run");
|
||||
}
|
||||
|
||||
SrsSipRequest req;
|
||||
req.sip_auth_id = id;
|
||||
return sip_service->send_bye(&req);
|
||||
return sip_service->send_bye(&req, chid);
|
||||
}
|
||||
|
||||
uint32_t SrsGb28181Manger::notify_sip_raw_data(std::string id, std::string data)
|
||||
srs_error_t SrsGb28181Manger::notify_sip_ptz(std::string id, std::string chid, std::string cmd,
|
||||
uint8_t speed, int priority)
|
||||
{
|
||||
if (!sip_service){
|
||||
return ERROR_GB28181_SIP_NOT_RUN;
|
||||
return srs_error_new(ERROR_GB28181_SIP_NOT_RUN, "sip not run");
|
||||
}
|
||||
|
||||
SrsSipRequest req;
|
||||
req.sip_auth_id = id;
|
||||
return sip_service->send_ptz(&req, chid, cmd, speed, priority);
|
||||
}
|
||||
|
||||
srs_error_t SrsGb28181Manger::notify_sip_raw_data(std::string id, std::string data)
|
||||
{
|
||||
if (!sip_service){
|
||||
return srs_error_new(ERROR_GB28181_SIP_NOT_RUN, "sip not run");
|
||||
}
|
||||
|
||||
SrsSipRequest req;
|
||||
|
@ -1762,13 +1798,31 @@ uint32_t SrsGb28181Manger::notify_sip_raw_data(std::string id, std::string data)
|
|||
|
||||
}
|
||||
|
||||
uint32_t SrsGb28181Manger::notify_sip_unregister(std::string id)
|
||||
srs_error_t SrsGb28181Manger::notify_sip_unregister(std::string id)
|
||||
{
|
||||
if (!sip_service){
|
||||
return ERROR_GB28181_SIP_NOT_RUN;
|
||||
return srs_error_new(ERROR_GB28181_SIP_NOT_RUN, "sip not run");
|
||||
}
|
||||
sip_service->remove_session(id);
|
||||
return delete_stream_channel(id);
|
||||
}
|
||||
|
||||
srs_error_t SrsGb28181Manger::notify_sip_query_catalog(std::string id)
|
||||
{
|
||||
if (!sip_service){
|
||||
return srs_error_new(ERROR_GB28181_SIP_NOT_RUN, "sip not run");
|
||||
}
|
||||
|
||||
delete_stream_channel(id);
|
||||
sip_service->remove_session(id);
|
||||
return ERROR_SUCCESS;
|
||||
SrsSipRequest req;
|
||||
req.sip_auth_id = id;
|
||||
return sip_service->send_query_catalog(&req);
|
||||
}
|
||||
|
||||
srs_error_t SrsGb28181Manger::query_sip_session(std::string id, SrsJsonArray* arr)
|
||||
{
|
||||
if (!sip_service){
|
||||
return srs_error_new(ERROR_GB28181_SIP_NOT_RUN, "sip not run");
|
||||
}
|
||||
|
||||
return sip_service->query_sip_session(id, arr);
|
||||
}
|
|
@ -218,7 +218,8 @@ private:
|
|||
SrsPithyPrint* pprint;
|
||||
SrsGb28181StreamChannel *channel;
|
||||
int stream_idle_timeout;
|
||||
srs_utime_t recv_stream_time;
|
||||
srs_utime_t recv_rtp_stream_time;
|
||||
srs_utime_t send_rtmp_stream_time;
|
||||
private:
|
||||
std::string channel_id;
|
||||
std::string _rtmp_url;
|
||||
|
@ -313,6 +314,7 @@ public:
|
|||
srs_utime_t sip_keepalive_timeout;
|
||||
bool sip_auto_play;
|
||||
bool sip_invite_port_fixed;
|
||||
srs_utime_t sip_query_catalog_interval;
|
||||
|
||||
public:
|
||||
SrsGb28181Config(SrsConfDirective* c);
|
||||
|
@ -392,9 +394,7 @@ private:
|
|||
std::map<uint32_t, SrsGb28181RtmpMuxer*> rtmpmuxers_ssrc;
|
||||
std::map<std::string, SrsGb28181RtmpMuxer*> rtmpmuxers;
|
||||
SrsCoroutineManager* manager;
|
||||
|
||||
SrsGb28181SipService* sip_service;
|
||||
|
||||
public:
|
||||
SrsGb28181Manger(SrsConfDirective* c);
|
||||
virtual ~SrsGb28181Manger();
|
||||
|
@ -413,14 +413,17 @@ public:
|
|||
|
||||
public:
|
||||
//stream channel api
|
||||
uint32_t create_stream_channel(SrsGb28181StreamChannel *channel);
|
||||
uint32_t delete_stream_channel(std::string id);
|
||||
uint32_t queue_stream_channel(std::string id, SrsJsonArray* arr);
|
||||
srs_error_t create_stream_channel(SrsGb28181StreamChannel *channel);
|
||||
srs_error_t delete_stream_channel(std::string id);
|
||||
srs_error_t query_stream_channel(std::string id, SrsJsonArray* arr);
|
||||
//sip api
|
||||
uint32_t notify_sip_invite(std::string id, std::string ip, int port, uint32_t ssrc);
|
||||
uint32_t notify_sip_bye(std::string id);
|
||||
uint32_t notify_sip_raw_data(std::string id, std::string data);
|
||||
uint32_t notify_sip_unregister(std::string id);
|
||||
srs_error_t notify_sip_invite(std::string id, std::string ip, int port, uint32_t ssrc, std::string chid);
|
||||
srs_error_t notify_sip_bye(std::string id, std::string chid);
|
||||
srs_error_t notify_sip_raw_data(std::string id, std::string data);
|
||||
srs_error_t notify_sip_unregister(std::string id);
|
||||
srs_error_t notify_sip_query_catalog(std::string id);
|
||||
srs_error_t notify_sip_ptz(std::string id, std::string chid, std::string cmd, uint8_t speed, int priority);
|
||||
srs_error_t query_sip_session(std::string id, SrsJsonArray* arr);
|
||||
|
||||
private:
|
||||
void destroy();
|
||||
|
|
|
@ -65,6 +65,18 @@ std::string srs_get_sip_session_status_str(SrsGb28181SipSessionStatusType status
|
|||
}
|
||||
}
|
||||
|
||||
SrsGb28181Device::SrsGb28181Device()
|
||||
{
|
||||
device_id = "";
|
||||
invite_status = SrsGb28181SipSessionUnkonw;
|
||||
invite_time = 0;
|
||||
device_status = "";
|
||||
|
||||
}
|
||||
|
||||
SrsGb28181Device::~SrsGb28181Device()
|
||||
{}
|
||||
|
||||
SrsGb28181SipSession::SrsGb28181SipSession(SrsGb28181SipService *c, SrsSipRequest* r)
|
||||
{
|
||||
servcie = c;
|
||||
|
@ -82,15 +94,19 @@ SrsGb28181SipSession::SrsGb28181SipSession(SrsGb28181SipService *c, SrsSipReques
|
|||
_register_time = 0;
|
||||
_alive_time = 0;
|
||||
_invite_time = 0;
|
||||
_query_catalog_time = 0;
|
||||
|
||||
_peer_ip = "";
|
||||
_peer_port = 0;
|
||||
|
||||
_fromlen = 0;
|
||||
_sip_cseq = 100;
|
||||
}
|
||||
|
||||
SrsGb28181SipSession::~SrsGb28181SipSession()
|
||||
{
|
||||
destroy();
|
||||
|
||||
srs_freep(req);
|
||||
srs_freep(trd);
|
||||
srs_freep(pprint);
|
||||
|
@ -107,12 +123,25 @@ srs_error_t SrsGb28181SipSession::serve()
|
|||
return err;
|
||||
}
|
||||
|
||||
void SrsGb28181SipSession::destroy()
|
||||
{
|
||||
//destory all device
|
||||
std::map<std::string, SrsGb28181Device*>::iterator it;
|
||||
for (it = _device_list.begin(); it != _device_list.end(); ++it) {
|
||||
srs_freep(it->second);
|
||||
}
|
||||
|
||||
_device_list.clear();
|
||||
}
|
||||
|
||||
srs_error_t SrsGb28181SipSession::do_cycle()
|
||||
{
|
||||
srs_error_t err = srs_success;
|
||||
_register_time = srs_get_system_time();
|
||||
_alive_time = srs_get_system_time();
|
||||
_invite_time = srs_get_system_time();
|
||||
//call it immediately after alive ok;
|
||||
_query_catalog_time = 0;
|
||||
|
||||
while (true) {
|
||||
|
||||
|
@ -121,14 +150,82 @@ srs_error_t SrsGb28181SipSession::do_cycle()
|
|||
if ((err = trd->pull()) != srs_success) {
|
||||
return srs_error_wrap(err, "gb28181 sip session cycle");
|
||||
}
|
||||
|
||||
|
||||
SrsGb28181Config *config = servcie->get_config();
|
||||
srs_utime_t now = srs_get_system_time();
|
||||
srs_utime_t reg_duration = now - _register_time;
|
||||
srs_utime_t alive_duration = now - _alive_time;
|
||||
srs_utime_t invite_duration = now - _invite_time;
|
||||
SrsGb28181Config *config = servcie->get_config();
|
||||
srs_utime_t query_duration = now - _query_catalog_time;
|
||||
|
||||
//send invite, play client av
|
||||
//start ps rtp listen, recv ps stream
|
||||
if (_register_status == SrsGb28181SipSessionRegisterOk &&
|
||||
_alive_status == SrsGb28181SipSessionAliveOk)
|
||||
{
|
||||
std::map<std::string, SrsGb28181Device*>::iterator it;
|
||||
for (it = _device_list.begin(); it != _device_list.end(); it++) {
|
||||
SrsGb28181Device *device = it->second;
|
||||
std::string chid = it->first;
|
||||
|
||||
//update device invite time
|
||||
srs_utime_t invite_duration = 0;
|
||||
if (device->invite_time != 0){
|
||||
invite_duration = srs_get_system_time() - device->invite_time;
|
||||
}
|
||||
|
||||
//It is possible that the camera head keeps pushing and opening,
|
||||
//and the duration will be very large. It will take 1 day to update
|
||||
if (invite_duration > 24 * SRS_UTIME_HOURS){
|
||||
device->invite_time = srs_get_system_time();
|
||||
}
|
||||
|
||||
if (device->invite_status == SrsGb28181SipSessionTrying &&
|
||||
invite_duration > config->sip_ack_timeout){
|
||||
device->invite_status = SrsGb28181SipSessionUnkonw;
|
||||
}
|
||||
|
||||
if (!config->sip_auto_play) continue;
|
||||
|
||||
//offline or already invite device does not need to send invite
|
||||
if (device->device_status != "ON" ||
|
||||
device->invite_status != SrsGb28181SipSessionUnkonw) continue;
|
||||
|
||||
SrsGb28181StreamChannel ch;
|
||||
|
||||
ch.set_channel_id(_session_id + "@" + chid);
|
||||
ch.set_ip(config->host);
|
||||
|
||||
if (config->sip_invite_port_fixed){
|
||||
ch.set_port_mode(RTP_PORT_MODE_FIXED);
|
||||
}else {
|
||||
ch.set_port_mode(RTP_PORT_MODE_RANDOM);
|
||||
}
|
||||
|
||||
//create stream channel, ready for recv device av stream
|
||||
srs_error_t err = _srs_gb28181->create_stream_channel(&ch);
|
||||
|
||||
if ((err = _srs_gb28181->create_stream_channel(&ch)) == srs_success){
|
||||
SrsSipRequest req;
|
||||
req.sip_auth_id = _session_id;
|
||||
|
||||
//send invite to device, req push av stream
|
||||
err = servcie->send_invite(&req, ch.get_ip(),
|
||||
ch.get_rtp_port(), ch.get_ssrc(), chid);
|
||||
}
|
||||
|
||||
int code = srs_error_code(err);
|
||||
if (err != srs_success){
|
||||
srs_error_reset(err);
|
||||
}
|
||||
|
||||
//the same device can't be sent too fast. the device can't handle it
|
||||
srs_usleep(1*SRS_UTIME_SECONDS);
|
||||
|
||||
srs_trace("gb28181: %s clients device=%s send invite code=%d",
|
||||
_session_id.c_str(), chid.c_str(), code);
|
||||
}//end for (it)
|
||||
}//end if (config)
|
||||
|
||||
|
||||
if (_register_status == SrsGb28181SipSessionRegisterOk &&
|
||||
reg_duration > _reg_expires){
|
||||
srs_trace("gb28181: sip session=%s register expire", _session_id.c_str());
|
||||
|
@ -142,29 +239,48 @@ srs_error_t SrsGb28181SipSession::do_cycle()
|
|||
break;
|
||||
}
|
||||
|
||||
if (_invite_status == SrsGb28181SipSessionTrying &&
|
||||
invite_duration > config->sip_ack_timeout){
|
||||
_invite_status == SrsGb28181SipSessionUnkonw;
|
||||
//query device channel
|
||||
if (_alive_status == SrsGb28181SipSessionAliveOk &&
|
||||
query_duration >= config->sip_query_catalog_interval) {
|
||||
SrsSipRequest req;
|
||||
req.sip_auth_id = _session_id;
|
||||
_query_catalog_time = srs_get_system_time();
|
||||
|
||||
srs_error_t err = servcie->send_query_catalog(&req);
|
||||
if (err != srs_success){
|
||||
srs_trace("gb28181: sip query catalog error %s",srs_error_desc(err).c_str());
|
||||
srs_error_reset(err);
|
||||
}
|
||||
|
||||
if (pprint->can_print()){
|
||||
srs_trace("gb28181: sip session=%s peer(%s, %d) status(%s,%s,%s) duration(%u,%u,%u)",
|
||||
//print device status
|
||||
srs_trace("gb28181: sip session=%s peer(%s, %d) status(%s,%s) duration(%u,%u)",
|
||||
_session_id.c_str(), _peer_ip.c_str(), _peer_port,
|
||||
srs_get_sip_session_status_str(_register_status).c_str(),
|
||||
srs_get_sip_session_status_str(_alive_status).c_str(),
|
||||
srs_get_sip_session_status_str(_invite_status).c_str(),
|
||||
(reg_duration / SRS_UTIME_SECONDS),
|
||||
(alive_duration / SRS_UTIME_SECONDS),
|
||||
(invite_duration / SRS_UTIME_SECONDS));
|
||||
(alive_duration / SRS_UTIME_SECONDS));
|
||||
|
||||
std::map<std::string, SrsGb28181Device*>::iterator it;
|
||||
for (it = _device_list.begin(); it != _device_list.end(); it++) {
|
||||
SrsGb28181Device *device = it->second;
|
||||
std::string chid = it->first;
|
||||
|
||||
//It is possible that the camera head keeps pushing and opening,
|
||||
//and the duration will be very large. It will take 1 day to update
|
||||
if (invite_duration > 24 * SRS_UTIME_HOURS){
|
||||
_invite_time = srs_get_system_time();
|
||||
srs_utime_t invite_duration = srs_get_system_time() - device->invite_time;
|
||||
|
||||
if (device->invite_status != SrsGb28181SipSessionTrying &&
|
||||
device->invite_status != SrsGb28181SipSessionInviteOk){
|
||||
invite_duration = 0;
|
||||
}
|
||||
|
||||
srs_trace("gb28181: sip session=%s device=%s status(%s, %s), duration(%u)",
|
||||
_session_id.c_str(), chid.c_str(), device->device_status.c_str(),
|
||||
srs_get_sip_session_status_str(device->invite_status).c_str(),
|
||||
(invite_duration / SRS_UTIME_SECONDS));
|
||||
}
|
||||
}
|
||||
srs_usleep(5* SRS_UTIME_SECONDS);
|
||||
}
|
||||
|
||||
srs_usleep(1 * SRS_UTIME_SECONDS);
|
||||
}//end while
|
||||
|
||||
return err;
|
||||
}
|
||||
|
@ -191,6 +307,72 @@ srs_error_t SrsGb28181SipSession::cycle()
|
|||
return err;
|
||||
}
|
||||
|
||||
void SrsGb28181SipSession::update_device_list(std::map<std::string, std::string> lst)
|
||||
{
|
||||
std::map<std::string, std::string>::iterator it;
|
||||
for (it = lst.begin(); it != lst.end(); ++it) {
|
||||
std::string id = it->first;
|
||||
std::string status = it->second;
|
||||
|
||||
if (_device_list.find(id) == _device_list.end()){
|
||||
SrsGb28181Device *device = new SrsGb28181Device();
|
||||
device->device_id = id;
|
||||
device->device_status = status;
|
||||
device->invite_status = SrsGb28181SipSessionUnkonw;
|
||||
device->invite_time = 0;
|
||||
_device_list[id] = device;
|
||||
|
||||
}else {
|
||||
SrsGb28181Device *device = _device_list[id];
|
||||
device->device_status = status;
|
||||
}
|
||||
|
||||
// srs_trace("gb28181: sip session %s, deviceid=%s status=(%s,%s)",
|
||||
// _session_id.c_str(), id.c_str(), status.c_str(),
|
||||
// srs_get_sip_session_status_str(device.invite_status).c_str());
|
||||
}
|
||||
}
|
||||
|
||||
SrsGb28181Device* SrsGb28181SipSession::get_device_info(std::string chid)
|
||||
{
|
||||
if (_device_list.find(chid) != _device_list.end()){
|
||||
return _device_list[chid];
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void SrsGb28181SipSession::dumps(SrsJsonObject* obj)
|
||||
{
|
||||
obj->set("id", SrsJsonAny::str(_session_id.c_str()));
|
||||
obj->set("device_sumnum", SrsJsonAny::integer(_device_list.size()));
|
||||
|
||||
SrsJsonArray* arr = SrsJsonAny::array();
|
||||
obj->set("devices", arr);
|
||||
std::map<std::string, SrsGb28181Device*>::iterator it;
|
||||
for (it = _device_list.begin(); it != _device_list.end(); ++it) {
|
||||
SrsGb28181Device *device = it->second;
|
||||
SrsJsonObject* obj = SrsJsonAny::object();
|
||||
arr->append(obj);
|
||||
obj->set("device_id", SrsJsonAny::str(device->device_id.c_str()));
|
||||
obj->set("device_status", SrsJsonAny::str(device->device_status.c_str()));
|
||||
obj->set("invite_status", SrsJsonAny::str(srs_get_sip_session_status_str(device->invite_status).c_str()));
|
||||
obj->set("invite_time", SrsJsonAny::integer(device->invite_time/SRS_UTIME_SECONDS));
|
||||
}
|
||||
|
||||
//obj->set("rtmp_port", SrsJsonAny::integer(rtmp_port));
|
||||
// obj->set("app", SrsJsonAny::str(app.c_str()));
|
||||
// obj->set("stream", SrsJsonAny::str(stream.c_str()));
|
||||
// obj->set("rtmp_url", SrsJsonAny::str(rtmp_url.c_str()));
|
||||
|
||||
// obj->set("ssrc", SrsJsonAny::integer(ssrc));
|
||||
// obj->set("rtp_port", SrsJsonAny::integer(rtp_port));
|
||||
// obj->set("port_mode", SrsJsonAny::str(port_mode.c_str()));
|
||||
// obj->set("rtp_peer_port", SrsJsonAny::integer(rtp_peer_port));
|
||||
// obj->set("rtp_peer_ip", SrsJsonAny::str(rtp_peer_ip.c_str()));
|
||||
// obj->set("recv_time", SrsJsonAny::integer(recv_time/SRS_UTIME_SECONDS));
|
||||
// obj->set("recv_time_str", SrsJsonAny::str(recv_time_str.c_str()));
|
||||
}
|
||||
|
||||
//gb28181 sip Service
|
||||
SrsGb28181SipService::SrsGb28181SipService(SrsConfDirective* c)
|
||||
{
|
||||
|
@ -232,8 +414,9 @@ srs_error_t SrsGb28181SipService::on_udp_packet(const sockaddr* from, const int
|
|||
}
|
||||
std::string peer_ip = std::string(address_string);
|
||||
int peer_port = atoi(port_string);
|
||||
|
||||
srs_error_t err = on_udp_sip(peer_ip, peer_port, buf, nb_buf, (sockaddr*)from, fromlen);
|
||||
|
||||
std::string recv_msg(buf, nb_buf);
|
||||
srs_error_t err = on_udp_sip(peer_ip, peer_port, recv_msg, (sockaddr*)from, fromlen);
|
||||
if (err != srs_success) {
|
||||
return srs_error_wrap(err, "process udp");
|
||||
}
|
||||
|
@ -241,20 +424,23 @@ srs_error_t SrsGb28181SipService::on_udp_packet(const sockaddr* from, const int
|
|||
}
|
||||
|
||||
srs_error_t SrsGb28181SipService::on_udp_sip(string peer_ip, int peer_port,
|
||||
char* buf, int nb_buf, sockaddr* from, const int fromlen)
|
||||
std::string recv_msg, sockaddr* from, const int fromlen)
|
||||
{
|
||||
srs_error_t err = srs_success;
|
||||
|
||||
srs_info("gb28181: request peer(%s, %d) nbbuf=%d", peer_ip.c_str(), peer_port, nb_buf);
|
||||
srs_info("gb28181: request recv message=%s", buf);
|
||||
int recv_len = recv_msg.size();
|
||||
char* recv_data = (char*)recv_msg.c_str();
|
||||
|
||||
srs_info("gb28181: request peer(%s, %d) nbbuf=%d", peer_ip.c_str(), peer_port, recv_len);
|
||||
srs_info("gb28181: request recv message=%s", recv_data);
|
||||
|
||||
if (nb_buf < 10) {
|
||||
if (recv_len < 10) {
|
||||
return err;
|
||||
}
|
||||
|
||||
SrsSipRequest* req = NULL;
|
||||
|
||||
if ((err = sip->parse_request(&req, buf, nb_buf)) != srs_success) {
|
||||
if ((err = sip->parse_request(&req, recv_data, recv_len)) != srs_success) {
|
||||
return srs_error_wrap(err, "parse sip request");
|
||||
}
|
||||
|
||||
|
@ -266,6 +452,10 @@ srs_error_t SrsGb28181SipService::on_udp_sip(string peer_ip, int peer_port,
|
|||
|
||||
if (req->is_register()) {
|
||||
std::vector<std::string> serial = srs_string_split(srs_string_replace(req->uri,"sip:", ""), "@");
|
||||
if (serial.empty()){
|
||||
return srs_error_new(ERROR_GB28181_SIP_PRASE_FAILED, "register string split");
|
||||
}
|
||||
|
||||
if (serial.at(0) != config->sip_serial){
|
||||
srs_warn("gb28181: client:%s request serial and server serial inconformity(%s:%s)",
|
||||
req->sip_auth_id.c_str(), serial.at(0).c_str(), config->sip_serial.c_str());
|
||||
|
@ -273,7 +463,7 @@ srs_error_t SrsGb28181SipService::on_udp_sip(string peer_ip, int peer_port,
|
|||
}
|
||||
|
||||
srs_trace("gb28181: request client id=%s peer(%s, %d)", req->sip_auth_id.c_str(), peer_ip.c_str(), peer_port);
|
||||
srs_trace("gb28181: request %s method=%s, uri=%s, version=%s expires=%d",
|
||||
srs_trace("gb28181: %s method=%s, uri=%s, version=%s expires=%d",
|
||||
req->get_cmdtype_str().c_str(), req->method.c_str(),
|
||||
req->uri.c_str(), req->version.c_str(), req->expires);
|
||||
|
||||
|
@ -283,7 +473,8 @@ srs_error_t SrsGb28181SipService::on_udp_sip(string peer_ip, int peer_port,
|
|||
return err;
|
||||
}
|
||||
srs_assert(sip_session);
|
||||
|
||||
sip_session->set_request(req);
|
||||
|
||||
send_status(req, from, fromlen);
|
||||
sip_session->set_register_status(SrsGb28181SipSessionRegisterOk);
|
||||
sip_session->set_register_time(srs_get_system_time());
|
||||
|
@ -292,71 +483,50 @@ srs_error_t SrsGb28181SipService::on_udp_sip(string peer_ip, int peer_port,
|
|||
sip_session->set_sockaddr_len(fromlen);
|
||||
sip_session->set_peer_ip(peer_ip);
|
||||
sip_session->set_peer_port(peer_port);
|
||||
|
||||
}else if (req->is_message()) {
|
||||
SrsGb28181SipSession* sip_session = fetch(session_id);
|
||||
|
||||
if (!sip_session){
|
||||
sip_session = fetch_session_by_callid(req->call_id);
|
||||
}
|
||||
|
||||
if (!sip_session || sip_session->register_status() == SrsGb28181SipSessionUnkonw){
|
||||
srs_trace("gb28181: %s client not registered", req->sip_auth_id.c_str());
|
||||
return err;
|
||||
}
|
||||
|
||||
//reponse status
|
||||
send_status(req, from, fromlen);
|
||||
//sip_session->set_register_status(SrsGb28181SipSessionRegisterOk);
|
||||
//sip_session->set_register_time(srs_get_system_time());
|
||||
sip_session->set_alive_status(SrsGb28181SipSessionAliveOk);
|
||||
sip_session->set_alive_time(srs_get_system_time());
|
||||
sip_session->set_sockaddr((sockaddr)*from);
|
||||
sip_session->set_sockaddr_len(fromlen);
|
||||
sip_session->set_peer_port(peer_port);
|
||||
sip_session->set_peer_ip(peer_ip);
|
||||
|
||||
//send invite, play client av
|
||||
//start ps rtp listen, recv ps stream
|
||||
if (config->sip_auto_play && sip_session->register_status() == SrsGb28181SipSessionRegisterOk &&
|
||||
sip_session->alive_status() == SrsGb28181SipSessionAliveOk &&
|
||||
sip_session->invite_status() == SrsGb28181SipSessionUnkonw)
|
||||
{
|
||||
srs_trace("gb28181: request client id=%s, peer(%s, %d)", req->sip_auth_id.c_str(),
|
||||
peer_ip.c_str(), peer_port);
|
||||
srs_trace("gb28181: request %s method=%s, uri=%s, version=%s ", req->get_cmdtype_str().c_str(),
|
||||
req->method.c_str(), req->uri.c_str(), req->version.c_str());
|
||||
|
||||
SrsGb28181StreamChannel ch;
|
||||
ch.set_channel_id(session_id);
|
||||
ch.set_ip(config->host);
|
||||
if (config->sip_invite_port_fixed){
|
||||
ch.set_port_mode(RTP_PORT_MODE_FIXED);
|
||||
}else {
|
||||
ch.set_port_mode(RTP_PORT_MODE_RANDOM);
|
||||
if (req->cmdtype == SrsSipCmdRequest){
|
||||
send_status(req, from, fromlen);
|
||||
sip_session->set_alive_status(SrsGb28181SipSessionAliveOk);
|
||||
sip_session->set_alive_time(srs_get_system_time());
|
||||
sip_session->set_sockaddr((sockaddr)*from);
|
||||
sip_session->set_sockaddr_len(fromlen);
|
||||
sip_session->set_peer_port(peer_port);
|
||||
sip_session->set_peer_ip(peer_ip);
|
||||
|
||||
//update device list
|
||||
if (req->device_list_map.size() > 0){
|
||||
sip_session->update_device_list(req->device_list_map);
|
||||
}
|
||||
|
||||
int code = _srs_gb28181->create_stream_channel(&ch);
|
||||
if (code == ERROR_SUCCESS){
|
||||
code = send_invite(req, ch.get_ip(),
|
||||
ch.get_rtp_port(), ch.get_ssrc());
|
||||
}
|
||||
|
||||
if (code == ERROR_SUCCESS){
|
||||
sip_session->set_invite_status(SrsGb28181SipSessionTrying);
|
||||
sip_session->set_invite_time(srs_get_system_time());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}else if (req->is_invite()) {
|
||||
SrsGb28181SipSession* sip_session = fetch(session_id);
|
||||
SrsGb28181SipSession* sip_session = fetch_session_by_callid(req->call_id);
|
||||
|
||||
srs_trace("gb28181: request client id=%s, peer(%s, %d)", req->sip_auth_id.c_str(),
|
||||
peer_ip.c_str(), peer_port);
|
||||
srs_trace("gb28181: request %s method=%s, uri=%s, version=%s ",
|
||||
srs_trace("gb28181: %s method=%s, uri=%s, version=%s ",
|
||||
req->get_cmdtype_str().c_str(), req->method.c_str(), req->uri.c_str(), req->version.c_str());
|
||||
|
||||
if (!sip_session){
|
||||
srs_trace("gb28181: %s client not registered", req->sip_auth_id.c_str());
|
||||
srs_trace("gb28181: call_id %s not map %s client ", req->call_id.c_str(), req->sip_auth_id.c_str());
|
||||
return err;
|
||||
}
|
||||
|
||||
sip_session->set_sockaddr((sockaddr)*from);
|
||||
sip_session->set_sockaddr_len(fromlen);
|
||||
// sip_session->set_sockaddr((sockaddr)*from);
|
||||
// sip_session->set_sockaddr_len(fromlen);
|
||||
|
||||
if (sip_session->register_status() == SrsGb28181SipSessionUnkonw ||
|
||||
sip_session->alive_status() == SrsGb28181SipSessionUnkonw) {
|
||||
|
@ -364,37 +534,72 @@ srs_error_t SrsGb28181SipService::on_udp_sip(string peer_ip, int peer_port,
|
|||
return err;
|
||||
}
|
||||
|
||||
if (req->cmdtype == SrsSipCmdRespone && req->status == "200") {
|
||||
if (req->cmdtype == SrsSipCmdRespone){
|
||||
srs_trace("gb28181: INVITE response %s client status=%s", req->sip_auth_id.c_str(), req->status.c_str());
|
||||
send_ack(req, from, fromlen);
|
||||
sip_session->set_invite_status(SrsGb28181SipSessionInviteOk);
|
||||
sip_session->set_invite_time(srs_get_system_time());
|
||||
//Record tag and branch, which are required by the 'bye' command,
|
||||
sip_session->set_request(req);
|
||||
}else{
|
||||
sip_session->set_invite_status(SrsGb28181SipSessionUnkonw);
|
||||
sip_session->set_invite_time(srs_get_system_time());
|
||||
|
||||
if (req->status == "200") {
|
||||
send_ack(req, from, fromlen);
|
||||
SrsGb28181Device *device = sip_session->get_device_info(req->sip_auth_id);
|
||||
if (device){
|
||||
device->invite_status = SrsGb28181SipSessionInviteOk;
|
||||
device->req_inivate.copy(req);
|
||||
device->invite_time = srs_get_system_time();
|
||||
}
|
||||
}else if (req->status == "100") {
|
||||
//send_ack(req, from, fromlen);
|
||||
SrsGb28181Device *device = sip_session->get_device_info(req->sip_auth_id);
|
||||
if (device){
|
||||
device->req_inivate.copy(req);
|
||||
device->invite_status = SrsGb28181SipSessionTrying;
|
||||
device->invite_time = srs_get_system_time();
|
||||
}
|
||||
}else{
|
||||
SrsGb28181Device *device = sip_session->get_device_info(req->sip_auth_id);
|
||||
if (device){
|
||||
device->req_inivate.copy(req);
|
||||
device->invite_status = SrsGb28181SipSessionUnkonw;
|
||||
device->invite_time = srs_get_system_time();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}else if (req->is_bye()) {
|
||||
srs_trace("gb28181: request client id=%s, peer(%s, %d)", req->sip_auth_id.c_str(),
|
||||
peer_ip.c_str(), peer_port);
|
||||
srs_trace("gb28181: request %s method=%s, uri=%s, version=%s ",
|
||||
srs_trace("gb28181: %s method=%s, uri=%s, version=%s ",
|
||||
req->get_cmdtype_str().c_str(), req->method.c_str(), req->uri.c_str(), req->version.c_str());
|
||||
|
||||
SrsGb28181SipSession* sip_session = fetch(session_id);
|
||||
send_status(req, from, fromlen);
|
||||
|
||||
SrsGb28181SipSession* sip_session = fetch_session_by_callid(req->call_id);
|
||||
srs_trace("gb28181: request client id=%s, peer(%s, %d)", req->sip_auth_id.c_str(),
|
||||
peer_ip.c_str(), peer_port);
|
||||
srs_trace("gb28181: %s method=%s, uri=%s, version=%s ",
|
||||
req->get_cmdtype_str().c_str(), req->method.c_str(), req->uri.c_str(), req->version.c_str());
|
||||
|
||||
if (!sip_session){
|
||||
srs_trace("gb28181: %s client not registered", req->sip_auth_id.c_str());
|
||||
srs_trace("gb28181: call_id %s not map %s client ", req->call_id.c_str(), req->sip_auth_id.c_str());
|
||||
return err;
|
||||
}
|
||||
|
||||
sip_session->set_sockaddr((sockaddr)*from);
|
||||
sip_session->set_sockaddr_len(fromlen);
|
||||
|
||||
sip_session->set_invite_status(SrsGb28181SipSessionBye);
|
||||
sip_session->set_invite_time(srs_get_system_time());
|
||||
|
||||
if (req->cmdtype == SrsSipCmdRespone){
|
||||
srs_trace("gb28181: BYE %s client status=%s", req->sip_auth_id.c_str(), req->status.c_str());
|
||||
|
||||
if (req->status == "200") {
|
||||
SrsGb28181Device *device = sip_session->get_device_info(req->sip_auth_id);
|
||||
if (device){
|
||||
device->invite_status = SrsGb28181SipSessionBye;
|
||||
device->invite_time = srs_get_system_time();
|
||||
}
|
||||
}else {
|
||||
//TODO:fixme
|
||||
SrsGb28181Device *device = sip_session->get_device_info(req->sip_auth_id);
|
||||
if (device){
|
||||
device->invite_status = SrsGb28181SipSessionBye;
|
||||
device->invite_time = srs_get_system_time();
|
||||
}
|
||||
}
|
||||
}
|
||||
}else{
|
||||
srs_trace("gb28181: ingor request method=%s", req->method.c_str());
|
||||
}
|
||||
|
@ -427,6 +632,7 @@ int SrsGb28181SipService::send_ack(SrsSipRequest *req, sockaddr *f, int l)
|
|||
req->host_port = config->sip_port;
|
||||
req->realm = config->sip_realm;
|
||||
req->serial = config->sip_serial;
|
||||
req->chid = req->sip_auth_id;
|
||||
|
||||
sip->req_ack(ss, req);
|
||||
return send_message(f, l, ss);
|
||||
|
@ -448,64 +654,97 @@ int SrsGb28181SipService::send_status(SrsSipRequest *req, sockaddr *f, int l)
|
|||
}
|
||||
|
||||
|
||||
int SrsGb28181SipService::send_invite(SrsSipRequest *req, string ip, int port, uint32_t ssrc)
|
||||
srs_error_t SrsGb28181SipService::send_invite(SrsSipRequest *req, string ip, int port, uint32_t ssrc, std::string chid)
|
||||
{
|
||||
srs_error_t err = srs_success;
|
||||
|
||||
srs_assert(req);
|
||||
|
||||
SrsGb28181SipSession *sip_session = fetch(req->sip_auth_id);
|
||||
|
||||
if (!sip_session){
|
||||
return ERROR_GB28181_SESSION_IS_NOTEXIST;
|
||||
return srs_error_new(ERROR_GB28181_SESSION_IS_NOTEXIST, "sip session not exist");
|
||||
}
|
||||
|
||||
//if you are inviting or succeed in invite,
|
||||
//you cannot invite again. you need to 'bye' and try again
|
||||
if (sip_session->invite_status() == SrsGb28181SipSessionTrying ||
|
||||
sip_session->invite_status() == SrsGb28181SipSessionInviteOk){
|
||||
return ERROR_GB28181_SIP_IS_INVITING;
|
||||
SrsGb28181Device *device = sip_session->get_device_info(chid);
|
||||
if (!device || device->device_status != "ON"){
|
||||
return srs_error_new(ERROR_GB28181_SIP_CH_OFFLINE, "sip device channel offline");
|
||||
}
|
||||
|
||||
|
||||
if (device->invite_status == SrsGb28181SipSessionTrying ||
|
||||
device->invite_status == SrsGb28181SipSessionInviteOk){
|
||||
return srs_error_new(ERROR_GB28181_SIP_IS_INVITING, "sip device channel inviting");
|
||||
}
|
||||
|
||||
req->host = config->host;
|
||||
req->host_port = config->sip_port;
|
||||
req->realm = config->sip_realm;
|
||||
req->serial = config->sip_serial;
|
||||
req->chid = chid;
|
||||
req->seq = sip_session->sip_cseq();
|
||||
|
||||
SrsSipRequest register_req = sip_session->request();
|
||||
req->to_realm = register_req.to_realm;
|
||||
req->from_realm = config->sip_realm;
|
||||
|
||||
std::stringstream ss;
|
||||
sip->req_invite(ss, req, ip, port, ssrc);
|
||||
|
||||
|
||||
sockaddr addr = sip_session->sockaddr_from();
|
||||
|
||||
if (send_message(&addr, sip_session->sockaddr_fromlen(), ss) <= 0)
|
||||
{
|
||||
return ERROR_GB28181_SIP_INVITE_FAILED;
|
||||
return srs_error_new(ERROR_GB28181_SIP_INVITE_FAILED, "sip device invite failed");
|
||||
}
|
||||
|
||||
sip_session->set_invite_status(SrsGb28181SipSessionTrying);
|
||||
//prame branch, from_tag, to_tag, call_id,
|
||||
//The parameter of 'bye' must be the same as 'invite'
|
||||
device->req_inivate.copy(req);
|
||||
device->invite_time = srs_get_system_time();
|
||||
device->invite_status = SrsGb28181SipSessionTrying;
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
//call_id map sip_session
|
||||
sip_session_map_by_callid(sip_session, req->call_id);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
int SrsGb28181SipService::send_bye(SrsSipRequest *req)
|
||||
srs_error_t SrsGb28181SipService::send_bye(SrsSipRequest *req, std::string chid)
|
||||
{
|
||||
srs_error_t err = srs_success;
|
||||
|
||||
srs_assert(req);
|
||||
|
||||
SrsGb28181SipSession *sip_session = fetch(req->sip_auth_id);
|
||||
|
||||
if (!sip_session){
|
||||
return ERROR_GB28181_SESSION_IS_NOTEXIST;
|
||||
return srs_error_new(ERROR_GB28181_SESSION_IS_NOTEXIST, "sip session not exist");
|
||||
}
|
||||
|
||||
SrsGb28181Device *device = sip_session->get_device_info(chid);
|
||||
if (!device){
|
||||
return srs_error_new(ERROR_GB28181_SIP_CH_NOTEXIST, "sip device channel not exist");
|
||||
}
|
||||
|
||||
//prame branch, from_tag, to_tag, call_id,
|
||||
//The parameter of 'bye' must be the same as 'invite'
|
||||
SrsSipRequest r = sip_session->request();
|
||||
req->copy(&r);
|
||||
//SrsSipRequest r = sip_session->request();
|
||||
|
||||
req->host = config->host;
|
||||
req->copy(&device->req_inivate);
|
||||
|
||||
req->host = config->host;
|
||||
req->host_port = config->sip_port;
|
||||
req->realm = config->sip_realm;
|
||||
req->serial = config->sip_serial;
|
||||
|
||||
req->chid = chid;
|
||||
req->seq = sip_session->sip_cseq();
|
||||
|
||||
SrsSipRequest register_req = sip_session->request();
|
||||
req->to_realm = register_req.to_realm;
|
||||
req->from_realm = config->sip_realm;
|
||||
|
||||
//get protocol stack
|
||||
std::stringstream ss;
|
||||
sip->req_bye(ss, req);
|
||||
|
@ -513,20 +752,22 @@ int SrsGb28181SipService::send_bye(SrsSipRequest *req)
|
|||
sockaddr addr = sip_session->sockaddr_from();
|
||||
if (send_message(&addr, sip_session->sockaddr_fromlen(), ss) <= 0)
|
||||
{
|
||||
return ERROR_GB28181_SIP_BYE_FAILED;
|
||||
return srs_error_new(ERROR_GB28181_SIP_BYE_FAILED, "sip bye failed");
|
||||
}
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
return err;
|
||||
}
|
||||
|
||||
int SrsGb28181SipService::send_sip_raw_data(SrsSipRequest *req, std::string data)
|
||||
srs_error_t SrsGb28181SipService::send_sip_raw_data(SrsSipRequest *req, std::string data)
|
||||
{
|
||||
srs_error_t err = srs_success;
|
||||
|
||||
srs_assert(req);
|
||||
|
||||
SrsGb28181SipSession *sip_session = fetch(req->sip_auth_id);
|
||||
|
||||
if (!sip_session){
|
||||
return ERROR_GB28181_SESSION_IS_NOTEXIST;
|
||||
return srs_error_new(ERROR_GB28181_SESSION_IS_NOTEXIST, "sip session no exist");
|
||||
}
|
||||
|
||||
std::stringstream ss;
|
||||
|
@ -535,10 +776,140 @@ int SrsGb28181SipService::send_sip_raw_data(SrsSipRequest *req, std::string dat
|
|||
sockaddr addr = sip_session->sockaddr_from();
|
||||
if (send_message(&addr, sip_session->sockaddr_fromlen(), ss) <= 0)
|
||||
{
|
||||
return ERROR_GB28181_SIP_BYE_FAILED;
|
||||
return srs_error_new(ERROR_GB28181_SIP_RAW_DATA_FAILED, "sip raw data failed");
|
||||
}
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
return err;
|
||||
}
|
||||
|
||||
srs_error_t SrsGb28181SipService::send_query_catalog(SrsSipRequest *req)
|
||||
{
|
||||
srs_error_t err = srs_success;
|
||||
|
||||
srs_assert(req);
|
||||
|
||||
SrsGb28181SipSession *sip_session = fetch(req->sip_auth_id);
|
||||
|
||||
if (!sip_session){
|
||||
return srs_error_new(ERROR_GB28181_SESSION_IS_NOTEXIST, "sip session not exist");
|
||||
}
|
||||
|
||||
req->host = config->host;
|
||||
req->host_port = config->sip_port;
|
||||
req->realm = config->sip_realm;
|
||||
req->serial = config->sip_serial;
|
||||
req->chid = req->sip_auth_id;
|
||||
req->seq = sip_session->sip_cseq();
|
||||
|
||||
//get protocol stack
|
||||
std::stringstream ss;
|
||||
sip->req_query_catalog(ss, req);
|
||||
|
||||
return send_sip_raw_data(req, ss.str());
|
||||
}
|
||||
|
||||
srs_error_t SrsGb28181SipService::send_ptz(SrsSipRequest *req, std::string chid, std::string cmd,
|
||||
uint8_t speed, int priority)
|
||||
{
|
||||
srs_error_t err = srs_success;
|
||||
|
||||
srs_assert(req);
|
||||
|
||||
SrsGb28181SipSession *sip_session = fetch(req->sip_auth_id);
|
||||
|
||||
if (!sip_session){
|
||||
return srs_error_new(ERROR_GB28181_SESSION_IS_NOTEXIST, "sip session not exist");
|
||||
}
|
||||
|
||||
SrsGb28181Device *device = sip_session->get_device_info(chid);
|
||||
if (!device){
|
||||
return srs_error_new(ERROR_GB28181_SIP_CH_NOTEXIST, "sip device channel not exist");
|
||||
}
|
||||
|
||||
if (device->invite_status != SrsGb28181SipSessionInviteOk){
|
||||
return srs_error_new(ERROR_GB28181_SIP_NOT_INVITE, "sip device channel not inviting");
|
||||
}
|
||||
|
||||
//prame branch, from_tag, to_tag, call_id,
|
||||
//The parameter of 'bye' must be the same as 'invite'
|
||||
//SrsSipRequest r = sip_session->request();
|
||||
req->copy(&device->req_inivate);
|
||||
|
||||
req->host = config->host;
|
||||
req->host_port = config->sip_port;
|
||||
req->realm = config->sip_realm;
|
||||
req->serial = config->sip_serial;
|
||||
req->chid = chid;
|
||||
req->seq = sip_session->sip_cseq();
|
||||
|
||||
SrsSipPtzCmdType ptzcmd = SrsSipPtzCmdRight;
|
||||
const char *ss_cmd = cmd.c_str();
|
||||
if (!strcasecmp(ss_cmd, "stop")){
|
||||
ptzcmd = SrsSipPtzCmdStop;
|
||||
}else if (!strcasecmp(ss_cmd, "right")){
|
||||
ptzcmd = SrsSipPtzCmdRight;
|
||||
}else if (!strcasecmp(ss_cmd, "left")){
|
||||
ptzcmd = SrsSipPtzCmdLeft;
|
||||
}else if (!strcasecmp(ss_cmd, "down")){
|
||||
ptzcmd = SrsSipPtzCmdDown;
|
||||
}else if (!strcasecmp(ss_cmd, "up")){
|
||||
ptzcmd = SrsSipPtzCmdUp;
|
||||
}else if (!strcasecmp(ss_cmd, "zoomout")){
|
||||
ptzcmd = SrsSipPtzCmdZoomOut;
|
||||
}else if (!strcasecmp(ss_cmd, "zoomin")){
|
||||
ptzcmd = SrsSipPtzCmdZoomIn;
|
||||
}else{
|
||||
return srs_error_new(ERROR_GB28181_SIP_PTZ_CMD_INVALID, "sip ptz cmd no support");
|
||||
}
|
||||
|
||||
if (speed < 0 || speed > 0xFF){
|
||||
return srs_error_new(ERROR_GB28181_SIP_PTZ_CMD_INVALID, "sip ptz cmd speed out of range");
|
||||
}
|
||||
|
||||
if (priority <= 0 ){
|
||||
priority = 5;
|
||||
}
|
||||
|
||||
//get protocol stack
|
||||
std::stringstream ss;
|
||||
sip->req_ptz(ss, req, ptzcmd, speed, priority);
|
||||
|
||||
sockaddr addr = sip_session->sockaddr_from();
|
||||
if (send_message(&addr, sip_session->sockaddr_fromlen(), ss) <= 0)
|
||||
{
|
||||
return srs_error_new(ERROR_GB28181_SIP_PTZ_FAILED, "sip ptz failed");
|
||||
}
|
||||
|
||||
//call_id map sip_session
|
||||
sip_session_map_by_callid(sip_session, req->call_id);
|
||||
|
||||
return err;
|
||||
|
||||
}
|
||||
|
||||
srs_error_t SrsGb28181SipService::query_sip_session(std::string sid, SrsJsonArray* arr)
|
||||
{
|
||||
srs_error_t err = srs_success;
|
||||
|
||||
if (!sid.empty()){
|
||||
SrsGb28181SipSession* sess = fetch(sid);
|
||||
if (!sess){
|
||||
return srs_error_new(ERROR_GB28181_SESSION_IS_NOTEXIST, "sip session not exist");
|
||||
}
|
||||
SrsJsonObject* obj = SrsJsonAny::object();
|
||||
arr->append(obj);
|
||||
sess->dumps(obj);
|
||||
}else {
|
||||
std::map<std::string, SrsGb28181SipSession*>::iterator it;
|
||||
for (it = sessions.begin(); it != sessions.end(); ++it) {
|
||||
SrsGb28181SipSession* sess = it->second;
|
||||
SrsJsonObject* obj = SrsJsonAny::object();
|
||||
arr->append(obj);
|
||||
sess->dumps(obj);
|
||||
}
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
srs_error_t SrsGb28181SipService::fetch_or_create_sip_session(SrsSipRequest *req, SrsGb28181SipSession** sip_session)
|
||||
|
@ -596,4 +967,30 @@ void SrsGb28181SipService::destroy()
|
|||
sessions.clear();
|
||||
}
|
||||
|
||||
void SrsGb28181SipService::sip_session_map_by_callid(SrsGb28181SipSession *sess, std::string call_id)
|
||||
{
|
||||
if (sessions_by_callid.find(call_id) == sessions_by_callid.end()) {
|
||||
sessions_by_callid[call_id] = sess;
|
||||
}
|
||||
}
|
||||
|
||||
void SrsGb28181SipService::sip_session_unmap_by_callid(std::string call_id)
|
||||
{
|
||||
std::map<std::string, SrsGb28181SipSession*>::iterator it = sessions_by_callid.find(call_id);
|
||||
if (it != sessions_by_callid.end()) {
|
||||
sessions_by_callid.erase(it);
|
||||
}
|
||||
}
|
||||
|
||||
SrsGb28181SipSession* SrsGb28181SipService::fetch_session_by_callid(std::string call_id)
|
||||
{
|
||||
SrsGb28181SipSession* session = NULL;
|
||||
if (sessions_by_callid.find(call_id) == sessions_by_callid.end()) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
session = sessions_by_callid[call_id];
|
||||
return session;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -41,6 +41,7 @@ class SrsSipRequest;
|
|||
class SrsGb28181Config;
|
||||
class SrsSipStack;
|
||||
class SrsGb28181SipService;
|
||||
class SrsGb28181Device;
|
||||
|
||||
enum SrsGb28181SipSessionStatusType{
|
||||
SrsGb28181SipSessionUnkonw = 0,
|
||||
|
@ -51,6 +52,19 @@ enum SrsGb28181SipSessionStatusType{
|
|||
SrsGb28181SipSessionBye = 5,
|
||||
};
|
||||
|
||||
class SrsGb28181Device
|
||||
{
|
||||
public:
|
||||
SrsGb28181Device();
|
||||
virtual ~SrsGb28181Device();
|
||||
public:
|
||||
std::string device_id;
|
||||
std::string device_status;
|
||||
SrsGb28181SipSessionStatusType invite_status;
|
||||
srs_utime_t invite_time;
|
||||
SrsSipRequest req_inivate;
|
||||
};
|
||||
|
||||
class SrsGb28181SipSession: public ISrsCoroutineHandler, public ISrsConnection
|
||||
{
|
||||
private:
|
||||
|
@ -67,6 +81,7 @@ private:
|
|||
srs_utime_t _alive_time;
|
||||
srs_utime_t _invite_time;
|
||||
srs_utime_t _reg_expires;
|
||||
srs_utime_t _query_catalog_time;
|
||||
|
||||
std::string _peer_ip;
|
||||
int _peer_port;
|
||||
|
@ -75,10 +90,17 @@ private:
|
|||
int _fromlen;
|
||||
SrsSipRequest *req;
|
||||
|
||||
std::map<std::string, SrsGb28181Device*> _device_list;
|
||||
//std::map<std::string, int> _device_status;
|
||||
int _sip_cseq;
|
||||
|
||||
public:
|
||||
SrsGb28181SipSession(SrsGb28181SipService *c, SrsSipRequest* r);
|
||||
virtual ~SrsGb28181SipSession();
|
||||
|
||||
private:
|
||||
void destroy();
|
||||
|
||||
public:
|
||||
void set_register_status(SrsGb28181SipSessionStatusType s) { _register_status = s;}
|
||||
void set_alive_status(SrsGb28181SipSessionStatusType s) { _alive_status = s;}
|
||||
|
@ -94,7 +116,6 @@ public:
|
|||
void set_sockaddr_len(int l) { _fromlen = l;}
|
||||
void set_request(SrsSipRequest *r) { req->copy(r);}
|
||||
|
||||
|
||||
SrsGb28181SipSessionStatusType register_status() { return _register_status;}
|
||||
SrsGb28181SipSessionStatusType alive_status() { return _alive_status;}
|
||||
SrsGb28181SipSessionStatusType invite_status() { return _invite_status;}
|
||||
|
@ -108,8 +129,13 @@ public:
|
|||
sockaddr sockaddr_from() { return _from;}
|
||||
int sockaddr_fromlen() { return _fromlen;}
|
||||
SrsSipRequest request() { return *req;}
|
||||
int sip_cseq(){ return _sip_cseq++;}
|
||||
|
||||
std::string session_id() { return _session_id;}
|
||||
public:
|
||||
void update_device_list(std::map<std::string, std::string> devlist);
|
||||
SrsGb28181Device *get_device_info(std::string chid);
|
||||
void dumps(SrsJsonObject* obj);
|
||||
|
||||
public:
|
||||
virtual srs_error_t serve();
|
||||
|
@ -130,6 +156,7 @@ private:
|
|||
srs_netfd_t lfd;
|
||||
|
||||
std::map<std::string, SrsGb28181SipSession*> sessions;
|
||||
std::map<std::string, SrsGb28181SipSession*> sessions_by_callid;
|
||||
public:
|
||||
SrsGb28181SipService(SrsConfDirective* c);
|
||||
virtual ~SrsGb28181SipService();
|
||||
|
@ -140,15 +167,17 @@ public:
|
|||
virtual void set_stfd(srs_netfd_t fd);
|
||||
private:
|
||||
void destroy();
|
||||
srs_error_t on_udp_sip(std::string host, int port, char* buf, int nb_buf, sockaddr* from, int fromlen);
|
||||
srs_error_t on_udp_sip(std::string host, int port, std::string recv_msg, sockaddr* from, int fromlen);
|
||||
public:
|
||||
int send_message(sockaddr* f, int l, std::stringstream& ss);
|
||||
|
||||
int send_ack(SrsSipRequest *req, sockaddr *f, int l);
|
||||
int send_status(SrsSipRequest *req, sockaddr *f, int l);
|
||||
|
||||
int send_invite(SrsSipRequest *req, std::string ip, int port, uint32_t ssrc);
|
||||
int send_bye(SrsSipRequest *req);
|
||||
srs_error_t send_invite(SrsSipRequest *req, std::string ip, int port, uint32_t ssrc, std::string chid);
|
||||
srs_error_t send_bye(SrsSipRequest *req, std::string chid);
|
||||
srs_error_t send_query_catalog(SrsSipRequest *req);
|
||||
srs_error_t send_ptz(SrsSipRequest *req, std::string chid, std::string cmd, uint8_t speed, int priority);
|
||||
|
||||
// The SIP command is transmitted through HTTP API,
|
||||
// and the body content is transmitted to the device,
|
||||
|
@ -164,7 +193,8 @@ public:
|
|||
// Content-Length: 0
|
||||
//
|
||||
//
|
||||
int send_sip_raw_data(SrsSipRequest *req, std::string data);
|
||||
srs_error_t send_sip_raw_data(SrsSipRequest *req, std::string data);
|
||||
srs_error_t query_sip_session(std::string sid, SrsJsonArray* arr);
|
||||
|
||||
public:
|
||||
srs_error_t fetch_or_create_sip_session(SrsSipRequest *req, SrsGb28181SipSession** sess);
|
||||
|
@ -172,6 +202,9 @@ public:
|
|||
void remove_session(std::string id);
|
||||
SrsGb28181Config* get_config();
|
||||
|
||||
void sip_session_map_by_callid(SrsGb28181SipSession *sess, std::string call_id);
|
||||
void sip_session_unmap_by_callid(std::string call_id);
|
||||
SrsGb28181SipSession* fetch_session_by_callid(std::string call_id);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1741,6 +1741,21 @@ SrsGoApiGb28181::~SrsGoApiGb28181()
|
|||
|
||||
srs_error_t SrsGoApiGb28181::serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* r)
|
||||
{
|
||||
srs_error_t err = srs_success;
|
||||
|
||||
if ((err = do_serve_http(w, r)) != srs_success) {
|
||||
srs_warn("Server GB28181 err %s", srs_error_desc(err).c_str());
|
||||
int code = srs_error_code(err); srs_error_reset(err);
|
||||
return srs_api_response_code(w, r, code);
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
srs_error_t SrsGoApiGb28181::do_serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* r)
|
||||
{
|
||||
srs_error_t err = srs_success;
|
||||
|
||||
SrsJsonObject* obj = SrsJsonAny::object();
|
||||
SrsAutoFree(SrsJsonObject, obj);
|
||||
|
||||
|
@ -1756,103 +1771,144 @@ srs_error_t SrsGoApiGb28181::serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessa
|
|||
//fixed, random
|
||||
string port_mode = r->query_get("port_mode");
|
||||
|
||||
if (_srs_gb28181) {
|
||||
if(action == "create_channel"){
|
||||
if (id.empty()){
|
||||
return srs_api_response_code(w, r, ERROR_GB28181_VALUE_EMPTY);
|
||||
}
|
||||
if (!_srs_gb28181) {
|
||||
return srs_error_new(ERROR_GB28181_SERVER_NOT_RUN, "no gb28181 engine");
|
||||
}
|
||||
|
||||
SrsGb28181StreamChannel channel;
|
||||
channel.set_channel_id(id);
|
||||
channel.set_app(app);
|
||||
channel.set_stream(stream);
|
||||
channel.set_port_mode(port_mode);
|
||||
|
||||
uint32_t code = _srs_gb28181->create_stream_channel(&channel);
|
||||
if (code != ERROR_SUCCESS) {
|
||||
return srs_api_response_code(w, r, code);
|
||||
}
|
||||
|
||||
data->set("query", SrsJsonAny::object()
|
||||
->set("id", SrsJsonAny::str(channel.get_channel_id().c_str()))
|
||||
->set("ip", SrsJsonAny::str(channel.get_ip().c_str()))
|
||||
->set("rtmp_port", SrsJsonAny::integer(channel.get_rtmp_port()))
|
||||
->set("app", SrsJsonAny::str(channel.get_app().c_str()))
|
||||
->set("stream", SrsJsonAny::str(channel.get_stream().c_str()))
|
||||
->set("rtp_port", SrsJsonAny::integer(channel.get_rtp_port()))
|
||||
->set("ssrc", SrsJsonAny::integer(channel.get_ssrc())));
|
||||
return srs_api_response(w, r, obj->dumps());
|
||||
|
||||
}
|
||||
else if(action == "delete_channel"){
|
||||
if (id.empty()){
|
||||
return srs_api_response_code(w, r, ERROR_GB28181_VALUE_EMPTY);
|
||||
}
|
||||
|
||||
uint32_t code = _srs_gb28181->delete_stream_channel(id);
|
||||
return srs_api_response_code(w, r, code);
|
||||
}
|
||||
else if(action == "query_channel") {
|
||||
SrsJsonArray* arr = SrsJsonAny::array();
|
||||
data->set("channels", arr);
|
||||
|
||||
uint32_t code = _srs_gb28181->queue_stream_channel(id, arr);
|
||||
if (code != ERROR_SUCCESS) {
|
||||
return srs_api_response_code(w, r, code);
|
||||
}
|
||||
|
||||
return srs_api_response(w, r, obj->dumps());
|
||||
}
|
||||
else if(action == "sip_invite"){
|
||||
if (id.empty()){
|
||||
return srs_api_response_code(w, r, ERROR_GB28181_VALUE_EMPTY);
|
||||
}
|
||||
|
||||
string ssrc = r->query_get("ssrc");
|
||||
string rtp_port = r->query_get("rtp_port");
|
||||
string ip = r->query_get("ip");
|
||||
|
||||
int _port = strtoul(rtp_port.c_str(), NULL, 10);
|
||||
uint32_t _ssrc = (uint32_t)(strtoul(ssrc.c_str(), NULL, 10));
|
||||
|
||||
|
||||
|
||||
int code = _srs_gb28181->notify_sip_invite(id, ip, _port, _ssrc);
|
||||
return srs_api_response_code(w, r, code);
|
||||
}
|
||||
else if(action == "sip_bye"){
|
||||
if (id.empty()){
|
||||
return srs_api_response_code(w, r, ERROR_GB28181_VALUE_EMPTY);
|
||||
}
|
||||
|
||||
int code = _srs_gb28181->notify_sip_bye(id);
|
||||
return srs_api_response_code(w, r, code);
|
||||
}
|
||||
else if(action == "sip_raw_data"){
|
||||
if (id.empty()){
|
||||
return srs_api_response_code(w, r, ERROR_GB28181_VALUE_EMPTY);
|
||||
}
|
||||
|
||||
std::string body;
|
||||
r->body_read_all(body);
|
||||
int code = _srs_gb28181->notify_sip_raw_data(id, body);
|
||||
return srs_api_response_code(w, r, code);
|
||||
}
|
||||
else if(action == "sip_unregister"){
|
||||
if (id.empty()){
|
||||
return srs_api_response_code(w, r, ERROR_GB28181_VALUE_EMPTY);
|
||||
}
|
||||
|
||||
int code = _srs_gb28181->notify_sip_unregister(id);
|
||||
return srs_api_response_code(w, r, code);
|
||||
}
|
||||
else
|
||||
{
|
||||
return srs_api_response_code(w, r, ERROR_GB28181_ACTION_INVALID);
|
||||
if(action == "create_channel"){
|
||||
if (id.empty()){
|
||||
return srs_error_new(ERROR_GB28181_VALUE_EMPTY, "no id");
|
||||
}
|
||||
|
||||
}else {
|
||||
return srs_api_response_code(w, r, ERROR_GB28181_SERVER_NOT_RUN);
|
||||
SrsGb28181StreamChannel channel;
|
||||
channel.set_channel_id(id);
|
||||
channel.set_app(app);
|
||||
channel.set_stream(stream);
|
||||
channel.set_port_mode(port_mode);
|
||||
|
||||
if ((err = _srs_gb28181->create_stream_channel(&channel)) != srs_success) {
|
||||
return srs_error_wrap(err, "create stream channel");
|
||||
}
|
||||
|
||||
data->set("query", SrsJsonAny::object()
|
||||
->set("id", SrsJsonAny::str(channel.get_channel_id().c_str()))
|
||||
->set("ip", SrsJsonAny::str(channel.get_ip().c_str()))
|
||||
->set("rtmp_port", SrsJsonAny::integer(channel.get_rtmp_port()))
|
||||
->set("app", SrsJsonAny::str(channel.get_app().c_str()))
|
||||
->set("stream", SrsJsonAny::str(channel.get_stream().c_str()))
|
||||
->set("rtp_port", SrsJsonAny::integer(channel.get_rtp_port()))
|
||||
->set("ssrc", SrsJsonAny::integer(channel.get_ssrc())));
|
||||
return srs_api_response(w, r, obj->dumps());
|
||||
|
||||
} else if(action == "delete_channel"){
|
||||
if (id.empty()){
|
||||
return srs_error_new(ERROR_GB28181_VALUE_EMPTY, "no id");
|
||||
}
|
||||
|
||||
if ((err = _srs_gb28181->delete_stream_channel(id)) != srs_success) {
|
||||
return srs_error_wrap(err, "delete stream channel");
|
||||
}
|
||||
|
||||
return srs_api_response_code(w, r, 0);
|
||||
} else if(action == "query_channel") {
|
||||
SrsJsonArray* arr = SrsJsonAny::array();
|
||||
data->set("channels", arr);
|
||||
|
||||
if ((err = _srs_gb28181->query_stream_channel(id, arr)) != srs_success) {
|
||||
return srs_error_wrap(err, "query stream channel");
|
||||
}
|
||||
|
||||
return srs_api_response(w, r, obj->dumps());
|
||||
} else if(action == "sip_invite"){
|
||||
string chid = r->query_get("chid");
|
||||
if (id.empty() || chid.empty()){
|
||||
return srs_error_new(ERROR_GB28181_VALUE_EMPTY, "no id or chid");
|
||||
}
|
||||
|
||||
string ssrc = r->query_get("ssrc");
|
||||
string rtp_port = r->query_get("rtp_port");
|
||||
string ip = r->query_get("ip");
|
||||
|
||||
int _port = strtoul(rtp_port.c_str(), NULL, 10);
|
||||
uint32_t _ssrc = (uint32_t)(strtoul(ssrc.c_str(), NULL, 10));
|
||||
|
||||
if ((err = _srs_gb28181->notify_sip_invite(id, ip, _port, _ssrc, chid)) != srs_success) {
|
||||
return srs_error_wrap(err, "notify sip invite");
|
||||
}
|
||||
|
||||
return srs_api_response_code(w, r, 0);
|
||||
} else if(action == "sip_bye"){
|
||||
string chid = r->query_get("chid");
|
||||
if (id.empty() || chid.empty()){
|
||||
return srs_error_new(ERROR_GB28181_VALUE_EMPTY, "no id or chid");
|
||||
}
|
||||
|
||||
if ((err = _srs_gb28181->notify_sip_bye(id, chid)) != srs_success) {
|
||||
return srs_error_wrap(err, "notify sip bye");
|
||||
}
|
||||
|
||||
return srs_api_response_code(w, r, 0);
|
||||
} else if(action == "sip_ptz"){
|
||||
string chid = r->query_get("chid");
|
||||
string ptzcmd = r->query_get("ptzcmd");
|
||||
string speed = r->query_get("speed");
|
||||
string priority = r->query_get("priority");
|
||||
if (id.empty() || chid.empty() || ptzcmd.empty() || speed.empty()){
|
||||
return srs_error_new(ERROR_GB28181_VALUE_EMPTY, "no id or chid or ptzcmd or speed");
|
||||
}
|
||||
|
||||
uint8_t _speed = (uint8_t)(strtoul(speed.c_str(), NULL, 10));
|
||||
int _priority = (int)(strtoul(priority.c_str(), NULL, 10));
|
||||
|
||||
if ((err = _srs_gb28181->notify_sip_ptz(id, chid, ptzcmd, _speed, _priority)) != srs_success) {
|
||||
return srs_error_wrap(err, "notify sip ptz");
|
||||
}
|
||||
|
||||
return srs_api_response_code(w, r, 0);
|
||||
} else if(action == "sip_raw_data"){
|
||||
if (id.empty()){
|
||||
return srs_error_new(ERROR_GB28181_VALUE_EMPTY, "no id");
|
||||
}
|
||||
|
||||
std::string body;
|
||||
r->body_read_all(body);
|
||||
|
||||
if ((err = _srs_gb28181->notify_sip_raw_data(id, body)) != srs_success) {
|
||||
return srs_error_wrap(err, "notify sip raw data");
|
||||
}
|
||||
|
||||
return srs_api_response_code(w, r, 0);
|
||||
} else if(action == "sip_unregister"){
|
||||
if (id.empty()){
|
||||
return srs_error_new(ERROR_GB28181_VALUE_EMPTY, "no id");
|
||||
}
|
||||
|
||||
if ((err = _srs_gb28181->notify_sip_unregister(id)) != srs_success) {
|
||||
return srs_error_wrap(err, "notify sip unregister");
|
||||
}
|
||||
|
||||
return srs_api_response_code(w, r, 0);
|
||||
} else if(action == "sip_query_catalog"){
|
||||
if (id.empty()){
|
||||
return srs_error_new(ERROR_GB28181_VALUE_EMPTY, "no id");
|
||||
}
|
||||
|
||||
if ((err = _srs_gb28181->notify_sip_query_catalog(id)) != srs_success) {
|
||||
return srs_error_wrap(err, "notify sip query catelog");
|
||||
}
|
||||
|
||||
return srs_api_response_code(w, r, 0);
|
||||
} else if(action == "sip_query_session"){
|
||||
SrsJsonArray* arr = SrsJsonAny::array();
|
||||
data->set("sessions", arr);
|
||||
|
||||
if ((err = _srs_gb28181->query_sip_session(id, arr)) != srs_success) {
|
||||
return srs_error_wrap(err, "notify sip session");
|
||||
}
|
||||
|
||||
return srs_api_response(w, r, obj->dumps());
|
||||
} else {
|
||||
return srs_error_new(ERROR_GB28181_ACTION_INVALID, "action %s", action.c_str());
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -249,6 +249,8 @@ public:
|
|||
virtual ~SrsGoApiGb28181();
|
||||
public:
|
||||
virtual srs_error_t serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* r);
|
||||
private:
|
||||
virtual srs_error_t do_serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* r);
|
||||
};
|
||||
#endif
|
||||
|
||||
|
|
|
@ -34,6 +34,8 @@ using namespace std;
|
|||
#include <unistd.h>
|
||||
|
||||
#include <netinet/udp.h>
|
||||
// Define macro for UDP GSO.
|
||||
// @see https://github.com/torvalds/linux/blob/master/tools/testing/selftests/net/udpgso.c
|
||||
#ifndef UDP_SEGMENT
|
||||
#define UDP_SEGMENT 103
|
||||
#endif
|
||||
|
|
|
@ -178,6 +178,8 @@
|
|||
#define SRS_CONSTS_LOG_EXEC "EXE"
|
||||
// The rtc.
|
||||
#define SRS_CONSTS_LOG_RTC "RTC"
|
||||
// The gb28181 stream log id.
|
||||
#define SRS_CONSTS_LOG_GB28181_CASTER "GBS"
|
||||
|
||||
///////////////////////////////////////////////////////////
|
||||
///////////////////////////////////////////////////////////
|
||||
|
|
|
@ -363,6 +363,13 @@
|
|||
#define ERROR_GB28181_SIP_BYE_FAILED 6009
|
||||
#define ERROR_GB28181_SIP_IS_INVITING 6010
|
||||
#define ERROR_GB28181_CREATER_RTMPMUXER_FAILED 6011
|
||||
#define ERROR_GB28181_SIP_CH_OFFLINE 6012
|
||||
#define ERROR_GB28181_SIP_CH_NOTEXIST 6013
|
||||
#define ERROR_GB28181_SIP_RAW_DATA_FAILED 6014
|
||||
#define ERROR_GB28181_SIP_PRASE_FAILED 6015
|
||||
#define ERROR_GB28181_SIP_PTZ_FAILED 6016
|
||||
#define ERROR_GB28181_SIP_NOT_INVITE 6017
|
||||
#define ERROR_GB28181_SIP_PTZ_CMD_INVALID 6018
|
||||
|
||||
///////////////////////////////////////////////////////
|
||||
// HTTP API error.
|
||||
|
|
|
@ -296,7 +296,7 @@ srs_error_t SrsFileReader::lseek(off_t offset, int whence, off_t* seeked)
|
|||
{
|
||||
off_t sk = _srs_lseek_fn(fd, offset, whence);
|
||||
if (sk < 0) {
|
||||
return srs_error_new(ERROR_SYSTEM_FILE_SEEK, "seek %v failed", (int)sk);
|
||||
return srs_error_new(ERROR_SYSTEM_FILE_SEEK, "seek %d failed", (int)sk);
|
||||
}
|
||||
|
||||
if (seeked) {
|
||||
|
|
|
@ -510,7 +510,7 @@ srs_error_t SrsMp4Box::encode_header(SrsBuffer* buf)
|
|||
|
||||
int lrsz = nb_header() - SrsMp4Box::nb_header();
|
||||
if (!buf->require(lrsz)) {
|
||||
return srs_error_new(ERROR_MP4_BOX_REQUIRE_SPACE, "box requires %v only %d bytes", lrsz, buf->left());
|
||||
return srs_error_new(ERROR_MP4_BOX_REQUIRE_SPACE, "box requires %d only %d bytes", lrsz, buf->left());
|
||||
}
|
||||
|
||||
return err;
|
||||
|
@ -3602,19 +3602,19 @@ srs_error_t SrsMp4ES_Descriptor::decode_payload(SrsBuffer* buf)
|
|||
|
||||
if (streamDependenceFlag) {
|
||||
if (!buf->require(2)) {
|
||||
return srs_error_new(ERROR_MP4_BOX_REQUIRE_SPACE, "ES requires 2 only %v bytes", buf->left());
|
||||
return srs_error_new(ERROR_MP4_BOX_REQUIRE_SPACE, "ES requires 2 only %d bytes", buf->left());
|
||||
}
|
||||
dependsOn_ES_ID = buf->read_2bytes();
|
||||
}
|
||||
|
||||
if (URL_Flag) {
|
||||
if (!buf->require(1)) {
|
||||
return srs_error_new(ERROR_MP4_BOX_REQUIRE_SPACE, "URLlength requires 1 only %v bytes", buf->left());
|
||||
return srs_error_new(ERROR_MP4_BOX_REQUIRE_SPACE, "URLlength requires 1 only %d bytes", buf->left());
|
||||
}
|
||||
uint8_t URLlength = buf->read_1bytes();
|
||||
|
||||
if (!buf->require(URLlength)) {
|
||||
return srs_error_new(ERROR_MP4_BOX_REQUIRE_SPACE, "URL requires %d only %v bytes", URLlength, buf->left());
|
||||
return srs_error_new(ERROR_MP4_BOX_REQUIRE_SPACE, "URL requires %d only %d bytes", URLlength, buf->left());
|
||||
}
|
||||
URLstring.resize(URLlength);
|
||||
buf->read_bytes(&URLstring[0], URLlength);
|
||||
|
@ -3622,7 +3622,7 @@ srs_error_t SrsMp4ES_Descriptor::decode_payload(SrsBuffer* buf)
|
|||
|
||||
if (OCRstreamFlag) {
|
||||
if (!buf->require(2)) {
|
||||
return srs_error_new(ERROR_MP4_BOX_REQUIRE_SPACE, "OCR requires 2 only %v bytes", buf->left());
|
||||
return srs_error_new(ERROR_MP4_BOX_REQUIRE_SPACE, "OCR requires 2 only %d bytes", buf->left());
|
||||
}
|
||||
OCR_ES_Id = buf->read_2bytes();
|
||||
}
|
||||
|
|
|
@ -45,10 +45,51 @@ using namespace std;
|
|||
|
||||
unsigned int srs_sip_random(int min,int max)
|
||||
{
|
||||
srand(int(time(0)));
|
||||
//it is possible to duplicate data with time(0)
|
||||
srand(unsigned(srs_update_system_time()));
|
||||
return rand() % (max - min + 1) + min;
|
||||
}
|
||||
|
||||
std::string srs_sip_generate_branch()
|
||||
{
|
||||
int rand = srs_sip_random(10000000, 99999999);
|
||||
std::stringstream branch;
|
||||
branch << "SrsGbB" << rand;
|
||||
return branch.str();
|
||||
}
|
||||
|
||||
std::string srs_sip_generate_to_tag()
|
||||
{
|
||||
uint32_t rand = srs_sip_random(10000000, 99999999);
|
||||
std::stringstream branch;
|
||||
branch << "SrsGbT" << rand;
|
||||
return branch.str();
|
||||
}
|
||||
|
||||
std::string srs_sip_generate_from_tag()
|
||||
{
|
||||
uint32_t rand = srs_sip_random(10000000, 99999999);
|
||||
std::stringstream branch;
|
||||
branch << "SrsGbF" << rand;
|
||||
return branch.str();
|
||||
}
|
||||
|
||||
std::string srs_sip_generate_call_id()
|
||||
{
|
||||
uint32_t rand = srs_sip_random(10000000, 99999999);
|
||||
std::stringstream branch;
|
||||
branch << "2020" << rand;
|
||||
return branch.str();
|
||||
}
|
||||
|
||||
std::string srs_sip_generate_sn()
|
||||
{
|
||||
uint32_t rand = srs_sip_random(10000000, 99999999);
|
||||
std::stringstream sn;
|
||||
sn << rand;
|
||||
return sn.str();
|
||||
}
|
||||
|
||||
std::string srs_sip_get_form_to_uri(std::string msg)
|
||||
{
|
||||
//<sip:34020000002000000001@3402000000>;tag=536961166
|
||||
|
@ -109,7 +150,7 @@ std::string srs_sip_get_param(std::string msg, std::string param)
|
|||
|
||||
std::vector<std::string> v_pram = srs_string_split(value, "=");
|
||||
|
||||
if (v_pram.size() > 0) {
|
||||
if (v_pram.size() > 1) {
|
||||
return v_pram.at(1);
|
||||
}
|
||||
}
|
||||
|
@ -156,6 +197,11 @@ SrsSipRequest::SrsSipRequest()
|
|||
sip_username = "";
|
||||
peer_ip = "";
|
||||
peer_port = 0;
|
||||
|
||||
chid = "";
|
||||
|
||||
from_realm = "";
|
||||
to_realm = "";
|
||||
}
|
||||
|
||||
SrsSipRequest::~SrsSipRequest()
|
||||
|
@ -203,43 +249,51 @@ std::string SrsSipRequest::get_cmdtype_str()
|
|||
|
||||
void SrsSipRequest::copy(SrsSipRequest* src)
|
||||
{
|
||||
if (!src){
|
||||
return;
|
||||
}
|
||||
|
||||
method = src->method;
|
||||
uri = src->uri;
|
||||
version = src->version;
|
||||
seq = src->seq;
|
||||
content_type = src->content_type;
|
||||
content_length = src->content_length;
|
||||
call_id = src->call_id;
|
||||
from = src->from;
|
||||
to = src->to;
|
||||
via = src->via;
|
||||
from_tag = src->from_tag;
|
||||
to_tag = src->to_tag;
|
||||
contact = src->contact;
|
||||
user_agent = src->user_agent;
|
||||
branch = src->branch;
|
||||
status = src->status;
|
||||
expires = src->expires;
|
||||
max_forwards = src->max_forwards;
|
||||
www_authenticate = src->www_authenticate;
|
||||
authorization = src->authorization;
|
||||
cmdtype = src->cmdtype;
|
||||
if (!src){
|
||||
return;
|
||||
}
|
||||
|
||||
method = src->method;
|
||||
uri = src->uri;
|
||||
version = src->version;
|
||||
seq = src->seq;
|
||||
content_type = src->content_type;
|
||||
content_length = src->content_length;
|
||||
call_id = src->call_id;
|
||||
from = src->from;
|
||||
to = src->to;
|
||||
via = src->via;
|
||||
from_tag = src->from_tag;
|
||||
to_tag = src->to_tag;
|
||||
contact = src->contact;
|
||||
user_agent = src->user_agent;
|
||||
branch = src->branch;
|
||||
status = src->status;
|
||||
expires = src->expires;
|
||||
max_forwards = src->max_forwards;
|
||||
www_authenticate = src->www_authenticate;
|
||||
authorization = src->authorization;
|
||||
cmdtype = src->cmdtype;
|
||||
|
||||
host = src->host;
|
||||
host_port = src->host_port;
|
||||
host = src->host;
|
||||
host_port = src->host_port;
|
||||
|
||||
serial = src->serial;
|
||||
realm = src->realm;
|
||||
|
||||
sip_auth_id = src->sip_auth_id;
|
||||
sip_auth_pwd = src->sip_auth_pwd;
|
||||
sip_username = src->sip_username;
|
||||
peer_ip = src->peer_ip;
|
||||
peer_port = src->peer_port;
|
||||
serial = src->serial;
|
||||
realm = src->realm;
|
||||
|
||||
sip_auth_id = src->sip_auth_id;
|
||||
sip_auth_pwd = src->sip_auth_pwd;
|
||||
sip_username = src->sip_username;
|
||||
peer_ip = src->peer_ip;
|
||||
peer_port = src->peer_port;
|
||||
|
||||
chid = src->chid;
|
||||
|
||||
xml_body_map = src->xml_body_map;
|
||||
device_list_map = src->device_list_map;
|
||||
|
||||
from_realm = src->from_realm;
|
||||
to_realm = src->to_realm;
|
||||
}
|
||||
|
||||
SrsSipStack::SrsSipStack()
|
||||
|
@ -267,12 +321,158 @@ srs_error_t SrsSipStack::parse_request(SrsSipRequest** preq, const char* recv_ms
|
|||
return err;
|
||||
}
|
||||
|
||||
srs_error_t SrsSipStack::parse_xml(std::string xml_msg, std::map<std::string, std::string> &json_map)
|
||||
{
|
||||
/*
|
||||
<?xml version="1.0" encoding="gb2312"?>
|
||||
<Notify>
|
||||
<CmdType>Keepalive</CmdType>
|
||||
<SN>2034</SN>
|
||||
<DeviceID>34020000001110000001</DeviceID>
|
||||
<Status>OK</Status>
|
||||
<Info>
|
||||
<DeviceID>34020000001320000002</DeviceID>
|
||||
<DeviceID>34020000001320000003</DeviceID>
|
||||
<DeviceID>34020000001320000005</DeviceID>
|
||||
<DeviceID>34020000001320000006</DeviceID>
|
||||
<DeviceID>34020000001320000007</DeviceID>
|
||||
<DeviceID>34020000001320000008</DeviceID>
|
||||
</Info>
|
||||
</Notify>
|
||||
*/
|
||||
|
||||
const char* start = xml_msg.c_str();
|
||||
const char* end = start + xml_msg.size();
|
||||
char* p = (char*)start;
|
||||
|
||||
char* value_start = NULL;
|
||||
|
||||
std::string xml_header;
|
||||
int xml_layer = 0;
|
||||
|
||||
//std::map<string, string> json_map;
|
||||
std::map<int, string> json_key;
|
||||
while (p < end) {
|
||||
if (p[0] == '\n'){
|
||||
p +=1;
|
||||
value_start = NULL;
|
||||
} else if (p[0] == '\r' && p[1] == '\n') {
|
||||
p +=2;
|
||||
value_start = NULL;
|
||||
} else if (p[0] == '<' && p[1] == '/') { //</Notify> xml item end flag
|
||||
std::string value = "";
|
||||
if (value_start) {
|
||||
value = std::string(value_start, p-value_start);
|
||||
}
|
||||
|
||||
//skip </
|
||||
p += 2;
|
||||
|
||||
//</Notify> get Notify
|
||||
char *s = p;
|
||||
while (p[0] != '>') {p++;}
|
||||
std::string key(s, p-s);
|
||||
|
||||
//<DeviceList Num="2"> get DeviceList
|
||||
std::vector<string> vec = srs_string_split(key, " ");
|
||||
if (vec.empty()){
|
||||
return srs_error_new(ERROR_GB28181_SIP_PRASE_FAILED, "prase xml");
|
||||
}
|
||||
|
||||
key = vec.at(0);
|
||||
|
||||
/*xml element to map
|
||||
<Notify>
|
||||
<info>
|
||||
<DeviceID>34020000001320000001</DeviceID>
|
||||
<DeviceID>34020000001320000002</DeviceID>
|
||||
</info>
|
||||
</Notify>
|
||||
to map is: Notify@Info@DeviceID:34020000001320000001,34020000001320000002
|
||||
*/
|
||||
|
||||
//get map key
|
||||
std::string mkey = "";
|
||||
for (int i = 0; i < xml_layer ; i++){
|
||||
if (mkey.empty()) {
|
||||
mkey = json_key[i];
|
||||
}else{
|
||||
mkey = mkey + "@" + json_key[i];
|
||||
}
|
||||
}
|
||||
|
||||
//set map value
|
||||
if (!mkey.empty()){
|
||||
if (json_map.find(mkey) == json_map.end()){
|
||||
json_map[mkey] = value;
|
||||
}else{
|
||||
json_map[mkey] = json_map[mkey] + ","+ value;
|
||||
}
|
||||
}
|
||||
|
||||
value_start = NULL;
|
||||
xml_layer--;
|
||||
|
||||
} else if (p[0] == '<') { //<Notify> xml item begin flag
|
||||
//skip <
|
||||
p +=1;
|
||||
|
||||
//<Notify> get Notify
|
||||
char *s = p;
|
||||
while (p[0] != '>') {p++;}
|
||||
std::string key(s, p-s);
|
||||
|
||||
if (srs_string_contains(key, "?xml")){
|
||||
//xml header
|
||||
xml_header = key;
|
||||
json_map["XmlHeader"] = xml_header;
|
||||
}else {
|
||||
//<DeviceList Num="2"> get DeviceList
|
||||
std::vector<string> vec = srs_string_split(key, " ");
|
||||
if (vec.empty()){
|
||||
return srs_error_new(ERROR_GB28181_SIP_PRASE_FAILED, "prase xml");
|
||||
}
|
||||
|
||||
key = vec.at(0);
|
||||
|
||||
//key to map by xml_layer
|
||||
//<Notify>
|
||||
// <info>
|
||||
// </info>
|
||||
//</Notify>
|
||||
//json_key[0] = "Notify"
|
||||
//json_key[1] = "info"
|
||||
json_key[xml_layer] = key;
|
||||
xml_layer++;
|
||||
}
|
||||
|
||||
p +=1;
|
||||
value_start = p;
|
||||
} else {
|
||||
p++;
|
||||
}
|
||||
}
|
||||
|
||||
// std::map<string, string>::iterator it2;
|
||||
// for (it2 = json_map.begin(); it2 != json_map.end(); ++it2) {
|
||||
// srs_trace("========%s:%s", it2->first.c_str(), it2->second.c_str());
|
||||
// }
|
||||
|
||||
return srs_success;
|
||||
}
|
||||
|
||||
srs_error_t SrsSipStack::do_parse_request(SrsSipRequest* req, const char* recv_msg)
|
||||
{
|
||||
srs_error_t err = srs_success;
|
||||
|
||||
std::vector<std::string> header_body = srs_string_split(recv_msg, SRS_RTSP_CRLFCRLF);
|
||||
if (header_body.empty()){
|
||||
return srs_error_new(ERROR_GB28181_SIP_PRASE_FAILED, "parse reques message");
|
||||
}
|
||||
|
||||
std::string header = header_body.at(0);
|
||||
//Must be added SRS_RTSP_CRLFCRLF in order to handle the last line header
|
||||
header += SRS_RTSP_CRLFCRLF;
|
||||
std::string body = "";
|
||||
|
||||
if (header_body.size() > 1){
|
||||
|
@ -296,7 +496,7 @@ srs_error_t SrsSipStack::do_parse_request(SrsSipRequest* req, const char* recv_m
|
|||
newline_start = p;
|
||||
|
||||
if (firstline == ""){
|
||||
firstline = oneline;
|
||||
firstline = srs_string_replace(oneline, "\r\n", "");
|
||||
srs_info("sip: first line=%s", firstline.c_str());
|
||||
}else{
|
||||
size_t pos = oneline.find(":");
|
||||
|
@ -311,7 +511,7 @@ srs_error_t SrsSipStack::do_parse_request(SrsSipRequest* req, const char* recv_m
|
|||
|
||||
if (!strcasecmp(phead, "call-id:")) {
|
||||
std::vector<std::string> vec_callid = srs_string_split(content, " ");
|
||||
req->call_id = vec_callid.at(0);
|
||||
req->call_id = vec_callid.empty() ? "" : vec_callid.at(0);
|
||||
}
|
||||
else if (!strcasecmp(phead, "contact:")) {
|
||||
req->contact = content;
|
||||
|
@ -327,8 +527,9 @@ srs_error_t SrsSipStack::do_parse_request(SrsSipRequest* req, const char* recv_m
|
|||
}
|
||||
else if (!strcasecmp(phead, "cseq:")) {
|
||||
std::vector<std::string> vec_seq = srs_string_split(content, " ");
|
||||
req->seq = strtoul(vec_seq.at(0).c_str(), NULL, 10);
|
||||
req->method = vec_seq.at(1);
|
||||
std::string seq = vec_seq.empty() ? "" : vec_seq.at(0);
|
||||
req->seq = strtoul(seq.c_str(), NULL, 10);
|
||||
req->method = vec_seq.size() > 0 ? vec_seq.at(1) : "";
|
||||
}
|
||||
else if (!strcasecmp(phead, "from:")) {
|
||||
content = srs_string_replace(content, "sip:", "");
|
||||
|
@ -336,6 +537,11 @@ srs_error_t SrsSipStack::do_parse_request(SrsSipRequest* req, const char* recv_m
|
|||
if (srs_string_contains(content, "tag")) {
|
||||
req->from_tag = srs_sip_get_param(content.c_str(), "tag");
|
||||
}
|
||||
|
||||
std::vector<std::string> vec = srs_string_split(req->from, "@");
|
||||
if (vec.size() > 1){
|
||||
req->from_realm = vec.at(1);
|
||||
}
|
||||
}
|
||||
else if (!strcasecmp(phead, "to:")) {
|
||||
content = srs_string_replace(content, "sip:", "");
|
||||
|
@ -343,9 +549,13 @@ srs_error_t SrsSipStack::do_parse_request(SrsSipRequest* req, const char* recv_m
|
|||
if (srs_string_contains(content, "tag")) {
|
||||
req->to_tag = srs_sip_get_param(content.c_str(), "tag");
|
||||
}
|
||||
|
||||
std::vector<std::string> vec = srs_string_split(req->to, "@");
|
||||
if (vec.size() > 1){
|
||||
req->to_realm = vec.at(1);
|
||||
}
|
||||
}
|
||||
else if (!strcasecmp(phead, "via:")) {
|
||||
//std::vector<std::string> vec_via = srs_string_split(content, ";");
|
||||
req->via = content;
|
||||
req->branch = srs_sip_get_param(content.c_str(), "branch");
|
||||
}
|
||||
|
@ -377,28 +587,81 @@ srs_error_t SrsSipStack::do_parse_request(SrsSipRequest* req, const char* recv_m
|
|||
}
|
||||
|
||||
std::vector<std::string> method_uri_ver = srs_string_split(firstline, " ");
|
||||
|
||||
if (method_uri_ver.empty()) {
|
||||
return srs_error_new(ERROR_GB28181_SIP_PRASE_FAILED, "parse request firstline is empty");
|
||||
}
|
||||
|
||||
//respone first line text:SIP/2.0 200 OK
|
||||
if (!strcasecmp(method_uri_ver.at(0).c_str(), "sip/2.0")) {
|
||||
req->cmdtype = SrsSipCmdRespone;
|
||||
//req->method= vec_seq.at(1);
|
||||
req->status = method_uri_ver.at(1);
|
||||
req->status = method_uri_ver.size() > 0 ? method_uri_ver.at(1) : "";
|
||||
req->version = method_uri_ver.at(0);
|
||||
req->uri = req->from;
|
||||
|
||||
vector<string> str = srs_string_split(req->to, "@");
|
||||
req->sip_auth_id = srs_string_replace(str.at(0), "sip:", "");
|
||||
std::string ss = str.empty() ? "" : str.at(0);
|
||||
req->sip_auth_id = srs_string_replace(ss, "sip:", "");
|
||||
|
||||
}else {//request first line text :MESSAGE sip:34020000002000000001@3402000000 SIP/2.0
|
||||
req->cmdtype = SrsSipCmdRequest;
|
||||
req->method= method_uri_ver.at(0);
|
||||
req->uri = method_uri_ver.at(1);
|
||||
req->version = method_uri_ver.at(2);
|
||||
req->uri = method_uri_ver.size() > 0 ? method_uri_ver.at(1) : "";
|
||||
req->version = method_uri_ver.size() > 1 ? method_uri_ver.at(2) : "";
|
||||
|
||||
vector<string> str = srs_string_split(req->from, "@");
|
||||
req->sip_auth_id = srs_string_replace(str.at(0), "sip:", "");
|
||||
std::string ss = str.empty() ? "" : str.at(0);
|
||||
req->sip_auth_id = srs_string_replace(ss, "sip:", "");
|
||||
}
|
||||
|
||||
req->sip_username = req->sip_auth_id;
|
||||
|
||||
//Content-Type: Application/MANSCDP+xml
|
||||
if (!strcasecmp(req->content_type.c_str(),"application/manscdp+xml")){
|
||||
std::map<std::string, std::string> body_map;
|
||||
//xml to map
|
||||
if ((err = parse_xml(body, body_map)) != srs_success) {
|
||||
return srs_error_wrap(err, "sip parse xml");
|
||||
};
|
||||
|
||||
//Response Cmd
|
||||
if (body_map.find("Response") != body_map.end()){
|
||||
std::string cmdtype = body_map["Response@CmdType"];
|
||||
if (cmdtype == "Catalog"){
|
||||
//Response@DeviceList@Item@DeviceID:3000001,3000002
|
||||
std::vector<std::string> vec_device_id = srs_string_split(body_map["Response@DeviceList@Item@DeviceID"], ",");
|
||||
//Response@DeviceList@Item@Status:ON,OFF
|
||||
std::vector<std::string> vec_device_status = srs_string_split(body_map["Response@DeviceList@Item@Status"], ",");
|
||||
|
||||
//map key:devicd_id value:status
|
||||
for(int i=0 ; i<vec_device_id.size(); i++){
|
||||
std::string status = "";
|
||||
if (vec_device_id.size() > i) {
|
||||
status = vec_device_status.at(i);
|
||||
}
|
||||
|
||||
req->device_list_map[vec_device_id.at(i)] = status;
|
||||
}
|
||||
}else{
|
||||
//TODO: fixme
|
||||
srs_trace("sip: Response cmdtype=%s not processed", cmdtype.c_str());
|
||||
}
|
||||
} //Notify Cmd
|
||||
else if (body_map.find("Notify") != body_map.end()){
|
||||
std::string cmdtype = body_map["Notify@CmdType"];
|
||||
if (cmdtype == "Keepalive"){
|
||||
//TODO: ????
|
||||
std::vector<std::string> vec_device_id = srs_string_split(body_map["Notify@Info@DeviceID"], ",");
|
||||
for(int i=0; i<vec_device_id.size(); i++){
|
||||
//req->device_list_map[vec_device_id.at(i)] = "OFF";
|
||||
}
|
||||
}else{
|
||||
//TODO: fixme
|
||||
srs_trace("sip: Notify cmdtype=%s not processed", cmdtype.c_str());
|
||||
}
|
||||
}// end if(body_map)
|
||||
}//end if (!strcasecmp)
|
||||
|
||||
srs_info("sip: method=%s uri=%s version=%s cmdtype=%s",
|
||||
req->method.c_str(), req->uri.c_str(), req->version.c_str(), req->get_cmdtype_str().c_str());
|
||||
|
@ -445,8 +708,12 @@ std::string SrsSipStack::get_sip_via(SrsSipRequest const *req)
|
|||
{
|
||||
std::string via = srs_string_replace(req->via, SRS_SIP_VERSION"/UDP ", "");
|
||||
std::vector<std::string> vec_via = srs_string_split(via, ";");
|
||||
std::string ip_port = vec_via.at(0);
|
||||
|
||||
std::string ip_port = vec_via.empty() ? "" : vec_via.at(0);
|
||||
std::vector<std::string> vec_ip_port = srs_string_split(ip_port, ":");
|
||||
|
||||
std::string ip = vec_ip_port.empty() ? "" : vec_ip_port.at(0);
|
||||
std::string port = vec_ip_port.size() > 1 ? vec_ip_port.at(1) : "";
|
||||
|
||||
std::string branch, rport, received;
|
||||
if (req->branch.empty()){
|
||||
|
@ -455,8 +722,16 @@ std::string SrsSipStack::get_sip_via(SrsSipRequest const *req)
|
|||
branch = ";branch=" + req->branch;
|
||||
}
|
||||
|
||||
received = ";received=" + vec_ip_port.at(0);
|
||||
rport = ";rport=" + vec_ip_port.at(1);
|
||||
if (!req->peer_ip.empty()){
|
||||
ip = req->peer_ip;
|
||||
|
||||
std::stringstream ss;
|
||||
ss << req->peer_port;
|
||||
port = ss.str();
|
||||
}
|
||||
|
||||
received = ";received=" + ip;
|
||||
rport = ";rport=" + port;
|
||||
|
||||
return SRS_SIP_VERSION"/UDP " + ip_port + rport + received + branch;
|
||||
}
|
||||
|
@ -640,10 +915,12 @@ void SrsSipStack::req_invite(stringstream& ss, SrsSipRequest *req, string ip, in
|
|||
User-Agent: SRS/4.0.4(Leo)
|
||||
Content-Length: 0
|
||||
*/
|
||||
|
||||
char _ssrc[11];
|
||||
sprintf(_ssrc, "%010d", ssrc);
|
||||
|
||||
std::stringstream sdp;
|
||||
sdp << "v=0" << SRS_RTSP_CRLF
|
||||
<< "o=" << req->sip_auth_id << " 0 0 IN IP4 " << ip << SRS_RTSP_CRLF
|
||||
<< "o=" << req->serial << " 0 0 IN IP4 " << ip << SRS_RTSP_CRLF
|
||||
<< "s=Play" << SRS_RTSP_CRLF
|
||||
<< "c=IN IP4 " << ip << SRS_RTSP_CRLF
|
||||
<< "t=0 0" << SRS_RTSP_CRLF
|
||||
|
@ -658,37 +935,44 @@ void SrsSipStack::req_invite(stringstream& ss, SrsSipRequest *req, string ip, in
|
|||
//<< "a=rtpmap:99 H265/90000" << SRS_RTSP_CRLF
|
||||
//<< "a=streamMode:MAIN\r\n"
|
||||
//<< "a=filesize:0\r\n"
|
||||
<< "y=" << ssrc << SRS_RTSP_CRLF;
|
||||
<< "y=" << _ssrc << SRS_RTSP_CRLF;
|
||||
|
||||
|
||||
int rand = srs_sip_random(1000, 9999);
|
||||
std::stringstream from, to, uri, branch, from_tag;
|
||||
std::stringstream from, to, uri;
|
||||
//"INVITE sip:34020000001320000001@3402000000 SIP/2.0\r\n
|
||||
uri << "sip:" << req->sip_auth_id << "@" << req->realm;
|
||||
uri << "sip:" << req->chid << "@" << req->realm;
|
||||
//From: <sip:34020000002000000001@%s:%s>;tag=500485%d\r\n
|
||||
from << req->serial << "@" << req->host << ":" << req->host_port;
|
||||
to << req->sip_auth_id << "@" << req->realm;
|
||||
|
||||
from << req->serial << "@" << req->realm;
|
||||
to << req->chid << "@" << req->realm;
|
||||
|
||||
req->from = from.str();
|
||||
req->to = to.str();
|
||||
req->to = to.str();
|
||||
|
||||
if (!req->to_realm.empty()){
|
||||
req->to = req->chid + "@" + req->to_realm;
|
||||
}
|
||||
|
||||
if (!req->from_realm.empty()){
|
||||
req->from = req->serial + "@" + req->from_realm;
|
||||
}
|
||||
|
||||
req->uri = uri.str();
|
||||
|
||||
branch << "z9hG4bK3420" << rand;
|
||||
from_tag << "51235" << rand;
|
||||
req->branch = branch.str();
|
||||
req->from_tag = from_tag.str();
|
||||
req->call_id = srs_sip_generate_call_id();
|
||||
req->branch = srs_sip_generate_branch();
|
||||
req->from_tag = srs_sip_generate_from_tag();
|
||||
|
||||
ss << "INVITE " << req->uri << " " << SRS_SIP_VERSION << SRS_RTSP_CRLF
|
||||
<< "Via: " << SRS_SIP_VERSION << "/UDP "<< req->host << ":" << req->host_port << ";rport;branch=" << req->branch << SRS_RTSP_CRLF
|
||||
<< "From: " << get_sip_from(req) << SRS_RTSP_CRLF
|
||||
<< "To: " << get_sip_to(req) << SRS_RTSP_CRLF
|
||||
<< "Call-ID: 20000" << rand <<SRS_RTSP_CRLF
|
||||
<< "CSeq: 20 INVITE" << SRS_RTSP_CRLF
|
||||
<< "Call-ID: " << req->call_id <<SRS_RTSP_CRLF
|
||||
<< "CSeq: " << req->seq << " INVITE" << SRS_RTSP_CRLF
|
||||
<< "Content-Type: Application/SDP" << SRS_RTSP_CRLF
|
||||
<< "Contact: <sip:" << req->to << ">" << SRS_RTSP_CRLF
|
||||
<< "Max-Forwards: 70" << " \r\n"
|
||||
<< "Max-Forwards: 70" << SRS_RTSP_CRLF
|
||||
<< "User-Agent: " << SRS_SIP_USER_AGENT <<SRS_RTSP_CRLF
|
||||
<< "Subject: "<< req->sip_auth_id << ":" << ssrc << "," << req->serial << ":0" << SRS_RTSP_CRLF
|
||||
<< "Subject: "<< req->chid << ":" << _ssrc << "," << req->serial << ":0" << SRS_RTSP_CRLF
|
||||
<< "Content-Length: " << sdp.str().length() << SRS_RTSP_CRLFCRLF
|
||||
<< sdp.str();
|
||||
}
|
||||
|
@ -703,7 +987,7 @@ void SrsSipStack::req_401_unauthorized(std::stringstream& ss, SrsSipRequest *req
|
|||
To: <sip:34020000001320000004@192.168.137.92:5061>;tag=102092689
|
||||
CSeq: 1 REGISTER
|
||||
Call-ID: 1650345118
|
||||
User-Agent: LiveGBS v200228
|
||||
User-Agent: SRS/4.0.4(Leo)
|
||||
Contact: <sip:34020000002000000001@192.168.1.23:15060>
|
||||
Content-Length: 0
|
||||
WWW-Authenticate: Digest realm="3402000000",qop="auth",nonce="f1da98bd160f3e2efe954c6eedf5f75a"
|
||||
|
@ -737,10 +1021,10 @@ void SrsSipStack::req_ack(std::stringstream& ss, SrsSipRequest *req){
|
|||
Content-Length: 0
|
||||
*/
|
||||
|
||||
ss << "ACK " << "sip:" << req->sip_auth_id << "@" << req->realm << " "<< SRS_SIP_VERSION << SRS_RTSP_CRLF
|
||||
ss << "ACK " << "sip:" << req->chid << "@" << req->realm << " "<< SRS_SIP_VERSION << SRS_RTSP_CRLF
|
||||
<< "Via: " << SRS_SIP_VERSION << "/UDP " << req->host << ":" << req->host_port << ";rport;branch=" << req->branch << SRS_RTSP_CRLF
|
||||
<< "From: <sip:" << req->serial << "@" << req->host + ":" << req->host_port << ">;tag=" << req->from_tag << SRS_RTSP_CRLF
|
||||
<< "To: <sip:"<< req->sip_auth_id << "@" << req->realm << ">\r\n"
|
||||
<< "From: " << get_sip_from(req) << SRS_RTSP_CRLF
|
||||
<< "To: "<< get_sip_to(req) << SRS_RTSP_CRLF
|
||||
<< "Call-ID: " << req->call_id << SRS_RTSP_CRLF
|
||||
<< "CSeq: " << req->seq << " ACK"<< SRS_RTSP_CRLF
|
||||
<< "Max-Forwards: 70" << SRS_RTSP_CRLF
|
||||
|
@ -775,15 +1059,23 @@ void SrsSipStack::req_bye(std::stringstream& ss, SrsSipRequest *req)
|
|||
*/
|
||||
|
||||
std::stringstream from, to, uri;
|
||||
uri << "sip:" << req->sip_auth_id << "@" << req->realm;
|
||||
uri << "sip:" << req->chid << "@" << req->realm;
|
||||
from << req->serial << "@" << req->realm;
|
||||
to << req->sip_auth_id << "@" << req->realm;
|
||||
to << req->chid << "@" << req->realm;
|
||||
|
||||
req->from = from.str();
|
||||
req->to = to.str();
|
||||
req->to = to.str();
|
||||
|
||||
if (!req->to_realm.empty()){
|
||||
req->to = req->chid + "@" + req->to_realm;
|
||||
}
|
||||
|
||||
if (!req->from_realm.empty()){
|
||||
req->from = req->serial + "@" + req->from_realm;
|
||||
}
|
||||
|
||||
req->uri = uri.str();
|
||||
|
||||
int seq = srs_sip_random(22, 99);
|
||||
ss << "BYE " << req->uri << " "<< SRS_SIP_VERSION << SRS_RTSP_CRLF
|
||||
//<< "Via: "<< SRS_SIP_VERSION << "/UDP "<< req->host << ":" << req->host_port << ";rport" << branch << SRS_RTSP_CRLF
|
||||
<< "Via: " << SRS_SIP_VERSION << "/UDP " << req->host << ":" << req->host_port << ";rport;branch=" << req->branch << SRS_RTSP_CRLF
|
||||
|
@ -791,12 +1083,243 @@ void SrsSipStack::req_bye(std::stringstream& ss, SrsSipRequest *req)
|
|||
<< "To: " << get_sip_to(req) << SRS_RTSP_CRLF
|
||||
//bye callid is inivte callid
|
||||
<< "Call-ID: " << req->call_id << SRS_RTSP_CRLF
|
||||
<< "CSeq: "<< seq <<" BYE" << SRS_RTSP_CRLF
|
||||
<< "CSeq: "<< req->seq <<" BYE" << SRS_RTSP_CRLF
|
||||
<< "Max-Forwards: 70" << SRS_RTSP_CRLF
|
||||
<< "User-Agent: " << SRS_SIP_USER_AGENT << SRS_RTSP_CRLF
|
||||
<< "Content-Length: 0" << SRS_RTSP_CRLFCRLF;
|
||||
|
||||
}
|
||||
|
||||
void SrsSipStack::req_query_catalog(std::stringstream& ss, SrsSipRequest *req)
|
||||
{
|
||||
/*
|
||||
//request: sip-agent <----MESSAGE Query Catalog--- sip-server
|
||||
MESSAGE sip:34020000001110000001@192.168.1.21:5060 SIP/2.0
|
||||
Via: SIP/2.0/UDP 192.168.1.17:5060;rport;branch=z9hG4bK563315752
|
||||
From: <sip:34020000001110000001@3402000000>;tag=387315752
|
||||
To: <sip:34020000001110000001@192.168.1.21:5060>
|
||||
Call-ID: 728315752
|
||||
CSeq: 32 MESSAGE
|
||||
Content-Type: Application/MANSCDP+xml
|
||||
Max-Forwards: 70
|
||||
User-Agent: SRS/4.0.20(Leo)
|
||||
Content-Length: 162
|
||||
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Query>
|
||||
<CmdType>Catalog</CmdType>
|
||||
<SN>419315752</SN>
|
||||
<DeviceID>34020000001110000001</DeviceID>
|
||||
</Query>
|
||||
SIP/2.0 200 OK
|
||||
Via: SIP/2.0/UDP 192.168.1.17:5060;rport=5060;branch=z9hG4bK563315752
|
||||
From: <sip:34020000001110000001@3402000000>;tag=387315752
|
||||
To: <sip:34020000001110000001@192.168.1.21:5060>;tag=1420696981
|
||||
Call-ID: 728315752
|
||||
CSeq: 32 MESSAGE
|
||||
User-Agent: Embedded Net DVR/NVR/DVS
|
||||
Content-Length: 0
|
||||
|
||||
//response: sip-agent ----MESSAGE Query Catalog---> sip-server
|
||||
SIP/2.0 200 OK
|
||||
Via: SIP/2.0/UDP 192.168.1.17:5060;rport=5060;received=192.168.1.17;branch=z9hG4bK563315752
|
||||
From: <sip:34020000001110000001@3402000000>;tag=387315752
|
||||
To: <sip:34020000001110000001@192.168.1.21:5060>;tag=1420696981
|
||||
CSeq: 32 MESSAGE
|
||||
Call-ID: 728315752
|
||||
User-Agent: SRS/4.0.20(Leo)
|
||||
Content-Length: 0
|
||||
|
||||
//request: sip-agent ----MESSAGE Response Catalog---> sip-server
|
||||
MESSAGE sip:34020000001110000001@3402000000.spvmn.cn SIP/2.0
|
||||
Via: SIP/2.0/UDP 192.168.1.21:5060;rport;branch=z9hG4bK1681502633
|
||||
From: <sip:34020000001110000001@3402000000.spvmn.cn>;tag=1194168247
|
||||
To: <sip:34020000001110000001@3402000000.spvmn.cn>
|
||||
Call-ID: 685380150
|
||||
CSeq: 20 MESSAGE
|
||||
Content-Type: Application/MANSCDP+xml
|
||||
Max-Forwards: 70
|
||||
User-Agent: Embedded Net DVR/NVR/DVS
|
||||
Content-Length: 909
|
||||
|
||||
<?xml version="1.0" encoding="gb2312"?>
|
||||
<Response>
|
||||
<CmdType>Catalog</CmdType>
|
||||
<SN>419315752</SN>
|
||||
<DeviceID>34020000001110000001</DeviceID>
|
||||
<SumNum>8</SumNum>
|
||||
<DeviceList Num="2">
|
||||
<Item>
|
||||
<DeviceID>34020000001320000001</DeviceID>
|
||||
<Name>Camera 01</Name>
|
||||
<Manufacturer>Manufacturer</Manufacturer>
|
||||
<Model>Camera</Model>
|
||||
<Owner>Owner</Owner>
|
||||
<CivilCode>CivilCode</CivilCode>
|
||||
<Address>192.168.254.18</Address>
|
||||
<Parental>0</Parental>
|
||||
<SafetyWay>0</SafetyWay>
|
||||
<RegisterWay>1</RegisterWay>
|
||||
<Secrecy>0</Secrecy>
|
||||
<Status>ON</Status>
|
||||
</Item>
|
||||
<Item>
|
||||
<DeviceID>34020000001320000002</DeviceID>
|
||||
<Name>IPCamera 02</Name>
|
||||
<Manufacturer>Manufacturer</Manufacturer>
|
||||
<Model>Camera</Model>
|
||||
<Owner>Owner</Owner>
|
||||
<CivilCode>CivilCode</CivilCode>
|
||||
<Address>192.168.254.14</Address>
|
||||
<Parental>0</Parental>
|
||||
<SafetyWay>0</SafetyWay>
|
||||
<RegisterWay>1</RegisterWay>
|
||||
<Secrecy>0</Secrecy>
|
||||
<Status>OFF</Status>
|
||||
</Item>
|
||||
</DeviceList>
|
||||
</Response>
|
||||
|
||||
*/
|
||||
|
||||
std::stringstream xml;
|
||||
std::string xmlbody;
|
||||
|
||||
xml << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" << SRS_RTSP_CRLF
|
||||
<< "<Query>" << SRS_RTSP_CRLF
|
||||
<< "<CmdType>Catalog</CmdType>" << SRS_RTSP_CRLF
|
||||
<< "<SN>" << srs_sip_generate_sn() << "</SN>" << SRS_RTSP_CRLF
|
||||
<< "<DeviceID>" << req->sip_auth_id << "</DeviceID>" << SRS_RTSP_CRLF
|
||||
<< "</Query>" << SRS_RTSP_CRLF;
|
||||
xmlbody = xml.str();
|
||||
|
||||
std::stringstream from, to, uri;
|
||||
//"INVITE sip:34020000001320000001@3402000000 SIP/2.0\r\n
|
||||
uri << "sip:" << req->sip_auth_id << "@" << req->realm;
|
||||
//From: <sip:34020000002000000001@%s:%s>;tag=500485%d\r\n
|
||||
from << req->serial << "@" << req->host << ":" << req->host_port;
|
||||
to << req->sip_auth_id << "@" << req->realm;
|
||||
|
||||
req->from = from.str();
|
||||
req->to = to.str();
|
||||
req->uri = uri.str();
|
||||
|
||||
req->call_id = srs_sip_generate_call_id();
|
||||
req->branch = srs_sip_generate_branch();
|
||||
req->from_tag = srs_sip_generate_from_tag();
|
||||
|
||||
ss << "MESSAGE " << req->uri << " " << SRS_SIP_VERSION << SRS_RTSP_CRLF
|
||||
<< "Via: " << SRS_SIP_VERSION << "/UDP "<< req->host << ":" << req->host_port << ";rport;branch=" << req->branch << SRS_RTSP_CRLF
|
||||
<< "From: " << get_sip_from(req) << SRS_RTSP_CRLF
|
||||
<< "To: " << get_sip_to(req) << SRS_RTSP_CRLF
|
||||
<< "Call-ID: " << req->call_id << SRS_RTSP_CRLF
|
||||
<< "CSeq: " << req->seq << " MESSAGE" << SRS_RTSP_CRLF
|
||||
<< "Content-Type: Application/MANSCDP+xml" << SRS_RTSP_CRLF
|
||||
<< "Max-Forwards: 70" << SRS_RTSP_CRLF
|
||||
<< "User-Agent: " << SRS_SIP_USER_AGENT << SRS_RTSP_CRLF
|
||||
<< "Content-Length: " << xmlbody.length() << SRS_RTSP_CRLFCRLF
|
||||
<< xmlbody;
|
||||
|
||||
}
|
||||
|
||||
void SrsSipStack::req_ptz(std::stringstream& ss, SrsSipRequest *req, uint8_t cmd, uint8_t speed, int priority)
|
||||
{
|
||||
|
||||
/*
|
||||
<?xml version="1.0"?>
|
||||
<Control>
|
||||
<CmdType>DeviceControl</CmdType>
|
||||
<SN>11</SN>
|
||||
<DeviceID>34020000001310000053</DeviceID>
|
||||
<PTZCmd>A50F01021F0000D6</PTZCmd>
|
||||
</Control>
|
||||
*/
|
||||
|
||||
uint8_t ptz_cmd[8] = {0};
|
||||
ptz_cmd[0] = SRS_SIP_PTZ_START;
|
||||
ptz_cmd[1] = 0x0F;
|
||||
ptz_cmd[2] = 0x01;
|
||||
ptz_cmd[3] = cmd;
|
||||
switch(cmd){
|
||||
case SrsSipPtzCmdStop: // = 0x00
|
||||
ptz_cmd[4] = 0;
|
||||
ptz_cmd[5] = 0;
|
||||
ptz_cmd[6] = 0;
|
||||
break;
|
||||
case SrsSipPtzCmdRight: // = 0x01,
|
||||
case SrsSipPtzCmdLeft: // = 0x02,
|
||||
ptz_cmd[4] = speed;
|
||||
break;
|
||||
case SrsSipPtzCmdDown: // = 0x04,
|
||||
case SrsSipPtzCmdUp: // = 0x08,
|
||||
ptz_cmd[5] = speed;
|
||||
break;
|
||||
case SrsSipPtzCmdZoomOut: // = 0x10,
|
||||
case SrsSipPtzCmdZoomIn: // = 0x20
|
||||
ptz_cmd[6] = (speed & 0x0F) << 4;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t check = 0;
|
||||
for (int i = 0; i < 7; i++){
|
||||
check += ptz_cmd[i];
|
||||
}
|
||||
|
||||
ptz_cmd[7] = (uint8_t)(check % 256);
|
||||
|
||||
std::stringstream ss_ptzcmd;
|
||||
for (int i = 0; i < 8; i++){
|
||||
char hex_cmd[3] = {0};
|
||||
sprintf(hex_cmd, "%02X", ptz_cmd[i]);
|
||||
ss_ptzcmd << hex_cmd;
|
||||
}
|
||||
|
||||
std::stringstream xml;
|
||||
std::string xmlbody;
|
||||
|
||||
xml << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" << SRS_RTSP_CRLF
|
||||
<< "<Control>" << SRS_RTSP_CRLF
|
||||
<< "<CmdType>DeviceControl</CmdType>" << SRS_RTSP_CRLF
|
||||
<< "<SN>" << srs_sip_generate_sn() << "</SN>" << SRS_RTSP_CRLF
|
||||
<< "<DeviceID>" << req->sip_auth_id << "</DeviceID>" << SRS_RTSP_CRLF
|
||||
<< "<PTZCmd>" << ss_ptzcmd.str() << "</PTZCmd>" << SRS_RTSP_CRLF
|
||||
<< "<Info>" << SRS_RTSP_CRLF
|
||||
<< "<ControlPriority>" << priority << "</ControlPriority>" << SRS_RTSP_CRLF
|
||||
<< "</Info>" << SRS_RTSP_CRLF
|
||||
<< "</Control>" << SRS_RTSP_CRLF;
|
||||
xmlbody = xml.str();
|
||||
|
||||
std::stringstream from, to, uri, call_id;
|
||||
//"INVITE sip:34020000001320000001@3402000000 SIP/2.0\r\n
|
||||
uri << "sip:" << req->sip_auth_id << "@" << req->realm;
|
||||
//From: <sip:34020000002000000001@%s:%s>;tag=500485%d\r\n
|
||||
from << req->serial << "@" << req->host << ":" << req->host_port;
|
||||
to << req->sip_auth_id << "@" << req->realm;
|
||||
|
||||
req->from = from.str();
|
||||
req->to = to.str();
|
||||
req->uri = uri.str();
|
||||
|
||||
req->call_id = srs_sip_generate_call_id();
|
||||
req->branch = srs_sip_generate_branch();
|
||||
req->from_tag = srs_sip_generate_from_tag();
|
||||
|
||||
ss << "MESSAGE " << req->uri << " "<< SRS_SIP_VERSION << SRS_RTSP_CRLF
|
||||
//<< "Via: "<< SRS_SIP_VERSION << "/UDP "<< req->host << ":" << req->host_port << ";rport" << branch << SRS_RTSP_CRLF
|
||||
<< "Via: " << SRS_SIP_VERSION << "/UDP " << req->host << ":" << req->host_port << ";rport;branch=" << req->branch << SRS_RTSP_CRLF
|
||||
<< "From: " << get_sip_from(req) << SRS_RTSP_CRLF
|
||||
<< "To: " << get_sip_to(req) << SRS_RTSP_CRLF
|
||||
<< "Call-ID: " << req->call_id << SRS_RTSP_CRLF
|
||||
<< "CSeq: "<< req->seq <<" MESSAGE" << SRS_RTSP_CRLF
|
||||
<< "Content-Type: Application/MANSCDP+xml" << SRS_RTSP_CRLF
|
||||
<< "Max-Forwards: 70" << SRS_RTSP_CRLF
|
||||
<< "User-Agent: " << SRS_SIP_USER_AGENT << SRS_RTSP_CRLF
|
||||
<< "Content-Length: " << xmlbody.length() << SRS_RTSP_CRLFCRLF
|
||||
<< xmlbody;
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
#include <map>
|
||||
|
||||
#include <srs_kernel_consts.hpp>
|
||||
#include <srs_rtsp_stack.hpp>
|
||||
|
@ -49,12 +50,24 @@ class SrsAudioFrame;
|
|||
#define SRS_SIP_VERSION "SIP/2.0"
|
||||
#define SRS_SIP_USER_AGENT RTMP_SIG_SRS_SERVER
|
||||
|
||||
#define SRS_SIP_PTZ_START 0xA5
|
||||
|
||||
|
||||
enum SrsSipCmdType{
|
||||
SrsSipCmdRequest=0,
|
||||
SrsSipCmdRespone=1
|
||||
};
|
||||
|
||||
enum SrsSipPtzCmdType{
|
||||
SrsSipPtzCmdStop = 0x00,
|
||||
SrsSipPtzCmdRight = 0x01,
|
||||
SrsSipPtzCmdLeft = 0x02,
|
||||
SrsSipPtzCmdDown = 0x04,
|
||||
SrsSipPtzCmdUp = 0x08,
|
||||
SrsSipPtzCmdZoomIn = 0x10,
|
||||
SrsSipPtzCmdZoomOut = 0x20
|
||||
};
|
||||
|
||||
std::string srs_sip_get_utc_date();
|
||||
|
||||
class SrsSipRequest
|
||||
|
@ -88,6 +101,11 @@ public:
|
|||
std::string www_authenticate;
|
||||
std::string authorization;
|
||||
|
||||
std::string chid;
|
||||
|
||||
std::map<std::string, std::string> xml_body_map;
|
||||
std::map<std::string, std::string> device_list_map;
|
||||
|
||||
public:
|
||||
std::string serial;
|
||||
std::string realm;
|
||||
|
@ -100,6 +118,9 @@ public:
|
|||
int host_port;
|
||||
SrsSipCmdType cmdtype;
|
||||
|
||||
std::string from_realm;
|
||||
std::string to_realm;
|
||||
|
||||
public:
|
||||
SrsRtspSdp* sdp;
|
||||
SrsRtspTransport* transport;
|
||||
|
@ -131,6 +152,7 @@ public:
|
|||
virtual srs_error_t parse_request(SrsSipRequest** preq, const char *recv_msg, int nb_buf);
|
||||
protected:
|
||||
virtual srs_error_t do_parse_request(SrsSipRequest* req, const char *recv_msg);
|
||||
virtual srs_error_t parse_xml(std::string xml_msg, std::map<std::string, std::string> &json_map);
|
||||
|
||||
private:
|
||||
//response from
|
||||
|
@ -146,10 +168,13 @@ public:
|
|||
virtual void resp_keepalive(std::stringstream& ss, SrsSipRequest *req);
|
||||
|
||||
//request: request sent by the sip-server, wait for sip-agent response
|
||||
virtual void req_invite(std::stringstream& ss, SrsSipRequest *req, std::string ip, int port, uint32_t ssrc);
|
||||
virtual void req_invite(std::stringstream& ss, SrsSipRequest *req, std::string ip,
|
||||
int port, uint32_t ssrc);
|
||||
virtual void req_ack(std::stringstream& ss, SrsSipRequest *req);
|
||||
virtual void req_bye(std::stringstream& ss, SrsSipRequest *req);
|
||||
virtual void req_401_unauthorized(std::stringstream& ss, SrsSipRequest *req);
|
||||
virtual void req_query_catalog(std::stringstream& ss, SrsSipRequest *req);
|
||||
virtual void req_ptz(std::stringstream& ss, SrsSipRequest *req, uint8_t cmd, uint8_t speed, int priority);
|
||||
|
||||
};
|
||||
|
||||
|
|
|
@ -94,7 +94,7 @@ srs_error_t srs_fd_closeexec(int fd)
|
|||
int flags = fcntl(fd, F_GETFD);
|
||||
flags |= FD_CLOEXEC;
|
||||
if (fcntl(fd, F_SETFD, flags) == -1) {
|
||||
return srs_error_new(ERROR_SOCKET_SETCLOSEEXEC, "FD_CLOEXEC fd=%v", fd);
|
||||
return srs_error_new(ERROR_SOCKET_SETCLOSEEXEC, "FD_CLOEXEC fd=%d", fd);
|
||||
}
|
||||
|
||||
return srs_success;
|
||||
|
@ -104,7 +104,7 @@ srs_error_t srs_fd_reuseaddr(int fd)
|
|||
{
|
||||
int v = 1;
|
||||
if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &v, sizeof(int)) == -1) {
|
||||
return srs_error_new(ERROR_SOCKET_SETREUSEADDR, "SO_REUSEADDR fd=%v", fd);
|
||||
return srs_error_new(ERROR_SOCKET_SETREUSEADDR, "SO_REUSEADDR fd=%d", fd);
|
||||
}
|
||||
|
||||
return srs_success;
|
||||
|
@ -119,7 +119,7 @@ srs_error_t srs_fd_reuseport(int fd)
|
|||
srs_warn("SO_REUSEPORT disabled for crossbuild");
|
||||
return srs_success;
|
||||
#else
|
||||
return srs_error_new(ERROR_SOCKET_SETREUSEADDR, "SO_REUSEPORT fd=%v", fd);
|
||||
return srs_error_new(ERROR_SOCKET_SETREUSEADDR, "SO_REUSEPORT fd=%d", fd);
|
||||
#endif
|
||||
}
|
||||
#else
|
||||
|
@ -402,6 +402,11 @@ int srs_sendto(srs_netfd_t stfd, void *buf, int len, const struct sockaddr * to,
|
|||
return st_sendto((st_netfd_t)stfd, buf, len, to, tolen, (st_utime_t)timeout);
|
||||
}
|
||||
|
||||
int srs_recvmsg(srs_netfd_t stfd, struct msghdr *msg, int flags, srs_utime_t timeout)
|
||||
{
|
||||
return st_recvmsg((st_netfd_t)stfd, msg, flags, (st_utime_t)timeout);
|
||||
}
|
||||
|
||||
int srs_sendmsg(srs_netfd_t stfd, const struct msghdr *msg, int flags, srs_utime_t timeout)
|
||||
{
|
||||
return st_sendmsg((st_netfd_t)stfd, msg, flags, (st_utime_t)timeout);
|
||||
|
|
|
@ -89,6 +89,7 @@ extern srs_netfd_t srs_netfd_open(int osfd);
|
|||
|
||||
extern int srs_recvfrom(srs_netfd_t stfd, void *buf, int len, struct sockaddr *from, int *fromlen, srs_utime_t timeout);
|
||||
extern int srs_sendto(srs_netfd_t stfd, void *buf, int len, const struct sockaddr *to, int tolen, srs_utime_t timeout);
|
||||
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);
|
||||
|
||||
#if !defined(SRS_AUTO_HAS_SENDMMSG)
|
||||
|
|
|
@ -526,6 +526,8 @@ VOID TEST(ProtocolAMF0Test, ApiAnyElem)
|
|||
*/
|
||||
VOID TEST(ProtocolAMF0Test, ApiAnyIO)
|
||||
{
|
||||
srs_error_t err;
|
||||
|
||||
SrsAmf0Any* o = NULL;
|
||||
|
||||
char buf[1024];
|
||||
|
@ -539,14 +541,15 @@ VOID TEST(ProtocolAMF0Test, ApiAnyIO)
|
|||
|
||||
o = SrsAmf0Any::object_eof();
|
||||
SrsAutoFree(SrsAmf0Any, o);
|
||||
|
||||
EXPECT_EQ(srs_success, o->read(&s));
|
||||
|
||||
HELPER_EXPECT_SUCCESS(o->read(&s));
|
||||
EXPECT_EQ(o->total_size(), s.pos());
|
||||
EXPECT_EQ(3, s.pos());
|
||||
|
||||
s.skip(-1 * s.pos());
|
||||
(s.data() + s.pos())[0] = 0x01;
|
||||
EXPECT_NE(srs_success, o->read(&s));
|
||||
|
||||
HELPER_EXPECT_FAILED(o->read(&s));
|
||||
}
|
||||
if (true) {
|
||||
s.skip(-1 * s.pos());
|
||||
|
@ -580,7 +583,7 @@ VOID TEST(ProtocolAMF0Test, ApiAnyIO)
|
|||
|
||||
s.skip(-1 * s.pos());
|
||||
(s.data() + s.pos())[3] = 'x';
|
||||
EXPECT_EQ(srs_success, o->read(&s));
|
||||
HELPER_EXPECT_SUCCESS(o->read(&s));
|
||||
EXPECT_EQ(o->total_size(), s.pos());
|
||||
EXPECT_STREQ("xinlin", o->to_str().c_str());
|
||||
}
|
||||
|
@ -599,7 +602,7 @@ VOID TEST(ProtocolAMF0Test, ApiAnyIO)
|
|||
EXPECT_EQ(0, s.read_1bytes());
|
||||
|
||||
s.skip(-1 * s.pos());
|
||||
EXPECT_EQ(srs_success, o->read(&s));
|
||||
HELPER_EXPECT_SUCCESS(o->read(&s));
|
||||
EXPECT_EQ(o->total_size(), s.pos());
|
||||
EXPECT_DOUBLE_EQ(10, o->to_number());
|
||||
}
|
||||
|
@ -618,7 +621,7 @@ VOID TEST(ProtocolAMF0Test, ApiAnyIO)
|
|||
EXPECT_EQ(1, s.read_1bytes());
|
||||
|
||||
s.skip(-1 * s.pos());
|
||||
EXPECT_EQ(srs_success, o->read(&s));
|
||||
HELPER_EXPECT_SUCCESS(o->read(&s));
|
||||
EXPECT_EQ(o->total_size(), s.pos());
|
||||
EXPECT_TRUE(o->to_boolean());
|
||||
}
|
||||
|
@ -635,7 +638,7 @@ VOID TEST(ProtocolAMF0Test, ApiAnyIO)
|
|||
EXPECT_EQ(1, s.read_1bytes());
|
||||
|
||||
s.skip(-1 * s.pos());
|
||||
EXPECT_EQ(srs_success, o->read(&s));
|
||||
HELPER_EXPECT_SUCCESS(o->read(&s));
|
||||
EXPECT_EQ(o->total_size(), s.pos());
|
||||
EXPECT_FALSE(o->to_boolean());
|
||||
}
|
||||
|
@ -654,7 +657,7 @@ VOID TEST(ProtocolAMF0Test, ApiAnyIO)
|
|||
EXPECT_EQ(5, s.read_1bytes());
|
||||
|
||||
s.skip(-1 * s.pos());
|
||||
EXPECT_EQ(srs_success, o->read(&s));
|
||||
HELPER_EXPECT_SUCCESS(o->read(&s));
|
||||
EXPECT_EQ(o->total_size(), s.pos());
|
||||
EXPECT_TRUE(o->is_null());
|
||||
}
|
||||
|
@ -673,7 +676,7 @@ VOID TEST(ProtocolAMF0Test, ApiAnyIO)
|
|||
EXPECT_EQ(6, s.read_1bytes());
|
||||
|
||||
s.skip(-1 * s.pos());
|
||||
EXPECT_EQ(srs_success, o->read(&s));
|
||||
HELPER_EXPECT_SUCCESS(o->read(&s));
|
||||
EXPECT_EQ(o->total_size(), s.pos());
|
||||
EXPECT_TRUE(o->is_undefined());
|
||||
}
|
||||
|
@ -838,6 +841,7 @@ VOID TEST(ProtocolAMF0Test, ApiAnyIO)
|
|||
*/
|
||||
VOID TEST(ProtocolAMF0Test, ApiAnyTypeAssert)
|
||||
{
|
||||
srs_error_t err;
|
||||
SrsAmf0Any* o = NULL;
|
||||
|
||||
char buf[1024];
|
||||
|
@ -848,7 +852,7 @@ VOID TEST(ProtocolAMF0Test, ApiAnyTypeAssert)
|
|||
if (true) {
|
||||
s.skip(-1 * s.pos());
|
||||
(s.data() + s.pos())[0] = 0x12;
|
||||
EXPECT_NE(srs_success, srs_amf0_read_any(&s, &o));
|
||||
HELPER_EXPECT_FAILED(srs_amf0_read_any(&s, &o));
|
||||
EXPECT_TRUE(NULL == o);
|
||||
srs_freep(o);
|
||||
}
|
||||
|
|
|
@ -3843,7 +3843,11 @@ VOID TEST(KernelFileWriterTest, WriteSpecialCase)
|
|||
|
||||
off_t seeked = 0;
|
||||
HELPER_EXPECT_SUCCESS(f.lseek(0, SEEK_CUR, &seeked));
|
||||
#ifdef SRS_AUTO_OSX
|
||||
EXPECT_EQ(10, seeked);
|
||||
#else
|
||||
EXPECT_EQ(0, seeked);
|
||||
#endif
|
||||
}
|
||||
|
||||
// Always fail.
|
||||
|
|
|
@ -110,6 +110,7 @@ VOID TEST(TCPServerTest, PingPong)
|
|||
SrsTcpClient c(_srs_tmp_host, _srs_tmp_port, _srs_tmp_timeout);
|
||||
HELPER_EXPECT_SUCCESS(c.connect());
|
||||
|
||||
srs_usleep(100 * SRS_UTIME_MILLISECONDS);
|
||||
EXPECT_TRUE(h.fd != NULL);
|
||||
}
|
||||
|
||||
|
@ -122,7 +123,10 @@ VOID TEST(TCPServerTest, PingPong)
|
|||
HELPER_EXPECT_SUCCESS(c.connect());
|
||||
|
||||
SrsStSocket skt;
|
||||
srs_usleep(100 * SRS_UTIME_MILLISECONDS);
|
||||
#ifdef SRS_AUTO_OSX
|
||||
ASSERT_TRUE(h.fd != NULL);
|
||||
#endif
|
||||
HELPER_EXPECT_SUCCESS(skt.initialize(h.fd));
|
||||
|
||||
HELPER_EXPECT_SUCCESS(c.write((void*)"Hello", 5, NULL));
|
||||
|
@ -141,7 +145,10 @@ VOID TEST(TCPServerTest, PingPong)
|
|||
HELPER_EXPECT_SUCCESS(c.connect());
|
||||
|
||||
SrsStSocket skt;
|
||||
srs_usleep(100 * SRS_UTIME_MILLISECONDS);
|
||||
#ifdef SRS_AUTO_OSX
|
||||
ASSERT_TRUE(h.fd != NULL);
|
||||
#endif
|
||||
HELPER_EXPECT_SUCCESS(skt.initialize(h.fd));
|
||||
|
||||
HELPER_EXPECT_SUCCESS(c.write((void*)"Hello", 5, NULL));
|
||||
|
@ -149,7 +156,7 @@ VOID TEST(TCPServerTest, PingPong)
|
|||
HELPER_EXPECT_SUCCESS(c.write((void*)"SRS", 3, NULL));
|
||||
|
||||
char buf[16] = {0};
|
||||
HELPER_EXPECT_SUCCESS(skt.read(buf, 9, NULL));
|
||||
HELPER_EXPECT_SUCCESS(skt.read_fully(buf, 9, NULL));
|
||||
EXPECT_STREQ(buf, "Hello SRS");
|
||||
}
|
||||
|
||||
|
@ -162,7 +169,10 @@ VOID TEST(TCPServerTest, PingPong)
|
|||
HELPER_EXPECT_SUCCESS(c.connect());
|
||||
|
||||
SrsStSocket skt;
|
||||
srs_usleep(100 * SRS_UTIME_MILLISECONDS);
|
||||
#ifdef SRS_AUTO_OSX
|
||||
ASSERT_TRUE(h.fd != NULL);
|
||||
#endif
|
||||
HELPER_EXPECT_SUCCESS(skt.initialize(h.fd));
|
||||
|
||||
HELPER_EXPECT_SUCCESS(c.write((void*)"Hello SRS", 9, NULL));
|
||||
|
@ -194,7 +204,10 @@ VOID TEST(TCPServerTest, PingPongWithTimeout)
|
|||
HELPER_EXPECT_SUCCESS(c.connect());
|
||||
|
||||
SrsStSocket skt;
|
||||
srs_usleep(100 * SRS_UTIME_MILLISECONDS);
|
||||
#ifdef SRS_AUTO_OSX
|
||||
ASSERT_TRUE(h.fd != NULL);
|
||||
#endif
|
||||
HELPER_EXPECT_SUCCESS(skt.initialize(h.fd));
|
||||
skt.set_recv_timeout(1 * SRS_UTIME_MILLISECONDS);
|
||||
|
||||
|
@ -213,7 +226,10 @@ VOID TEST(TCPServerTest, PingPongWithTimeout)
|
|||
HELPER_EXPECT_SUCCESS(c.connect());
|
||||
|
||||
SrsStSocket skt;
|
||||
srs_usleep(100 * SRS_UTIME_MILLISECONDS);
|
||||
#ifdef SRS_AUTO_OSX
|
||||
ASSERT_TRUE(h.fd != NULL);
|
||||
#endif
|
||||
HELPER_EXPECT_SUCCESS(skt.initialize(h.fd));
|
||||
skt.set_recv_timeout(1 * SRS_UTIME_MILLISECONDS);
|
||||
|
||||
|
@ -232,7 +248,10 @@ VOID TEST(TCPServerTest, PingPongWithTimeout)
|
|||
HELPER_EXPECT_SUCCESS(c.connect());
|
||||
|
||||
SrsStSocket skt;
|
||||
srs_usleep(100 * SRS_UTIME_MILLISECONDS);
|
||||
#ifdef SRS_AUTO_OSX
|
||||
ASSERT_TRUE(h.fd != NULL);
|
||||
#endif
|
||||
HELPER_EXPECT_SUCCESS(skt.initialize(h.fd));
|
||||
skt.set_recv_timeout(1 * SRS_UTIME_MILLISECONDS);
|
||||
|
||||
|
@ -363,7 +382,9 @@ VOID TEST(TCPServerTest, StringIsHex)
|
|||
char* str = (char*)"!1234567890";
|
||||
char* parsed = str; errno = 0;
|
||||
EXPECT_EQ(0x0, ::strtol(str, &parsed, 16));
|
||||
#ifndef SRS_AUTO_OSX
|
||||
EXPECT_EQ(0, errno);
|
||||
#endif
|
||||
EXPECT_EQ(str, parsed);
|
||||
}
|
||||
|
||||
|
@ -379,7 +400,9 @@ VOID TEST(TCPServerTest, StringIsHex)
|
|||
char* str = (char*)"";
|
||||
char* parsed = str; errno = 0;
|
||||
EXPECT_EQ(0x0, ::strtol(str, &parsed, 16));
|
||||
#ifndef SRS_AUTO_OSX
|
||||
EXPECT_EQ(0, errno);
|
||||
#endif
|
||||
EXPECT_EQ(str, parsed);
|
||||
}
|
||||
|
||||
|
@ -405,7 +428,10 @@ VOID TEST(TCPServerTest, WritevIOVC)
|
|||
HELPER_EXPECT_SUCCESS(c.connect());
|
||||
|
||||
SrsStSocket skt;
|
||||
srs_usleep(100 * SRS_UTIME_MILLISECONDS);
|
||||
#ifdef SRS_AUTO_OSX
|
||||
ASSERT_TRUE(h.fd != NULL);
|
||||
#endif
|
||||
HELPER_EXPECT_SUCCESS(skt.initialize(h.fd));
|
||||
|
||||
iovec iovs[3];
|
||||
|
@ -432,7 +458,10 @@ VOID TEST(TCPServerTest, WritevIOVC)
|
|||
HELPER_EXPECT_SUCCESS(c.connect());
|
||||
|
||||
SrsStSocket skt;
|
||||
srs_usleep(100 * SRS_UTIME_MILLISECONDS);
|
||||
#ifdef SRS_AUTO_OSX
|
||||
ASSERT_TRUE(h.fd != NULL);
|
||||
#endif
|
||||
HELPER_EXPECT_SUCCESS(skt.initialize(h.fd));
|
||||
|
||||
iovec iovs[3];
|
||||
|
|
Loading…
Reference in a new issue