void release() { if(g_clients!=NULL) { logD(TAG," release g_clients"); releaseClientArray(); g_clients=NULL; } if(g_context!=NULL) { logD(TAG," release g_context"); if(g_context->pServer!=NULL) { if(g_context->pServer->listen_ip!=NULL) { free(g_context->pServer->listen_ip); } if(g_context->pServer->name!=NULL) { free(g_context->pServer->name); } memset(g_context->pServer,0,sizeof(TGServer)); free(g_context->pServer); } if(g_context->listenfd>=0) { #ifdef LINUX shutdown(g_context->listenfd,SHUT_RDWR); #endif close(g_context->listenfd); } if(g_context->localAdminfd>=0) { close(g_context->localAdminfd); } memset(g_context,0,sizeof(TGContext)); free(g_context); g_context=NULL; } clients_ar_size=0; logD(TAG," finish release "); }
bool RecpathConfig::IsPathExist(const std::string & path) { logD(recpath, _func_); //m_mutex.lock(); ConfigMap::iterator itr = m_configs.find(path); bool bRes = (itr != m_configs.end()); if(bRes) logD(recpath, _func_, "path [", path.c_str(), "] exist"); else logD(recpath, _func_, "path [", path.c_str(), "] doesnt exist"); //m_mutex.unlock(); return bRes; }
void MModLoader::setVars(IVars *v) { IV_LOGGER = reinterpret_cast<ILogger*>(v->get("eLogger")); IV_VARS = v; IV_SETT = reinterpret_cast<ISettings*>(v->get("eSettings")); IV_SETC = reinterpret_cast<ISettCont*>(v->get("eSettCont")); MV_CORE_MODS = new MCoreMods(); MV_MODS = new MMods(); logD("ModLoader initialized"); }
Time Timers::getSleepTime_microseconds () { Time const cur_time = getTimeMicroseconds (); MutexLock l (&mutex); TimerChain * const chain = expiration_tree_leftmost; if (chain == NULL) { logD (timers, _func, ": null chain"); return (Time) -1; } if (chain->nearest_time <= cur_time) { logD (timers, _func, ": now"); return 0; } logD (timers, _func, ": nearest: ", chain->nearest_time, ", cur: ", cur_time, ", delta: ", chain->nearest_time - cur_time); return chain->nearest_time - cur_time; }
std::string RecpathConfig::GetNextPath(const std::string & prev_path) { logD(recpath, _func_); //m_mutex.lock(); if(m_configs.size() == 0) { //m_mutex.unlock(); logD(recpath, _func_, "Config is empty"); return std::string(""); } std::string next_path; if(prev_path.size()) { logD(recpath, _func_, "prev_path is ", prev_path.c_str()); ConfigMap::iterator itr = m_configs.find(std::string(prev_path)); if(itr == m_configs.end()) { // we dont know last path, so dont know next, so return first next_path = m_configs.begin()->first; logD(recpath, _func_, "prev_path not exist, so return first path [", next_path.c_str(), "]"); } else { itr++; if(itr == m_configs.end()) { // that was last path in list, so return empty path next_path = ""; logD(recpath, _func_, "prev_path is last path, so return empty path"); } else { // return next path next_path = itr->first; logD(recpath, _func_, "return next path [", next_path.c_str(), "]"); } } } else { // if there's no prev path, so return first ConfigMap::iterator itr1 = m_configs.begin(); next_path = itr1->first; logD(recpath, _func_, "return first path [", next_path.c_str(), "]"); } //m_mutex.unlock(); return next_path; }
void loadService(const char * path) { if(path==NULL || strlen(path)==0) { logN(TAG ,LOG_LEVEL_WARNING," path is empty"); return; } logI(TAG," prepare to load service from library:%s",path); void * dlHandler=NULL; char * errmsg; #ifdef LINUX dlHandler=dlopen(path,RTLD_NOW); if(dlHandler==NULL) { errmsg=dlerror(); logN("SERVICE",LOG_LEVEL_WARNING," can not open library:%s %s",path,errmsg); return; } #elif WIN32 #endif struct TGService * pService=NULL; if(checkLib(dlHandler,&pService)==0) { logD(TAG,"check lib successfully"); //FIXME use system seportor char * pLibName=NULL; getLibName(path,&pLibName); if(pLibName==NULL) { pLibName=(char *)malloc(sizeof(5)); memset(pLibName,0,10); sprintf(pLibName,"%d",pService->sID); } pService->serviceName=pLibName; addService(pService); } else { logW(TAG,"check library error"); } }
void getLibName(char * path,char ** ppName) { if(path!=NULL) { int size=strlen(path)+1; char buf[size]; memset(buf,0,size); memcpy(buf,path,size-1); buf[size-1]='\0'; //FIXME should use maco of system int pos=lastFindSeparator(buf,"/"); if(pos>=0) { int nsize=size-pos; char * pc=(char *) malloc(nsize); memset(pc,0,nsize); strncpy(pc,&buf[pos+1],nsize-1); *ppName=pc; logD("UTIL"," get lib name:%s\n",pc); } } }
// copy parameters to pSer void setServiceCreateParameters(struct TGService * pSer,const char * para) { if(pSer==NULL) { logE(TAG," service not exist"); return; } if(pSer->parameters==NULL) { pSer->parCounts=0; int size=SERVICE_DEFAULT_PARA_COUNTS*sizeof(char *); pSer->parameters=(char **)malloc(size); memset(pSer->parameters,0,size); } // parameters is out of array need create new else if(pSer->parCounts!=0 && (pSer->parCounts)%SERVICE_DEFAULT_PARA_COUNTS==0) { int size=(pSer->parCounts+SERVICE_DEFAULT_PARA_COUNTS)*sizeof(char *); logI(TAG," create new parameters for id:%d parCounts:%d", pSer->sID,pSer->parCounts); char ** pOld=pSer->parameters; pSer->parameters=(char **)malloc(size); memset(pSer->parameters,0,size); memcpy(pSer->parameters,pOld,pSer->parCounts*sizeof(char *)); free(pOld); } char *pBuf=NULL; int bufSize=strlen(para)+1; pBuf=(char *)malloc(bufSize); memset(pBuf,0,bufSize); strncpy(pBuf,para,bufSize-1); pBuf[bufSize-1]='\0'; pSer->parameters[pSer->parCounts++]=pBuf; logD(TAG," parameters:%d, %s",pSer->parCounts,pSer->parameters); }
bool RecpathConfig::LoadConfig(const std::string & path_to_config) { logD(recpath, _func_); //m_mutex.lock(); m_configs.clear(); m_bIsEmpty = true; Json::Value root; // will contains the root value after parsing. Json::Reader reader; std::ifstream config_file(path_to_config, std::ifstream::binary); if(!config_file.good()) { //m_mutex.unlock(); logE_(_func_, "fail to load config"); return false; } bool parsingSuccessful = reader.parse( config_file, root, false ); if(!parsingSuccessful) { //m_mutex.unlock(); logE_(_func_, "fail to parse config"); return false; } Json::Value configs = root["configs"]; if(configs.empty()) { //m_mutex.unlock(); logE_(_func_, "fail to find \"configs\" section"); return false; } for( Json::ValueIterator itr = configs.begin() ; itr != configs.end() ; itr++ ) { Json::Value value = (*itr); Json::Value path = value["path"]; // Json::Value quota = value["quota"]; // Json::Value mode = value["mode"]; if(path.empty())// || quota.empty() || mode.empty()) { m_configs.clear(); //m_mutex.unlock(); logE_(_func_, "fail to parse params for section No ", itr.index()); return false; } m_configs[path.asString()] = ConfigParam(); } // dump config in log int i = 0; for(ConfigMap::const_iterator it = m_configs.begin(); it != m_configs.end(); ++it) { logD(recpath, _func_, "PathEntry ", i++); logD(recpath, _func_, "Path: ", it->first.c_str()); // logD(recpath, _func_, "Quota: ", it->second.quota); // logD(recpath, _func_, "Mode: ", it->second.write_mode); } m_configJson = root.toStyledString(); m_bIsInit = true; //m_mutex.unlock(); return true; }
std::string RecpathConfig::GetNextPathForStream() { logD(recpath, _func_); //m_mutex.lock(); if(m_configs.size() == 0) { //m_mutex.unlock(); logD(recpath, _func_, "Config is empty"); return std::string(""); } else logD(recpath, _func_, "Config size is ", m_configs.size()); std::string next_path; while(true) { for(ConfigMap::const_iterator it = m_configs.begin(); it != m_configs.end(); ++it) { Int64 freeSize = MemoryDispatcher::Instance().GetDiskFreeSizeFromDiskname(it->first); logD(recpath, _func_, "diskname is ", it->first.c_str()); logD(recpath, _func_, "freeSize is ", freeSize); if(freeSize > MINFREESIZE) { next_path = it->first; logD(recpath, _func_, "next_path is ", next_path.c_str()); break; } } if(next_path.size()) { break; } else { logD(recpath, _func_, "next_path is empty"); } // cleaning logD(recpath, _func_, "CLEANING"); ChannelChecker::ChannelFileDiskTimes channelFileDiskTimes; std::map<std::string, WeakRef<FFmpegStream> >::iterator itFFStream = m_pStreams->begin(); for(itFFStream; itFFStream != m_pStreams->end(); itFFStream++) { logD(recpath, _func_, "channel_name = ", itFFStream->first.c_str()); Ref<ChannelChecker> channelChecker = itFFStream->second.getRefPtr()->GetChannelChecker(); std::pair<std::string, ChChDiskTimes> oldestFileDiskTimes = channelChecker->GetOldestFileDiskTimes(); logD(recpath, _func_, "filename = ", oldestFileDiskTimes.first.c_str()); logD(recpath, _func_, "diskname = ", oldestFileDiskTimes.second.diskName.c_str()); logD(recpath, _func_, "beginTime = ", oldestFileDiskTimes.second.times.timeStart); logD(recpath, _func_, "endTime = ", oldestFileDiskTimes.second.times.timeEnd); if(oldestFileDiskTimes.first.size()) { channelFileDiskTimes.insert(oldestFileDiskTimes); } } // find most older file int minTime = std::numeric_limits<int>::max(); std::string fileName; std::string diskName; ChannelChecker::ChannelFileDiskTimes::iterator iter = channelFileDiskTimes.begin(); for(iter; iter != channelFileDiskTimes.end(); iter++) { if(minTime > iter->second.times.timeStart) { minTime = iter->second.times.timeStart; fileName = iter->first; diskName = iter->second.diskName; } } logD(recpath, _func_, "minTime = ", minTime); logD(recpath, _func_, "minfileName = ", fileName.c_str()); logD(recpath, _func_, "mindiskName = ", diskName.c_str()); // delete it (if filename is not recorded at current time) StRef<String> dir_name = st_makeString(diskName.c_str()); StRef<String> file_name = st_makeString(fileName.c_str()); StRef<String> full_file_name = st_makeString(dir_name, "/", file_name, ".flv"); if(!MemoryDispatcher::Instance().IsFilenameRecorded(full_file_name->cstr())) { Ref<Vfs> vfs = Vfs::createDefaultLocalVfs (dir_name->mem()); StRef<String> const filenameFull = st_makeString(fileName.c_str(), ".flv"); logD(recpath, _func_, "filenameFull to remove = ", filenameFull); vfs->removeFile (filenameFull->mem()); vfs->removeSubdirsForFilename (filenameFull->mem()); std::string channel_name = fileName.substr(0,fileName.find("/")); (*m_pStreams)[channel_name].getRefPtr()->GetChannelChecker()->DeleteFromCache(diskName, fileName); } else { break; } } //m_mutex.unlock(); return next_path; }
mt_throws Result updateTime () { LibMary_ThreadLocal * const tlocal = libMary_getThreadLocal(); #ifdef LIBMARY_PLATFORM_WIN32 DWORD const win_time_dw = timeGetTime(); if (tlocal->prv_win_time_dw >= win_time_dw) { tlocal->win_time_offs += 0x100000000; } tlocal->prv_win_time_dw = win_time_dw; DWORD const win_time = win_time_dw + tlocal->win_time_offs; Time const new_seconds = (Time) win_time / 1000; Time const new_microseconds = (Time) win_time * 1000; #else #ifdef __MACH__ mach_timespec_t mts; { #warning TODO call host_get_clock_service only once clock_serv_t clk; host_get_clock_service (mach_host_self(), SYSTEM_CLOCK, &clk); clock_get_time (clk, &mts); mach_port_deallocate (mach_task_self(), clk); } Time const new_seconds = mts.tv_sec; Time const new_microseconds = (Uint64) mts.tv_sec * 1000000 + (Uint64) mts.tv_nsec / 1000; #if 0 // Deprecated gint64 const mono_time = g_get_monotonic_time (); Int64 const mono_time = 0; Time const new_seconds = mono_time / 1000000; Time const new_microseconds = mono_time; #endif #else struct timespec ts; // Note that clock_gettime is well-optimized on Linux x86_64 and does not carry // full syscall overhead (depends on system configuration). int const res = clock_gettime (CLOCK_MONOTONIC, &ts); if (res == -1) { exc_throw (PosixException, errno); exc_push (InternalException, InternalException::BackendError); logE_ (_func, "clock_gettime() failed: ", errnoString (errno)); return Result::Failure; } else if (res != 0) { exc_throw (InternalException, InternalException::BackendError); logE_ (_func, "clock_gettime(): unexpected return value: ", res); return Result::Failure; } logD (time, _func, "tv_sec: ", ts.tv_sec, ", tv_nsec: ", ts.tv_nsec); Time const new_seconds = ts.tv_sec; Time const new_microseconds = (Uint64) ts.tv_sec * 1000000 + (Uint64) ts.tv_nsec / 1000; #endif #endif tlocal->time_log_frac = new_microseconds % 1000000 / 100; if (new_seconds >= tlocal->time_seconds) tlocal->time_seconds = new_seconds; else logW_ (_func, "seconds backwards: ", new_seconds, " (was ", tlocal->time_seconds, ")"); if (new_microseconds >= tlocal->time_microseconds) tlocal->time_microseconds = new_microseconds; else logW_ (_func, "microseconds backwards: ", new_microseconds, " (was ", tlocal->time_microseconds, ")"); logD (time, _func, fmt_hex, tlocal->time_seconds, ", ", tlocal->time_microseconds); if (tlocal->saved_monotime < tlocal->time_seconds || tlocal->saved_unixtime == 0) { // Updading saved unixtime once in a minute. if (tlocal->time_seconds - tlocal->saved_monotime >= 60 || tlocal->saved_unixtime == 0) { // Obtaining current unixtime. This is an extra syscall. tlocal->saved_unixtime = time (NULL); tlocal->saved_monotime = tlocal->time_seconds; } // Updating localtime (broken-down time). time_t const cur_unixtime = tlocal->saved_unixtime + (tlocal->time_seconds - tlocal->saved_monotime); tlocal->unixtime = cur_unixtime; // Note that we call tzset() in libMary_posixInit() for localtime_r() to work correctly. #ifdef LIBMARY_PLATFORM_WIN32 #ifdef LIBMARY_WIN32_SECURE_CRT if (localtime_s (&tlocal->localtime, &cur_unixtime) != 0) logF_ (_func, "localtime_s() failed"); #else libraryLock (); struct tm * const tmp_localtime = localtime (&cur_unixtime); if (tmp_localtime) { tlocal->localtime = *tmp_localtime; } libraryUnlock (); if (!tmp_localtime) logF_ (_func, "localtime() failed"); #endif #else // TODO FIXME This lib function is dog-slow and has huge synchronization overhead. localtime_r (&cur_unixtime, &tlocal->localtime); #endif } // long const timezone_abs = timezone >= 0 ? timezone : -timezone; long const timezone_abs = 0; // tlocal->timezone_str [0] = timezone >= 0 ? '+' : '-'; tlocal->timezone_str [0] = '+'; tlocal->timezone_str [1] = '0' + timezone_abs / 36000; tlocal->timezone_str [2] = '0' + timezone_abs / 3600 % 10; tlocal->timezone_str [3] = '0' + timezone_abs / 600 % 6; tlocal->timezone_str [4] = '0' + timezone_abs / 60 % 10; return Result::Success; }
mt_sync_domain (readTask) bool GetFileSession::readTask (void * const _self) { GetFileSession * const self = static_cast <GetFileSession*> (_self); logD (getfile, _func_); if (self->session_state == SessionState_Header) { MOMENT_SERVER__HEADERS_DATE for (;;) { MediaReader::ReadFrameResult const res = self->media_reader->readMoreData (&read_frame_backend, self); if (res == MediaReader::ReadFrameResult_Failure) { logE_ (_func, "ReadFrameResult_Failure"); ConstMemory msg = "Data retrieval error"; self->sender->send (self->page_pool, true /* do_flush */, // TODO No cache MOMENT_SERVER__500_HEADERS (msg.len()), "\r\n", msg); if (!self->req_is_keepalive) self->sender->closeAfterFlush (); logA_ ("mod_nvr 500 ", self->req_client_addr, " ", self->req_request_line); return false /* do not reschedule */; } bool header_done = false; if (res == MediaReader::ReadFrameResult_NoData) { logD (getfile, _func, "ReadFrameResult_NoData"); if (!self->got_last_audio_ts && !self->got_last_video_ts) { ConstMemory msg = "Requested video data not found"; self->sender->send (self->page_pool, true /* do_flush */, // TODO No cache MOMENT_SERVER__404_HEADERS (msg.len()), "\r\n", msg); if (!self->req_is_keepalive) self->sender->closeAfterFlush (); logA_ ("mod_nvr 404 ", self->req_client_addr, " ", self->req_request_line); return false /* do not reschedule */; } header_done = true; } else if (res == MediaReader::ReadFrameResult_Finish) { logD (getfile, _func, "ReadFrameResult_Finish"); header_done = true; } if (header_done) { self->session_state = SessionState_Data; self->media_reader->reset (); break; } assert (res != MediaReader::ReadFrameResult_BurstLimit); assert (res == MediaReader::ReadFrameResult_Success); } PagePool::PageListInfo const mp4_header = self->mp4_muxer.pass1_complete (self->duration_sec * 1000); { self->sender->send (self->page_pool, true /* do_flush */, // TODO No cache MOMENT_SERVER__OK_HEADERS ( (!self->octet_stream_mime ? ConstMemory ("video/mp4") : ConstMemory ("application/octet-stream")), mp4_header.data_len + self->mp4_muxer.getTotalDataSize()), "\r\n"); logD_ (_func, "CONTENT-LENGTH: ", mp4_header.data_len + self->mp4_muxer.getTotalDataSize()); if (!self->req_is_keepalive) self->sender->closeAfterFlush (); logA_ ("mod_nvr 200 ", self->req_client_addr, " ", self->req_request_line); } { SenderMessageEntry_Pages * const msg_pages = SenderMessageEntry_Pages::createNew (/*header_len=*/ 0); msg_pages->init (mp4_header.first, self->page_pool, /*msg_offs=*/ 0, mp4_header.data_len); self->sender->sendMessage (msg_pages, true /* do_flush */); } self->transfer_start_time_millisec = getTimeMilliseconds(); self->bytes_transferred += mp4_header.data_len; self->sender->getEventInformer()->subscribe ( CbDesc<Sender::Frontend> (&sender_frontend, self, self)); }
Timers::TimerKey Timers::addTimer_microseconds (CbDesc<TimerCallback> const &cb, Time const time_microseconds, bool const periodical, bool const auto_delete, bool const delete_after_tick) { logD (timers, _func, "time_microseconds: ", time_microseconds); Timer * const timer = new (std::nothrow) Timer (this, cb); assert (timer); timer->periodical = periodical; timer->delete_after_tick = delete_after_tick; timer->due_time = getTimeMicroseconds() + time_microseconds; if (timer->due_time < time_microseconds) { logW_ (_func, "Expiration time overflow"); timer->due_time = (Time) -1; } if (auto_delete && cb.coderef_container) { timer->del_sbn = cb.coderef_container->addDeletionCallback ( CbDesc<Object::DeletionCallback> (subscriberDeletionCallback, timer, getCoderefContainer())); } logD (timers, _func, "getTimeMicroseconds(): ", getTimeMicroseconds(), ", due_time: ", timer->due_time); mutex.lock (); bool first_timer = false; TimerChain *chain = interval_tree.lookup (time_microseconds); if (!chain) { chain = new (std::nothrow) TimerChain; assert (chain); chain->interval_microseconds = time_microseconds; chain->nearest_time = timer->due_time; if (expiration_tree.isEmpty() || expiration_tree_leftmost->nearest_time > chain->nearest_time) { first_timer = true; } interval_tree.add (chain); expiration_tree.add (chain); expiration_tree_leftmost = expiration_tree.getLeftmost(); } timer->chain = chain; chain->timer_list.append (timer); mutex.unlock (); if (first_timer) { logD (timers, _func, "calling first_added_cb()"); first_added_cb.call_ (); } return timer; }
void Timers::processTimers () { Time const cur_time = getTimeMicroseconds (); mutex.lock (); TimerChain *chain = expiration_tree_leftmost; if (chain == NULL) { mutex.unlock (); return; } while (!chain->timer_list.isEmpty () && chain->nearest_time <= cur_time) { Time const cur_nearest_time = chain->nearest_time; logD (timers, _func, "cur_nearest_time: ", cur_nearest_time, ", cur_time: ", cur_time); Timer * const timer = chain->timer_list.getFirst (); assert (timer->active); chain->timer_list.remove (timer); bool delete_timer = false; if (timer->periodical) { timer->due_time += chain->interval_microseconds; if (timer->due_time < chain->interval_microseconds) { logW_ (_func, "Expiration time overflow"); timer->due_time = (Time) -1; } chain->timer_list.append (timer); } else { timer->active = false; if (timer->delete_after_tick) { if (timer->del_sbn) { // TODO We create CodeRef twice: here and in call_unlocks_mutex_(). // Should do this only once for efficiency. CodeRef const code_ref = timer->timer_cb.getWeakCodeRef(); // If 'code_ref' is null, then doDeleteTimer() will be called // by subscriberDeletionCallback(), which is likely just about // to be called. if (code_ref) { code_ref->removeDeletionCallback (timer->del_sbn); delete_timer = true; } } else { delete_timer = true; } } } bool delete_chain; if (chain->timer_list.isEmpty ()) { expiration_tree.remove (chain); expiration_tree_leftmost = expiration_tree.getLeftmost(); interval_tree.remove (chain); delete_chain = true; } else { if (cur_nearest_time != chain->timer_list.getFirst ()->due_time) { expiration_tree.remove (chain); chain->nearest_time = chain->timer_list.getFirst ()->due_time; expiration_tree.add (chain); expiration_tree_leftmost = expiration_tree.getLeftmost(); } delete_chain = false; } timer->timer_cb.call_unlocks_mutex_ (mutex); // 'timer' might have been deleted by the user and should not be used // directly anymore. // // We can't delete the timer ourselves here for a similar reason: its // lifetime is controlled by the user, so we can't tie it to callback's // weak_obj. if (delete_timer) delete timer; if (delete_chain) delete chain; mutex.lock (); // 'chain' might have been deleted due to user's actions in 'timer_cb' callback. chain = expiration_tree_leftmost; if (chain == NULL) { mutex.unlock (); return; } } mutex.unlock (); }