diff options
Diffstat (limited to 'src/Net/ServerConnection.cpp')
-rw-r--r-- | src/Net/ServerConnection.cpp | 145 |
1 files changed, 145 insertions, 0 deletions
diff --git a/src/Net/ServerConnection.cpp b/src/Net/ServerConnection.cpp new file mode 100644 index 0000000..4a0bf15 --- /dev/null +++ b/src/Net/ServerConnection.cpp @@ -0,0 +1,145 @@ +/* + * ServerConnection.cpp + * + * Copyright (C) 2008 Matthias Schiffer <matthias@gamezock.de> + * + * 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 <http://www.gnu.org/licenses/>. + */ + +#include "ServerConnection.h" +#include "IPAddress.h" +#include <cstring> +#include <cerrno> +#include <fstream> +#include <sys/socket.h> + +namespace Mad { +namespace Net { + +bool ServerConnection::loadDHParams(const std::string &file) { + std::ifstream stream(file.c_str()); + + if(!stream.is_open()) + return false; + + std::string data, line; + + while(!stream.eof()) { + std::getline(stream, line); + data += line + "\n"; + } + + stream.close(); + + gnutls_datum_t datum; + datum.data = new unsigned char[data.size()]; + datum.size = data.size(); + + std::memcpy(datum.data, data.data(), data.size()); + + int ret = gnutls_dh_params_import_pkcs3(dh_params, &datum, GNUTLS_X509_FMT_PEM); + + if(ret == 0) + gnutls_anon_set_server_dh_params(anoncred, dh_params); + + delete [] datum.data; + + return (ret == 0); +} + +bool ServerConnection::listen(const IPAddress &address) { + const int kx_list[] = {GNUTLS_KX_ANON_DH, 0}; + + if(connected) + disconnect(); + + int listen_sock = socket(PF_INET, SOCK_STREAM, 0); + if(listen_sock < 0) + return false; + + peer = new IPAddress(address); + + if(bind(listen_sock, peer->getSockAddr(), peer->getSockAddrLength()) < 0) { + close(listen_sock); + delete peer; + return false; + } + + if(::listen(listen_sock, 1024) < 0) { + close(listen_sock); + delete peer; + return false; + } + + sock = accept(listen_sock, NULL, NULL); + if(sock < 0) { + close(listen_sock); + delete peer; + return false; + } + + close(listen_sock); + + connected = true; + + gnutls_init(&session, GNUTLS_SERVER); + + gnutls_set_default_priority(session); + gnutls_kx_set_priority(session, kx_list); + + gnutls_credentials_set(session, GNUTLS_CRD_ANON, anoncred); + + gnutls_transport_set_ptr(session, reinterpret_cast<gnutls_transport_ptr_t>(sock)); + + int ret = gnutls_handshake(session); + if(ret < 0) { + disconnect(); + + return false; + } + + return true; +} + +void ServerConnection::disconnect() { + if(!connected) + return; + + gnutls_bye(session, GNUTLS_SHUT_RDWR); + + shutdown(sock, SHUT_RDWR); + close(sock); + + gnutls_deinit(session); + + delete peer; + + connected = false; +} + +bool ServerConnection::dataPending() { + if(!connected) + return false; + + fd_set fds; + FD_ZERO(&fds); + FD_SET(sock, &fds); + + struct timeval timeout = {0, 0}; + + return (select(sock + 1, &fds, NULL, NULL, &timeout) == 1); +} + +} +} |