void SrsThread::dispose() { if (disposed) { return; } // the interrupt will cause the socket to read/write error, // which will terminate the cycle thread. st_thread_interrupt(tid); // when joinable, wait util quit. if (_joinable) { // wait the thread to exit. int ret = st_thread_join(tid, NULL); if (ret) { srs_warn("core: ignore join thread failed."); } } // wait the thread actually terminated. // sometimes the thread join return -1, for example, // when thread use st_recvfrom, the thread join return -1. // so here, we use a variable to ensure the thread stopped. // @remark even the thread not joinable, we must ensure the thread stopped when stop. while (!really_terminated) { st_usleep(10 * 1000); if (really_terminated) { break; } srs_warn("core: wait thread to actually terminated"); } disposed = true; }
int SrsServer::accept_client(SrsListenerType type, st_netfd_t client_stfd) { int ret = ERROR_SUCCESS; int max_connections = _srs_config->get_max_connections(); if ((int)conns.size() >= max_connections) { int fd = st_netfd_fileno(client_stfd); srs_error("exceed the max connections, drop client: " "clients=%d, max=%d, fd=%d", (int)conns.size(), max_connections, fd); srs_close_stfd(client_stfd); return ret; } SrsConnection* conn = NULL; if (type == SrsListenerRtmpStream) { conn = new SrsRtmpConn(this, client_stfd); } else if (type == SrsListenerHttpApi) { #ifdef SRS_AUTO_HTTP_API conn = new SrsHttpApi(this, client_stfd, http_api_handler); #else srs_warn("close http client for server not support http-api"); srs_close_stfd(client_stfd); return ret; #endif } else if (type == SrsListenerHttpStream) { #ifdef SRS_AUTO_HTTP_SERVER conn = new SrsHttpConn(this, client_stfd, http_stream_handler); #else srs_warn("close http client for server not support http-server"); srs_close_stfd(client_stfd); return ret; #endif } else { // TODO: FIXME: handler others } srs_assert(conn); // directly enqueue, the cycle thread will remove the client. conns.push_back(conn); srs_verbose("add conn to vector."); // cycle will start process thread and when finished remove the client. // @remark never use the conn, for it maybe destroyed. if ((ret = conn->start()) != ERROR_SUCCESS) { return ret; } srs_verbose("conn started success."); srs_verbose("accept client finished. conns=%d, ret=%d", (int)conns.size(), ret); return ret; }
void check_macro_features() { // for special features. #ifdef SRS_AUTO_HTTP_SERVER srs_warn("http server is dev feature, @see %s", RTMP_SIG_SRS_HTTP_SERVER); #endif #if VERSION_MAJOR > 1 #warning "using develop SRS, please use release instead." srs_warn("SRS %s is develop branch, please use %s instead", RTMP_SIG_SRS_VERSION, RTMP_SIG_SRS_RELEASE); #endif }
int SrsServer::do_cycle() { int ret = ERROR_SUCCESS; // find the max loop int max = srs_max(0, SRS_SYS_TIME_RESOLUTION_MS_TIMES); max = srs_max(max, SRS_SYS_RUSAGE_RESOLUTION_TIMES); max = srs_max(max, SRS_SYS_CPU_STAT_RESOLUTION_TIMES); max = srs_max(max, SRS_SYS_MEMINFO_RESOLUTION_TIMES); max = srs_max(max, SRS_SYS_PLATFORM_INFO_RESOLUTION_TIMES); // the deamon thread, update the time cache while (true) { for (int i = 1; i < max + 1; i++) { st_usleep(SRS_SYS_CYCLE_INTERVAL * 1000); // for gperf heap checker, // @see: research/gperftools/heap-checker/heap_checker.cc // if user interrupt the program, exit to check mem leak. // but, if gperf, use reload to ensure main return normally, // because directly exit will cause core-dump. #ifdef SRS_AUTO_GPERF_MC if (signal_gmc_stop) { srs_warn("gmc got singal to stop server."); return ret; } #endif if (signal_reload) { signal_reload = false; srs_info("get signal reload, to reload the config."); if ((ret = _srs_config->reload()) != ERROR_SUCCESS) { srs_error("reload config failed. ret=%d", ret); return ret; } srs_trace("reload config success."); } // update the cache time or rusage. if ((i % SRS_SYS_TIME_RESOLUTION_MS_TIMES) == 0) { srs_update_system_time_ms(); } if ((i % SRS_SYS_RUSAGE_RESOLUTION_TIMES) == 0) { srs_update_system_rusage(); } if ((i % SRS_SYS_CPU_STAT_RESOLUTION_TIMES) == 0) { srs_update_proc_stat(); } if ((i % SRS_SYS_MEMINFO_RESOLUTION_TIMES) == 0) { srs_update_meminfo(); } if ((i % SRS_SYS_PLATFORM_INFO_RESOLUTION_TIMES) == 0) { srs_update_platform_info(); } } } return ret; }
int SrsConnection::cycle() { int ret = ERROR_SUCCESS; _srs_context->generate_id(); ip = srs_get_peer_ip(st_netfd_fileno(stfd)); ret = do_cycle(); // if socket io error, set to closed. if (srs_is_client_gracefully_close(ret)) { ret = ERROR_SOCKET_CLOSED; } // success. if (ret == ERROR_SUCCESS) { srs_trace("client finished."); } // client close peer. if (ret == ERROR_SOCKET_CLOSED) { srs_warn("client disconnect peer. ret=%d", ret); } // set loop to stop to quit. pthread->stop_loop(); return ERROR_SUCCESS; }
bool get_proc_system_stat(SrsProcSystemStat& r) { FILE* f = fopen("/proc/stat", "r"); if (f == NULL) { srs_warn("open system cpu stat failed, ignore"); return false; } for (;;) { int ret = fscanf(f, "%4s %lu %lu %lu %lu %lu " "%lu %lu %lu %lu\n", r.label, &r.user, &r.nice, &r.sys, &r.idle, &r.iowait, &r.irq, &r.softirq, &r.steal, &r.guest); r.ok = false; if (ret == EOF) { break; } if (strcmp("cpu", r.label) == 0) { r.ok = true; break; } } fclose(f); return r.ok; }
bool get_proc_self_stat(SrsProcSelfStat& r) { FILE* f = fopen("/proc/self/stat", "r"); if (f == NULL) { srs_warn("open self cpu stat failed, ignore"); return false; } int ret = fscanf(f, "%d %32s %c %d %d %d %d " "%d %u %lu %lu %lu %lu " "%lu %lu %ld %ld %ld %ld " "%ld %ld %llu %lu %ld " "%lu %lu %lu %lu %lu " "%lu %lu %lu %lu %lu " "%lu %lu %lu %d %d " "%u %u %llu " "%lu %ld", &r.pid, r.comm, &r.state, &r.ppid, &r.pgrp, &r.session, &r.tty_nr, &r.tpgid, &r.flags, &r.minflt, &r.cminflt, &r.majflt, &r.cmajflt, &r.utime, &r.stime, &r.cutime, &r.cstime, &r.priority, &r.nice, &r.num_threads, &r.itrealvalue, &r.starttime, &r.vsize, &r.rss, &r.rsslim, &r.startcode, &r.endcode, &r.startstack, &r.kstkesp, &r.kstkeip, &r.signal, &r.blocked, &r.sigignore, &r.sigcatch, &r.wchan, &r.nswap, &r.cnswap, &r.exit_signal, &r.processor, &r.rt_priority, &r.policy, &r.delayacct_blkio_ticks, &r.guest_time, &r.cguest_time); fclose(f); if (ret >= 0) { r.ok = true; } return r.ok; }
int SrsDH::copy_shared_key(const char* ppkey, int32_t ppkey_size, char* skey, int32_t& skey_size) { int ret = ERROR_SUCCESS; BIGNUM* ppk = NULL; if ((ppk = BN_bin2bn((const unsigned char*)ppkey, ppkey_size, 0)) == NULL) { ret = ERROR_OpenSslGetPeerPublicKey; return ret; } // if failed, donot return, do cleanup, @see ./test/dhtest.c:168 // maybe the key_size is 127, but dh will write all 128bytes skey, // so, donot need to set/initialize the skey. // @see https://github.com/winlinvip/simple-rtmp-server/issues/165 int32_t key_size = DH_compute_key((unsigned char*)skey, ppk, pdh); if (key_size < ppkey_size) { srs_warn("shared key size=%d, ppk_size=%d", key_size, ppkey_size); } if (key_size < 0 || key_size > skey_size) { ret = ERROR_OpenSslComputeSharedKey; } else { skey_size = key_size; } if (ppk) { BN_free(ppk); } return ret; }
void SrsEncoder::encoder_cycle() { int ret = ERROR_SUCCESS; log_context->generate_id(); srs_trace("encoder cycle start"); while (loop) { if ((ret = cycle()) != ERROR_SUCCESS) { srs_warn("encoder cycle failed, ignored and retry, ret=%d", ret); } else { srs_info("encoder cycle success, retry"); } if (!loop) { break; } st_usleep(SRS_ENCODER_SLEEP_MS * 1000); } // kill ffmpeg when finished and it alive std::vector<SrsFFMPEG*>::iterator it; for (it = ffmpegs.begin(); it != ffmpegs.end(); ++it) { SrsFFMPEG* ffmpeg = *it; ffmpeg->stop(); } srs_trace("encoder cycle finished"); }
void SrsThread::thread_cycle() { int ret = ERROR_SUCCESS; _srs_context->generate_id(); srs_info("thread cycle start"); _cid = _srs_context->get_id(); srs_assert(handler); handler->on_thread_start(); // wait for cid to ready, for parent thread to get the cid. while (!can_run && loop) { st_usleep(10 * 1000); } while (loop) { if ((ret = handler->on_before_cycle()) != ERROR_SUCCESS) { srs_warn("thread on before cycle failed, ignored and retry, ret=%d", ret); goto failed; } srs_info("thread on before cycle success"); if ((ret = handler->cycle()) != ERROR_SUCCESS) { srs_warn("thread cycle failed, ignored and retry, ret=%d", ret); goto failed; } srs_info("thread cycle success"); if ((ret = handler->on_end_cycle()) != ERROR_SUCCESS) { srs_warn("thread on end cycle failed, ignored and retry, ret=%d", ret); goto failed; } srs_info("thread on end cycle success"); failed: if (!loop) { break; } st_usleep(cycle_interval_us); } handler->on_thread_stop(); srs_info("thread cycle finished"); }
int SrsServer::cycle() { int ret = ERROR_SUCCESS; ret = do_cycle(); #ifdef SRS_AUTO_GPERF_MC destroy(); srs_warn("sleep a long time for system st-threads to cleanup."); st_usleep(3 * 1000 * 1000); srs_warn("system quit"); #else srs_warn("main cycle terminated, system quit normally."); exit(0); #endif return ret; }
void srs_update_system_time_ms() { timeval now; if (gettimeofday(&now, NULL) < 0) { srs_warn("gettimeofday failed, ignore"); return; } // @see: https://github.com/winlinvip/simple-rtmp-server/issues/35 // we must convert the tv_sec/tv_usec to int64_t. int64_t now_us = ((int64_t)now.tv_sec) * 1000 * 1000 + (int64_t)now.tv_usec; if (now_us < _srs_system_time_us_cache) { srs_warn("system time negative, " "history=%"PRId64"us, now=%"PRId64"", _srs_system_time_us_cache, now_us); } _srs_system_time_us_cache = now_us; }
void SrsThread::thread_cycle() { int ret = ERROR_SUCCESS; srs_assert(handler); log_context->generate_id(); srs_trace("thread cycle start"); handler->on_end_cycle(); loop = true; while (loop) { if ((ret = handler->on_before_cycle()) != ERROR_SUCCESS) { srs_warn("thread on before cycle failed, ignored and retry, ret=%d", ret); goto failed; } srs_info("thread on before cycle success"); if ((ret = handler->cycle()) != ERROR_SUCCESS) { srs_warn("thread cycle failed, ignored and retry, ret=%d", ret); goto failed; } srs_info("thread cycle success"); if ((ret = handler->on_end_cycle()) != ERROR_SUCCESS) { srs_warn("thread on end cycle failed, ignored and retry, ret=%d", ret); goto failed; } srs_info("thread on end cycle success"); failed: if (!loop) { break; } st_usleep(cycle_interval_us); } handler->on_leave_loop(); srs_trace("thread cycle finished"); }
int SrsListener::cycle() { int ret = ERROR_SUCCESS; st_netfd_t client_stfd = st_accept(stfd, NULL, NULL, ST_UTIME_NO_TIMEOUT); if(client_stfd == NULL){ // ignore error. srs_warn("ignore accept thread stoppped for accept client error"); return ret; } srs_verbose("get a client. fd=%d", st_netfd_fileno(client_stfd)); if ((ret = server->accept_client(type, client_stfd)) != ERROR_SUCCESS) { srs_warn("accept client error. ret=%d", ret); return ret; } return ret; }
int SrsForwarder::on_publish(SrsRequest* req, std::string forward_server) { int ret = ERROR_SUCCESS; // forward app app = req->app; stream_name = req->stream; server = forward_server; std::string s_port = RTMP_DEFAULT_PORT; port = ::atoi(RTMP_DEFAULT_PORT); size_t pos = forward_server.find(":"); if (pos != std::string::npos) { s_port = forward_server.substr(pos + 1); server = forward_server.substr(0, pos); } // discovery vhost std::string vhost = req->vhost; srs_vhost_resolve(vhost, s_port); port = ::atoi(s_port.c_str()); // generate tcUrl tc_url = "rtmp://"; tc_url += vhost; tc_url += "/"; tc_url += req->app; // dead loop check std::string source_ep = req->vhost; source_ep += ":"; source_ep += req->port; std::string dest_ep = vhost; dest_ep += ":"; dest_ep += s_port; if (source_ep == dest_ep) { ret = ERROR_SYSTEM_FORWARD_LOOP; srs_warn("farder loop detected. src=%s, dest=%s, ret=%d", source_ep.c_str(), dest_ep.c_str(), ret); return ret; } srs_trace("start forward %s to %s, stream: %s/%s", source_ep.c_str(), dest_ep.c_str(), tc_url.c_str(), stream_name.c_str()); if ((ret = pthread->start()) != ERROR_SUCCESS) { srs_error("start srs thread failed. ret=%d", ret); return ret; } return ret; }
void srs_update_system_rusage() { if (getrusage(RUSAGE_SELF, &_srs_system_rusage.r) < 0) { srs_warn("getrusage failed, ignore"); return; } srs_update_system_time_ms(); _srs_system_rusage.sample_time = srs_get_system_time_ms(); _srs_system_rusage.ok = true; }
void SrsServer::destroy() { srs_warn("start destroy server"); _srs_config->unsubscribe(this); close_listeners(SrsListenerRtmpStream); close_listeners(SrsListenerHttpApi); close_listeners(SrsListenerHttpStream); #ifdef SRS_AUTO_INGEST ingester->stop(); #endif #ifdef SRS_AUTO_HTTP_API srs_freep(http_api_handler); #endif #ifdef SRS_AUTO_HTTP_SERVER srs_freep(http_stream_handler); #endif #ifdef SRS_AUTO_HTTP_PARSER srs_freep(http_heartbeat); #endif #ifdef SRS_AUTO_INGEST srs_freep(ingester); #endif if (pid_fd > 0) { ::close(pid_fd); pid_fd = -1; } srs_freep(signal_manager); srs_freep(kbps); for (std::vector<SrsConnection*>::iterator it = conns.begin(); it != conns.end();) { SrsConnection* conn = *it; // remove the connection, then free it, // for the free will remove itself from server, // when erased here, the remove of server will ignore. it = conns.erase(it); srs_freep(conn); } conns.clear(); SrsSource::destroy(); }
void srs_update_meminfo() { FILE* f = fopen("/proc/meminfo", "r"); if (f == NULL) { srs_warn("open meminfo failed, ignore"); return; } SrsMemInfo& r = _srs_system_meminfo; r.ok = false; for (;;) { static char label[64]; static unsigned long value; static char postfix[64]; int ret = fscanf(f, "%64s %lu %64s\n", label, &value, postfix); if (ret == EOF) { break; } if (strcmp("MemTotal:", label) == 0) { r.MemTotal = value; } else if (strcmp("MemFree:", label) == 0) { r.MemFree = value; } else if (strcmp("Buffers:", label) == 0) { r.Buffers = value; } else if (strcmp("Cached:", label) == 0) { r.Cached = value; } else if (strcmp("SwapTotal:", label) == 0) { r.SwapTotal = value; } else if (strcmp("SwapFree:", label) == 0) { r.SwapFree = value; } } fclose(f); r.sample_time = srs_get_system_time_ms(); r.MemActive = r.MemTotal - r.MemFree; r.RealInUse = r.MemActive - r.Buffers - r.Cached; r.NotInUse = r.MemTotal - r.RealInUse; r.ok = true; if (r.MemTotal > 0) { r.percent_ram = (float)(r.RealInUse / (double)r.MemTotal); } if (r.SwapTotal > 0) { r.percent_swap = (float)((r.SwapTotal - r.SwapFree) / (double)r.SwapTotal); } }
void srs_update_platform_info() { SrsPlatformInfo& r = _srs_system_platform_info; r.ok = true; if (true) { FILE* f = fopen("/proc/uptime", "r"); if (f == NULL) { srs_warn("open uptime failed, ignore"); return; } int ret = fscanf(f, "%lf %lf\n", &r.os_uptime, &r.os_ilde_time); fclose(f); if (ret < 0) { r.ok = false; } } if (true) { FILE* f = fopen("/proc/loadavg", "r"); if (f == NULL) { srs_warn("open loadavg failed, ignore"); return; } int ret = fscanf(f, "%lf %lf %lf\n", &r.load_one_minutes, &r.load_five_minutes, &r.load_fifteen_minutes); fclose(f); if (ret < 0) { r.ok = false; } } }
int SrsEdgeIngester::cycle() { int ret = ERROR_SUCCESS; if ((ret = connect_server()) != ERROR_SUCCESS) { return ret; } srs_assert(client); client->set_recv_timeout(SRS_CONSTS_RTMP_RECV_TIMEOUT_US); client->set_send_timeout(SRS_CONSTS_RTMP_SEND_TIMEOUT_US); SrsRequest* req = _req; if ((ret = client->handshake()) != ERROR_SUCCESS) { srs_error("handshake with server failed. ret=%d", ret); return ret; } if ((ret = client->connect_app(req->app, req->tcUrl, req)) != ERROR_SUCCESS) { srs_error("connect with server failed, tcUrl=%s. ret=%d", req->tcUrl.c_str(), ret); return ret; } if ((ret = client->create_stream(stream_id)) != ERROR_SUCCESS) { srs_error("connect with server failed, stream_id=%d. ret=%d", stream_id, ret); return ret; } if ((ret = client->play(req->stream, stream_id)) != ERROR_SUCCESS) { srs_error("connect with server failed, stream=%s, stream_id=%d. ret=%d", req->stream.c_str(), stream_id, ret); return ret; } if ((ret = _source->on_publish()) != ERROR_SUCCESS) { srs_error("edge pull stream then publish to edge failed. ret=%d", ret); return ret; } if ((ret = _edge->on_ingest_play()) != ERROR_SUCCESS) { return ret; } ret = ingest(); if (srs_is_client_gracefully_close(ret)) { srs_warn("origin disconnected, retry. ret=%d", ret); ret = ERROR_SUCCESS; } return ret; }
int SrsEdgeForwarder::connect_server() { int ret = ERROR_SUCCESS; // reopen close_underlayer_socket(); SrsConfDirective* conf = _srs_config->get_vhost_edge_origin(_req->vhost); srs_assert(conf); // select the origin. std::string server = conf->args.at(origin_index % conf->args.size()); origin_index = (origin_index + 1) % conf->args.size(); std::string s_port = SRS_CONSTS_RTMP_DEFAULT_PORT; int port = ::atoi(SRS_CONSTS_RTMP_DEFAULT_PORT); size_t pos = server.find(":"); if (pos != std::string::npos) { s_port = server.substr(pos + 1); server = server.substr(0, pos); port = ::atoi(s_port.c_str()); } // open socket. int64_t timeout = SRS_EDGE_FORWARDER_TIMEOUT_US; if ((ret = srs_socket_connect(server, port, timeout, &stfd)) != ERROR_SUCCESS) { srs_warn("edge push failed, stream=%s, tcUrl=%s to server=%s, port=%d, timeout=%"PRId64", ret=%d", _req->stream.c_str(), _req->tcUrl.c_str(), server.c_str(), port, timeout, ret); return ret; } srs_freep(client); srs_freep(io); srs_assert(stfd); io = new SrsStSocket(stfd); client = new SrsRtmpClient(io); kbps->set_io(io, io); // open socket. srs_trace("edge push connected, stream=%s, tcUrl=%s to server=%s, port=%d", _req->stream.c_str(), _req->tcUrl.c_str(), server.c_str(), port); return ret; }
void SrsServer::remove(SrsConnection* conn) { std::vector<SrsConnection*>::iterator it = std::find(conns.begin(), conns.end(), conn); // removed by destroy, ignore. if (it == conns.end()) { srs_warn("server moved connection, ignore."); return; } conns.erase(it); srs_info("conn removed. conns=%d", (int)conns.size()); // all connections are created by server, // so we free it here. srs_freep(conn); }
void SrsThread::stop() { if (tid) { loop = false; // the interrupt will cause the socket to read/write error, // which will terminate the cycle thread. st_thread_interrupt(tid); // wait the thread to exit. int ret = st_thread_join(tid, NULL); // TODO: FIXME: the join maybe failed, should use a variable to ensure thread terminated. if (ret != 0) { srs_warn("join thread failed. code=%d", ret); } tid = NULL; } }
int SrsDH::initialize(bool ensure_128bytes_public_key) { int ret = ERROR_SUCCESS; for (;;) { if ((ret = do_initialize()) != ERROR_SUCCESS) { return ret; } if (ensure_128bytes_public_key) { int32_t key_size = BN_num_bytes(pdh->pub_key); if (key_size != 128) { srs_warn("regenerate 128B key, current=%dB", key_size); continue; } } break; } return ret; }
void SrsThread::thread_cycle() { int ret = ERROR_SUCCESS; _srs_context->generate_id(); srs_info("thread %s cycle start", _name); _cid = _srs_context->get_id(); srs_assert(handler); handler->on_thread_start(); // thread is running now. really_terminated = false; // wait for cid to ready, for parent thread to get the cid. while (!can_run && loop) { st_usleep(10 * 1000); } while (loop) { if ((ret = handler->on_before_cycle()) != ERROR_SUCCESS) { srs_warn("thread %s on before cycle failed, ignored and retry, ret=%d", _name, ret); goto failed; } srs_info("thread %s on before cycle success"); if ((ret = handler->cycle()) != ERROR_SUCCESS) { if (!srs_is_client_gracefully_close(ret) && !srs_is_system_control_error(ret)) { srs_warn("thread %s cycle failed, ignored and retry, ret=%d", _name, ret); } goto failed; } srs_info("thread %s cycle success", _name); if ((ret = handler->on_end_cycle()) != ERROR_SUCCESS) { srs_warn("thread %s on end cycle failed, ignored and retry, ret=%d", _name, ret); goto failed; } srs_info("thread %s on end cycle success", _name); failed: if (!loop) { break; } // to improve performance, donot sleep when interval is zero. // @see: https://github.com/ossrs/srs/issues/237 if (cycle_interval_us != 0) { st_usleep(cycle_interval_us); } } // readly terminated now. really_terminated = true; // when thread terminated normally, also disposed. // we must set to disposed before the on_thread_stop, which may free the thread. // @see https://github.com/ossrs/srs/issues/546 disposed = true; handler->on_thread_stop(); srs_info("thread %s cycle finished", _name); }
int SrsSource::on_meta_data(SrsCommonMessage* msg, SrsOnMetaDataPacket* metadata) { int ret = ERROR_SUCCESS; #ifdef SRS_HLS if ((ret = hls->on_meta_data(metadata)) != ERROR_SUCCESS) { srs_error("hls process onMetaData message failed. ret=%d", ret); return ret; } #endif metadata->metadata->set("server", new SrsAmf0String( RTMP_SIG_SRS_KEY" "RTMP_SIG_SRS_VERSION" ("RTMP_SIG_SRS_URL_SHORT")")); SrsAmf0Any* prop = NULL; if ((prop = metadata->metadata->get_property("audiosamplerate")) != NULL) { if (prop->is_number()) { sample_rate = (int)(srs_amf0_convert<SrsAmf0Number>(prop)->value); } } if ((prop = metadata->metadata->get_property("framerate")) != NULL) { if (prop->is_number()) { frame_rate = (int)(srs_amf0_convert<SrsAmf0Number>(prop)->value); } } // encode the metadata to payload int size = metadata->get_payload_length(); if (size <= 0) { srs_warn("ignore the invalid metadata. size=%d", size); return ret; } srs_verbose("get metadata size success."); char* payload = new char[size]; memset(payload, 0, size); if ((ret = metadata->encode(size, payload)) != ERROR_SUCCESS) { srs_error("encode metadata error. ret=%d", ret); srs_freepa(payload); return ret; } srs_verbose("encode metadata success."); // create a shared ptr message. srs_freep(cache_metadata); cache_metadata = new SrsSharedPtrMessage(); // dump message to shared ptr message. if ((ret = cache_metadata->initialize(msg, payload, size)) != ERROR_SUCCESS) { srs_error("initialize the cache metadata failed. ret=%d", ret); return ret; } srs_verbose("initialize shared ptr metadata success."); // copy to all consumer if (true) { std::vector<SrsConsumer*>::iterator it; for (it = consumers.begin(); it != consumers.end(); ++it) { SrsConsumer* consumer = *it; if ((ret = consumer->enqueue(cache_metadata->copy(), sample_rate, frame_rate)) != ERROR_SUCCESS) { srs_error("dispatch the metadata failed. ret=%d", ret); return ret; } } srs_trace("dispatch metadata success."); } // copy to all forwarders if (true) { std::vector<SrsForwarder*>::iterator it; for (it = forwarders.begin(); it != forwarders.end(); ++it) { SrsForwarder* forwarder = *it; if ((ret = forwarder->on_meta_data(cache_metadata->copy())) != ERROR_SUCCESS) { srs_error("forwarder process onMetaData message failed. ret=%d", ret); return ret; } } } return ret; }
int SrsForwarder::on_publish(SrsRequest* req, std::string forward_server) { int ret = ERROR_SUCCESS; // forward app app = req->app; stream_name = req->stream; server = forward_server; std::string s_port = RTMP_DEFAULT_PORT; port = ::atoi(RTMP_DEFAULT_PORT); // TODO: FIXME: parse complex params size_t pos = forward_server.find(":"); if (pos != std::string::npos) { s_port = forward_server.substr(pos + 1); server = forward_server.substr(0, pos); } // discovery vhost std::string vhost = req->vhost; srs_vhost_resolve(vhost, s_port); port = ::atoi(s_port.c_str()); // generate tcUrl tc_url = "rtmp://"; if (vhost == RTMP_VHOST_DEFAULT) { tc_url += forward_server; } else { tc_url += vhost; } tc_url += "/"; tc_url += req->app; // dead loop check std::string source_ep = "rtmp://"; source_ep += req->host; source_ep += ":"; source_ep += req->port; source_ep += "?vhost="; source_ep += req->vhost; std::string dest_ep = "rtmp://"; if (forward_server == "127.0.0.1") { dest_ep += req->host; } else { dest_ep += forward_server; } dest_ep += ":"; dest_ep += s_port; dest_ep += "?vhost="; dest_ep += vhost; if (source_ep == dest_ep) { ret = ERROR_SYSTEM_FORWARD_LOOP; srs_warn("forward loop detected. src=%s, dest=%s, ret=%d", source_ep.c_str(), dest_ep.c_str(), ret); return ret; } srs_trace("start forward %s to %s, tcUrl=%s, stream=%s", source_ep.c_str(), dest_ep.c_str(), tc_url.c_str(), stream_name.c_str()); if ((ret = pthread->start()) != ERROR_SUCCESS) { srs_error("start srs thread failed. ret=%d", ret); return ret; } srs_trace("forward thread cid=%d, current_cid=%d", pthread->cid(), _srs_context->get_id()); return ret; }
/** * show the features by macro, the actual macro values. */ void show_macro_features() { #ifdef SRS_AUTO_SSL srs_trace("check feature rtmp handshake: on"); #else srs_warn("check feature rtmp handshake: off"); #endif #ifdef SRS_AUTO_HLS srs_trace("check feature hls: on"); #else srs_warn("check feature hls: off"); #endif #ifdef SRS_AUTO_HTTP_CALLBACK srs_trace("check feature http callback: on"); #else srs_warn("check feature http callback: off"); #endif #ifdef SRS_AUTO_HTTP_API srs_trace("check feature http api: on"); #else srs_warn("check feature http api: off"); #endif #ifdef SRS_AUTO_HTTP_SERVER srs_trace("check feature http server: on"); #else srs_warn("check feature http server: off"); #endif #ifdef SRS_AUTO_HTTP_PARSER srs_trace("check feature http parser: on"); #else srs_warn("check feature http parser: off"); #endif #ifdef SRS_AUTO_DVR srs_trace("check feature dvr: on"); #else srs_warn("check feature dvr: off"); #endif #ifdef SRS_AUTO_TRANSCODE srs_trace("check feature transcode: on"); #else srs_warn("check feature transcode: off"); #endif #ifdef SRS_AUTO_INGEST srs_trace("check feature ingest: on"); #else srs_warn("check feature ingest: off"); #endif #ifdef SRS_AUTO_STAT srs_trace("check feature system stat: on"); #else srs_warn("check feature system stat: off"); #endif #ifdef SRS_AUTO_NGINX srs_trace("check feature compile nginx: on"); #else srs_warn("check feature compile nginx: off"); #endif #ifdef SRS_AUTO_FFMPEG_TOOL srs_trace("check feature compile ffmpeg: on"); #else srs_warn("check feature compile ffmpeg: off"); #endif }
int SrsServer::do_cycle() { int ret = ERROR_SUCCESS; // find the max loop int max = srs_max(0, SRS_SYS_TIME_RESOLUTION_MS_TIMES); max = srs_max(max, SRS_SYS_RUSAGE_RESOLUTION_TIMES); max = srs_max(max, SRS_SYS_CPU_STAT_RESOLUTION_TIMES); max = srs_max(max, SRS_SYS_DISK_STAT_RESOLUTION_TIMES); max = srs_max(max, SRS_SYS_MEMINFO_RESOLUTION_TIMES); max = srs_max(max, SRS_SYS_PLATFORM_INFO_RESOLUTION_TIMES); max = srs_max(max, SRS_SYS_NETWORK_DEVICE_RESOLUTION_TIMES); max = srs_max(max, SRS_SYS_NETWORK_RTMP_SERVER_RESOLUTION_TIMES); // the deamon thread, update the time cache while (true) { // the interval in config. int heartbeat_max_resolution = (int)(_srs_config->get_heartbeat_interval() / 100); // dynamic fetch the max. int __max = max; __max = srs_max(__max, heartbeat_max_resolution); for (int i = 0; i < __max; i++) { st_usleep(SRS_SYS_CYCLE_INTERVAL * 1000); // for gperf heap checker, // @see: research/gperftools/heap-checker/heap_checker.cc // if user interrupt the program, exit to check mem leak. // but, if gperf, use reload to ensure main return normally, // because directly exit will cause core-dump. #ifdef SRS_AUTO_GPERF_MC if (signal_gmc_stop) { srs_warn("gmc got singal to stop server."); return ret; } #endif if (signal_reload) { signal_reload = false; srs_info("get signal reload, to reload the config."); if ((ret = _srs_config->reload()) != ERROR_SUCCESS) { srs_error("reload config failed. ret=%d", ret); return ret; } srs_trace("reload config success."); } // update the cache time or rusage. if ((i % SRS_SYS_TIME_RESOLUTION_MS_TIMES) == 0) { srs_info("update current time cache."); srs_update_system_time_ms(); } if ((i % SRS_SYS_RUSAGE_RESOLUTION_TIMES) == 0) { srs_info("update resource info, rss."); srs_update_system_rusage(); } if ((i % SRS_SYS_CPU_STAT_RESOLUTION_TIMES) == 0) { srs_info("update cpu info, cpu usage."); srs_update_proc_stat(); } if ((i % SRS_SYS_DISK_STAT_RESOLUTION_TIMES) == 0) { srs_info("update disk info, disk iops."); srs_update_disk_stat(); } if ((i % SRS_SYS_MEMINFO_RESOLUTION_TIMES) == 0) { srs_info("update memory info, usage/free."); srs_update_meminfo(); } if ((i % SRS_SYS_PLATFORM_INFO_RESOLUTION_TIMES) == 0) { srs_info("update platform info, uptime/load."); srs_update_platform_info(); } if ((i % SRS_SYS_NETWORK_DEVICE_RESOLUTION_TIMES) == 0) { srs_info("update network devices info."); srs_update_network_devices(); } if ((i % SRS_SYS_NETWORK_RTMP_SERVER_RESOLUTION_TIMES) == 0) { srs_info("update network rtmp server info."); resample_kbps(NULL); srs_update_rtmp_server((int)conns.size(), kbps); } #ifdef SRS_AUTO_HTTP_PARSER if (_srs_config->get_heartbeat_enabled()) { if ((i % heartbeat_max_resolution) == 0) { srs_info("do http heartbeat, for internal server to report."); http_heartbeat->heartbeat(); } } #endif srs_info("server main thread loop"); } } return ret; }