/* * 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 "ServerConnection.h" #include #include #include #include namespace Mad { namespace Net { Listener::Listener(const IPAddress &address0) throw(ConnectionException) : 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 ConnectionException("socket()", std::strerror(errno)); // Set non-blocking flag int flags = fcntl(sock, F_GETFL, 0); if(flags < 0) { close(sock); throw ConnectionException("fcntl()", std::strerror(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 ConnectionException("bind()", std::strerror(errno)); } if(listen(sock, 64) < 0) { close(sock); throw ConnectionException("listen()", std::strerror(errno)); } } 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); } std::vector Listener::getPollfds() const { std::vector pollfds; struct pollfd fd = {sock, POLLIN, 0}; pollfds.push_back(fd); for(std::list::const_iterator con = connections.begin(); con != connections.end(); ++con) pollfds.push_back((*con)->getPollfd()); return pollfds; } ServerConnection* Listener::getConnection(const std::map &pollfdMap) { // TODO: Logging int sd; struct sockaddr_in sa; socklen_t addrlen = sizeof(sa); while((sd = accept(sock, reinterpret_cast(&sa), &addrlen)) >= 0) { connections.push_back(new ServerConnection(sd, IPAddress(sa), dh_params)); addrlen = sizeof(sa); } for(std::list::iterator con = connections.begin(); con != connections.end(); ++con) { std::map::const_iterator events = pollfdMap.find((*con)->getSocket()); if(events != pollfdMap.end()) (*con)->sendReceive(*events->second); else (*con)->sendReceive(); } 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; } } }