Пример #1
0
int Cconnection::post_select(fd_set* fd_read_set, fd_set* fd_write_set)
{
	return FD_ISSET(m_s, fd_read_set) && recv()
		|| FD_ISSET(m_s, fd_write_set) && send()
		|| srv_time() - m_ctime > 10
		|| m_state == 5 && m_r.empty();
}
Пример #2
0
void write_db_users()
{
	m_write_db_users_time = srv_time();
	if (!m_use_sql)
		return;
	if (!m_torrents_users_updates_buffer.empty())
	{
		m_torrents_users_updates_buffer.pop_back();
		async_query("insert into " + db_name("files_users") + " (active, announced, completed, downloaded, `left`, uploaded, mtime, fid, uid) values "
			+ m_torrents_users_updates_buffer
			+ " on duplicate key update"
			+ "  active = values(active),"
			+ "  announced = announced + values(announced),"
			+ "  completed = completed + values(completed),"
			+ "  downloaded = downloaded + values(downloaded),"
			+ "  `left` = values(`left`),"
			+ "  uploaded = uploaded + values(uploaded),"
			+ "  mtime = values(mtime)");
		m_torrents_users_updates_buffer.erase();
	}
	async_query("update " + db_name("files_users") + " set active = 0 where mtime < unix_timestamp() - 60 * 60");
	if (!m_users_updates_buffer.empty())
	{
		m_users_updates_buffer.pop_back();
		async_query("insert into " + db_name("users") + " (downloaded, uploaded, " + db_name("uid") + ") values "
			+ m_users_updates_buffer
			+ " on duplicate key update"
			+ "  downloaded = downloaded + values(downloaded),"
			+ "  uploaded = uploaded + values(uploaded)");
		m_users_updates_buffer.erase();
	}
}
Пример #3
0
void arrival() /* a customer arrives */

