Esempio n. 1
0
mt_throws Result
TcpServer::open ()
{
    fd = WSASocket (AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, 0);
    if (fd == INVALID_SOCKET) {
        exc_throw (WSAException, WSAGetLastError ());
        exc_throw (InternalException, InternalException::BackendError);
        return Result::Failure;
    }

    {
        u_long value = 1;
        int const res = ioctlsocket (fd, FIONBIO, &value);
        if (res != 0) {
            if (res != SOCKET_ERROR) {
                exc_throw (InternalException, InternalException::BackendMalfunction);
                logE_ (_func, "ioctlsocket(): unexpected return value: ", res);
                return Result::Failure;
            }

            int const error = WSAGetLastError ();
            exc_throw (WSAException, error);
            exc_push (InternalException, InternalException::BackendError);
            logE_ (_func, "ioctlsocket() failed: ", wsaErrorToString (error));
            return Result::Failure;
        }
    }

    if (!_libMary_win32_setsockopt_reuseaddr (fd))
        return Result::Failure;

    return Result::Success;
}
Esempio n. 2
0
mt_throws Result
Thread::spawn (bool const joinable)
{
    this->ref ();

    mutex.lock ();
    GError *error = NULL;
    GThread * const tmp_thread = g_thread_create (wrapperThreadFunc,
						  this,
						  joinable ? TRUE : FALSE,
						  &error);
    this->thread = tmp_thread;
    mutex.unlock ();

    if (tmp_thread == NULL) {
	exc_throw (InternalException, InternalException::BackendError);
	logE_ (_func, "g_thread_create() failed: ",
	       error->message, error->message ? strlen (error->message) : 0);
	g_clear_error (&error);

	this->unref ();

	return Result::Failure;
    }

    return Result::Success;
}
Esempio n. 3
0
Ref<FetchProtocol>
SourceManager::getFetchProtocolForUri (ConstMemory const uri)
{
    ConstMemory protocol_name;
    {
        Count i = 0;
        for (Count const i_end = uri.len(); i < i_end; ++i) {
            if (uri.mem() [i] == ':')
                break;
        }
        protocol_name = uri.region (0, i);
    }

    Ref<FetchProtocol> fetch_protocol;
    {
        mutex.lock ();
        FetchProtocolHash::EntryKey const fetch_protocol_key = fetch_protocol_hash.lookup (protocol_name);
        if (fetch_protocol_key) {
            fetch_protocol = fetch_protocol_key.getData();
        }
        mutex.unlock ();
    }

    if (!fetch_protocol) {
        logE_ (_func, "Fetch protocol not found: ", protocol_name);
        return NULL;
    }

    return fetch_protocol;
}
Esempio n. 4
0
gpointer
Thread::wrapperThreadFunc (gpointer const _self)
{
    Thread * const self = static_cast <Thread*> (_self);

    try {
	self->mutex.lock ();
	Cb<ThreadFunc> const tmp_cb = self->thread_cb;
	self->mutex.unlock ();

	tmp_cb.call_ ();
    } catch (...) {
	logE_ (_func, "unhandled C++ exception");
    }

    self->mutex.lock ();
    self->thread_cb.reset ();
    self->mutex.unlock ();

    self->unref ();

    // TODO Release thread-local data, if any
    // libMary_releaseThreadLocal ();
#warning DO DO DO RELEASE !!!

    return (gpointer) 0;
}
Esempio n. 5
0
bool
EventService::acceptOneConnection ()
{
    Ref<Session> const session = grab (new (std::nothrow) Session (NULL /* embed_container */));

    IpAddress client_addr;
    {
        TcpServer::AcceptResult const res = tcp_server->accept (session->tcp_conn,
                                                                &client_addr);
        if (res == TcpServer::AcceptResult::Error) {
            logE_ (_func, "tcp_server.accept() failed: ", exc->toString());
            return false;
        }

        if (res == TcpServer::AcceptResult::NotAccepted)
            return false;

        assert (res == TcpServer::AcceptResult::Accepted);
    }

    session->weak_event_service = this;

    Ref<ServerThreadContext> const thread_ctx = server_ctx->selectThreadContext ();
    session->weak_thread_ctx = thread_ctx;

    session->sender->setFrontend (CbDesc<Sender::Frontend> (&sender_frontend, session, session));
    session->sender->setConnection (session->tcp_conn);
    session->sender->setQueue (thread_ctx->getDeferredConnectionSenderQueue());
    session->receiver->init (session->tcp_conn,
                             thread_ctx->getDeferredProcessor());
    session->line_server->init (session->receiver,
                                CbDesc<LineServer::Frontend> (&line_server_frontend, session, session));

    mutex.lock ();
    session->pollable_key = thread_ctx->getPollGroup()->addPollable (session->tcp_conn->getPollable());
    if (!session->pollable_key) {
        mutex.unlock ();
        logE_ (_func, "addPollable() failed: ", exc->toString());
        return true;
    }

    session->session_list_el = session_list.append (session);
    mutex.unlock ();

    session->receiver->start ();
    return true;
}
Esempio n. 6
0
mt_mutex (mutex) mt_throws Result
LinePipe::openPipeSession ()
{
    assert (!pipe_session);
    pipe_session = grab (new (std::nothrow) PipeSession (NULL /* embed_container */));
    pipe_session->weak_line_pipe = this;

    bool opened = false;
    if (!pipe_session->line_file->open (filename->mem(), 0 /* open_flags */, FileAccessMode::ReadOnly)) {
        goto _close;
    }
    opened = true;

    pipe_session->line_receiver->init (pipe_session->line_file,
                                       deferred_processor);
    pipe_session->line_server->init (pipe_session->line_receiver,
                                     CbDesc<LineServer::Frontend> (&line_frontend, pipe_session, pipe_session),
                                     max_line_len);

    pipe_session->pollable_key = poll_group->addPollable (pipe_session->line_file->getPollable());
    if (!pipe_session->pollable_key)
        goto _close;

    pipe_session->line_receiver->start ();

    return Result::Success;

_close:
    {
        StRef<String> const error_str = exc->toString();
        if (!prv_error_str || !equal (prv_error_str->mem(), error_str ? error_str->mem() : ConstMemory())) {
            prv_error_str = st_grab (new (std::nothrow) String (error_str ? error_str->mem() : ConstMemory()));
            logW_ (_func, "could not open pipe\"", filename, "\": ", error_str);
        }
    }

    ExceptionBuffer * const exc_buf = exc_swap_nounref ();

    if (opened) {
        if (!pipe_session->line_file->close (false /* flush_data */))
            logE_ (_func, "file.close() failed: ", exc->toString());
    }

    pipe_session = NULL;

    if (timers) {
        reopen_timer = timers->addTimer_microseconds (
                               CbDesc<Timers::TimerCallback> (reopenTimerTick, this, this),
                               reopen_timeout_millisec * 1000,
                               false /* periodical */);
    }

    exc_set_noref (exc_buf);
    return Result::Failure;
}
Esempio n. 7
0
PollPollGroup::~PollPollGroup ()
{
    mutex.lock ();
    {
	PollableList::iter iter (pollable_list);
	while (!pollable_list.iter_done (iter)) {
	    PollableEntry * const pollable_entry = pollable_list.iter_next (iter);
	    assert (pollable_entry->activated);
	    delete pollable_entry;
	}
    }

    {
	PollableList::iter iter (inactive_pollable_list);
	while (!inactive_pollable_list.iter_done (iter)) {
	    PollableEntry * const pollable_entry = inactive_pollable_list.iter_next (iter);
	    assert (!pollable_entry->activated);
	    delete pollable_entry;
	}
    }
    mutex.unlock ();

    for (int i = 0; i < 2; ++i) {
	if (trigger_pipe [i] != -1) {
	    for (;;) {
		int const res = close (trigger_pipe [i]);
		if (res == -1) {
		    if (errno == EINTR)
			continue;

		    logE_ (_func, "trigger_pipe[", i, "]: close() failed: ", errnoString (errno));
		} else
		if (res != 0) {
		    logE_ (_func, "trigger_pipe[", i, "]: close(): unexpected return value: ", res);
		}

		break;
	    }
	}
    }
}
Esempio n. 8
0
Result FileNameToUnixTimeStamp::Convert(const StRef<String> & fileName, /*output*/ Time & timeOfRecord)
{
    if(fileName == NULL || !fileName->len())
        return Result::Failure;

    Result res = Result::Success;
    std::string stdStr(fileName->cstr());
    std::string delimiter1 = "_";
    std::string delimiter2 = ".";
    size_t pos = 0;
    std::string token;
    pos = stdStr.rfind(delimiter1);

    if(pos != std::string::npos)
    {
        token = stdStr.substr(0, pos);
        stdStr.erase(0, pos + delimiter1.length());
        pos = stdStr.rfind(delimiter2);

        if(pos != std::string::npos)
        {
            token = stdStr.substr(0, pos);
            res = strToUint64_safe(token.c_str(), &timeOfRecord);
        }
        else
        {
            logE_(_func_,"Didn't find '.' symbol in file_name = ", fileName->mem());
            res = Result::Failure;
        }
    }
    else
    {
        logE_(_func_,"Didn't find '_' symbol in file_name = ", fileName->mem());
        res = Result::Failure;
    }

    return res;
}
Esempio n. 9
0
mt_mutex (mutex) void
LinePipe::releasePipeSession ()
{
    if (!pipe_session)
        return;

    assert (pipe_session->pollable_key);
    poll_group->removePollable (pipe_session->pollable_key);
    pipe_session->pollable_key = NULL;

    if (!pipe_session->line_file->close (false /* flush_data */))
        logE_ (_func, "could not close pipe file: ", exc->toString());

    pipe_session = NULL;
}
Esempio n. 10
0
void libMaryInit ()
{
    {
	static bool initialized = false;

	if (initialized) {
	    return;
	}
	initialized = true;
    }

    // Setting numeric locale for snprintf() to behave uniformly in all cases.
    // Specifically, we need dot ('.') to be used as a decimal separator.
    if (setlocale (LC_NUMERIC, "C") == NULL)
        fprintf (stderr, "WARNING: Could not set LC_NUMERIC locale to \"C\"\n");

  #ifndef LIBMARY_PLATFORM_WIN32
    // GStreamer calls setlocale(LC_ALL, ""), which is lame. We fight this with setenv().
    if (setenv ("LC_NUMERIC", "C", 1 /* overwrite */) == -1)
        perror ("WARNING: Could not set LC_NUMERIC environment variable to \"C\"");
  #endif

  #ifdef LIBMARY_MT_SAFE
    #ifdef LIBMARY__OLD_GTHREAD_API
      if (!g_thread_get_initialized ())
          g_thread_init (NULL);
    #endif
  #endif

    initStatCounters ();

    _libMary_stat = new (std::nothrow) Stat;
    assert (_libMary_stat);

    libMary_threadLocalInit ();
    libMary_platformInit ();

  // log*() logging is now available.

    if (!updateTime ())
        logE_ (_func, exc->toString());

  #ifdef LIBMARY_ENABLE_MWRITEV
    libMary_mwritevInit ();
  #endif

    randomSetSeed ((Uint32) getTimeMicroseconds());
}
Esempio n. 11
0
StRef<String>
DefaultNamingScheme::getPath (ConstMemory   const channel_name,
                              const timeval & tv,
                              Time        * const ret_next_unixtime_sec)
{
    const Time unixtime_sec = tv.tv_sec;

    struct tm tm;
    if (!unixtimeToStructTm (unixtime_sec, &tm)) {
        logE_ (_func, "unixtimeToStructTm() failed");
        return NULL;
    }

//    logD_ (_func, "unixtimeToStructTm() cur_unixtime_sec: ", cur_unixtime_sec);
//    logD_ (_func, "unixtimeToStructTm() unixtime_sec: ", unixtime_sec);
//    logD_ (_func, "unixtimeToStructTm() tv.tv_sec: ", tv.tv_sec, ", tv.tv_usec: ", tv.tv_usec);
    //double time_in_mill = (tv.tv_sec) * 1000 + (tv.tv_usec) / 1000 ; // convert tv_sec & tv_usec to millisecond

    unsigned const    day_duration = 3600 * 24;
    unsigned const   hour_duration = 3600;
    unsigned const minute_duration = 60;
    Time file_duration_sec_local = file_duration_sec;

    Format fmt;
    fmt.min_digits = 2;

    StRef<String> res_str;

    //  previous file    gmtime   next file boundary 
    //    boundary          |             |
    //       |              v             |
    // ______|____________________________|_____________________
    //        \____________/^
    //              |       |
    //              |   unixtime
    //              |
    //           offset

    if (file_duration_sec_local >= day_duration) {
        // The offset is approximate but close.
        // There may a few seconds of difference, and we don't account for that here,
        // rounding to the neares day instead.
//        unsigned const offset = tm.tm_hour * 3600 + tm.tm_min * 60 + tm.tm_sec;

//        *ret_next_unixtime_sec = unixtime_sec + (day_duration - offset);
//        res_str = st_makeString (tm.tm_year + 1900, "/", fmt, tm.tm_mon + 1, "/", tm.tm_mday);
//    } else
        file_duration_sec_local = day_duration - 1;
    }
    if (file_duration_sec_local < minute_duration)
    {
        file_duration_sec_local = minute_duration;
    }

    if (file_duration_sec_local >= hour_duration) {
        unsigned hours = file_duration_sec_local / hour_duration;
        unsigned const offset = (tm.tm_hour % hours) * 3600 + tm.tm_min * 60 + tm.tm_sec;
        *ret_next_unixtime_sec = unixtime_sec + (hours * 3600 - offset);
        //logD_ (_func, "tm.tm_mday: ", tm.tm_mday, ", tm.tm_hour: ", tm.tm_hour, ", hour: ", tm.tm_hour - tm.tm_hour % hours);
        res_str = st_makeString (tm.tm_year + 1900, "/", fmt, tm.tm_mon + 1, "/", tm.tm_mday, "/", tm.tm_hour/* - tm.tm_hour % hours*/, tm.tm_min, tm.tm_sec);
    }
    else // (file_duration_sec_local >= minute_duration)
    {
        unsigned minutes = file_duration_sec_local / minute_duration;
        unsigned const offset = (tm.tm_min % minutes) * 60 + tm.tm_sec;
        *ret_next_unixtime_sec = unixtime_sec + (minutes * 60 - offset);
        res_str = st_makeString (tm.tm_year + 1900, "/", fmt, tm.tm_mon + 1, "/", tm.tm_mday, "/", tm.tm_hour, tm.tm_min/* - tm.tm_min % minutes*/, tm.tm_sec);
    }
//    else {
//        unsigned const offset = tm.tm_sec % file_duration_sec_local;
//        *ret_next_unixtime_sec = unixtime_sec + (file_duration_sec_local - offset);
//        res_str = st_makeString (tm.tm_year + 1900, "/", fmt, tm.tm_mon + 1, "/", tm.tm_mday, "/", tm.tm_hour, tm.tm_min, tm.tm_sec - offset);
//    }

    if (*ret_next_unixtime_sec == unixtime_sec)
        *ret_next_unixtime_sec = unixtime_sec + 1;

    Time unixtimeprefix = (Time)tv.tv_sec * 1000000000LL + (Time)tv.tv_usec * 1000;
    res_str = st_makeString (channel_name, "/", res_str, "_", unixtimeprefix);
//    logD_ (_func, "res_str: ", res_str);

    return res_str;
}
Esempio n. 12
0
mt_throws Result
PollPollGroup::poll (Uint64 const timeout_microsec)
{
    Time const start_microsec = getTimeMicroseconds ();

    Result ret_res = Result::Success;

    SelectedList selected_list;
    for (;;) {
	selected_list.clear ();

	Count cur_num_pollables = 1;
	struct pollfd pollfds [num_pollables];

	pollfds [0].fd = trigger_pipe [0];
	pollfds [0].events = POLLIN;

	{
	    mutex.lock ();
	    PollableList::iter iter (pollable_list);
	    while (!pollable_list.iter_done (iter)) {
		PollableEntry * const pollable_entry = pollable_list.iter_next (iter);
		selected_list.append (pollable_entry);
		pollfds [cur_num_pollables].fd = pollable_entry->fd;

		pollfds [cur_num_pollables].events =
#ifdef __linux__
			POLLRDHUP;
#else
			0;
#endif

		if (pollable_entry->need_input)
		    pollfds [cur_num_pollables].events |= POLLIN;

		if (pollable_entry->need_output)
		    pollfds [cur_num_pollables].events |= POLLOUT;

		pollable_entry->ref ();
		++cur_num_pollables;
	    }
	    assert (cur_num_pollables == num_pollables + 1);
	    mutex.unlock ();
	}

	Time elapsed_microsec;
	int nfds;
	{
	    Time cur_microsec = getTimeMicroseconds ();
	    if (cur_microsec < start_microsec)
		cur_microsec = start_microsec;

	    elapsed_microsec = cur_microsec - start_microsec;

            int timeout;
            if (!got_deferred_tasks) {
                if (timeout_microsec != (Uint64) -1) {
                    if (timeout_microsec > elapsed_microsec) {
                        Uint64 const tmp_timeout = (timeout_microsec - elapsed_microsec) / 1000;
                        timeout = (int) tmp_timeout;
                        if ((Uint64) timeout != tmp_timeout || timeout < 0)
                            timeout = Int_Max - 1;

                        if (timeout == 0)
                            timeout = 1;
                    } else {
                        timeout = 0;
                    }
                } else {
                    timeout = -1;
                }
            } else {
                timeout = 0;
            }

            mutex.lock ();
            if (triggered || timeout == 0) {
                block_trigger_pipe = true;
                timeout = 0;
            } else {
                block_trigger_pipe = false;
            }
            mutex.unlock ();

	    nfds = ::poll (pollfds, cur_num_pollables, timeout);
	    if (nfds == -1) {
		if (errno == EINTR) {
		    SelectedList::iter iter (selected_list);
		    mutex.lock ();
		    while (!selected_list.iter_done (iter)) {
			PollableEntry * const pollable_entry = selected_list.iter_next (iter);
			pollable_entry->unref ();
		    }
		    mutex.unlock ();

		    // Re-initializing pollfds.
		    continue;
		}

                exc_throw (PosixException, errno);
                exc_push (InternalException, InternalException::BackendError);
                logE_ (_func, "poll() failed: ", errnoString (errno));
                ret_res = Result::Failure;
                goto _poll_interrupted;
	    } else
	    if (nfds < 0) {
		logE_ (_func, "unexpected return value from poll(): ", nfds);
		exc_throw (InternalException, InternalException::BackendMalfunction);
		ret_res = Result::Failure;
		goto _poll_interrupted;
	    }
	}

        mutex.lock ();
        block_trigger_pipe = true;
        bool const was_triggered = triggered;
        triggered = false;
        mutex.unlock ();

        got_deferred_tasks = false;

	if (frontend)
	    frontend.call (frontend->pollIterationBegin);

	bool trigger_pipe_ready = false;
	{
	    if (pollfds [0].revents & (POLLIN | POLLERR | POLLHUP
#ifdef __linux__
			| POLLRDHUP
#endif
			))
		trigger_pipe_ready = true;

	    mutex.lock ();

	    SelectedList::iter iter (selected_list);
	    Count i = 1;
	    while (!selected_list.iter_done (iter)) {
		PollableEntry * const pollable_entry = selected_list.iter_next (iter);

		if (nfds > 0 &&
		    pollable_entry->valid)
		{
		    Uint32 event_flags = 0;

		    if (pollfds [i].revents & POLLNVAL) {
			logW_ (_func, "POLLNVAL for pollable_entry "
			       "0x", fmt_hex, (UintPtr) pollable_entry, ", "
			       "fd ", pollable_entry->fd, " (", pollfds [i].fd, ")");
			++i;
			continue;
		    }

		    if (pollfds [i].revents & POLLIN) {
			pollable_entry->need_input = false;
			event_flags |= PollGroup::Input;
		    }

		    if (pollfds [i].revents & POLLOUT) {
			pollable_entry->need_output = false;
			event_flags |= PollGroup::Output;
		    }

		    if (pollfds [i].revents & POLLHUP
#ifdef __linux__
			|| pollfds [i].revents & POLLRDHUP
#endif
			)
		    {
			event_flags |= PollGroup::Hup;
		    }

		    if (pollfds [i].revents & POLLERR) {
			event_flags |= PollGroup::Error;
		    }

		    if (event_flags) {
			mutex.unlock ();
			pollable_entry->pollable.call (pollable_entry->pollable->processEvents, /*(*/ event_flags /*)*/);
			mutex.lock ();
		    }
		}

		pollable_entry->unref ();
		++i;
	    }
	    assert (i == cur_num_pollables);

	    mutex.unlock ();
	}

	if (frontend) {
	    bool extra_iteration_needed = false;
	    frontend.call_ret (&extra_iteration_needed, frontend->pollIterationEnd);
	    if (extra_iteration_needed)
		got_deferred_tasks = true;
	}

        if (trigger_pipe_ready) {
            if (!commonTriggerPipeRead (trigger_pipe [0])) {
                logF_ (_func, "commonTriggerPipeRead() failed: ", exc->toString());
                return Result::Failure;
            }
            break;
        }

        if (was_triggered)
            break;

	if (elapsed_microsec >= timeout_microsec) {
	  // Timeout expired.
	    break;
	}
    }

    return ret_res;

_poll_interrupted:
    SelectedList::iter iter (selected_list);
    mutex.lock ();
    while (!selected_list.iter_done (iter)) {
	PollableEntry * const pollable_entry = selected_list.iter_next (iter);
	pollable_entry->unref ();
    }
    mutex.unlock ();

    return ret_res;
}
Esempio n. 13
0
mt_throws Result
loadModule (ConstMemory   const filename,
            void        * const app_specific)
{
  #ifdef LIBMARY_GLIB
    GModule * const module = g_module_open ((gchar const*) makeString (filename)->cstr(),
                                            (GModuleFlags) (G_MODULE_BIND_LAZY | G_MODULE_BIND_LOCAL));
    if (!module) {
        exc_throw (InternalException, InternalException::BackendError);
        logE_ (_func, "failed to open module ", filename, ": ",  g_module_error());
        return Result::Failure;
    }

    ModuleInitFunc init_ptr;
    if (!g_module_symbol (module, "libMary_moduleInit_wrapper", (gpointer*) &init_ptr)) {
        exc_throw (InternalException, InternalException::BackendError);
        logE_ (_func, "failed to open module ", filename, ": "
               "g_module_symbol (\"libMary_moduleInit_wrapper\") failed: ", g_module_error());
        return Result::Failure;
    }

    if (!init_ptr (app_specific)) {
        logE_ (_func, "could notd initialize module ", filename);
        return Result::Failure;
    }

    return Result::Success;
  #else
    libraryLock ();
    void * const handle = dlopen (
          #ifdef LIBMARY_PLATFORM_MACOSX
            makeString (filename, ".0.dylib")->cstr(),
          #else
            makeString (filename, ".so")->cstr(),
          #endif
            RTLD_LAZY);
    if (!handle) {
        char const * const err_str = dlerror ();
        libraryUnlock ();
        exc_throw (InternalException, InternalException::BackendError);
        logE_ (_func, "dlopen (", filename, ") failed: ", err_str);
        return Result::Failure;
    }

    dlerror (); // Clearing any old error conditions. See man dlsym(3).
    void * const init_ptr = dlsym (handle, "libMary_moduleInit");
    if (!init_ptr) {
        char const * const err_str = dlerror ();
        libraryUnlock ();
        exc_throw (InternalException, InternalException::BackendError);
        logE_ (_func, "dlsym (", filename, ", libMary_moduleInit) failed: ", err_str);
        return Result::Failure;
    }
    libraryUnlock ();

    bool const res = ((ModuleInitFunc) init_ptr) (app_specific);
    if (!res) {
        exc_throw (InternalException, InternalException::BackendError);
        logE_ (_func, "module init failed: ", filename);
    }

    return res ? Result::Success : Result::Failure;
  #endif
}
Esempio n. 14
0
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));
    }
