/* * Listener.cpp * * Copyright (C) 2008 Matthias Schiffer * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program. If not, see . */ #include "Listener.h" #include "FdManager.h" #include "ServerConnection.h" #include #include #include namespace Mad { namespace Net { void Listener::acceptHandler(int) { int sd; struct sockaddr_in sa; socklen_t addrlen = sizeof(sa); while((sd = accept(sock, (struct sockaddr*)&sa, &addrlen)) >= 0) { connections.push_back(new ServerConnection(sd, IPAddress(sa), dh_params, x905CertFile, x905KeyFile)); addrlen = sizeof(sa); } } Listener::Listener(const std::string &x905CertFile0, const std::string &x905KeyFile0, const IPAddress &address0) throw(Common::Exception) : x905CertFile(x905CertFile0), x905KeyFile(x905KeyFile0), address(address0) { gnutls_dh_params_init(&dh_params); gnutls_dh_params_generate2(dh_params, 768); sock = socket(PF_INET, SOCK_STREAM, 0); if(sock < 0) throw Common::Exception("socket()", Common::Exception::INTERNAL_ERRNO, errno); // Set non-blocking flag int flags = fcntl(sock, F_GETFL, 0); if(flags < 0) { close(sock); throw Common::Exception("fcntl()", Common::Exception::INTERNAL_ERRNO, errno); } fcntl(sock, F_SETFL, flags | O_NONBLOCK); // Don't linger struct linger linger = {1, 0}; setsockopt(sock, SOL_SOCKET, SO_LINGER, &linger, sizeof(linger)); if(bind(sock, address.getSockAddr(), address.getSockAddrLength()) < 0) { close(sock); throw Common::Exception("bind()", Common::Exception::INTERNAL_ERRNO, errno); } if(listen(sock, 64) < 0) { close(sock); throw Common::Exception("listen()", Common::Exception::INTERNAL_ERRNO, errno); } FdManager::get()->registerFd(sock, sigc::mem_fun(this, &Listener::acceptHandler), POLLIN); } Listener::~Listener() { for(std::list::iterator con = connections.begin(); con != connections.end(); ++con) { (*con)->disconnect(); delete *con; } shutdown(sock, SHUT_RDWR); close(sock); gnutls_dh_params_deinit(dh_params); } ServerConnection* Listener::getConnection() { // TODO: Logging for(std::list::iterator con = connections.begin(); con != connections.end();) { if(!(*con)->isConnected()) { delete *con; connections.erase(con++); // Erase unincremented iterator continue; } if(!(*con)->isConnecting()) { ServerConnection *connection = *con; connections.erase(con); return connection; } ++con; } return 0; } } }