<commit_before>#include <QCoreApplication>
#include <QSettings>
#include <QStringList>
#include <QThread>
#include <QFile>
#include <QTextStream>
#include <QDebug>

#include <unistd.h>
#include <sys/types.h>
#include <pwd.h>
#include <grp.h>
#include <getopt.h>

#include "Bitoxy.h"
#include "Router.h"
#include "routers/StaticRouter.h"
#include "routers/SqlRouter.h"
#include "services/ftp/FtpServer.h"

Bitoxy::Bitoxy(QObject *parent) :
        QObject(parent)
{
}

Bitoxy::~Bitoxy()
{
	qDebug() << "Stopping workers";

	foreach(Worker *w, workers)
		w->thread()->quit();

	qDebug() << "Waiting for workers to quit...";

	foreach(Worker *w, workers)
	{
		w->thread()->wait();
		delete w;
	}

	QList<Router*> routers = Router::routers();
	foreach(Router *r, routers)
		delete r;
}

bool Bitoxy::init(QString config)
{
	QSettings cfg(config, QSettings::IniFormat);

	if(cfg.status() == QSettings::AccessError)
	{
		qCritical() << "Cannot access config file" << config;
		return false;
	} else if(cfg.status() == QSettings::FormatError) {
		qCritical() << "Cannot parse config file" << config;
		return false;
	}

	QStringList groups = cfg.childGroups();
	QHash<QString, int> routers;

	QString user, group;
	uid_t uid = geteuid();
	gid_t gid = getegid();
	uid_t newUid;
	gid_t newGid;
	bool dropPrivileges = false;

	if(!uid || !gid)
	{
		user = cfg.value("User").toString();
		group = cfg.value("Group").toString();

		if(user.isEmpty() || group.isEmpty())
		{
			qWarning() << "WARNING: Running as root! U mad?";
		} else {
			struct passwd *pwd;
			struct group *grp;

			if((pwd = getpwnam(user.toAscii().data())) == NULL)
			{
				qWarning() << "User" << user << "does not exist.";
				return false;
			} else if((grp = getgrnam(group.toAscii().data())) == NULL) {
				qWarning() << "Group" << group << "does not exist.";
				return false;
			}

			if(!pwd->pw_uid || !grp->gr_gid)
			{
				qWarning() << "WARNING: Running as root! You're just mad.";
			}

			dropPrivileges = true;
			newUid = pwd->pw_uid;
			newGid = grp->gr_gid;
		}
	}

	foreach(QString group, groups)
	{
		QStringList type = group.split(':');

		if(type.count() < 2)
		{
			qDebug() << "Invalid group" << group;
			continue;
		}

		cfg.beginGroup(group);

		if(!type[0].compare("service", Qt::CaseInsensitive))
		{
			BaseTcpServer *server = 0;
			QHostAddress addr;
			quint16 port;
			QString router;
			int routerId = 0;

			if(!addr.setAddress(cfg.value("Host", "0.0.0.0").toString()))
			{
				addr.setAddress("0.0.0.0");
			}

			if(!(port = cfg.value("Port", 0).toInt()))
			{
				qWarning() << "Invalid port";

				cfg.endGroup();
				continue;
			}

			if((router = cfg.value("Router").toString()).isEmpty())
			{
				qWarning() << "No router specified for service" << type[1];

				cfg.endGroup();
				continue;
			} else {
				routerId = routers[router];
			}

#ifdef SERVICE_FTP
			if(!type[1].compare("ftp", Qt::CaseInsensitive))
			{
				server = new FtpServer(cfg, this);
				if(server->listen(addr, port))
					qDebug() << "FTP server: Listening on" << addr << port;
				else
					qDebug() << "FTP server: Unable to listen:" << server->serverError();
			}
#endif

			if(server)
			{
				connect(server, SIGNAL(newConnection(IncomingConnection)),
					this, SLOT(processNewConnection(IncomingConnection))
				);

				server->setRouter(routerId);
			}

		} else if(!type[0].compare("router", Qt::CaseInsensitive)) {
			Router *router = 0;

			if(!type[1].compare("Static", Qt::CaseInsensitive))
			{
				router = new StaticRouter(cfg);

			} else if(!type[1].compare("Sql", Qt::CaseInsensitive)) {
				router = new SqlRouter(cfg);
			}

			if(router)
			{
				qDebug() << "Register router" << type[1];
				routers[ type[2] ] = Router::registerRouter(router);
			}
		}

		cfg.endGroup();
	}

	if(dropPrivileges)
	{
		if(setgid(newGid) == -1)
		{
			qWarning() << "Unable to setgid" << newGid;
			return false;<commit_msg>One service can be listening on multiple IP addresses.<commit_after>#include <QCoreApplication>
#include <QSettings>
#include <QStringList>
#include <QThread>
#include <QFile>
#include <QTextStream>
#include <QDebug>

#include <unistd.h>
#include <sys/types.h>
#include <pwd.h>
#include <grp.h>
#include <getopt.h>

#include "Bitoxy.h"
#include "Router.h"
#include "routers/StaticRouter.h"
#include "routers/SqlRouter.h"
#include "services/ftp/FtpServer.h"

Bitoxy::Bitoxy(QObject *parent) :
        QObject(parent)
{
}

Bitoxy::~Bitoxy()
{
	qDebug() << "Stopping workers";

	foreach(Worker *w, workers)
		w->thread()->quit();

	qDebug() << "Waiting for workers to quit...";

	foreach(Worker *w, workers)
	{
		w->thread()->wait();
		delete w;
	}

	QList<Router*> routers = Router::routers();
	foreach(Router *r, routers)
		delete r;
}

bool Bitoxy::init(QString config)
{
	QSettings cfg(config, QSettings::IniFormat);

	if(cfg.status() == QSettings::AccessError)
	{
		qCritical() << "Cannot access config file" << config;
		return false;
	} else if(cfg.status() == QSettings::FormatError) {
		qCritical() << "Cannot parse config file" << config;
		return false;
	}

	QStringList groups = cfg.childGroups();
	QHash<QString, int> routers;

	QString user, group;
	uid_t uid = geteuid();
	gid_t gid = getegid();
	uid_t newUid;
	gid_t newGid;
	bool dropPrivileges = false;

	if(!uid || !gid)
	{
		user = cfg.value("User").toString();
		group = cfg.value("Group").toString();

		if(user.isEmpty() || group.isEmpty())
		{
			qWarning() << "WARNING: Running as root! U mad?";
		} else {
			struct passwd *pwd;
			struct group *grp;

			if((pwd = getpwnam(user.toAscii().data())) == NULL)
			{
				qWarning() << "User" << user << "does not exist.";
				return false;
			} else if((grp = getgrnam(group.toAscii().data())) == NULL) {
				qWarning() << "Group" << group << "does not exist.";
				return false;
			}

			if(!pwd->pw_uid || !grp->gr_gid)
			{
				qWarning() << "WARNING: Running as root! You're just mad.";
			}

			dropPrivileges = true;
			newUid = pwd->pw_uid;
			newGid = grp->gr_gid;
		}
	}

	foreach(QString group, groups)
	{
		QStringList type = group.split(':');

		if(type.count() < 2)
		{
			qDebug() << "Invalid group" << group;
			continue;
		}

		cfg.beginGroup(group);

		if(!type[0].compare("service", Qt::CaseInsensitive))
		{
			BaseTcpServer *server = 0;
			QStringList addrs;
			QHostAddress hostAddr;
			quint16 port;
			QString router;
			int routerId = 0;

			addrs = cfg.value("Host").toStringList();

			foreach(QString addr, addrs)
			{
				if(!hostAddr.setAddress(addr))
				{
					qWarning() << "Invalid address" << addr;
					continue;
				}

				if(!(port = cfg.value("Port", 0).toInt()))
				{
					qWarning() << "Invalid port";
					continue;
				}

				if((router = cfg.value("Router").toString()).isEmpty())
				{
					qWarning() << "No router specified for service" << type[1];
					continue;
				} else {
					routerId = routers[router];
				}

#ifdef SERVICE_FTP
				if(!type[1].compare("ftp", Qt::CaseInsensitive))
				{
					server = new FtpServer(cfg, this);
					if(server->listen(hostAddr, port))
						qDebug() << "FTP server: Listening on" << QString("%1:%2").arg(addr).arg(port);
					else
						qDebug() << "FTP server: Unable to listen on" << QString("%1:%2").arg(addr).arg(port) <<":" << server->serverError();
				}
#endif

				if(server)
				{
					connect(server, SIGNAL(newConnection(IncomingConnection)),
						this, SLOT(processNewConnection(IncomingConnection))
					);

					server->setRouter(routerId);
				}
			}

		} else if(!type[0].compare("router", Qt::CaseInsensitive)) {
			Router *router = 0;

			if(!type[1].compare("Static", Qt::CaseInsensitive))
			{
				router = new StaticRouter(cfg);

			} else if(!type[1].compare("Sql", Qt::CaseInsensitive)) {
				router = new SqlRouter(cfg);
			}

			if(router)
			{
				qDebug() << "Registered router" << type[1];
				routers[ type[2] ] = Router::registerRouter(router);
			}
		}

		cfg.endGroup();
	}

	if(dropPrivileges)
	{
		if(setgid(newGid) == -1)
		{
			qWarning() << "Unable to setgid" << newGid;
			return false;
{'fraction_non_alphanumeric': 0.18181818181818182, 'fraction_numerical': 0.005471956224350205, 'mean_word_length': 3.5641316685584563, 'pattern_counts': {'":': 1, '<': 151, '<?xml version=': 0, '>': 53, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 2, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6223260', 'n_tokens_mistral': 3437, 'n_tokens_neox': 2899, 'n_words': 612}