Esempio n. 15
0
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;
}
Esempio n. 16
0
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;
}
Esempio n. 17
0
void libMaryInit ()
{
    {
	static bool initialized = false;

	if (initialized) {
	    return;
	}
	initialized = true;
    }

    // Setting numeric locale for snprintf() to behave uniformly in all cases.
    // Specifically, we need dot ('.') to be used as a decimal separator.
    if (setlocale (LC_NUMERIC, "C") == NULL)
        fprintf (stderr, "WARNING: Could not set LC_NUMERIC locale to \"C\"\n");

#ifndef LIBMARY_PLATFORM_WIN32
    // GStreamer calls setlocale(LC_ALL, ""), which is lame. We fight this with setenv().
    if (setenv ("LC_NUMERIC", "C", 1 /* overwrite */) == -1)
        perror ("WARNING: Could not set LC_NUMERIC environment variable to \"C\"");
#endif

#ifdef LIBMARY_MT_SAFE
  #ifdef LIBMARY__OLD_GTHREAD_API
    if (!g_thread_get_initialized ())
	g_thread_init (NULL);
  #endif
#endif

    _libMary_stat = new Stat;

    libMary_threadLocalInit ();
    libMary_platformInit ();

  // log*() logging is now available.

    if (!updateTime ())
        logE_ (_func, exc->toString());

#ifdef LIBMARY_ENABLE_MWRITEV
    libMary_mwritevInit ();
#endif

    randomSetSeed ((Uint32) getTime());

#ifdef LIBMARY_PLATFORM_WIN32
    WSADATA wsaData;
    WORD wVersionRequested = MAKEWORD(2, 2);
    int res = WSAStartup(wVersionRequested, &wsaData);
    if (res != 0) {
        logE_ (_func_, "WSAStartup failed");
    } else {
        if (LOBYTE(wsaData.wVersion) != 2 ||
            HIBYTE(wsaData.wVersion) != 2) {
            logE_ (_func_, "Could not find a requested version of Winsock.dll");
            WSACleanup();
        }
        else {
            logD_ (_func_, "The Winsock 2.2 dll was found");
        }
    }
#endif
}