Exemplo n.º 1
0
Arquivo: main.cpp Projeto: WST/mawar
int main(int argc, const char **argv)
{
	// Конфигурация
	ConfigFile *config = new ConfigFile(PATH_CONFIG);
	
	// открыть лог файлы до смены пользователя
	open_access_log(PATH_ACCESS_LOG);
	open_error_log(PATH_ERROR_LOG);
	FILE *fpid = fopen(PATH_PID, "w");
	
	// установить лимиты до смены пользователя
	if ( getuid() == 0 )
	{
		struct rlimit rl;
		rl.rlim_cur = config->filesLimit();
		rl.rlim_max = config->filesLimit();
		if ( setrlimit(RLIMIT_NOFILE, &rl) == -1 )
		{
			fprintf(stderr, "setrlimit fault: %s\n", strerror(errno));
		}
	}
	else
	{
		struct rlimit rl;
		if ( getrlimit(RLIMIT_NOFILE, &rl) == -1 )
		{
			fprintf(stderr, "getrlimit fault: %s\n", strerror(errno));
		}
		else
		{
			rl.rlim_cur = config->filesLimit();
			if ( config->filesLimit() > rl.rlim_max )
			{
				fprintf(stderr, "only root can increase over hard limit (RLIMIT_NOFILE)\ntry to increase up to hard limit (%lu)\n", rl.rlim_max);
				rl.rlim_cur = rl.rlim_max;
			}
			if ( setrlimit(RLIMIT_NOFILE, &rl) == -1 )
			{
				fprintf(stderr, "setrlimit fault: %s\n", strerror(errno));
			}
		}
	}
	
	// если запущены под root, то сменить пользователя
	if ( getuid() == 0 )
	{
		fprintf(stdout, "Trying to switch to user: "******"\n");
		struct passwd *pw = getpwnam(config->user());
		if(pw)
		{
			if(setgid(pw->pw_gid) != 0) fprintf(stderr, "Failed to setgid!\n");
			if(setuid(pw->pw_uid) != 0 ) fprintf(stderr, "Failed to setuid!\n");
		}
		else
		{
			fprintf(stderr, "user %s not found\n", config->user());
		}
	}
	
	if ( argc > 1 && strcmp(argv[1], "-d") == 0 )
	{
		printf("try fork\n");
		pid_t parpid;
		if((parpid = fork()) < 0) {
			mawarError("Failed to fork!", 99);
		}
		else if(parpid != 0) {
			exit(0); // успешно создан дочерний процесс, основной можно завершить
		}
		setsid();
	}
	
	// после форка записать pid
	if ( fpid )
	{
		fprintf(fpid, "%d", getpid());
		fclose(fpid);
		fpid = 0;
	}
	
	// демон управляющий воркерами вводом-выводом
	struct rlimit rl;
	if ( getrlimit(RLIMIT_NOFILE, &rl) == -1 )
	{
		fprintf(stderr, "getrlimit fault: %s\n", strerror(errno));
		return 1;
	}
	printf("files limit: %lu\n", rl.rlim_cur);
	NetDaemon daemon(rl.rlim_cur, config->getOutputBuffers());
	
	// устанавливаем скорректированное число воркеров
	daemon.setWorkerCount(config->workers() - 1);
	
	// XMPP-сервер
	server = new XMPPServer(&daemon);
	server->config = config;
	
	// подключемся к c2s-порту из конфига
	server->bind(config->c2s());
	
	// не более 10 ожидающих соединений
	server->listen(10);
	
	// добавляем виртуальные хосты
	printf("[main] loading virtual hosts\n");
	for(XmlTag *vhost = config->firstHost(); vhost; vhost = config->nextHost(vhost)) {
		printf("[main] load vhost: %s\n", vhost->getAttribute("name").c_str());
		server->addHost(vhost->getAttribute("name"), vhost);
	}
	printf("[main] virtual hosts loaded\n");
	
	// асинхронный резолвер
	nanosoft::ptr<AsyncDNS> dns = new AsyncDNS(&daemon);
	daemon.addObject(dns);
	server->adns = dns;
	
	// добавляем сервер в демона
	daemon.addObject(server);
	
	int port = config->xep0114();
	if ( port > 0 ) {
		nanosoft::ptr<XEP0114Listener> xep0114 = new XEP0114Listener(server.getObject());
		xep0114->bind(port);
		xep0114->listen(10);
		daemon.addObject(xep0114);
	}
	
	port = config->s2s();
	if ( port > 0 )
	{
		server->s2s = new S2SListener(server.getObject());
		server->s2s->bind(port);
		server->s2s->listen(10);
		daemon.addObject(server->s2s);
	}
	
	string path = config->status();
	if ( path != "" )
	{
		nanosoft::ptr<ServerStatus> status = new ServerStatus(server.getObject());
		status->bind(path.c_str());
		status->listen(1);
		daemon.addObject(status);
	}
	
	// консоль управления сервером
	//MyConsole console(&daemon, 0);
	//daemon.addObject(&console);
	
	struct sigaction sa;
	memset(&sa, 0, sizeof(sa));
	sa.sa_handler = on_signal;
	sigaction(SIGTERM, &sa, 0);
	sigaction(SIGHUP, &sa, 0);
	sigaction(SIGINT, &sa, 0);
	
	// запускаем демона
	fprintf(stderr, "[main] run daemon\n");
	daemon.run();
	fprintf(stderr, "[main] daemon exited\n");
	
	cleanup();
	
	return 0;
}