{
    struct packet_info *t, *x;
    narr += 1;                /* keep tally of number of arrivals */
    q_sum += q;
    schedule(negexp(iat), ARRIVAL); /* schedule the next arrival */

    int new_pkt_len = (int)(-log(drand48()) * mean_pkt_length);
    double utilisation =  (q_len * 8 * iat)/(pow(10.0, 6.0));
    if(utilisation>0.9) {
        nloss += 1;
    }
    else if ((new_pkt_len+q_len) <= buffer_size) {
        /* still space in buffer */
        q += 1;
        q_len += new_pkt_len;
        t = NEW(PACKET_Q);
        for(x=headPkt ; x->next!=tailPkt ; x=x->next);
        t->pkt_len = new_pkt_len;
        t->next = x->next;
        x->next = t;
        if (q == 1)
            schedule(srv_time(headPkt->next->pkt_len), DEPARTURE);
    }
    else {
        /* buffer is full; packet is dropped */
        nloss += 1;
    }
}
Пример #4
0
Cconnection::Cconnection(const Csocket& s, const sockaddr_in& a)
{
	m_s = s;
	m_a = a;
	m_ctime = srv_time();

	m_state = 0;
	m_w = m_read_b;
}
Пример #5
0
void read_db_users()
{
	m_read_db_users_time = srv_time();
	if (!m_use_sql)
		return;
	try
	{
		Csql_query q(m_database, "select @uid");
		if (m_read_users_can_leech)
			q += ", can_leech";
		if (m_read_users_peers_limit)
			q += ", peers_limit";
		if (m_read_users_torrent_pass)
			q += ", torrent_pass";
		q += ", torrent_pass_version";
		if (m_read_users_wait_time)
			q += ", wait_time";
		q += " from @users";
		Csql_result result = q.execute();
		// m_users.reserve(result.size());
		for (auto& i : m_users)
			i.second.marked = true;
		m_users_torrent_passes.clear();
		while (Csql_row row = result.fetch_row())
		{
			t_user& user = m_users[row[0].i()];
			user.marked = false;
			int c = 0;
			user.uid = row[c++].i();
			if (m_read_users_can_leech)
				user.can_leech = row[c++].i();
			if (m_read_users_peers_limit)
				user.peers_limit = row[c++].i();
			if (m_read_users_torrent_pass)
			{
				if (row[c].size() == 32)
					m_users_torrent_passes[to_array<char, 32>(row[c])] = &user;
				c++;
			}
			user.torrent_pass_version = row[c++].i();
			if (m_read_users_wait_time)
				user.wait_time = row[c++].i();
		}
		for (auto i = m_users.begin(); i != m_users.end(); )
		{
			if (i->second.marked)
				m_users.erase(i++);
			else
				i++;
		}
	}
	catch (bad_query&)
	{
	}
}
Пример #6
0
void write_db_torrents()
{
	m_write_db_torrents_time = srv_time();
	if (!m_use_sql)
		return;
	try
	{
		std::string buffer;
		while (1)
		{
			for (auto& i : m_torrents)
			{
				t_torrent& file = i.second;
				if (!file.dirty)
					continue;
				if (!file.fid)
				{
					Csql_query(m_database, "insert into @files (info_hash, mtime, ctime) values (?, unix_timestamp(), unix_timestamp())")(i.first).execute();
					file.fid = m_database.insert_id();
				}
				buffer += Csql_query(m_database, "(?,?,?,?),")(file.leechers)(file.seeders)(file.completed)(file.fid).read();
				file.dirty = false;
				if (buffer.size() > 255 << 10)
					break;
			}
			if (buffer.empty())
				break;
			buffer.pop_back();
			async_query("insert into " + db_name("files") + " (" + db_name("leechers") + ", " + db_name("seeders") + ", " + db_name("completed") + ", " + db_name("fid") + ") values "
				+ buffer
				+ " on duplicate key update"
				+ "  " + db_name("leechers") + " = values(" + db_name("leechers") + "),"
				+ "  " + db_name("seeders") + " = values(" + db_name("seeders") + "),"
				+ "  " + db_name("completed") + " = values(" + db_name("completed") + "),"
				+ "  mtime = unix_timestamp()");
			buffer.clear();
		}
	}
	catch (bad_query&)
	{
	}
	if (!m_announce_log_buffer.empty())
	{
		m_announce_log_buffer.pop_back();
		async_query("insert delayed into " + db_name("announce_log") + " (ipa, port, event, info_hash, peer_id, downloaded, left0, uploaded, uid, mtime) values " + m_announce_log_buffer);
		m_announce_log_buffer.erase();
	}
	if (!m_scrape_log_buffer.empty())
	{
		m_scrape_log_buffer.pop_back();
		async_query("insert delayed into " + db_name("scrape_log") + " (ipa, uid, mtime) values " + m_scrape_log_buffer);
		m_scrape_log_buffer.erase();
	}
}
Пример #7
0
void debug(const t_torrent& t, std::ostream& os)
{
	for (auto& i : t.peers)
	{
		os << "<tr><td>" + Csocket::inet_ntoa(i.first.host_)
			<< "<td class=ar>" << ntohs(i.second.port)
			<< "<td class=ar>" << i.second.uid
			<< "<td class=ar>" << i.second.left
			<< "<td class=ar>" << srv_time() - i.second.mtime
			<< "<td>" << hex_encode(i.second.peer_id);
	}
}
Пример #8
0
void departure()  /* a customer departs */

{
	struct packet_info *x;
	
	q -= 1;
	x = headPkt->next;                 /* Delete event from linked list */
	q_len -= x->pkt_len;
	headPkt->next = headPkt->next->next;
	free(x);
	if (q > 0)
		schedule(srv_time(headPkt->next->pkt_len), DEPARTURE);
}
Пример #9
0
void arrival() /* a customer arrives */

