|
|
@ -6,6 +6,13 @@
|
|
|
|
|
|
|
|
|
|
|
|
#include "srt_handle.hpp"
|
|
|
|
#include "srt_handle.hpp"
|
|
|
|
#include "time_help.h"
|
|
|
|
#include "time_help.h"
|
|
|
|
|
|
|
|
#include "srt_log.hpp"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#include <srs_kernel_log.hpp>
|
|
|
|
|
|
|
|
#include <srs_kernel_error.hpp>
|
|
|
|
|
|
|
|
#include <srs_app_rtmp_conn.hpp>
|
|
|
|
|
|
|
|
#include <srs_app_config.hpp>
|
|
|
|
|
|
|
|
|
|
|
|
#include <srt/udt.h>
|
|
|
|
#include <srt/udt.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <vector>
|
|
|
|
#include <vector>
|
|
|
@ -14,11 +21,6 @@
|
|
|
|
#include <assert.h>
|
|
|
|
#include <assert.h>
|
|
|
|
#include <list>
|
|
|
|
#include <list>
|
|
|
|
|
|
|
|
|
|
|
|
#include <srs_kernel_log.hpp>
|
|
|
|
|
|
|
|
#include <srs_kernel_error.hpp>
|
|
|
|
|
|
|
|
#include <srs_app_rtmp_conn.hpp>
|
|
|
|
|
|
|
|
#include <srs_app_config.hpp>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static bool MONITOR_STATICS_ENABLE = false;
|
|
|
|
static bool MONITOR_STATICS_ENABLE = false;
|
|
|
|
static long long MONITOR_TIMEOUT = 5000;
|
|
|
|
static long long MONITOR_TIMEOUT = 5000;
|
|
|
|
const unsigned int DEF_DATA_SIZE = 188*7;
|
|
|
|
const unsigned int DEF_DATA_SIZE = 188*7;
|
|
|
@ -66,7 +68,7 @@ void srt_handle::debug_statics(SRTSOCKET srtsocket, const std::string& streamid)
|
|
|
|
output << "LINK RTT: " << std::setw(9) << mon.msRTT << "ms BANDWIDTH: " << std::setw(7) << mon.mbpsBandwidth << "Mb/s " << std::endl;
|
|
|
|
output << "LINK RTT: " << std::setw(9) << mon.msRTT << "ms BANDWIDTH: " << std::setw(7) << mon.mbpsBandwidth << "Mb/s " << std::endl;
|
|
|
|
output << "BUFFERLEFT: SND: " << std::setw(11) << mon.byteAvailSndBuf << " RCV: " << std::setw(11) << mon.byteAvailRcvBuf << std::endl;
|
|
|
|
output << "BUFFERLEFT: SND: " << std::setw(11) << mon.byteAvailSndBuf << " RCV: " << std::setw(11) << mon.byteAvailRcvBuf << std::endl;
|
|
|
|
|
|
|
|
|
|
|
|
srs_trace("\r\n%s", output.str().c_str());
|
|
|
|
srt_log_trace("\r\n%s", output.str().c_str());
|
|
|
|
return;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
@ -79,10 +81,10 @@ void srt_handle::add_new_puller(SRT_CONN_PTR conn_ptr, std::string stream_id) {
|
|
|
|
srtsocket_map.insert(std::make_pair(conn_ptr->get_conn(), conn_ptr));
|
|
|
|
srtsocket_map.insert(std::make_pair(conn_ptr->get_conn(), conn_ptr));
|
|
|
|
|
|
|
|
|
|
|
|
_streamid_map.insert(std::make_pair(stream_id, srtsocket_map));
|
|
|
|
_streamid_map.insert(std::make_pair(stream_id, srtsocket_map));
|
|
|
|
srs_trace("add new puller fd:%d, streamid:%s", conn_ptr->get_conn(), stream_id.c_str());
|
|
|
|
srt_log_trace("add new puller fd:%d, streamid:%s", conn_ptr->get_conn(), stream_id.c_str());
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
iter->second.insert(std::make_pair(conn_ptr->get_conn(), conn_ptr));
|
|
|
|
iter->second.insert(std::make_pair(conn_ptr->get_conn(), conn_ptr));
|
|
|
|
srs_trace("add new puller fd:%d, streamid:%s, size:%d",
|
|
|
|
srt_log_trace("add new puller fd:%d, streamid:%s, size:%d",
|
|
|
|
conn_ptr->get_conn(), stream_id.c_str(), iter->second.size());
|
|
|
|
conn_ptr->get_conn(), stream_id.c_str(), iter->second.size());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
@ -90,7 +92,7 @@ void srt_handle::add_new_puller(SRT_CONN_PTR conn_ptr, std::string stream_id) {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void srt_handle::close_pull_conn(SRTSOCKET srtsocket, std::string stream_id) {
|
|
|
|
void srt_handle::close_pull_conn(SRTSOCKET srtsocket, std::string stream_id) {
|
|
|
|
srs_warn("close_pull_conn read_fd=%d, streamid=%s", srtsocket, stream_id.c_str());
|
|
|
|
srt_log_trace("close_pull_conn read_fd=%d, streamid=%s", srtsocket, stream_id.c_str());
|
|
|
|
srt_epoll_remove_usock(_handle_pollid, srtsocket);
|
|
|
|
srt_epoll_remove_usock(_handle_pollid, srtsocket);
|
|
|
|
|
|
|
|
|
|
|
|
auto streamid_iter = _streamid_map.find(stream_id);
|
|
|
|
auto streamid_iter = _streamid_map.find(stream_id);
|
|
|
@ -140,36 +142,36 @@ void srt_handle::add_newconn(SRT_CONN_PTR conn_ptr, int events) {
|
|
|
|
int opt64_len = sizeof(int64_t);
|
|
|
|
int opt64_len = sizeof(int64_t);
|
|
|
|
|
|
|
|
|
|
|
|
srt_getsockopt(conn_ptr->get_conn(), 0, SRTO_LATENCY, &val_i, &opt_len);
|
|
|
|
srt_getsockopt(conn_ptr->get_conn(), 0, SRTO_LATENCY, &val_i, &opt_len);
|
|
|
|
srs_trace("srto SRTO_LATENCY=%d", val_i);
|
|
|
|
srt_log_trace("srto SRTO_LATENCY=%d", val_i);
|
|
|
|
|
|
|
|
|
|
|
|
srt_getsockopt(conn_ptr->get_conn(), 0, SRTO_PEERLATENCY, &val_i, &opt_len);
|
|
|
|
srt_getsockopt(conn_ptr->get_conn(), 0, SRTO_PEERLATENCY, &val_i, &opt_len);
|
|
|
|
srs_trace("srto SRTO_PEERLATENCY=%d", val_i);
|
|
|
|
srt_log_trace("srto SRTO_PEERLATENCY=%d", val_i);
|
|
|
|
srt_getsockopt(conn_ptr->get_conn(), 0, SRTO_RCVLATENCY, &val_i, &opt_len);
|
|
|
|
srt_getsockopt(conn_ptr->get_conn(), 0, SRTO_RCVLATENCY, &val_i, &opt_len);
|
|
|
|
srs_trace("srto SRTO_RCVLATENCY=%d", val_i);
|
|
|
|
srt_log_trace("srto SRTO_RCVLATENCY=%d", val_i);
|
|
|
|
|
|
|
|
|
|
|
|
srt_getsockopt(conn_ptr->get_conn(), 0, SRTO_SNDBUF, &val_i, &opt_len);
|
|
|
|
srt_getsockopt(conn_ptr->get_conn(), 0, SRTO_SNDBUF, &val_i, &opt_len);
|
|
|
|
srs_trace("srto SRTO_SNDBUF=%d", val_i);
|
|
|
|
srt_log_trace("srto SRTO_SNDBUF=%d", val_i);
|
|
|
|
srt_getsockopt(conn_ptr->get_conn(), 0, SRTO_RCVBUF, &val_i, &opt_len);
|
|
|
|
srt_getsockopt(conn_ptr->get_conn(), 0, SRTO_RCVBUF, &val_i, &opt_len);
|
|
|
|
srs_trace("srto SRTO_RCVBUF=%d", val_i);
|
|
|
|
srt_log_trace("srto SRTO_RCVBUF=%d", val_i);
|
|
|
|
srt_getsockopt(conn_ptr->get_conn(), 0, SRTO_MAXBW, &val_i64, &opt64_len);
|
|
|
|
srt_getsockopt(conn_ptr->get_conn(), 0, SRTO_MAXBW, &val_i64, &opt64_len);
|
|
|
|
srs_trace("srto SRTO_MAXBW=%d", val_i64);
|
|
|
|
srt_log_trace("srto SRTO_MAXBW=%d", val_i64);
|
|
|
|
srs_trace("srt mix_correct is %s.", _srs_config->get_srt_mix_correct() ? "enable" : "disable");
|
|
|
|
srt_log_trace("srt mix_correct is %s.", _srs_config->get_srt_mix_correct() ? "enable" : "disable");
|
|
|
|
srs_trace("srt h264 sei filter is %s.", _srs_config->get_srt_sei_filter() ? "enable" : "disable");
|
|
|
|
srt_log_trace("srt h264 sei filter is %s.", _srs_config->get_srt_sei_filter() ? "enable" : "disable");
|
|
|
|
|
|
|
|
|
|
|
|
if (conn_ptr->get_mode() == PULL_SRT_MODE) {
|
|
|
|
if (conn_ptr->get_mode() == PULL_SRT_MODE) {
|
|
|
|
add_new_puller(conn_ptr, conn_ptr->get_subpath());
|
|
|
|
add_new_puller(conn_ptr, conn_ptr->get_subpath());
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
if(add_new_pusher(conn_ptr) == false) {
|
|
|
|
if(add_new_pusher(conn_ptr) == false) {
|
|
|
|
srs_trace("push connection is repeated and rejected, fd:%d, streamid:%s",
|
|
|
|
srt_log_trace("push connection is repeated and rejected, fd:%d, streamid:%s",
|
|
|
|
conn_ptr->get_conn(), conn_ptr->get_streamid().c_str());
|
|
|
|
conn_ptr->get_conn(), conn_ptr->get_streamid().c_str());
|
|
|
|
conn_ptr->close();
|
|
|
|
conn_ptr->close();
|
|
|
|
return;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
srs_trace("new conn added fd:%d, event:0x%08x", conn_ptr->get_conn(), events);
|
|
|
|
srt_log_trace("new conn added fd:%d, event:0x%08x", conn_ptr->get_conn(), events);
|
|
|
|
int ret = srt_epoll_add_usock(_handle_pollid, conn_ptr->get_conn(), &events);
|
|
|
|
int ret = srt_epoll_add_usock(_handle_pollid, conn_ptr->get_conn(), &events);
|
|
|
|
if (ret < 0) {
|
|
|
|
if (ret < 0) {
|
|
|
|
srs_error("srt handle run add epoll error:%d", ret);
|
|
|
|
srt_log_error("srt handle run add epoll error:%d", ret);
|
|
|
|
return;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
@ -183,19 +185,19 @@ void srt_handle::handle_push_data(SRT_SOCKSTATUS status, const std::string& subp
|
|
|
|
srt_conn_ptr = get_srt_conn(conn_fd);
|
|
|
|
srt_conn_ptr = get_srt_conn(conn_fd);
|
|
|
|
|
|
|
|
|
|
|
|
if (!srt_conn_ptr) {
|
|
|
|
if (!srt_conn_ptr) {
|
|
|
|
srs_error("handle_push_data fd:%d fail to find srt connection.", conn_fd);
|
|
|
|
srt_log_error("handle_push_data fd:%d fail to find srt connection.", conn_fd);
|
|
|
|
return;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (status != SRTS_CONNECTED) {
|
|
|
|
if (status != SRTS_CONNECTED) {
|
|
|
|
srs_error("handle_push_data error status:%d fd:%d", status, conn_fd);
|
|
|
|
srt_log_error("handle_push_data error status:%d fd:%d", status, conn_fd);
|
|
|
|
close_push_conn(conn_fd);
|
|
|
|
close_push_conn(conn_fd);
|
|
|
|
return;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
ret = srt_conn_ptr->read(data, DEF_DATA_SIZE);
|
|
|
|
ret = srt_conn_ptr->read(data, DEF_DATA_SIZE);
|
|
|
|
if (ret <= 0) {
|
|
|
|
if (ret <= 0) {
|
|
|
|
srs_error("handle_push_data srt connect read error:%d, fd:%d", ret, conn_fd);
|
|
|
|
srt_log_error("handle_push_data srt connect read error:%d, fd:%d", ret, conn_fd);
|
|
|
|
close_push_conn(conn_fd);
|
|
|
|
close_push_conn(conn_fd);
|
|
|
|
return;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -208,10 +210,10 @@ void srt_handle::handle_push_data(SRT_SOCKSTATUS status, const std::string& subp
|
|
|
|
//streamid, play map<SRTSOCKET, SRT_CONN_PTR>
|
|
|
|
//streamid, play map<SRTSOCKET, SRT_CONN_PTR>
|
|
|
|
auto streamid_iter = _streamid_map.find(subpath);
|
|
|
|
auto streamid_iter = _streamid_map.find(subpath);
|
|
|
|
if (streamid_iter == _streamid_map.end()) {//no puler
|
|
|
|
if (streamid_iter == _streamid_map.end()) {//no puler
|
|
|
|
srs_info("receive data size(%d) from pusher(%d) but no puller", ret, conn_fd);
|
|
|
|
srt_log_info("receive data size(%d) from pusher(%d) but no puller", ret, conn_fd);
|
|
|
|
return;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
srs_info("receive data size(%d) from pusher(%d) to pullers, count:%d",
|
|
|
|
srt_log_info("receive data size(%d) from pusher(%d) to pullers, count:%d",
|
|
|
|
ret, conn_fd, streamid_iter->second.size());
|
|
|
|
ret, conn_fd, streamid_iter->second.size());
|
|
|
|
|
|
|
|
|
|
|
|
for (auto puller_iter = streamid_iter->second.begin();
|
|
|
|
for (auto puller_iter = streamid_iter->second.begin();
|
|
|
@ -219,11 +221,11 @@ void srt_handle::handle_push_data(SRT_SOCKSTATUS status, const std::string& subp
|
|
|
|
puller_iter++) {
|
|
|
|
puller_iter++) {
|
|
|
|
auto player_conn = puller_iter->second;
|
|
|
|
auto player_conn = puller_iter->second;
|
|
|
|
if (!player_conn) {
|
|
|
|
if (!player_conn) {
|
|
|
|
srs_error("handle_push_data get srt connect error from fd:%d", puller_iter->first);
|
|
|
|
srt_log_error("handle_push_data get srt connect error from fd:%d", puller_iter->first);
|
|
|
|
continue;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
int write_ret = player_conn->write(data, ret);
|
|
|
|
int write_ret = player_conn->write(data, ret);
|
|
|
|
srs_info("send data size(%d) to puller fd:%d", write_ret, puller_iter->first);
|
|
|
|
srt_log_info("send data size(%d) to puller fd:%d", write_ret, puller_iter->first);
|
|
|
|
if (write_ret > 0) {
|
|
|
|
if (write_ret > 0) {
|
|
|
|
puller_iter->second->update_timestamp(srt_now_ms);
|
|
|
|
puller_iter->second->update_timestamp(srt_now_ms);
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -261,15 +263,15 @@ void srt_handle::check_alive() {
|
|
|
|
{
|
|
|
|
{
|
|
|
|
SRT_CONN_PTR conn_ptr = *del_iter;
|
|
|
|
SRT_CONN_PTR conn_ptr = *del_iter;
|
|
|
|
if (conn_ptr->get_mode() == PUSH_SRT_MODE) {
|
|
|
|
if (conn_ptr->get_mode() == PUSH_SRT_MODE) {
|
|
|
|
srs_warn("check alive close pull connection fd:%d, streamid:%s",
|
|
|
|
srt_log_warn("check alive close pull connection fd:%d, streamid:%s",
|
|
|
|
conn_ptr->get_conn(), conn_ptr->get_subpath().c_str());
|
|
|
|
conn_ptr->get_conn(), conn_ptr->get_subpath().c_str());
|
|
|
|
close_push_conn(conn_ptr->get_conn());
|
|
|
|
close_push_conn(conn_ptr->get_conn());
|
|
|
|
} else if (conn_ptr->get_mode() == PULL_SRT_MODE) {
|
|
|
|
} else if (conn_ptr->get_mode() == PULL_SRT_MODE) {
|
|
|
|
srs_warn("check alive close pull connection fd:%d, streamid:%s",
|
|
|
|
srt_log_warn("check alive close pull connection fd:%d, streamid:%s",
|
|
|
|
conn_ptr->get_conn(), conn_ptr->get_subpath().c_str());
|
|
|
|
conn_ptr->get_conn(), conn_ptr->get_subpath().c_str());
|
|
|
|
close_pull_conn(conn_ptr->get_conn(), conn_ptr->get_subpath());
|
|
|
|
close_pull_conn(conn_ptr->get_conn(), conn_ptr->get_subpath());
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
srs_error("check_alive get unkown srt mode:%d, fd:%d",
|
|
|
|
srt_log_error("check_alive get unkown srt mode:%d, fd:%d",
|
|
|
|
conn_ptr->get_mode(), conn_ptr->get_conn());
|
|
|
|
conn_ptr->get_mode(), conn_ptr->get_conn());
|
|
|
|
assert(0);
|
|
|
|
assert(0);
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -302,17 +304,17 @@ bool srt_handle::add_new_pusher(SRT_CONN_PTR conn_ptr) {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
_push_conn_map.insert(std::make_pair(conn_ptr->get_subpath(), conn_ptr));
|
|
|
|
_push_conn_map.insert(std::make_pair(conn_ptr->get_subpath(), conn_ptr));
|
|
|
|
_conn_map.insert(std::make_pair(conn_ptr->get_conn(), conn_ptr));
|
|
|
|
_conn_map.insert(std::make_pair(conn_ptr->get_conn(), conn_ptr));
|
|
|
|
srs_trace("srt_handle add new pusher streamid:%s, subpath:%s",
|
|
|
|
srt_log_trace("srt_handle add new pusher streamid:%s, subpath:%s",
|
|
|
|
conn_ptr->get_streamid().c_str(), conn_ptr->get_subpath().c_str());
|
|
|
|
conn_ptr->get_streamid().c_str(), conn_ptr->get_subpath().c_str());
|
|
|
|
return true;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void srt_handle::handle_pull_data(SRT_SOCKSTATUS status, const std::string& subpath, SRTSOCKET conn_fd) {
|
|
|
|
void srt_handle::handle_pull_data(SRT_SOCKSTATUS status, const std::string& subpath, SRTSOCKET conn_fd) {
|
|
|
|
srs_info("handle_pull_data status:%d, subpath:%s, fd:%d",
|
|
|
|
srt_log_info("handle_pull_data status:%d, subpath:%s, fd:%d",
|
|
|
|
status, subpath.c_str(), conn_fd);
|
|
|
|
status, subpath.c_str(), conn_fd);
|
|
|
|
auto conn_ptr = get_srt_conn(conn_fd);
|
|
|
|
auto conn_ptr = get_srt_conn(conn_fd);
|
|
|
|
if (!conn_ptr) {
|
|
|
|
if (!conn_ptr) {
|
|
|
|
srs_error("handle_pull_data fail to find fd(%d)", conn_fd);
|
|
|
|
srt_log_error("handle_pull_data fail to find fd(%d)", conn_fd);
|
|
|
|
assert(0);
|
|
|
|
assert(0);
|
|
|
|
return;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -327,7 +329,7 @@ void srt_handle::handle_srt_socket(SRT_SOCKSTATUS status, SRTSOCKET conn_fd)
|
|
|
|
|
|
|
|
|
|
|
|
if (!conn_ptr) {
|
|
|
|
if (!conn_ptr) {
|
|
|
|
if (status != SRTS_CLOSED) {
|
|
|
|
if (status != SRTS_CLOSED) {
|
|
|
|
srs_error("handle_srt_socket find srt connection error, fd:%d, status:%d",
|
|
|
|
srt_log_error("handle_srt_socket find srt connection error, fd:%d, status:%d",
|
|
|
|
conn_fd, status);
|
|
|
|
conn_fd, status);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
return;
|
|
|
@ -349,13 +351,13 @@ void srt_handle::handle_srt_socket(SRT_SOCKSTATUS status, SRTSOCKET conn_fd)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
case SRTS_BROKEN:
|
|
|
|
case SRTS_BROKEN:
|
|
|
|
{
|
|
|
|
{
|
|
|
|
srs_warn("srt push disconnected event fd:%d, streamid:%s",
|
|
|
|
srt_log_warn("srt push disconnected event fd:%d, streamid:%s",
|
|
|
|
conn_fd, conn_ptr->get_streamid().c_str());
|
|
|
|
conn_fd, conn_ptr->get_streamid().c_str());
|
|
|
|
close_push_conn(conn_fd);
|
|
|
|
close_push_conn(conn_fd);
|
|
|
|
break;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
default:
|
|
|
|
srs_error("push mode unkown status:%d, fd:%d", status, conn_fd);
|
|
|
|
srt_log_error("push mode unkown status:%d, fd:%d", status, conn_fd);
|
|
|
|
break;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else if (mode == PULL_SRT_MODE) {
|
|
|
|
} else if (mode == PULL_SRT_MODE) {
|
|
|
@ -368,13 +370,13 @@ void srt_handle::handle_srt_socket(SRT_SOCKSTATUS status, SRTSOCKET conn_fd)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
case SRTS_BROKEN:
|
|
|
|
case SRTS_BROKEN:
|
|
|
|
{
|
|
|
|
{
|
|
|
|
srs_warn("srt pull disconnected fd:%d, streamid:%s",
|
|
|
|
srt_log_warn("srt pull disconnected fd:%d, streamid:%s",
|
|
|
|
conn_fd, conn_ptr->get_streamid().c_str());
|
|
|
|
conn_fd, conn_ptr->get_streamid().c_str());
|
|
|
|
close_pull_conn(conn_fd, subpath);
|
|
|
|
close_pull_conn(conn_fd, subpath);
|
|
|
|
break;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
default:
|
|
|
|
srs_error("pull mode unkown status:%d, fd:%d", status, conn_fd);
|
|
|
|
srt_log_error("pull mode unkown status:%d, fd:%d", status, conn_fd);
|
|
|
|
break;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|