Ejemplo n.º 1
0
int sockets_add(int sock, struct sockaddr_in *sa, int sid, int type,
                socket_action a, socket_action c, socket_action t)
{
    int i;
    char ra[50];
    if (init_sock == 0)
    {
        init_sock = 1;
        for (i = 0; i < MAX_SOCKS; i++)
            s[i].sock = -1;
    }
    for (i = 0; i < MAX_SOCKS; i++)
        if (s[i].sock < 0)
            break;
    if (i == MAX_SOCKS)
        return -1;
    s[i].sock = sock;
    memset(&s[i].sa, 0, sizeof(s[i].sa));
    if (sa)
        memcpy(&s[i].sa, sa, sizeof(s[i].sa));
    s[i].action = s[i].close = s[i].timeout = NULL;
    if (a)
        s[i].action = a;
    if (c)
        s[i].close = c;
    if (t)
        s[i].timeout = t;
    s[i].sid = sid;
    s[i].type = type & ~TYPE_CONNECT;
    s[i].rtime = getTick();
    s[i].wtime = 0;
    if (max_sock <= i)
        max_sock = i + 1;
    s[i].buf = NULL;
    s[i].lbuf = 0;
    s[i].close_sec = 0;
    s[i].id = i;
    s[i].read = (read_action) sockets_read;
    if (s[i].type == TYPE_UDP || s[i].type == TYPE_RTCP)
        s[i].read = (read_action) sockets_recv;
    else if (s[i].type == TYPE_SERVER)
        s[i].read = (read_action) sockets_accept;
    pf[i].fd = sock;
    pf[i].events = POLLIN | POLLPRI;
    if (type & TYPE_CONNECT)
        pf[i].events |= POLLOUT;
    pf[i].revents = 0;

    LOG(
        "sockets_add: handle %d (type %d) returning socket index %d [%s:%d] read: %p",
        s[i].sock, s[i].type, i, get_socket_rhost(i, ra, sizeof(ra)),
        ntohs(s[i].sa.sin_port), s[i].read);
    return i;
}
Ejemplo n.º 2
0
int sockets_add(int sock, struct sockaddr_in *sa, int sid, int type,
		socket_action a, socket_action c, socket_action t)
{
	int i;
	char ra[50];
	sockets *ss;

	i = add_new_lock((void **) s, MAX_SOCKS, sizeof(sockets), &s_mutex);
	if (i == -1)
		LOG_AND_RETURN(-1, "sockets_add failed for socks %d", sock);

	ss = s[i];
	ss->enabled = 1;
	ss->sock = sock;
	ss->tid = get_tid();
	memset(&ss->sa, 0, sizeof(ss->sa));
	if (sa)
		memcpy(&ss->sa, sa, sizeof(ss->sa));
	ss->action = ss->close = ss->timeout = NULL;
	if (a)
		ss->action = a;
	if (c)
		ss->close = c;
	if (t)
		ss->timeout = t;
	ss->sid = sid;
	ss->type = type & ~TYPE_CONNECT;
	ss->rtime = getTick();
	ss->wtime = 0;
	if (max_sock <= i)
		max_sock = i + 1;
	ss->buf = NULL;
	ss->lbuf = 0;
	ss->timeout_ms = 0;
	ss->id = i;
	ss->read = (read_action) sockets_read;
	ss->lock = NULL;
	if (ss->type == TYPE_UDP || ss->type == TYPE_RTCP)
		ss->read = (read_action) sockets_recv;
	else if (ss->type == TYPE_SERVER)
		ss->read = (read_action) sockets_accept;
	ss->events = POLLIN | POLLPRI;
	if (type & TYPE_CONNECT)
		ss->events |= POLLOUT;

	LOG(
			"sockets_add: handle %d (type %d) returning socket index %d [%s:%d] read: %p",
			ss->sock, ss->type, i, get_socket_rhost(i, ra, sizeof(ra)),
			ntohs(ss->sa.sin_port), ss->read);
	mutex_unlock(&ss->mutex);
	return i;
}
Ejemplo n.º 3
0
void *select_and_execute(void *arg)
{
	fd_set io;
	int i, rv, rlen, les, es;
	unsigned char buf[2001];
	int err;
	struct pollfd pf[MAX_SOCKS];
	int64_t lt, c_time;
	int read_ok;
	char ra[50];

	if (arg)
		thread_name = (char *) arg;
	else
		thread_name = "main";

	tid = get_tid();
	les = 1;
	es = 0;
	lt = getTick();
	memset(&pf, -1, sizeof(pf));
	LOG("Starting select_and_execute on thread ID %x, thread_name %s", tid,
			thread_name);
	while (run_loop)
	{
		c_time = getTick();
		es = 0;
		clean_mutexes();
		for (i = 0; i < max_sock; i++)
			if (s[i] && s[i]->enabled && s[i]->tid == tid)
			{
				pf[i].fd = s[i]->sock;
				pf[i].events = s[i]->events;
				pf[i].revents = 0;
				s[i]->last_poll = c_time;
				es++;
			}
			else
			{
				pf[i].fd = -1;
				pf[i].events = pf[i].revents = 0;
			}
		i = -1;
		if (les == 0 && es == 0 && tid != main_tid)
		{
			LOG("No enabled sockets for Thread ID %lx name %s ... exiting ",
					tid, thread_name);
			break;
		}
		les = es;
		//    LOG("start select");
		if ((rv = poll(pf, max_sock, 100)) < 0)
		{
			LOG("select_and_execute: select() error %d: %s", errno,
					strerror(errno));
			continue;
		}
		//              LOG("select returned %d",rv);
		if (rv > 0)
			while (++i < max_sock)
				if ((pf[i].fd >= 0) && pf[i].revents)
				{
					sockets *ss = s[i];
					if (!ss)
						continue;

					c_time = getTick();

					LOGL(6,
							"event on socket index %d handle %d type %d (poll fd:%d, revents=%d)",
							i, ss->sock, ss->type, pf[i].fd, pf[i].revents);
					sockets_lock(ss);

					if (pf[i].revents & POLLOUT)
					{
						ss->events &= ~POLLOUT;
					}
					if (!ss->buf || ss->buf == buf)
					{
						ss->buf = buf;
						ss->lbuf = sizeof(buf) - 1;
						ss->rlen = 0;
					}
					if (ss->rlen >= ss->lbuf)
					{
						LOG(
								"Socket buffer full, handle %d, sock_id %d, type %d, lbuf %d, rlen %d, ss->buf = %p, buf %p",
								ss->sock, i, ss->type, ss->lbuf, ss->rlen,
								ss->buf, buf);
						ss->rlen = 0;
					}
					rlen = 0;
					if (opts.bw > 0 && bw > opts.bw && ss->type == TYPE_DVR)
					{
						int64_t ms = 1000 - c_time + bwtt;
						if (bwnotify++ == 0)
							LOG(
									"capping %d sock %d for the next %jd ms, sleeping for the next %jd ms",
									i, ss->sock, ms, ms / 50);
						if (ms > 50)
							usleep(ms * 20);
						sockets_unlock(ss);
						continue;

					}

					read_ok = ss->read(ss->sock, &ss->buf[ss->rlen],
							ss->lbuf - ss->rlen, ss, &rlen);

					if (opts.log >= 1)
					{
						int64_t now = getTick();
						if (now - c_time > 100)
							LOG(
									"WARNING: read on socket id %d, handle %d, took %jd ms",
									ss->id, ss->sock, now - c_time);
					}

					err = 0;
					if (rlen < 0)
						err = errno;
					if (rlen > 0)
						ss->rtime = c_time;
					if (read_ok && rlen >= 0)
						ss->rlen += rlen;
					else
						ss->rlen = 0;
					//force 0 at the end of the string
					if (ss->lbuf >= ss->rlen)
						ss->buf[ss->rlen] = 0;
					LOGL(6,
							"Read %s %d (rlen:%d/total:%d) bytes from %d -> %p - iteration %d action %p",
							read_ok ? "OK" : "NOK", rlen, ss->rlen, ss->lbuf,
							ss->sock, ss->buf, it++, ss->action);

					if (((ss->rlen > 0) || err == EWOULDBLOCK) && ss->action
							&& (ss->type != TYPE_SERVER))
						ss->action(ss);
					sockets_unlock(ss);

					if (!read_ok && ss->type != TYPE_SERVER)
					{
						char *err_str;
						char *types[] =
						{ "udp", "tcp", "server", "http", "rtsp", "dvr" };
						if (rlen == 0)
						{
							err = 0;
							err_str = "Close";
						}
						else if (err == EOVERFLOW)
							err_str = "EOVERFLOW";
						else if (err == EWOULDBLOCK)
							err_str = "Connected";
						else
							err_str = strerror(err);

						if (ss->type == TYPE_RTCP || ss->sock == SOCK_TIMEOUT)
						{
							LOG(
									"ignoring error on sock_id %d handle %d type %d error %d : %s",
									ss->id, ss->sock, ss->type, err, err_str);
							continue; // do not close the RTCP socket, we might get some errors here but ignore them
						}
						LOG(
								"select_and_execute[%d]: %s on socket %d (sid:%d) from %s:%d - type %s errno %d",
								i, err_str, ss->sock, ss->sid,
								get_socket_rhost(ss->id, ra, sizeof(ra)),
								ntohs(ss->sa.sin_port), types[ss->type], err);
						if (err == EOVERFLOW || err == EWOULDBLOCK)
							continue;
						if (err == EAGAIN)
						{
							ss->err++;
							if (ss->err < 10)
								continue;
						}
						sockets_del(i);

						LOG("Delete socket %d done: sid %d", i, ss->sid);
						continue;
					}

//					ss->err = 0;					
				}
		// checking every 60seconds for idle connections - or if select times out
		c_time = getTick();
		if (rv == 0 || (c_time - lt >= 200))
		{
			sockets *ss;
			lt = c_time;
			i = -1;
			while (++i < max_sock)
				if ((ss = get_sockets(i)) && (ss->tid == tid)
						&& ((ss->timeout_ms > 0
								&& lt - ss->rtime > ss->timeout_ms)
								|| (ss->timeout_ms == 1)))
				{
					if (ss->timeout)
					{
						int rv;
						if (ss->sock == SOCK_TIMEOUT)
							ss->rtime = getTick();
						sockets_lock(ss);
						rv = ss->timeout(ss);
						sockets_unlock(ss);
						if (rv)
							sockets_del(i);
					}

					if (!ss->timeout)
						sockets_del(i);
				}
		}
	}

	clean_mutexes();

	if (tid == main_tid)
		LOG("The main loop ended, run_loop = %d", run_loop);
	add_join_thread(tid);

	return NULL;
}
Ejemplo n.º 4
0
int read_rtsp(sockets * s)
{
	char *arg[50];
	int cseq, la, i, rlen;
	char *transport = NULL;
	int sess_id = 0;
	char buf[2000];
	char tmp_ra[50];
	streams *sid = get_sid(s->sid);

	if (s->buf[0] == 0x24 && s->buf[1] < 2)
	{
		if (sid)
			sid->rtime = s->rtime;

		int rtsp_len = s->buf[2] * 256 + s->buf[3];
		LOG(
				"Received RTSP over tcp packet (sock_id %d, stream %d, rlen %d) packet len: %d, type %02X %02X discarding %s...",
				s->id, s->sid, s->rlen, rtsp_len, s->buf[4], s->buf[5],
				(s->rlen == rtsp_len + 4) ? "complete" : "fragment");
		if (s->rlen == rtsp_len + 4)
		{ // we did not receive the entire packet
			s->rlen = 0;
			return 0;
		}
	}

	if (s->rlen < 4 || !end_of_header(s->buf + s->rlen - 4))
	{
		if (s->rlen > RBUF - 10)
		{
			LOG(
					"Discarding %d bytes from the socket buffer, request > %d, consider increasing  RBUF",
					s->rlen, RBUF);
			s->rlen = 0;
		}
		LOG(
				"read_rtsp: read %d bytes from handle %d, sock_id %d, flags %d not ending with \\r\\n\\r\\n",
				s->rlen, s->sock, s->id, s->flags);
		if (s->flags & 1)
			return 0;
		unsigned char *new_alloc = malloc1(RBUF);
		memcpy(new_alloc, s->buf, s->rlen);
		s->buf = new_alloc;
		s->flags = s->flags | 1;
		return 0;
	}

	rlen = s->rlen;
	s->rlen = 0;

	LOG("read RTSP (from handle %d sock_id %d, len: %d, sid %d):\n%s", s->sock,
			s->id, s->rlen, s->sid, s->buf);

	if ((s->type != TYPE_HTTP)
			&& (strncasecmp((const char*) s->buf, "GET", 3) == 0))
	{
		http_response(s, 404, NULL, NULL, 0, 0);
		return 0;
	}

	la = split(arg, (char*) s->buf, 50, ' ');
	cseq = 0;
	if (la < 2)
		LOG_AND_RETURN(0,
				"Most likely not an RTSP packet sock_id: %d sid: %d rlen: %d, dropping ....",
				s->id, s->sid, rlen);

	if (s->sid < 0)
		for (i = 0; i < la; i++)
			if (strncasecmp("Session:", arg[i], 8) == 0)
			{
				sess_id = map_int(header_parameter(arg, i), NULL);
				s->sid = find_session_id(sess_id);
			}
/*	if (s->sid < 0 && strstr(arg[1], "stream=")) // stream= in URL
	{
		char *str_id = strstr(arg[1], "stream=") + 7;
		sess_id = map_intd(str_id, NULL, 0) - 1;
		if ((sid = get_sid(sess_id)))
		{
			s->sid = sid->sid;
			LOG("Adopting the session id from the stream %d", s->sid);
		}
	}
*/
	
	if (strstr(arg[1], "freq") || strstr(arg[1], "pids"))
	{
		sid = (streams *) setup_stream(arg[1], s);
	}

//	if(!get_sid(s->sid) && ((strncasecmp (arg[0], "PLAY", 4) == 0) || (strncasecmp (arg[0], "GET", 3) == 0) || (strncasecmp (arg[0], "SETUP", 5) == 0)))
//		sid = (streams *) setup_stream (arg[1], s);  //setup empty stream

	sid = get_sid(s->sid);
	if (sid)
		sid->rtime = s->rtime;

	if (sess_id)
		set_session_id(s->sid, sess_id);

	for (i = 0; i < la; i++)
		if (strncasecmp("CSeq:", arg[i], 5) == 0)
			cseq = map_int(header_parameter(arg, i), NULL);
		else if (strncasecmp("Transport:", arg[i], 9) == 0)
		{
			transport = header_parameter(arg, i);

			if (-1 == decode_transport(s, transport, opts.rrtp, opts.start_rtp))
			{
				http_response(s, 400, NULL, NULL, cseq, 0);
				return 0;
			}
		}
		else if (strstr(arg[i], "LIVE555"))
		{
			if (sid)
				sid->timeout = 0;
		}
		else if (strstr(arg[i], "Lavf"))
		{
			if (sid)
				sid->timeout = 0;
		}

	if ((strncasecmp(arg[0], "PLAY", 4) == 0)
			|| (strncasecmp(arg[0], "GET", 3) == 0)
			|| (strncasecmp(arg[0], "SETUP", 5) == 0))
	{
		char ra[100];
		int rv;

		if (!(sid = get_sid(s->sid)))
		{
			http_response(s, 454, NULL, NULL, cseq, 0);
			return 0;
		}

		if ((strncasecmp(arg[0], "PLAY", 3) == 0)
				|| (strncasecmp(arg[0], "GET", 3) == 0))
			if ((rv = start_play(sid, s)) < 0)
			{
				http_response(s, -rv, NULL, NULL, cseq, 0);
				return 0;
			}
		get_socket_rhost(sid->sid, ra, sizeof(ra));
		buf[0] = 0;
		if (transport)
		{
			int s_timeout;

			if (sid->timeout == 1)
				sid->timeout = opts.timeout_sec;

			s_timeout = (
					(sid->timeout > 20000) ? sid->timeout : opts.timeout_sec)
					/ 1000;
			switch (sid->type)
			{
			case STREAM_RTSP_UDP:
				if (atoi(ra) < 224)
					snprintf(buf, sizeof(buf),
							"Transport: RTP/AVP;unicast;destination=%s;source=%s;client_port=%d-%d;server_port=%d-%d\r\nSession: %010d;timeout=%d\r\ncom.ses.streamID: %d",
							ra, get_sock_shost(s->sock),
							get_stream_rport(sid->sid),
							get_stream_rport(sid->sid) + 1,
//							opts.start_rtp, opts.start_rtp + 1,
							get_sock_sport(sid->rsock),
							get_sock_sport(sid->rtcp), get_session_id(s->sid),
							s_timeout, sid->sid + 1);
				else
					snprintf(buf, sizeof(buf),
							"Transport: RTP/AVP;multicast;destination=%s;port=%d-%d\r\nSession: %010d;timeout=%d\r\ncom.ses.streamID: %d",
							ra, get_stream_rport(sid->sid),
							ntohs (sid->sa.sin_port) + 1,
							get_session_id(s->sid), s_timeout, sid->sid + 1);
				break;
			case STREAM_RTSP_TCP:
				snprintf(buf, sizeof(buf),
						"Transport: RTP/AVP/TCP;interleaved=0-1\r\nSession: %010d;timeout=%d\r\ncom.ses.streamID: %d",
						get_session_id(s->sid), s_timeout, sid->sid + 1);
				break;
			}
		}

		if (strncasecmp(arg[0], "PLAY", 4) == 0)
		{
			char *qm = strchr(arg[1], '?');
			if (qm)
				*qm = 0;
			if (buf[0])
				strcat(buf, "\r\n");

			snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf) - 1,
					"RTP-Info: url=%s;seq=%d;rtptime=%lld\r\nRange: npt=0.000-",
					arg[1], getTick(), (long long int) (getTickUs() / 1000000));
		}
		if (buf[0] == 0 && sid->type == STREAM_HTTP)
			snprintf(buf, sizeof(buf), "Content-Type: video/mp2t");
		http_response(s, 200, buf, NULL, cseq, 0);
	}
	else if (strncmp(arg[0], "TEARDOWN", 8) == 0)
	{
		buf[0] = 0;
		if (get_sid(s->sid))
			sprintf(buf, "Session: %010d", get_session_id(s->sid));
		close_stream(s->sid);
		http_response(s, 200, buf, NULL, cseq, 0);
	}
	else
	{
		if (strncmp(arg[0], "DESCRIBE", 8) == 0)
		{
			char sbuf[1000];
			char *rv = NULL;
			rv = describe_streams(s, arg[1], sbuf, sizeof(sbuf));
			if (!rv)
			{
				http_response(s, 404, NULL, NULL, cseq, 0);
				return 0;
			}
			snprintf(buf, sizeof(buf),
					"Content-type: application/sdp\r\nContent-Base: rtsp://%s/",
					get_sock_shost(s->sock));
			http_response(s, 200, buf, sbuf, cseq, 0);

		}
		else if (strncmp(arg[0], "OPTIONS", 8) == 0)
		{
			http_response(s, 200, public, NULL, cseq, 0);
		}
	}