{
	int i;
	struct packet_info *t, *x;
	narr += 1;                /* keep tally of number of arrivals */
	q_sum += q;
	schedule(negexp(iat), ARRIVAL); /* schedule the next arrival */
	
	/* check whether to schedule a batch or individual packet arrival */
	if (batch_interval == 1 || narr % batch_interval == 0) {
		num_packets = batch_size;
		batch_arrival = 1;
		batch_packets += num_packets;
	}
	else {
		num_packets = 1;
		batch_arrival = 0;
	}
	
	/* Create the appropriate number of packets for the type of arrival */
	for (i = 0; i < num_packets; ++i) { 
		total_packets += 1;
		int new_pkt_len = (int)(-log(drand48()) * MEAN_PKT_LENGTH); 
		if ((new_pkt_len+q_len) <= BUFFER_SIZE) {
			/* still space in buffer */
			q += 1;
			q_len += new_pkt_len;
			t = NEW(PACKET_Q);
			for(x=headPkt ; x->next!=tailPkt ; x=x->next);
			t->pkt_len = new_pkt_len;
			t->next = x->next;
			x->next = t;
			if (q == 1)
				schedule(srv_time(headPkt->next->pkt_len), DEPARTURE);
		}
		else {
			/* buffer is full; packet is dropped */
			if (batch_arrival) {
				batch_nloss += 1;
			}
			else {
				nloss += 1;
			}
		}
	}
}
Пример #10
0
void read_config()
{
	if (m_use_sql)
	{
		try
		{
			Csql_result result = Csql_query(m_database, "select name, value from @config where value is not null").execute();
			Cconfig config;
			while (Csql_row row = result.fetch_row())
			{
				if (config.set(row[0].s(), row[1].s()))
					std::cerr << "unknown config name: " << row[0].s() << std::endl;
			}
			config.load(m_conf_file);
			if (config.m_torrent_pass_private_key.empty())
			{
				config.m_torrent_pass_private_key = generate_random_string(27);
				Csql_query(m_database, "insert into @config (name, value) values ('torrent_pass_private_key', ?)")(config.m_torrent_pass_private_key).execute();
			}
			m_config = config;
			m_database.set_name("completed", m_config.m_column_files_completed);
			m_database.set_name("leechers", m_config.m_column_files_leechers);
			m_database.set_name("seeders", m_config.m_column_files_seeders);
			m_database.set_name("fid", m_config.m_column_files_fid);
			m_database.set_name("uid", m_config.m_column_users_uid);
			m_database.set_name("announce_log", m_config.m_table_announce_log.empty() ? m_table_prefix + "announce_log" : m_config.m_table_announce_log);
			m_database.set_name("files", m_config.m_table_torrents.empty() ? m_table_prefix + "files" : m_config.m_table_torrents);
			m_database.set_name("files_users", m_config.m_table_torrents_users.empty() ? m_table_prefix + "files_users" : m_config.m_table_torrents_users);
			m_database.set_name("scrape_log", m_config.m_table_scrape_log.empty() ? m_table_prefix + "scrape_log" : m_config.m_table_scrape_log);
			m_database.set_name("users", m_config.m_table_users.empty() ? m_table_prefix + "users" : m_config.m_table_users);
		}
		catch (bad_query&)
		{
		}
	}
	else
	{
		Cconfig config;
		if (!config.load(m_conf_file))
			m_config = config;
	}
	if (m_config.m_listen_ipas.empty())
		m_config.m_listen_ipas.insert(htonl(INADDR_ANY));
	if (m_config.m_listen_ports.empty())
		m_config.m_listen_ports.insert(2710);
	m_read_config_time = srv_time();
}
Пример #11
0
void read_db_torrents()
{
	m_read_db_torrents_time = srv_time();
	if (m_use_sql)
		read_db_torrents_sql();
	else if (!m_config.m_auto_register)
	{
		std::set<t_torrent*> new_torrents;
		std::ifstream is("xbt_torrents.txt");
		for (std::string s; getline(is, s); )
		{
			s = hex_decode(s);
			if (s.size() == 20)
				new_torrents.insert(&m_torrents[to_array<char, 20>(s)]);
		}
		for (auto i = m_torrents.begin(); i != m_torrents.end(); )
		{
			if (new_torrents.count(&i->second))
				i++;
			else
				m_torrents.erase(i++);
		}
	}
}
Пример #12
0
std::string srv_statistics()
{
	std::ostringstream os;
	os << "<!DOCTYPE HTML><meta http-equiv=refresh content=60><title>XBT Tracker</title>";
	os << "<style>.ar { text-align: right }</style>";
	int leechers = 0;
	int seeders = 0;
	int torrents = 0;
	for (auto& i : m_torrents)
	{
		leechers += i.second.leechers;
		seeders += i.second.seeders;
		torrents += i.second.leechers || i.second.seeders;
	}
	int peers = leechers + seeders;
	time_t t = srv_time();
	time_t up_time = std::max<time_t>(1, t - m_stats.start_time);
	os << "<table>"
		<< "<tr><td>peers<td class=ar>" << peers;
	if (peers)
	{
		os << "<tr><td>seeders<td class=ar>" << seeders << "<td class=ar>" << seeders * 100 / peers << " %"
			<< "<tr><td>leechers<td class=ar>" << leechers << "<td class=ar>" << leechers * 100 / peers << " %";
	}
	os << "<tr><td>torrents<td class=ar>" << torrents
		<< "<tr><td>"
		<< "<tr><td>accepted tcp<td class=ar>" << m_stats.accepted_tcp << "<td class=ar>" << m_stats.accepted_tcp / up_time << " /s"
		<< "<tr><td>slow tcp<td class=ar>" << m_stats.slow_tcp << "<td class=ar>" << m_stats.slow_tcp / up_time << " /s"
		<< "<tr><td>rejected tcp<td class=ar>" << m_stats.rejected_tcp
		<< "<tr><td>accept errors<td class=ar>" << m_stats.accept_errors;
	if (m_stats.announced())
	{
		os << "<tr><td>announced<td class=ar>" << m_stats.announced() << "<td class=ar>" << m_stats.announced() * 100 / m_stats.accepted_tcp << " %"
			<< "<tr><td>announced http <td class=ar>" << m_stats.announced_http << "<td class=ar>" << m_stats.announced_http * 100 / m_stats.announced() << " %"
			<< "<tr><td>announced udp<td class=ar>" << m_stats.announced_udp << "<td class=ar>" << m_stats.announced_udp * 100 / m_stats.announced() << " %";
	}
	os << "<tr><td>scraped full<td class=ar>" << m_stats.scraped_full;
	os << "<tr><td>scraped multi<td class=ar>" << m_stats.scraped_multi;
	if (m_stats.scraped())
	{
		os << "<tr><td>scraped<td class=ar>" << m_stats.scraped() << "<td class=ar>" << m_stats.scraped() * 100 / m_stats.accepted_tcp << " %"
			<< "<tr><td>scraped http<td class=ar>" << m_stats.scraped_http << "<td class=ar>" << m_stats.scraped_http * 100 / m_stats.scraped() << " %"
			<< "<tr><td>scraped udp<td class=ar>" << m_stats.scraped_udp << "<td class=ar>" << m_stats.scraped_udp * 100 / m_stats.scraped() << " %";
	}
	os << "<tr><td>"
		<< "<tr><td>up time<td class=ar>" << duration2a(up_time)
		<< "<tr><td>"
		<< "<tr><td>anonymous announce<td class=ar>" << m_config.m_anonymous_announce
		<< "<tr><td>anonymous scrape<td class=ar>" << m_config.m_anonymous_scrape
		<< "<tr><td>auto register<td class=ar>" << m_config.m_auto_register
		<< "<tr><td>full scrape<td class=ar>" << m_config.m_full_scrape
		<< "<tr><td>read config time<td class=ar>" << t - m_read_config_time << " / " << m_config.m_read_config_interval
		<< "<tr><td>clean up time<td class=ar>" << t - m_clean_up_time << " / " << m_config.m_clean_up_interval
		<< "<tr><td>read db files time<td class=ar>" << t - m_read_db_torrents_time << " / " << m_config.m_read_db_interval;
	if (m_use_sql)
	{
		os << "<tr><td>read db users time<td class=ar>" << t - m_read_db_users_time << " / " << m_config.m_read_db_interval
			<< "<tr><td>write db files time<td class=ar>" << t - m_write_db_torrents_time << " / " << m_config.m_write_db_interval
			<< "<tr><td>write db users time<td class=ar>" << t - m_write_db_users_time << " / " << m_config.m_write_db_interval;
	}
	os << "</table>";
	return os.str();
}
Пример #13
0
std::string srv_scrape(const Ctracker_input& ti, t_user* user)
{
	if (m_use_sql && m_config.m_log_scrape)
		m_scrape_log_buffer += Csql_query(m_database, "(?,?,?),")(ntohl(ti.m_ipa))(user ? user->uid : 0)(srv_time()).read();
	if (!m_config.m_anonymous_scrape && !user)
		return "d14:failure reason25:unregistered torrent passe";
	std::string d;
	d += "d5:filesd";
	if (ti.m_info_hashes.empty())
	{
		m_stats.scraped_full++;
		d.reserve(90 * m_torrents.size());
		for (auto& i : m_torrents)
		{
			if (i.second.leechers || i.second.seeders)
				d += (boost::format("20:%sd8:completei%de10:downloadedi%de10:incompletei%dee") % boost::make_iterator_range(i.first) % i.second.seeders % i.second.completed % i.second.leechers).str();
		}
	}
	else
	{
		m_stats.scraped_http++;
		if (ti.m_info_hashes.size() > 1)
			m_stats.scraped_multi++;
		for (auto& j : ti.m_info_hashes)
		{
			if (const t_torrent* i = find_torrent(j))
				d += (boost::format("20:%sd8:completei%de10:downloadedi%de10:incompletei%dee") % j % i->seeders % i->completed % i->leechers).str();
		}
	}
	d += "e";
	if (m_config.m_scrape_interval)
		d += (boost::format("5:flagsd20:min_request_intervali%dee") % m_config.m_scrape_interval).str();
	d += "e";
	return d;
}
Пример #14
0
std::string srv_insert_peer(const Ctracker_input& v, bool udp, t_user* user)
{
	if (m_use_sql && m_config.m_log_announce)
	{
		m_announce_log_buffer += Csql_query(m_database, "(?,?,?,?,?,?,?,?,?,?),")
			(ntohl(v.m_ipa))
			(ntohs(v.m_port))
			(v.m_event)
			(v.m_info_hash)
			(v.m_peer_id)
			(v.m_downloaded)
			(v.m_left)
			(v.m_uploaded)
			(user ? user->uid : 0)
			(srv_time())
			.read();
	}
	if (!m_config.m_offline_message.empty())
		return m_config.m_offline_message;
	if (0)
		return bts_banned_client;
	if (!m_config.m_anonymous_announce && !user)
		return bts_unregistered_torrent_pass;
	if (!m_config.m_auto_register && !find_torrent(v.m_info_hash))
		return bts_unregistered_torrent;
	if (v.m_left && user && !user->can_leech)
		return bts_can_not_leech;
	t_torrent& file = m_torrents[to_array<char, 20>(v.m_info_hash)];
	if (!file.ctime)
		file.ctime = srv_time();
	if (v.m_left && user && user->wait_time && file.ctime + user->wait_time > srv_time())
		return bts_wait_time;
	peer_key_c peer_key(v.m_ipa, user ? user->uid : 0);
	t_peer* i = find_ptr(file.peers, peer_key);
	if (i)
		(i->left ? file.leechers : file.seeders)--;
	else if (v.m_left && user && user->peers_limit)
	{
		int c = 0;
		for (auto& j : file.peers)
			c += j.second.left && j.second.uid == user->uid;
		if (c >= user->peers_limit)
			return bts_peers_limit_reached;
	}
	if (m_use_sql && user && file.fid)
	{
		long long downloaded = 0;
		long long uploaded = 0;
		if (i
			&& i->uid == user->uid
			&& boost::equals(i->peer_id, v.m_peer_id)
			&& v.m_downloaded >= i->downloaded
			&& v.m_uploaded >= i->uploaded)
		{
			downloaded = v.m_downloaded - i->downloaded;
			uploaded = v.m_uploaded - i->uploaded;
		}
		m_torrents_users_updates_buffer += Csql_query(m_database, "(?,1,?,?,?,?,?,?,?),")
			(v.m_event != Ctracker_input::e_stopped)
			(v.m_event == Ctracker_input::e_completed)
			(downloaded)
			(v.m_left)
			(uploaded)
			(srv_time())
			(file.fid)
			(user->uid)
			.read();
		if (downloaded || uploaded)
			m_users_updates_buffer += Csql_query(m_database, "(?,?,?),")(downloaded)(uploaded)(user->uid).read();
		if (m_torrents_users_updates_buffer.size() > 255 << 10)
			write_db_users();
	}
	if (v.m_event == Ctracker_input::e_stopped)
		file.peers.erase(peer_key);
	else
	{
		t_peer& peer = i ? *i : file.peers[peer_key];
		peer.downloaded = v.m_downloaded;
		peer.left = v.m_left;
		peer.peer_id = v.m_peer_id;
		peer.port = v.m_port;
		peer.uid = user ? user->uid : 0;
		peer.uploaded = v.m_uploaded;
		(peer.left ? file.leechers : file.seeders)++;
		peer.mtime = srv_time();
	}
	if (v.m_event == Ctracker_input::e_completed)
		file.completed++;
	(udp ? m_stats.announced_udp : m_stats.announced_http)++;
	file.dirty = true;
	return std::string();
}
Пример #15
0
int srv_run(const std::string& table_prefix, bool use_sql, const std::string& conf_file)
{
	for (int i = 0; i < 8; i++)
		m_secret = m_secret << 8 ^ rand();
	m_conf_file = conf_file;
	m_database.set_name("config", table_prefix + "config");
	m_table_prefix = table_prefix;
	m_use_sql = use_sql;

	read_config();
	if (test_sql())
		return 1;
	if (m_epoll.create() == -1)
	{
		std::cerr << "epoll_create failed" << std::endl;
		return 1;
	}
	std::list<Ctcp_listen_socket> lt;
	std::list<Cudp_listen_socket> lu;
	for (auto& j : m_config.m_listen_ipas)
	{
		for (auto& i : m_config.m_listen_ports)
		{
			Csocket l;
			if (l.open(SOCK_STREAM) == INVALID_SOCKET)
				std::cerr << "socket failed: " << Csocket::error2a(WSAGetLastError()) << std::endl;
			else if (l.setsockopt(SOL_SOCKET, SO_REUSEADDR, true),
				l.bind(j, htons(i)))
				std::cerr << "bind failed: " << Csocket::error2a(WSAGetLastError()) << std::endl;
			else if (l.listen())
				std::cerr << "listen failed: " << Csocket::error2a(WSAGetLastError()) << std::endl;
			else
			{
#ifdef SO_ACCEPTFILTER
				accept_filter_arg afa;
				bzero(&afa, sizeof(afa));
				strcpy(afa.af_name, "httpready");
				if (l.setsockopt(SOL_SOCKET, SO_ACCEPTFILTER, &afa, sizeof(afa)))
					std::cerr << "setsockopt failed: " << Csocket::error2a(WSAGetLastError()) << std::endl;
#elif 0 // TCP_DEFER_ACCEPT
				if (l.setsockopt(IPPROTO_TCP, TCP_DEFER_ACCEPT, 90))
					std::cerr << "setsockopt failed: " << Csocket::error2a(WSAGetLastError()) << std::endl;
#endif
				lt.push_back(Ctcp_listen_socket(l));
				if (!m_epoll.ctl(EPOLL_CTL_ADD, l, EPOLLIN | EPOLLOUT | EPOLLPRI | EPOLLERR | EPOLLHUP, &lt.back()))
					continue;
			}
			return 1;
		}
		for (auto& i : m_config.m_listen_ports)
		{
			Csocket l;
			if (l.open(SOCK_DGRAM) == INVALID_SOCKET)
				std::cerr << "socket failed: " << Csocket::error2a(WSAGetLastError()) << std::endl;
			else if (l.setsockopt(SOL_SOCKET, SO_REUSEADDR, true),
				l.bind(j, htons(i)))
				std::cerr << "bind failed: " << Csocket::error2a(WSAGetLastError()) << std::endl;
			else
			{
				lu.push_back(Cudp_listen_socket(l));
				if (!m_epoll.ctl(EPOLL_CTL_ADD, l, EPOLLIN | EPOLLPRI | EPOLLERR | EPOLLHUP, &lu.back()))
					continue;
			}
			return 1;
		}
	}
	clean_up();
	read_db_torrents();
	read_db_users();
	write_db_torrents();
	write_db_users();
#ifndef NDEBUG
	// test_announce();
#endif
#ifndef WIN32
	if (m_config.m_daemon)
	{
		if (daemon(true, false))
			std::cerr << "daemon failed" << std::endl;
		std::ofstream(m_config.m_pid_file.c_str()) << getpid() << std::endl;
		struct sigaction act;
		act.sa_handler = sig_handler;
		sigemptyset(&act.sa_mask);
		act.sa_flags = 0;
		if (sigaction(SIGTERM, &act, NULL))
			std::cerr << "sigaction failed" << std::endl;
		act.sa_handler = SIG_IGN;
		if (sigaction(SIGPIPE, &act, NULL))
			std::cerr << "sigaction failed" << std::endl;
	}
#endif
#ifdef EPOLL
	std::array<epoll_event, 64> events;
#else
	fd_set fd_read_set;
	fd_set fd_write_set;
	fd_set fd_except_set;
#endif
	while (!g_sig_term)
	{
#ifdef EPOLL
		int r = m_epoll.wait(events.data(), events.size(), 5000);
		if (r == -1)
			std::cerr << "epoll_wait failed: " << errno << std::endl;
		else
		{
			time_t prev_time = m_time;
			m_time = ::time(NULL);
			for (int i = 0; i < r; i++)
				reinterpret_cast<Cclient*>(events[i].data.ptr)->process_events(events[i].events);
			if (m_time == prev_time)
				continue;
			for (auto i = m_connections.begin(); i != m_connections.end(); )
			{
				if (i->run())
					i = m_connections.erase(i);
				else
					i++;
			}
		}
#else
		FD_ZERO(&fd_read_set);
		FD_ZERO(&fd_write_set);
		FD_ZERO(&fd_except_set);
		int n = 0;
		for (auto& i : m_connections)
		{
			int z = i.pre_select(&fd_read_set, &fd_write_set);
			n = std::max(n, z);
		}
		for (auto& i : lt)
		{
			FD_SET(i.s(), &fd_read_set);
			n = std::max<int>(n, i.s());
		}
		for (auto& i : lu)
		{
			FD_SET(i.s(), &fd_read_set);
			n = std::max<int>(n, i.s());
		}
		timeval tv;
		tv.tv_sec = 5;
		tv.tv_usec = 0;
		if (select(n + 1, &fd_read_set, &fd_write_set, &fd_except_set, &tv) == SOCKET_ERROR)
			std::cerr << "select failed: " << Csocket::error2a(WSAGetLastError()) << std::endl;
		else
		{
			m_time = ::time(NULL);
			for (auto& i : lt)
			{
				if (FD_ISSET(i.s(), &fd_read_set))
					accept(i.s());
			}
			for (auto& i : lu)
			{
				if (FD_ISSET(i.s(), &fd_read_set))
					Ctransaction(i.s()).recv();
			}
			for (auto i = m_connections.begin(); i != m_connections.end(); )
			{
				if (i->post_select(&fd_read_set, &fd_write_set))
					i = m_connections.erase(i);
				else
					i++;
			}
		}
#endif
		if (srv_time() - m_read_config_time > m_config.m_read_config_interval)
			read_config();
		else if (srv_time() - m_clean_up_time > m_config.m_clean_up_interval)
			clean_up();
		else if (srv_time() - m_read_db_torrents_time > m_config.m_read_db_interval)
			read_db_torrents();
		else if (srv_time() - m_read_db_users_time > m_config.m_read_db_interval)
			read_db_users();
		else if (m_config.m_write_db_interval && srv_time() - m_write_db_torrents_time > m_config.m_write_db_interval)
			write_db_torrents();
		else if (m_config.m_write_db_interval && srv_time() - m_write_db_users_time > m_config.m_write_db_interval)
			write_db_users();
	}
	write_db_torrents();
	write_db_users();
	unlink(m_config.m_pid_file.c_str());
	return 0;
}
Пример #16
0
void clean_up()
{
	for (auto& i : m_torrents)
		clean_up(i.second, srv_time() - static_cast<int>(1.5 * m_config.m_announce_interval));
	m_clean_up_time = srv_time();
}
Пример #17
0
void Cconnection::read(const std::string& v)
{
#ifndef NDEBUG
	std::cout << v << std::endl;
#endif
	if (srv_config().m_log_access)
	{
		static std::ofstream f("xbt_tracker_raw.log");
		f << srv_time() << '\t' << inet_ntoa(m_a.sin_addr) << '\t' << ntohs(m_a.sin_port) << '\t' << v << std::endl;
	}
	Ctracker_input ti;
	size_t e = v.find('?');
	if (e == std::string::npos)
		e = v.size();
	else
	{
		size_t a = e + 1;
		size_t b = v.find(' ', a);
		if (b == std::string::npos)
			return;
		while (a < b)
		{
			size_t c = v.find('=', a);
			if (c++ == std::string::npos)
				break;
			size_t d = v.find_first_of(" &", c);
			if (d == std::string::npos)
				break;
			ti.set(v.substr(a, c - a - 1), uri_decode(v.substr(c, d - c)));
			a = d + 1;
		}
	}
	if (!ti.m_ipa || !is_private_ipa(m_a.sin_addr.s_addr))
		ti.m_ipa = m_a.sin_addr.s_addr;
	str_ref torrent_pass;
	size_t a = 4;
	if (a < e && v[a] == '/')
	{
		a++;
		if (a + 32 < e && v[a + 32] == '/')
		{
			torrent_pass.assign(&v[a], 32);
			a += 33;
		}
	}
	std::string h = "HTTP/1.0 200 OK\r\n";
	std::string s;
	bool gzip = true;
	switch (a < v.size() ? v[a] : 0)
	{
	case 'a':
		if (ti.valid())
		{
			gzip = false;
			std::string error = srv_insert_peer(ti, false, find_user_by_torrent_pass(torrent_pass, ti.m_info_hash));
			s = error.empty() ? srv_select_peers(ti) : (boost::format("d14:failure reason%d:%se") % error.size() % error).str();
		}
		break;
	case 'd':
		if (srv_config().m_debug)
		{
			h += "Content-Type: text/html; charset=us-ascii\r\n";
			s = srv_debug(ti);
		}
		break;
	case 's':
		if (v.size() >= 7 && v[6] == 't')
		{
			h += "Content-Type: text/html; charset=us-ascii\r\n";
			s = srv_statistics();
		}
		else if (srv_config().m_full_scrape || !ti.m_info_hash.empty())
		{
			gzip = srv_config().m_gzip_scrape && ti.m_info_hash.empty();
 			s = srv_scrape(ti, find_user_by_torrent_pass(torrent_pass, ti.m_info_hash));
		}
		break;
	}
	if (s.empty())
	{
		if (!ti.m_info_hash.empty() || srv_config().m_redirect_url.empty())
			h = "HTTP/1.0 404 Not Found\r\n";
		else
		{
			h = "HTTP/1.0 302 Found\r\n"
				"Location: " + srv_config().m_redirect_url + (ti.m_info_hash.empty() ? "" : "?info_hash=" + uri_encode(ti.m_info_hash)) + "\r\n";
		}
	}
	else if (gzip)
	{
		shared_data s2 = xcc_z::gzip(s);
#ifndef NDEBUG
		static std::ofstream f("xbt_tracker_gzip.log");
		f << srv_time() << '\t' << v[5] << '\t' << s.size() << '\t' << s2.size() << std::endl;
#endif
		if (s2.size() + 24 < s.size())
		{
			h += "Content-Encoding: gzip\r\n";
			s = to_string(s2);
		}
	}
	h += "\r\n";
#ifdef WIN32
	m_write_b = shared_data(h.size() + s.size());
	memcpy(m_write_b.data(), h);
	memcpy(m_write_b.data() + h.size(), s);
	int r = m_s.send(m_write_b);
#else
	std::array<iovec, 2> d;
	d[0].iov_base = const_cast<char*>(h.data());
	d[0].iov_len = h.size();
	d[1].iov_base = const_cast<char*>(s.data());
	d[1].iov_len = s.size();
	msghdr m;
	m.msg_name = NULL;
	m.msg_namelen = 0;
	m.msg_iov = const_cast<iovec*>(d.data());
	m.msg_iovlen = d.size();
	m.msg_control = NULL;
	m.msg_controllen = 0;
	m.msg_flags = 0;
	int r = sendmsg(m_s, &m, MSG_NOSIGNAL);
#endif
	if (r == SOCKET_ERROR)
	{
		if (WSAGetLastError() != WSAECONNRESET)
			std::cerr << "send failed: " << Csocket::error2a(WSAGetLastError()) << std::endl;
	}
	else if (r != h.size() + s.size())
	{
#ifndef WIN32
		if (r < h.size())
		{
			m_write_b = shared_data(h.size() + s.size());
			memcpy(m_write_b.data(), h);
			memcpy(m_write_b.data() + h.size(), s);
		}
		else
		{
			m_write_b = make_shared_data(s);
			r -= h.size();
		}
#endif
		m_r = m_write_b;
		m_r.advance_begin(r);
	}
	if (m_r.empty())
		m_write_b.clear();
}
Пример #18
0
int Cconnection::run()
{
	return s() == INVALID_SOCKET || srv_time() - m_ctime > 10;
}