/* * 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 #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) { ServerConnection *con = new ServerConnection(sd, IPAddress(sa), dh_params, x905CertFile, x905KeyFile); sigc::connection con1 = con->signalConnected().connect(sigc::bind(sigc::mem_fun(this, &Listener::connectHandler), con)); sigc::connection con2 = con->signalDisconnected().connect(sigc::bind(sigc::mem_fun(this, &Listener::disconnectHandler), con)); connections.insert(std::make_pair(con, std::make_pair(con1, con2))); addrlen = sizeof(sa); } } void Listener::connectHandler(ServerConnection *con) { std::map >::iterator it = connections.find(con); if(it == connections.end()) return; // Disconnect signal handlers it->second.first.disconnect(); it->second.second.disconnect(); connections.erase(it); signal(con); } void Listener::disconnectHandler(ServerConnection *con) { std::map >::iterator it = connections.find(con); if(it == connections.end()) return; delete it->first; connections.erase(it); } Listener::Listener(const std::string &x905CertFile0, const std::string &x905KeyFile0, const IPAddress &address0) throw(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 Exception("socket()", Exception::INTERNAL_ERRNO, errno); // Set non-blocking flag int flags = fcntl(sock, F_GETFL, 0); if(flags < 0) { close(sock); throw Exception("fcntl()", 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 Exception("bind()", Exception::INTERNAL_ERRNO, errno); } if(listen(sock, 64) < 0) { close(sock); throw Exception("listen()", Exception::INTERNAL_ERRNO, errno); } FdManager::get()->registerFd(sock, sigc::mem_fun(this, &Listener::acceptHandler), POLLIN); } Listener::~Listener() { for(std::map >::iterator con = connections.begin(); con != connections.end(); ++con) { con->first->disconnect(); delete con->first; } shutdown(sock, SHUT_RDWR); close(sock); gnutls_dh_params_deinit(dh_params); } } }