Ejemplo n.º 5
0
int select_and_execute()
{
    fd_set io;
    int i, rv, rlen;
    unsigned char buf[2001];
    int err;
    run_loop = 1;
    int lt, read_ok, c_time;
    char ra[50];
    lt = getTick();
    while (run_loop)
    {
        FD_ZERO(&io);
        i = -1;
        //    LOG("start select");
        if ((rv = poll(pf, max_sock, 100)) < 0)
        {
            perror("select_and_execute: select() error");
            continue;
        }
        c_time = getTick();
        //              LOG("select returned %d",rv);
        if (rv > 0)
            while (++i < max_sock)
                if (pf[i].revents)
                {
                    sockets *ss = &s[i];
                    c_time = getTick();

                    LOGL(6,
                         "event on socket index %d handle %d type %d (poll fd:%d, revents=%d)",
                         i, ss->sock, ss->type, pf[i].fd, pf[i].revents);
                    if (pf[i].revents & POLLOUT)
                    {
                        pf[i].events &= ~POLLOUT;
                    }
                    if (!ss->buf || ss->buf == buf)
                    {
                        ss->buf = buf;
                        ss->lbuf = sizeof(buf) - 1;
                        ss->rlen = 0;
                    }
                    if (ss->rlen >= ss->lbuf)
                    {
                        LOG(
                            "Socket buffer full, handle %d, sock_id %d, type %d, lbuf %d, rlen %d, ss->buf = %p, buf %p",
                            ss->sock, i, ss->type, ss->lbuf, ss->rlen,
                            ss->buf, buf);
                        ss->rlen = 0;
                    }
                    rlen = 0;
                    if (c_time - bwtt > 1000)
                    {
                        bwtt = c_time;
                        tbw += bw;
                        if (bw > 2000)
                            LOG(
                                "BW %dKB/s, Total BW: %ld MB, ns/read %lld, r: %d, tt: %lld ms, n: %d (s: %d ms, s_cnt %d)",
                                (int ) bw / 1024, tbw / 1024576,
                                nsecs / reads, reads, nsecs / 1000,
                                bwnotify, sleeping / 1000, sleeping_cnt);
                        bw = 0;
                        bwnotify = 0;
                        nsecs = 0;
                        reads = 0;
                        sleeping = sleeping_cnt = 0;
                    }
                    if (opts.bw > 0 && bw > opts.bw && ss->type == TYPE_DVR)
                    {
                        int ms = 1000 - c_time + bwtt;
                        if (bwnotify++ == 0)
                            LOG(
                                "capping %d sock %d for the next %d ms, sleeping for the next %d ms",
                                i, ss->sock, ms, ms / 50);
                        if (ms > 50)
                            usleep(ms * 20);
                        continue;

                    }

                    read_ok = ss->read(ss->sock, &ss->buf[ss->rlen],
                                       ss->lbuf - ss->rlen, ss, &rlen);

                    if (opts.log >= 1)
                    {
                        int now = getTick();
                        if (now - c_time > 100)
                            LOG(
                                "WARNING: read on socket id %d, handle %d, took %d ms",
                                ss->id, ss->sock, now - c_time);
                    }

                    err = 0;
                    if (rlen < 0)
                        err = errno;
                    if (rlen > 0)
                        ss->rtime = c_time;
                    if (read_ok && rlen > 0)
                        ss->rlen += rlen;
                    else
                        ss->rlen = 0;
                    //force 0 at the end of the string
                    if (ss->lbuf >= ss->rlen)
                        ss->buf[ss->rlen] = 0;
                    LOGL(6,
                         "Read %s %d (rlen:%d/total:%d) bytes from %d -> %p - iteration %d action %p",
                         read_ok ? "OK" : "NOK", rlen, ss->rlen, ss->lbuf,
                         ss->sock, ss->buf, it++, ss->action);

                    if (((ss->rlen > 0) || err == EWOULDBLOCK) && ss->action
                            && (ss->type != TYPE_SERVER))
                        ss->action(ss);
                    //              if(s[i].type==TYPE_DVR && (c_time/1000 % 10 == 0))sockets_del(i); // we do this in stream.c in flush_stream*
                    if (!read_ok && ss->type != TYPE_SERVER)
                    {
                        char *err_str;
                        char *types[] =
                        { "udp", "tcp", "server", "http", "rtsp", "dvr" };
                        if (rlen == 0)
                        {
                            err = 0;
                            err_str = "Close";
                        }
                        else if (err == EOVERFLOW)
                            err_str = "EOVERFLOW";
                        else if (err == EWOULDBLOCK)
                            err_str = "Connected";
                        else
                            err_str = strerror(err);

                        if (ss->type == TYPE_RTCP)
                            continue; // do not close the RTCP socket, we might get some errors here but ignore them

                        LOG(
                            "select_and_execute[%d]: %s on socket %d (sid:%d) from %s:%d - type %s errno %d",
                            i, err_str, ss->sock, ss->sid,
                            get_socket_rhost(ss->id, ra, sizeof(ra)),
                            ntohs(ss->sa.sin_port), types[ss->type], err);
                        if (err == EOVERFLOW || err == EWOULDBLOCK)
                            continue;
                        if (err == EAGAIN)
                        {
                            ss->err++;
                            if (ss->err < 10)
                                continue;
                        }
                        sockets_del(i);
                        LOG("Delete socket %d done: sid %d", i, ss->sid);
                        continue;
                    }

//					ss->err = 0;
                }
        // checking every 60seconds for idle connections - or if select times out
        if (rv == 0 || c_time - lt >= 200)
        {
            lt = c_time;
            i = -1;
            while (++i < max_sock)
                if (( s[i].sock > 0 ) && ((s[i].close_sec > 0 && lt - s[i].rtime > s[i].close_sec)
                                          || (s[i].close_sec == 1)))
                {
                    if (s[i].timeout && s[i].timeout(&s[i]))
                        sockets_del(i);
                    if (!s[i].timeout)
                        sockets_del(i);
                }
            stream_timeouts();
        }
    }
    LOG("The main loop ended, run_loop = %d", run_loop);
    return 0;
}