From 113b1f4bbdecfab24ed9781b730a76a442adad6f Mon Sep 17 00:00:00 2001 From: Matthias Schiffer Date: Fri, 19 Sep 2008 11:15:14 +0200 Subject: Exceptions vereinheitlicht --- src/Common/Exception.cpp | 34 ++++++++++++++++++++++--------- src/Common/Exception.h | 26 +++++++++++++++--------- src/Core/ConfigManager.cpp | 2 +- src/Core/ConnectionManager.cpp | 6 +++--- src/Net/ClientConnection.cpp | 8 ++++---- src/Net/ClientConnection.h | 4 ++-- src/Net/ConnectionException.h | 42 --------------------------------------- src/Net/Exception.h | 36 --------------------------------- src/Net/IPAddress.cpp | 10 +++++----- src/Net/IPAddress.h | 6 +++--- src/Net/InvalidAddressException.h | 41 -------------------------------------- src/Net/Listener.cpp | 10 +++++----- src/Net/Listener.h | 5 +++-- src/Net/Makefile.am | 3 +-- src/Net/Makefile.in | 4 +--- src/Net/Packets/ErrorPacket.cpp | 9 +++++++-- src/Net/Packets/ErrorPacket.h | 10 ++++++++-- src/Net/ServerConnection.h | 2 +- src/mad.cpp | 4 ++-- src/madc.cpp | 4 ++-- 20 files changed, 90 insertions(+), 176 deletions(-) delete mode 100644 src/Net/ConnectionException.h delete mode 100644 src/Net/Exception.h delete mode 100644 src/Net/InvalidAddressException.h diff --git a/src/Common/Exception.cpp b/src/Common/Exception.cpp index 002ba82..dc04f7d 100644 --- a/src/Common/Exception.cpp +++ b/src/Common/Exception.cpp @@ -19,25 +19,41 @@ #include "Exception.h" +#include +#include + namespace Mad { namespace Common { -const char* Exception::strerror() const { +std::string Exception::strerror() const { + std::string ret; + + if(!where.empty()) + ret = where + ": "; + switch(errorCode) { case SUCCESS: - return "Success"; + return ret + "Success"; case UNEXPECTED_PACKET: - return "An unexpected packet was received"; + return ret + "An unexpected packet was received"; case INVALID_ACTION: - return "The action is invalid"; + return ret + "The action is invalid"; + case NOT_AVAILABLE: + return ret + "Not available"; + case NOT_FINISHED: + return ret + "Not finished"; + case INTERNAL_ERRNO: + return ret + "Internal error: " + std::strerror(subCode); + case INTERNAL_GNUTLS: + return ret + "GnuTLS error: " + gnutls_strerror(subCode); + case INVALID_ADDRESS: + return ret + "Invalid address"; case ALREADY_IDENTIFIED: - return "The host is already identified"; + return ret + "The host is already identified"; case UNKNOWN_DAEMON: - return "The daemon is unknown"; - case DAEMON_INACTIVE: - return "The daemon is inactive"; + return ret + "The daemon is unknown"; default: - return "Unknown error"; + return ret + "Unknown error"; } } diff --git a/src/Common/Exception.h b/src/Common/Exception.h index 25bc56c..9862f9b 100644 --- a/src/Common/Exception.h +++ b/src/Common/Exception.h @@ -20,31 +20,39 @@ #ifndef MAD_COMMON_EXCEPTION_H_ #define MAD_COMMON_EXCEPTION_H_ +#include + namespace Mad { namespace Common { class Exception { public: enum ErrorCode { - SUCCESS = 0x0000, UNEXPECTED_PACKET = 0x0001, INVALID_ACTION = 0x0002, - NOT_FINISHED = 0x0010, - ALREADY_IDENTIFIED = 0x0020, UNKNOWN_DAEMON = 0x0021, DAEMON_INACTIVE = 0x0022 + SUCCESS = 0x0000, UNEXPECTED_PACKET = 0x0001, INVALID_ACTION = 0x0002, NOT_AVAILABLE = 0x0003, NOT_FINISHED = 0x0004, + INTERNAL_ERRNO = 0x0010, INTERNAL_GNUTLS = 0x0011, + INVALID_ADDRESS = 0x0020, + ALREADY_IDENTIFIED = 0x0030, UNKNOWN_DAEMON = 0x0031 }; private: + std::string where; + ErrorCode errorCode; - unsigned long subCode; - unsigned long subSubCode; + long subCode; + long subSubCode; public: - Exception(ErrorCode errorCode0, unsigned long subCode0 = 0, unsigned long subSubCode0 = 0) : errorCode(errorCode0), subCode(subCode0), subSubCode(subSubCode0) {} + Exception(const std::string &where0, ErrorCode errorCode0, long subCode0 = 0, long subSubCode0 = 0) + : where(where0), errorCode(errorCode0), subCode(subCode0), subSubCode(subSubCode0) {} + Exception(ErrorCode errorCode0, long subCode0 = 0, long subSubCode0 = 0) : errorCode(errorCode0), subCode(subCode0), subSubCode(subSubCode0) {} virtual ~Exception() {} + const std::string& getWhere() const {return where;} ErrorCode getErrorCode() const {return errorCode;} - unsigned long getSubCode() const {return subCode;} - unsigned long getSubSubCode() const {return subSubCode;} + long getSubCode() const {return subCode;} + long getSubSubCode() const {return subSubCode;} - const char* strerror() const; + std::string strerror() const; }; } diff --git a/src/Core/ConfigManager.cpp b/src/Core/ConfigManager.cpp index 4484420..9361493 100644 --- a/src/Core/ConfigManager.cpp +++ b/src/Core/ConfigManager.cpp @@ -38,7 +38,7 @@ bool ConfigManager::parseLine(const std::vector §ion, const std try { listeners.push_back(Net::IPAddress(value)); } - catch(Net::InvalidAddressException &e) { + catch(Common::Exception &e) { // TODO Logging } } diff --git a/src/Core/ConnectionManager.cpp b/src/Core/ConnectionManager.cpp index 546d097..ceefe18 100644 --- a/src/Core/ConnectionManager.cpp +++ b/src/Core/ConnectionManager.cpp @@ -81,7 +81,7 @@ ConnectionManager::ConnectionManager() { try { listeners.push_back(new Net::Listener(configManager->getX509CertFile(), configManager->getX509KeyFile())); } - catch(Net::Exception &e) { + catch(Common::Exception &e) { // TODO Log error } } @@ -90,7 +90,7 @@ ConnectionManager::ConnectionManager() { try { listeners.push_back(new Net::Listener(configManager->getX509CertFile(), configManager->getX509KeyFile(), *address)); } - catch(Net::Exception &e) { + catch(Common::Exception &e) { // TODO Log error } } @@ -169,7 +169,7 @@ Net::Connection* ConnectionManager::getDaemonConnection(const std::string &name) throw Common::Exception(Common::Exception::UNKNOWN_DAEMON); if(!daemon->second) - throw Common::Exception(Common::Exception::DAEMON_INACTIVE); + throw Common::Exception(Common::Exception::NOT_AVAILABLE); return daemon->second; } diff --git a/src/Net/ClientConnection.cpp b/src/Net/ClientConnection.cpp index 695cba5..5c602e1 100644 --- a/src/Net/ClientConnection.cpp +++ b/src/Net/ClientConnection.cpp @@ -52,7 +52,7 @@ void ClientConnection::connectionHeader() { rawReceive(sizeof(ConnectionHeader), sigc::mem_fun(this, &ClientConnection::connectionHeaderReceiveHandler)); } -void ClientConnection::connect(const IPAddress &address, bool daemon0) throw(ConnectionException) { +void ClientConnection::connect(const IPAddress &address, bool daemon0) throw(Common::Exception) { daemon = daemon0; if(isConnected()) @@ -61,7 +61,7 @@ void ClientConnection::connect(const IPAddress &address, bool daemon0) throw(Con sock = socket(PF_INET, SOCK_STREAM, 0); if(sock < 0) - throw ConnectionException("socket()", std::strerror(errno)); + throw Common::Exception("socket()", Common::Exception::INTERNAL_ERRNO, errno); if(peer) delete peer; @@ -73,7 +73,7 @@ void ClientConnection::connect(const IPAddress &address, bool daemon0) throw(Con close(sock); delete peer; peer = 0; - throw ConnectionException("connect()", std::strerror(errno)); + throw Common::Exception("connect()", Common::Exception::INTERNAL_ERRNO, errno); } // Set non-blocking flag @@ -82,7 +82,7 @@ void ClientConnection::connect(const IPAddress &address, bool daemon0) throw(Con if(flags < 0) { close(sock); - throw ConnectionException("fcntl()", std::strerror(errno)); + throw Common::Exception("fcntl()", Common::Exception::INTERNAL_ERRNO, errno); } fcntl(sock, F_SETFL, flags | O_NONBLOCK); diff --git a/src/Net/ClientConnection.h b/src/Net/ClientConnection.h index 280f382..88bdf09 100644 --- a/src/Net/ClientConnection.h +++ b/src/Net/ClientConnection.h @@ -21,7 +21,7 @@ #define MAD_NET_CLIENTCONNECTION_H_ #include "Connection.h" -#include "ConnectionException.h" +#include namespace Mad { namespace Net { @@ -40,7 +40,7 @@ class ClientConnection : public Connection { public: ClientConnection() : daemon(0) {} - void connect(const IPAddress &address, bool daemon0 = false) throw(ConnectionException); + void connect(const IPAddress &address, bool daemon0 = false) throw(Common::Exception); }; } diff --git a/src/Net/ConnectionException.h b/src/Net/ConnectionException.h deleted file mode 100644 index cb9e10e..0000000 --- a/src/Net/ConnectionException.h +++ /dev/null @@ -1,42 +0,0 @@ -/* - * ConnectionException.h - * - * 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 . - */ - -#ifndef MAD_NET_CONNECTIONEXCEPTION_H_ -#define MAD_NET_CONNECTIONEXCEPTION_H_ - -#include "Exception.h" - -namespace Mad { -namespace Net { - -class ConnectionException : public Exception { - private: - std::string str; - - public: - ConnectionException(const std::string &during, const std::string &error) - : str(during + ": " + error) {} - - virtual std::string& what() {return str;} -}; - -} -} - -#endif /*MAD_NET_CONNECTIONEXCEPTION_H_*/ diff --git a/src/Net/Exception.h b/src/Net/Exception.h deleted file mode 100644 index 10a9167..0000000 --- a/src/Net/Exception.h +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Exception.h - * - * 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 . - */ - -#ifndef MAD_NET_EXCEPTION_H_ -#define MAD_NET_EXCEPTION_H_ - -#include - -namespace Mad { -namespace Net { - -class Exception { - public: - virtual std::string& what() = 0; -}; - -} -} - -#endif /*MAD_NET_EXCEPTION_H_*/ diff --git a/src/Net/IPAddress.cpp b/src/Net/IPAddress.cpp index 9c9793e..6bf79a3 100644 --- a/src/Net/IPAddress.cpp +++ b/src/Net/IPAddress.cpp @@ -36,7 +36,7 @@ IPAddress::IPAddress(uint32_t address, uint16_t port0) : addr(address), port(por sa.sin_addr.s_addr = htonl(addr); } -IPAddress::IPAddress(const std::string &address) throw(InvalidAddressException) { +IPAddress::IPAddress(const std::string &address) throw(Common::Exception) { std::string ip; size_t pos = address.find_first_of(':'); @@ -51,7 +51,7 @@ IPAddress::IPAddress(const std::string &address) throw(InvalidAddressException) char *endptr; port = std::strtol(address.substr(pos+1).c_str(), &endptr, 10); if(*endptr != 0 || port == 0) - throw InvalidAddressException(address); + throw Common::Exception(Common::Exception::INVALID_ADDRESS); } sa.sin_family = AF_INET; @@ -60,17 +60,17 @@ IPAddress::IPAddress(const std::string &address) throw(InvalidAddressException) if(ip == "*") sa.sin_addr.s_addr = INADDR_ANY; else if(!inet_pton(AF_INET, ip.c_str(), &sa.sin_addr)) - throw InvalidAddressException(address); + throw Common::Exception(Common::Exception::INVALID_ADDRESS); addr = ntohl(sa.sin_addr.s_addr); } -IPAddress::IPAddress(const std::string &address, uint16_t port0) throw(InvalidAddressException) : port(port0) { +IPAddress::IPAddress(const std::string &address, uint16_t port0) throw(Common::Exception) : port(port0) { sa.sin_family = AF_INET; sa.sin_port = htons(port); if(!inet_pton(AF_INET, address.c_str(), &sa.sin_addr)) - throw InvalidAddressException(address); + throw Common::Exception(Common::Exception::INVALID_ADDRESS); addr = ntohl(sa.sin_addr.s_addr); } diff --git a/src/Net/IPAddress.h b/src/Net/IPAddress.h index 1d6140f..d67ec3e 100644 --- a/src/Net/IPAddress.h +++ b/src/Net/IPAddress.h @@ -20,7 +20,7 @@ #ifndef MAD_NET_IPADDRESS_H_ #define MAD_NET_IPADDRESS_H_ -#include "InvalidAddressException.h" +#include #include #include @@ -39,8 +39,8 @@ class IPAddress { // TODO Default port IPAddress(uint16_t port0 = 6666); IPAddress(uint32_t address, uint16_t port0); - IPAddress(const std::string &address) throw(InvalidAddressException); - IPAddress(const std::string &address, uint16_t port0) throw(InvalidAddressException); + IPAddress(const std::string &address) throw(Common::Exception); + IPAddress(const std::string &address, uint16_t port0) throw(Common::Exception); IPAddress(const struct sockaddr_in &address); uint32_t getAddress() const {return addr;} diff --git a/src/Net/InvalidAddressException.h b/src/Net/InvalidAddressException.h deleted file mode 100644 index a547106..0000000 --- a/src/Net/InvalidAddressException.h +++ /dev/null @@ -1,41 +0,0 @@ -/* - * InvalidAddressException.h - * - * 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 . - */ - -#ifndef MAD_NET_INVALIDADDRESSEXCEPTION_H_ -#define MAD_NET_INVALIDADDRESSEXCEPTION_H_ - -#include "Exception.h" - -namespace Mad { -namespace Net { - -class InvalidAddressException : public Exception { - private: - std::string str; - - public: - InvalidAddressException(const std::string &addr) : str("Invalid address: " + addr) {} - - virtual std::string& what() {return str;} -}; - -} -} - -#endif /*MAD_NET_INVALIDADDRESSEXCEPTION_H_*/ diff --git a/src/Net/Listener.cpp b/src/Net/Listener.cpp index f470896..9233a79 100644 --- a/src/Net/Listener.cpp +++ b/src/Net/Listener.cpp @@ -26,7 +26,7 @@ namespace Mad { namespace Net { -Listener::Listener(const std::string &x905CertFile0, const std::string &x905KeyFile0, const IPAddress &address0) throw(ConnectionException) +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); @@ -34,7 +34,7 @@ Listener::Listener(const std::string &x905CertFile0, const std::string &x905KeyF sock = socket(PF_INET, SOCK_STREAM, 0); if(sock < 0) - throw ConnectionException("socket()", std::strerror(errno)); + throw Common::Exception("socket()", Common::Exception::INTERNAL_ERRNO, errno); // Set non-blocking flag int flags = fcntl(sock, F_GETFL, 0); @@ -42,7 +42,7 @@ Listener::Listener(const std::string &x905CertFile0, const std::string &x905KeyF if(flags < 0) { close(sock); - throw ConnectionException("fcntl()", std::strerror(errno)); + throw Common::Exception("fcntl()", Common::Exception::INTERNAL_ERRNO, errno); } fcntl(sock, F_SETFL, flags | O_NONBLOCK); @@ -54,13 +54,13 @@ Listener::Listener(const std::string &x905CertFile0, const std::string &x905KeyF if(bind(sock, address.getSockAddr(), address.getSockAddrLength()) < 0) { close(sock); - throw ConnectionException("bind()", std::strerror(errno)); + throw Common::Exception("bind()", Common::Exception::INTERNAL_ERRNO, errno); } if(listen(sock, 64) < 0) { close(sock); - throw ConnectionException("listen()", std::strerror(errno)); + throw Common::Exception("listen()", Common::Exception::INTERNAL_ERRNO, errno); } } diff --git a/src/Net/Listener.h b/src/Net/Listener.h index 63e12c6..9c4ddab 100644 --- a/src/Net/Listener.h +++ b/src/Net/Listener.h @@ -21,7 +21,8 @@ #define MAD_NET_LISTENER_H_ #include "IPAddress.h" -#include "ConnectionException.h" +#include + #include #include #include @@ -49,7 +50,7 @@ class Listener { Listener& operator=(const Listener &o); public: - Listener(const std::string &x905CertFile0, const std::string &x905KeyFile0, const IPAddress &address0 = IPAddress()) throw(ConnectionException); + Listener(const std::string &x905CertFile0, const std::string &x905KeyFile0, const IPAddress &address0 = IPAddress()) throw(Common::Exception); virtual ~Listener(); std::vector getPollfds() const; diff --git a/src/Net/Makefile.am b/src/Net/Makefile.am index 967e989..84ef644 100644 --- a/src/Net/Makefile.am +++ b/src/Net/Makefile.am @@ -4,5 +4,4 @@ noinst_LTLIBRARIES = libnet.la libnet_la_SOURCES = ClientConnection.cpp ServerConnection.cpp Connection.cpp IPAddress.cpp Listener.cpp Packet.cpp libnet_la_LIBADD = Packets/libpackets.la -noinst_HEADERS = ClientConnection.h ServerConnection.h Connection.h Exception.h ConnectionException.h \ - InvalidAddressException.h IPAddress.h Listener.h Packet.h +noinst_HEADERS = ClientConnection.h ServerConnection.h Connection.h IPAddress.h Listener.h Packet.h diff --git a/src/Net/Makefile.in b/src/Net/Makefile.in index 02f1166..3cf8ff9 100644 --- a/src/Net/Makefile.in +++ b/src/Net/Makefile.in @@ -200,9 +200,7 @@ SUBDIRS = Packets noinst_LTLIBRARIES = libnet.la libnet_la_SOURCES = ClientConnection.cpp ServerConnection.cpp Connection.cpp IPAddress.cpp Listener.cpp Packet.cpp libnet_la_LIBADD = Packets/libpackets.la -noinst_HEADERS = ClientConnection.h ServerConnection.h Connection.h Exception.h ConnectionException.h \ - InvalidAddressException.h IPAddress.h Listener.h Packet.h - +noinst_HEADERS = ClientConnection.h ServerConnection.h Connection.h IPAddress.h Listener.h Packet.h all: all-recursive .SUFFIXES: diff --git a/src/Net/Packets/ErrorPacket.cpp b/src/Net/Packets/ErrorPacket.cpp index 2a72415..28d364a 100644 --- a/src/Net/Packets/ErrorPacket.cpp +++ b/src/Net/Packets/ErrorPacket.cpp @@ -18,6 +18,7 @@ */ #include "ErrorPacket.h" +#include namespace Mad { namespace Net { @@ -26,18 +27,22 @@ namespace Packets { ErrorPacket::ErrorPacket(Type type, uint16_t requestId, const Common::Exception &exception) : Packet(type, requestId) { - setLength(sizeof(ErrorData)); + setLength(sizeof(ErrorData) + exception.getWhere().length()); errorData = (ErrorData*)&rawData->data; errorData->errorCode = htonl(exception.getErrorCode()); errorData->subCode = htonl(exception.getSubCode()); errorData->subSubCode = htonl(exception.getSubSubCode()); + + std::memcpy(errorData->where, exception.getWhere().c_str(), exception.getWhere().length()); } ErrorPacket& ErrorPacket::operator=(const Packet &p) { Packet::operator=(p); - setLength(sizeof(ErrorData)); + if(getLength() < sizeof(ErrorData)) + setLength(sizeof(ErrorData)); + errorData = (ErrorData*)&rawData->data; return *this; diff --git a/src/Net/Packets/ErrorPacket.h b/src/Net/Packets/ErrorPacket.h index 4c6a026..01c1303 100644 --- a/src/Net/Packets/ErrorPacket.h +++ b/src/Net/Packets/ErrorPacket.h @@ -33,6 +33,7 @@ class ErrorPacket : public Packet { uint32_t errorCode; uint32_t subCode; uint32_t subSubCode; + uint8_t where[0]; }; ErrorData *errorData; @@ -41,7 +42,9 @@ class ErrorPacket : public Packet { ErrorPacket(Type type, uint16_t requestId, const Common::Exception &exception); ErrorPacket(const Packet &p) : Packet(p) { - setLength(sizeof(ErrorData)); + if(getLength() < sizeof(ErrorData)) + setLength(sizeof(ErrorData)); + errorData = (ErrorData*)&rawData->data; } @@ -56,7 +59,10 @@ class ErrorPacket : public Packet { } Common::Exception getException() const { - return Common::Exception((Common::Exception::ErrorCode)ntohl(errorData->errorCode), ntohl(errorData->subCode), ntohl(errorData->subSubCode)); + return Common::Exception( + std::string((char*)errorData->where, getLength()-sizeof(ErrorData)), (Common::Exception::ErrorCode)ntohl(errorData->errorCode), + ntohl(errorData->subCode), ntohl(errorData->subSubCode) + ); } }; diff --git a/src/Net/ServerConnection.h b/src/Net/ServerConnection.h index 9a4d86b..9a67c13 100644 --- a/src/Net/ServerConnection.h +++ b/src/Net/ServerConnection.h @@ -21,7 +21,7 @@ #define MAD_NET_SERVERCONNECTION_H_ #include "Connection.h" -#include "ConnectionException.h" +#include #include namespace Mad { diff --git a/src/mad.cpp b/src/mad.cpp index 0985bb0..bbcedcc 100644 --- a/src/mad.cpp +++ b/src/mad.cpp @@ -73,8 +73,8 @@ int main() { Mad::Common::RequestManager::getRequestManager()->unregisterConnection(connection); } - catch(Mad::Net::Exception &e) { - Mad::Common::Logger::log(Mad::Common::Logger::CRITICAL, "Connection error: " + e.what()); + catch(Mad::Common::Exception &e) { + Mad::Common::Logger::log(Mad::Common::Logger::CRITICAL, "Connection error: " + e.strerror()); } delete connection; diff --git a/src/madc.cpp b/src/madc.cpp index 66e235d..48b15c9 100644 --- a/src/madc.cpp +++ b/src/madc.cpp @@ -118,8 +118,8 @@ int main(int argc, char *argv[]) { Mad::Common::RequestManager::getRequestManager()->unregisterConnection(connection); } - catch(Mad::Net::Exception &e) { - Mad::Common::Logger::log(Mad::Common::Logger::CRITICAL, "Connection error: " + e.what()); + catch(Mad::Common::Exception &e) { + Mad::Common::Logger::log(Mad::Common::Logger::CRITICAL, "Connection error: " + e.strerror()); } delete connection; -- cgit v1.2.3