구현 | 서버생성

유효성 검사

서버 매니저는 configuration file을 의미 있는 단위(block)로 나누고, 각 블록에 대해 유효성을 검증한 뒤 문제가 없다면 서버 생성자의 인자로 넘겨 서버를 생성합니다. 서버는 여러 개가 만들어질 수 있기 때문에 서버 매니저의 벡터 멤버 변수로 관리합니다.

void
ServerManager::createServer(const std::string& configuration_file_path, char **env)
{
	std::string config_string = ft::getStringFromFile(configuration_file_path);
	std::string config_block;
	std::vector<std::string> server_strings;

	if (!splitConfigString(config_string, config_block, server_strings))
		throw (std::invalid_argument("Failed to split configuration string"));
	if (!isValidConfigBlock(config_block))
		throw (std::invalid_argument("Config block is not valid."));
	m_config = Config(config_block, env);
	for (size_t i = 0; i < server_strings.size(); ++i)
	{
		std::string server_block;
		std::vector<std::string> location_blocks;
		if (!splitServerString(server_strings[i], server_block, location_blocks))
			throw (std::invalid_argument("Failed to split Sever string(" + ft::to_string(i) + ")"));
		if (!isValidServerBlock(server_block))
			throw (std::invalid_argument("Server block(" + ft::to_string(i) + ") is not valid."));
		for (size_t j = 0; j < location_blocks.size(); ++j) {
			if (!isValidLocationBlock(location_blocks[j]))
				throw (std::invalid_argument("Location block(" + ft::to_string(i) \
				+ "-" + ft::to_string(j) + ") is not valid."));
		}
		m_servers.push_back(Server(this, server_block, location_blocks, &this->m_config));
		m_server_fdset.insert(m_servers.back().get_m_fd());
	}
	writeCreateServerLog();
}

Server 생성자

이미 유효성 검사가 끝난 safety block들이 인자로 들어오기 때문에, Server 생성자에서 해야 하는 작업은 많지 않습니다. server_block을 파싱하여 Server 인스턴스의 멤버 변수에 값을 저장하고, location block들은 그대로 Location 생성자에 넘겨 Server 인스턴스의 벡터 멤버 변수에 저장합니다. 그 외에는 일반적인 서버 프로그램과 같습니다.

Server::Server(
	ServerManager* server_manager,
	const std::string& server_block,
	std::vector<std::string>& location_blocks,
	Config* config)
{
...
	if((m_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1)
		throw std::runtime_error("SOCKET ERROR");
	if (setsockopt(m_fd, SOL_SOCKET, SO_REUSEADDR, &value, sizeof(int)) == -1)
		throw std::runtime_error("SOCKET_OPTION ERROR");
	ft::bzero(&server_addr, sizeof(struct sockaddr_in));
	server_addr.sin_family = AF_INET;
	server_addr.sin_addr.s_addr = ft::inet_addr(m_host.c_str());
	server_addr.sin_port = ft::ws_htons(m_port);
	if(bind(m_fd, reinterpret_cast<struct sockaddr *>(&server_addr), sizeof(struct sockaddr)) == -1)
		throw std::runtime_error("BIND ERROR");
	if(listen(m_fd, 256) == -1)
		throw std::runtime_error("LISTEN ERROR");
	if (fcntl(m_fd, F_SETFL, O_NONBLOCK) == -1)
		throw std::runtime_error("FCNTL ERROR");
...
}

허용되지 않은 함수들(inet_addr, inet_ntoa, htonl, htons)은 모두 만들어야 합니다. 서버 생성의 각 과정, 외부 함수를 호출할 때에는 예외처리를 해주어야 합니다.

Last updated