[seiscomp, scanloc] Install, add .gitignore

This commit is contained in:
2025-10-09 15:07:02 +02:00
commit 20f5301bb1
2848 changed files with 1315858 additions and 0 deletions

View File

@ -0,0 +1,314 @@
/***************************************************************************
* Copyright (C) gempa GmbH *
* All rights reserved. *
* Contact: gempa GmbH (seiscomp-dev@gempa.de) *
* *
* GNU Affero General Public License Usage *
* This file may be used under the terms of the GNU Affero *
* Public License version 3.0 as published by the Free Software Foundation *
* and appearing in the file LICENSE included in the packaging of this *
* file. Please review the following information to ensure the GNU Affero *
* Public License version 3.0 requirements will be met: *
* https://www.gnu.org/licenses/agpl-3.0.html. *
* *
* Other Usage *
* Alternatively, this file may be used in accordance with the terms and *
* conditions contained in a signed written agreement between you and *
* gempa GmbH. *
***************************************************************************/
#ifndef SEISCOMP_CLIENT_CONNECTION_H
#define SEISCOMP_CLIENT_CONNECTION_H
#include <seiscomp/core/message.h>
#include <seiscomp/messaging/protocol.h>
#include <seiscomp/utils/timer.h>
#include <openssl/x509.h>
#include <mutex>
#include <functional>
namespace Seiscomp {
namespace Client {
DEFINE_SMARTPOINTER(Connection);
/**
* @brief The Connection class implements the high level connection to a
* messaging backend. It requires a protocol implementation and
* parses the message from the wire into an object tree.
*
* @code
* ConnectionPtr c = new Connection;
* if ( c->setSource("scmp://app@localhost/testing") != OK ) {
* cerr << "Invalid source" <<endl;
* exit(1);
* }
*
* if ( c->connect() != OK ) {
* cerr << "Could not open connection" <<endl;
* exit(1);
* }
*
* cout << "Connected as " << c->clientName() << endl;
* Message *nmsg;
* while ( msg = c->receive(&nmsg) ) {
* cout << "Received message from " << nmsg->sender << endl;
* }
*
* c->close();
* @endcode
*/
class SC_SYSTEM_CLIENT_API Connection : public Core::BaseObject {
public:
typedef std::list<Connection*> Connections;
typedef std::function<void (const Core::Time &, std::ostream&)> InfoCallback;
// ----------------------------------------------------------------------
// X'truction
// ----------------------------------------------------------------------
public:
//! C'tor
Connection(Protocol *proto = nullptr);
//! D'tor
~Connection();
// ----------------------------------------------------------------------
// Public interface
// ----------------------------------------------------------------------
public:
/**
* @brief Sets the default content encoding passed to the final
* implementation of \ref Protocol.sendMessage.
*
* This is taken as a hint and implementations can or cannot respect
* it. The default encoding is deflate.
*
* @param enc The content encoding
*/
void setContentEncoding(Protocol::ContentEncoding enc);
/**
* @brief Sets the default content type passed to the final
* implementation of \ref Protocol.sendMessage.
*
* This is taken as a hint and implementations can or cannot respect
* it. The default type is binary.
*
* @param type The content type
*/
void setContentType(Protocol::ContentType type);
/**
* @brief Creates a connection to the given URL.
*
* The protocol implementation is created from the given protocol.
* The default is 'scmp' and can be omitted: 'localhost/testing' and
* 'scmp://localhost/testing' are equal.
* If a username is passed then it will be required for registration
* otherwise a random username (clientname) will be created and
* assigned to the connection.
*
* Only the protocol implementation will be instantiated and the
* address will be saved. A real connection attempt isn't being
* made at this point.
*
* If a protocol has been set already in the constructor then it will
* be used if the protocol is omitted in the URL. Otherwise it will be
* replaced by the given protocol.
*
* @param url The URL in format proto://user@host/queue
* @return An unmanaged connection pointer or nullptr in case of error.
*/
Result setSource(const char *URL);
Result setSource(const std::string &URL);
//! Returns the configured source
const std::string &source() const;
/**
* @brief Sets whether membership info of clients should be received.
* This information informs about when another client enters
* one of the groups this connection is subscribed to, when
* another clients leaves one of the groups this connection is
* subscribed to and when a client disconnects from the
* broker.
* This method has to be called prior to connect and after
* setSource to have an affect.
* @param enable true if membership info should be received, false
* otherwise.
*/
Result setMembershipInfo(bool enable);
/**
* @brief Attempts to connect to the messaging backend located at the
* given source (@setSource).
* @param clientName An optional clientname.
* @param primaryGroup The primary messaging group. If empty then the
* connection is treated as read-only connection.
* @param timeoutMs The handshake timeout in milliseconds. If zero then
* no timeout is being used.
* @return Result code
*/
Result connect(const std::string &clientName,
const std::string &primaryGroup,
unsigned int timeoutMs = 3000);
//! Disconnects from the backend
Result disconnect();
//! Returns whether a connection is established or not
bool isConnected() const;
/**
* @brief Reconnects the last established connection.
*
* If the connection is still established then it will disconnect
* first.
*
* @return Result code
*/
Result reconnect();
//! Closes the connection to the backend the hard way
Result close();
/**
* @brief Sets the read timeout for receiving a message. If the
* timeout hits then TimeoutError is returned.
* @param milliseconds The timeout in milliseconds. Zero or a negative
* value disabled the timeout.
* @return Result code
*/
Result setTimeout(int milliseconds);
Result subscribe(const char *group);
Result subscribe(const std::string &group);
Result unsubscribe(const char *group);
Result unsubscribe(const std::string &group);
/**
* @brief Waits for a new message to arrive so that a subsequent call
* to \ref recv() will return immediately.
* @return Result code
*/
Result fetchInbox();
/**
* @brief Synchronizes the outbox with the remote server.
* See Protocol::syncOutbox().
* @return Result code
*/
Result syncOutbox();
/**
* @brief Reads a message from the backend. If no message is available
* locally the call will block until a message arrives.
* @param packet An optional storage pointer to the transmitted packet
* from which the message has been created. The ownership
* goes to the caller.
* @param status An optional status storage which holds the result of
* the operation.
* @return The message pointer. nullptr is returned if either an error
* occurred or a system packet was received. This requires a
* package storage pointer to be passed.
*/
Core::Message *recv(Packet **packet = nullptr, Result *status = nullptr);
Core::Message *recv(PacketPtr &packet, Result *status = nullptr);
Result sendMessage(const Core::Message *msg);
Result sendMessage(const std::string &targetGroup, const Core::Message *msg);
//! The following three functions are actually convenience wrapper for
//! backward compatibility
bool send(const Core::Message *msg);
bool send(const std::string &targetGroup, const Core::Message *msg);
size_t inboxSize() const;
const Protocol::State *state() const;
Result lastError() const;
const std::string lastErrorMessage() const;
Protocol *protocol() const;
void setInfoCallback(InfoCallback);
void getInfo(const Core::Time &timestamp, std::ostream &os);
Result setCertificate(const std::string &cert);
// ----------------------------------------------------------------------
// Query functions
// ----------------------------------------------------------------------
public:
/**
* @brief Returns the client name. Either the one given during connect
* or the one assigned by the server.
* @return The client name
*/
const std::string &clientName() const;
/**
* @brief Returns the schema version supported by the remote end.
* This requires a successfull connection to be valid.
* @return The version of the remote schema
*/
Core::Version schemaVersion() const;
// See Protocoll::configurationParameters
const Protocol::KeyValueStore *extendedParameters() const;
// ----------------------------------------------------------------------
// Protected interface
// ----------------------------------------------------------------------
protected:
static void registerConnection(Connection *con);
static void unregisterConnection(Connection *con);
protected:
ProtocolPtr _protocol;
Protocol::ContentEncoding _defaultContentEncoding;
Protocol::ContentType _defaultContentType;
std::string _address;
std::string _clientName;
std::string _primaryGroup;
unsigned int _timeoutMs;
Result _lastError;
InfoCallback _infoCallback;
Connections::iterator _poolIterator;
};
inline Result Connection::lastError() const {
return _lastError;
}
inline const std::string &Connection::source() const {
return _address;
}
inline bool Connection::send(const Core::Message *msg) {
return sendMessage(msg) == OK;
}
inline bool Connection::send(const std::string &targetGroup, const Core::Message *msg) {
return sendMessage(targetGroup, msg) == OK;
}
}
}
#endif

View File

@ -0,0 +1,120 @@
/***************************************************************************
* Copyright (C) gempa GmbH *
* All rights reserved. *
* Contact: gempa GmbH (seiscomp-dev@gempa.de) *
* *
* GNU Affero General Public License Usage *
* This file may be used under the terms of the GNU Affero *
* Public License version 3.0 as published by the Free Software Foundation *
* and appearing in the file LICENSE included in the packaging of this *
* file. Please review the following information to ensure the GNU Affero *
* Public License version 3.0 requirements will be met: *
* https://www.gnu.org/licenses/agpl-3.0.html. *
* *
* Other Usage *
* Alternatively, this file may be used in accordance with the terms and *
* conditions contained in a signed written agreement between you and *
* gempa GmbH. *
***************************************************************************/
#ifndef SEISCOMP_CLIENT_DATABASEMESSAGE_H
#define SEISCOMP_CLIENT_DATABASEMESSAGE_H
#include <seiscomp/messaging/messages/service.h>
#include <seiscomp/io/database.h>
namespace Seiscomp {
// Forward declarations
namespace IO {
class DatabaseInterface;
}
namespace Client {
DEFINE_SMARTPOINTER(DatabaseRequestMessage);
/**
* \brief Message for requesting a database service
* This message type requests a databaseservice.
* The servicename is optional. If the servicename is not
* given the serviceprovider can choose between different
* services it offers of this type.
* So if the provider offers a mysql database and a postgresql
* database it can select the published service by its own.
* If the servicename is set the provider has to publish
* the service matching this name if it is able to do so.
*/
class SC_SYSTEM_CLIENT_API DatabaseRequestMessage : public ServiceRequestMessage {
DECLARE_SC_CLASS(DatabaseRequestMessage)
public:
//! Constructor
DatabaseRequestMessage();
/**
* Constructor
* @param service The requested service name.
* The name can be set nullptr to let the
* service request handler decide which
* interface it will return.
*/
DatabaseRequestMessage(const char *service);
};
DEFINE_SMARTPOINTER(DatabaseProvideMessage);
/**
* \brief Message for providing a database service
* When receiving this message a corresponding databaseinterface
* can be created which one connects to using the provided
* parameters.
* \code
* DatabaseProvideMessagePtr msg = DatabaseProvideMessage_Cast(con->read());
* Seiscomp::IO::DatabaseInterfacePtr db = msg->interface();
* if ( db != nullptr ) {
* // do fancy things with the interface
* }
* \endcode
*/
class SC_SYSTEM_CLIENT_API DatabaseProvideMessage : public ServiceProvideMessage {
DECLARE_SC_CLASS(DatabaseProvideMessage)
public:
//! Constructor
DatabaseProvideMessage();
/**
* Constructor
* @param service The provided service name.
* @param params The connection parameters.
*/
DatabaseProvideMessage(const char *service,
const char *params);
public:
/**
* Returns a database interface for the provided service
* which is already connected to the database.
* @return The connected database interface. nullptr, if the
* databaseinterface cannot be created or if the
* connection fails.
* NOTE: The caller is reponsible for deleting the
* returned object.
*/
IO::DatabaseInterface *database() const;
};
}
}
#endif

View File

@ -0,0 +1,122 @@
/***************************************************************************
* Copyright (C) gempa GmbH *
* All rights reserved. *
* Contact: gempa GmbH (seiscomp-dev@gempa.de) *
* *
* GNU Affero General Public License Usage *
* This file may be used under the terms of the GNU Affero *
* Public License version 3.0 as published by the Free Software Foundation *
* and appearing in the file LICENSE included in the packaging of this *
* file. Please review the following information to ensure the GNU Affero *
* Public License version 3.0 requirements will be met: *
* https://www.gnu.org/licenses/agpl-3.0.html. *
* *
* Other Usage *
* Alternatively, this file may be used in accordance with the terms and *
* conditions contained in a signed written agreement between you and *
* gempa GmbH. *
***************************************************************************/
#ifndef SEISCOMP_MESSAGING_MESSAGES_DATABASE_H
#define SEISCOMP_MESSAGING_MESSAGES_DATABASE_H
#include <seiscomp/core/message.h>
#include <seiscomp/client.h>
namespace Seiscomp {
namespace Client {
DEFINE_SMARTPOINTER(ServiceRequestMessage);
/**
* \brief Message for requesting a service
* This class is the base class for all kinds of service
* requests being sent over the network.
* It holds an optional servicename. If the servicename
* is not set the request handler can choose a service
* matching the servicetype defined by the classname.
* A message of this type cannot not be sent. One has to
* derive a class to define the type of service (database,
* fileaccess, ...).
*/
class SC_SYSTEM_CLIENT_API ServiceRequestMessage : public Core::Message {
DECLARE_SC_CLASS(ServiceRequestMessage)
DECLARE_SERIALIZATION;
protected:
//! Constructor
ServiceRequestMessage();
/**
* C'tor
* @param service The requested service name.
* The name can be set nullptr to let the
* service request handler decide which
* interface it will return.
*/
ServiceRequestMessage(const char *service);
//! Implemented interface from Message
bool empty() const override;
public:
/**
* @return The requested service name
*/
const char* service() const;
private:
std::string _serviceName;
};
DEFINE_SMARTPOINTER(ServiceProvideMessage);
/**
* \brief Message for providing a service
* This class is the base class for all kinds of service
* providers.
* It holds a servicename and the connection parameters.
*/
class SC_SYSTEM_CLIENT_API ServiceProvideMessage : public Seiscomp::Core::Message {
DECLARE_SC_CLASS(ServiceProvideMessage)
DECLARE_SERIALIZATION;
protected:
/**
* Constructor
* @param service The provided service name.
* @param params The connection parameters.
*/
ServiceProvideMessage(const char *service,
const char *params);
public:
/**
* @return The provided service name.
*/
const char *service() const;
/**
* @return The connection parameters.
*/
const char *parameters() const;
//! Implemented interface from Message
virtual bool empty() const;
private:
std::string _serviceName;
std::string _parameters;
};
}
}
#endif

View File

@ -0,0 +1,89 @@
/***************************************************************************
* Copyright (C) gempa GmbH *
* All rights reserved. *
* Contact: gempa GmbH (seiscomp-dev@gempa.de) *
* *
* GNU Affero General Public License Usage *
* This file may be used under the terms of the GNU Affero *
* Public License version 3.0 as published by the Free Software Foundation *
* and appearing in the file LICENSE included in the packaging of this *
* file. Please review the following information to ensure the GNU Affero *
* Public License version 3.0 requirements will be met: *
* https://www.gnu.org/licenses/agpl-3.0.html. *
* *
* Other Usage *
* Alternatively, this file may be used in accordance with the terms and *
* conditions contained in a signed written agreement between you and *
* gempa GmbH. *
***************************************************************************/
#ifndef SEISCOMP_CLIENT_PACKET_H
#define SEISCOMP_CLIENT_PACKET_H
#include <seiscomp/core/message.h>
#include <seiscomp/client.h>
#include <string>
#include <stdint.h>
namespace Seiscomp {
namespace Client {
DEFINE_SMARTPOINTER(Packet);
/**
* @brief The Packet struct provides access to a data packet received
* from a messaging backend.
*
* Apart from metadata a package only contains a vector of octetts which
* are parsed in the next layer. A packet is usually transformed to and
* from a message.
*/
struct SC_SYSTEM_CLIENT_API Packet : Core::BaseObject {
DECLARE_CASTS(Packet)
Packet() : type(Undefined), seqNo(-1) {}
enum Type {
Undefined = -1,
Data = 0,
Enter = 1,
Leave = 2,
Status = 3,
Disconnected = 4
};
Type type; //!< The message type
std::string headerContentEncoding; //!< The encoding raw string
std::string headerContentType; //!< The content type raw string
std::string sender; //!< The sender's client name
std::string target; //!< The target group or peer
std::string subject; //!< For ENTER, LEAVE, STATE and DISCONNECTED messages
uint64_t seqNo; //!< The optional sequence number
std::string payload; //!< The actual payload or *the* message
Packet &swap(Packet &other);
};
inline Packet &Packet::swap(Packet &other) {
std::swap(type, other.type);
sender.swap(other.sender);
target.swap(other.target);
headerContentEncoding.swap(other.headerContentEncoding);
headerContentType.swap(other.headerContentType);
subject.swap(other.subject);
std::swap(seqNo, other.seqNo);
payload.swap(other.payload);
return *this;
}
}
}
#endif

View File

@ -0,0 +1,588 @@
/***************************************************************************
* Copyright (C) gempa GmbH *
* All rights reserved. *
* Contact: gempa GmbH (seiscomp-dev@gempa.de) *
* *
* GNU Affero General Public License Usage *
* This file may be used under the terms of the GNU Affero *
* Public License version 3.0 as published by the Free Software Foundation *
* and appearing in the file LICENSE included in the packaging of this *
* file. Please review the following information to ensure the GNU Affero *
* Public License version 3.0 requirements will be met: *
* https://www.gnu.org/licenses/agpl-3.0.html. *
* *
* Other Usage *
* Alternatively, this file may be used in accordance with the terms and *
* conditions contained in a signed written agreement between you and *
* gempa GmbH. *
***************************************************************************/
#ifndef SEISCOMP_CLIENT_PROTOCOL_H
#define SEISCOMP_CLIENT_PROTOCOL_H
#include <seiscomp/core/interruptible.h>
#include <seiscomp/core/enumeration.h>
#include <seiscomp/core/interfacefactory.h>
#include <seiscomp/core/optional.h>
#include <seiscomp/messaging/packet.h>
#include <deque>
#include <map>
#include <mutex>
#include <set>
#include <string>
namespace Seiscomp {
namespace Client {
PREPAREENUM(Result,
EVALUES(
/** Everything went find */
OK = 0,
/** The value/string passed is not an URL */
InvalidURL,
/** The URL parameters are not correct / not understood */
InvalidURLParameters,
/** Protocol implementation is not available */
InvalidProtocol,
/** No content encoding specified e.g. when sending messages */
ContentEncodingRequired,
/** No content type specified e.g. when sending messages */
ContentTypeRequired,
/** An unknown content encoding was received */
ContentEncodingUnknown,
/** An unknown content type was received */
ContentTypeUnknown,
/** There is already an active connection */
AlreadyConnected,
/** There is currently no active connection to handle */
NotConnected,
/** The server closed the connection */
ConnectionClosedByPeer,
/** A system error, check errno */
SystemError,
/** The connection timed out */
TimeoutError,
/** A network error, check errno */
NetworkError,
/** An application protocol error occurred */
NetworkProtocolError,
/** The requested username is connected already */
DuplicateUsername,
/** The remote group does not exist */
GroupDoesNotExist,
/** There are no inbox messages */
InboxUnderflow,
/** Too many inbox messages which are not processed */
InboxOverflow,
/** Too many unacknowledged outbox messages */
OutboxOverflow,
/** You can't subscribe again to groups you are already subscribed to */
AlreadySubscribed,
/** You can't unsubscribe from groups you are not subscribed to */
NotSubscribed,
/** Messages could not be encoded into a packet */
EncodingError,
/** Package could not be decoded into a message */
DecodingError,
/** Missing group, e.g. when sending data */
MissingGroup,
/** Invalid message type enumeration e.g. when sending messages/data */
InvalidMessageType,
/** Message too large */
MessageTooLarge,
/** Unspecified error */
Error
),
ENAMES(
"OK",
"InvalidURL",
"InvalidURLParameters",
"InvalidProtocol",
"ContentEncodingRequired",
"ContentTypeRequired",
"ContentEncodingUnknown",
"ContentTypeUnknown",
"AlreadyConnected",
"NotConnected",
"ConnectionClosedByPeer",
"SystemError",
"TimeoutError",
"NetworkError",
"NetworkProtocolError",
"DuplicateUsername",
"GroupDoesNotExist",
"InboxUnderflow",
"InboxOverflow",
"OutboxOverflow",
"AlreadySubscribed",
"NotSubscribed",
"EncodingError",
"DecodingError",
"MissingGroup",
"InvalidMessageType",
"MessageTooLarge",
"Error"
)
);
class Result : public ENUMWRAPPERCLASS(Result) {
public:
Result(Type value = Type(0)) : ENUMWRAPPERCLASS(Result)(value) {}
Type code() const { return _value; }
operator bool() const { return _value == OK; }
// Disable implicit casts to the enumeration and therefore to
// a bool value. A special bool operator is used that maps true to
// OK.
private:
operator Type() const { return ENUMWRAPPERCLASS(Result)::operator Type(); }
};
DEFINE_SMARTPOINTER(Protocol);
/**
* @brief The abstract class Protocol implements the low-level message
* transport protocol.
*
* The protocol handles one connection to a messaging broker and supports
* the publish/subscribe pattern. It must implement the methods to subscribe
* to a group, unsubscribe from a group and to receive and send messages.
* Messages are just binary blobs with associated metadata. The message
* content is not interpreted or parsed in any way.
*
* @code
* ProtocolPtr proto = Protocol::Create("scmp");
* if ( !proto ) exit(1);
* if ( proto->connect("localhost") ) {
* cerr << "Connection failed" << endl;
* exit(1);
* }
*
* cout << "Connected as " << proto->clientName() << endl;
* proto->subscribe("PICK");
*
* PacketPtr p;
* while ( (p = c->recv() ) {
* cout << "Packet from " << p->sender() << " to " << p->target << endl;
* }
*
* proto->disconnect();
* @endcode
*
* ## Message Types
* ### Regular
*
* Regular messages will be queued, receive a sequence number and their
* content will not be touched by the server unless certain processing
* profiles are enabled. That is the default mode of the messaging API.
*
* ### Transient
*
* Transient messages are like regular messages but they are not queued and
* will not be processed. A client that connects to continue with a sequence
* number will not receive such a message.
*
* ### Service
*
* Service messages are like transient messages but are evaluated by the
* server. They are mainly used to interact with the server. State-of-health
* messages and sync messages are typical service messages.
*/
class SC_SYSTEM_CLIENT_API Protocol : public Core::InterruptibleObject {
// ----------------------------------------------------------------------
// Public types
// ----------------------------------------------------------------------
public:
struct State {
State();
uint64_t localSequenceNumber;
OPT(uint64_t) sequenceNumber;
uint64_t receivedMessages;
uint64_t sentMessages;
uint64_t bytesSent;
uint64_t bytesReceived;
uint64_t bytesBuffered;
uint64_t maxBufferedBytes;
uint64_t maxInboxSize;
uint64_t maxOutboxSize;
uint64_t systemReadCalls;
uint64_t systemWriteCalls;
};
MAKEENUM(
ContentEncoding,
EVALUES(
Identity,
Deflate,
GZip,
LZ4
),
ENAMES(
"identity",
"deflate",
"gzip",
"lz4"
)
);
MAKEENUM(
ContentType,
EVALUES(
Binary,
JSON,
BSON,
XML,
IMPORTED_XML,
Text
),
ENAMES(
"application/x-sc-bin",
"text/json",
"application/x-sc-bson",
"application/x-sc-xml",
"text/xml",
"text/plain"
)
);
MAKEENUM(
MessageType,
EVALUES(
Regular,
Transient,
Status
),
ENAMES(
"regular",
"transient",
"status"
)
);
static const std::string STATUS_GROUP;
static const std::string LISTENER_GROUP;
static const std::string IMPORT_GROUP;
//! A list of group names
using Groups = std::set<std::string>;
using KeyValueStore = std::map<std::string, std::string>;
// ----------------------------------------------------------------------
// X'truction
// ----------------------------------------------------------------------
public:
Protocol();
virtual ~Protocol();
// ----------------------------------------------------------------------
// Public interface
// ----------------------------------------------------------------------
public:
/**
* @brief Sets whether membership info of clients should be received.
* This information informs about when another client enters
* one of the groups this connection is subscribed to, when
* another clients leaves one of the groups this connection is
* subscribed to and when a client disconnects from the
* broker.
* This method has to be called prior to connect to have an
* affect.
* @param enable true if membership info should be received, false
* otherwise.
*/
void setMembershipInfo(bool enable);
/**
* @brief connect
* @param address The connection address, e.g. host:port/queue
* @param timeoutMs The timeout in milliseconds
* @param clientName The desired client name. If it is nullptr then the
* server will choose a random client name.
* @return
*/
virtual Result connect(const char *address, unsigned int timeoutMs,
const char *clientName = nullptr) = 0;
Result connect(const std::string &address, unsigned int timeoutMs,
const std::string &clientName = std::string());
/**
* @brief Returns the schema version supported by the remote end.
* This requires a successfull connection to be valid.
* @return The version of the remote schema
*/
Core::Version schemaVersion() const;
/**
* @brief Returns configuration parameters as key-value store
* returned by the broker.
* Those parameters can be used or not, it is up to the user of
* the connection.
* @return The key-value store with additional parameters
*/
const KeyValueStore &extendedParameters() const;
/**
* @brief Returns the client name. Either the one given during connect
* or the one assigned by the server.
* @return The client name
*/
const std::string &clientName() const;
/**
* @brief Subscribes to a group which must exist
* @param group The group name
* @return Result code
*/
virtual Result subscribe(const std::string &group) = 0;
/**
* @brief Unsubscribes from a group where the client was subscribed to.
* @param group The group name
* @return Result code
*/
virtual Result unsubscribe(const std::string &group) = 0;
/**
* @brief Sends data with a particular content type.
* @param targetGroup The group name to send the message to
* @param data The data pointer to the octett stream.
* @param len Length in bytes of the octett stream.
* @param encoding The data content encoding.
* @param type The data content type.
* @return Result code
*/
virtual Result sendData(const std::string &targetGroup,
const char *data, size_t len,
MessageType type,
ContentEncoding contentEncoding,
ContentType contentType) = 0;
/**
* @brief Sends a message. A message is actually a binary stream
* of certain length. Optionally a content type can be
* associated with it.
* @param targetGroup The group name to send the message to
* @param msg The message pointer.
* @param contentType An optional content type which will be or
* won't be associated with the packet. This is
* implementation specific.
* @return Result code
*/
virtual Result sendMessage(const std::string &targetGroup,
const Core::Message *msg,
MessageType type = Regular,
OPT(ContentEncoding) contentEncoding = Core::None,
OPT(ContentType) contentType = Core::None) = 0;
/**
* @brief Receives a data packet.
* The call will block if the local inbox is empty.
* @param p The packet instance which will hold the packet
* information and the payload.
* @return Result code
*/
virtual Result recv(Packet &p) = 0;
/**
* @brief Receives a data packet.
* The call will block if the local inbox is empty.
* @param result An optional storage for the result code
* @return A packet pointer which must be handled by the caller.
*/
virtual Packet *recv(Result *result = nullptr) = 0;
/**
* @brief Waits for a new message to arrive so that a subsequent call
* to \ref recv will return immediately.
* @return Result code
*/
virtual Result fetchInbox() = 0;
/**
* @brief Synchronizes the outbox with the remote server.
* @details This means if this method returns successfully then all
* sent messages have been acknowledged by the remote end.
* This operation blocks until all messages have been
* acknowledged.
* Writing is not possible while the function is running even
* from another thread.
* Usually this function does not need to be called from
* user code. It is there for completeness to allow clients
* to be sure that all messages were handled by the server
* at a certain point in time without having to disconnect.
* @return Result code
*/
virtual Result syncOutbox() = 0;
/**
* @brief Disconnects gracefully from the broker. It sends a disconnect
* message and wait for the receipt. In contrast to close, this
* is the nice way to say 'good bye'.
* @return Result code
*/
virtual Result disconnect() = 0;
/**
* @brief Checks for an active connection.
* @return True if a connection is established, false otherwise
*/
virtual bool isConnected() = 0;
/**
* @brief Closes the underlying socket and resources. This is the
* hard way to close a connection.
* @return Result code
*/
virtual Result close() = 0;
/**
* @brief Sets the read timeout for receiving a message. If the
* timeout hits then TimeoutError is returned.
* @param milliseconds The timeout in milliseconds. Zero or a negative
* value disabled the timeout.
* @return Result code
*/
virtual Result setTimeout(int milliseconds) = 0;
/**
* @brief Returns the names of the available message groups.
* @details This call only returns valid content after a connection
* was established. If a reconnect occurred during the
* lifetime of the connection and the groups of the queue
* have changed then this will be reflected in the returned
* vector.
* @return The available groups
*/
const Groups &groups() const;
bool erroneous() const;
/**
* @brief Returns the error message corresponding to the last
* erroneous call.
* @return The message or empty.
*/
const std::string &lastErrorMessage() const;
const State &state() const;
/**
* @brief Queries the local message inbox size. It is safe to call this
* method from separate threads.
* @return The number of messages queued in the local inbox.
*/
size_t inboxSize() const;
/**
* @brief Queries the local message outbox size. If a message is still
* in the outbox does not mean that is hasn't been sent over the
* wire. It just means that the server hasn't acknowledged the
* message yet and that in case of a reconnect the outbox will
* be sent again.
* @return The number of unacknowledged messages.
*/
virtual size_t outboxSize() const = 0;
void setCertificate(const std::string &cert);
static Core::Message *decode(const std::string &blob,
ContentEncoding encoding,
ContentType type);
static Core::Message *decode(const char *blob, size_t blob_length,
ContentEncoding encoding,
ContentType type);
static bool encode(std::string &blob, const Core::Message *msg,
ContentEncoding encoding, ContentType type,
int schemaVersion);
// ----------------------------------------------------------------------
// Interruptible interface
// ----------------------------------------------------------------------
protected:
virtual void handleInterrupt(int) override;
// ----------------------------------------------------------------------
// Protected methods
// ----------------------------------------------------------------------
protected:
void queuePacket(Packet *p);
/**
* Clears all messages in the inbox. This method is not intended for
* public use. Note that it does not lock the read mutex.
*/
void clearInbox();
// ----------------------------------------------------------------------
// Private types and members
// ----------------------------------------------------------------------
protected:
using PacketQueue = std::deque<Packet*>;
bool _wantMembershipInfo;
Groups _groups;
PacketQueue _inbox;
std::string _errorMessage;
State _state;
std::string _registeredClientName;
Core::Version _schemaVersion; //!< The schema version the
//!< server supports
KeyValueStore _extendedParameters;
std::string _certificate; //!< Optional client certificate
// Mutexes to synchronize read access from separate threads.
mutable std::mutex _readMutex;
};
DEFINE_INTERFACE_FACTORY(Protocol);
#define REGISTER_CONNECTION_PROTOCOL(Class, Service) \
Seiscomp::Core::Generic::InterfaceFactory<Seiscomp::Client::Protocol, Class> __##Class##InterfaceFactory__(Service)
inline Core::Version Protocol::schemaVersion() const {
return _schemaVersion;
}
inline const Protocol::KeyValueStore &Protocol::extendedParameters() const {
return _extendedParameters;
}
inline const std::string &Protocol::clientName() const {
return _registeredClientName;
}
inline bool Protocol::erroneous() const {
return !_errorMessage.empty();
}
inline const std::string &Protocol::lastErrorMessage() const {
return _errorMessage;
}
inline const Protocol::State &Protocol::state() const {
return _state;
}
}
}
#endif

View File

@ -0,0 +1,119 @@
/***************************************************************************
* Copyright (C) gempa GmbH *
* All rights reserved. *
* Contact: gempa GmbH (seiscomp-dev@gempa.de) *
* *
* GNU Affero General Public License Usage *
* This file may be used under the terms of the GNU Affero *
* Public License version 3.0 as published by the Free Software Foundation *
* and appearing in the file LICENSE included in the packaging of this *
* file. Please review the following information to ensure the GNU Affero *
* Public License version 3.0 requirements will be met: *
* https://www.gnu.org/licenses/agpl-3.0.html. *
* *
* Other Usage *
* Alternatively, this file may be used in accordance with the terms and *
* conditions contained in a signed written agreement between you and *
* gempa GmbH. *
***************************************************************************/
#ifndef SEISCOMP_CLIENT_STATUS_H
#define SEISCOMP_CLIENT_STATUS_H
#include <stdint.h>
#include <seiscomp/core/enumeration.h>
namespace Seiscomp {
namespace Client {
struct Status {
MAKEENUM(
Tag,
EVALUES(
Time,
Hostname,
Clientname,
Programname,
PID,
CPUUsage,
TotalMemory,
ClientMemoryUsage,
SentMessages,
SentBytes,
ReceivedMessages,
ReceivedBytes,
MessageQueueSize,
ObjectCount,
Address,
Uptime,
ResponseTime
),
ENAMES(
"time",
"hostname",
"clientname",
"programname",
"pid",
"cpuusage",
"totalmemory",
"clientmemoryusage",
"sentmessages",
"sentbytes",
"receivedmessages",
"receivedbytes",
"messagequeuesize",
"objectcount",
"address",
"uptime",
"responsetime"
)
);
void clear();
bool parse(const std::string &data);
std::string values[ETagQuantity];
};
// Primary Template
template <Status::ETag T>
struct StatusT;
// Specializations
#define SPECIALIZE_CONNECTIONINFOT(TAG, TYPE) \
template <> struct StatusT<TAG> { \
typedef TYPE Type; \
};
SPECIALIZE_CONNECTIONINFOT(Status::Time, std::string)
SPECIALIZE_CONNECTIONINFOT(Status::Hostname, std::string)
SPECIALIZE_CONNECTIONINFOT(Status::Clientname, std::string)
SPECIALIZE_CONNECTIONINFOT(Status::Programname, std::string)
SPECIALIZE_CONNECTIONINFOT(Status::PID, int)
SPECIALIZE_CONNECTIONINFOT(Status::CPUUsage, double)
SPECIALIZE_CONNECTIONINFOT(Status::TotalMemory, int)
SPECIALIZE_CONNECTIONINFOT(Status::ClientMemoryUsage, int)
SPECIALIZE_CONNECTIONINFOT(Status::SentMessages, int)
SPECIALIZE_CONNECTIONINFOT(Status::SentBytes, uint64_t)
SPECIALIZE_CONNECTIONINFOT(Status::ReceivedMessages, int)
SPECIALIZE_CONNECTIONINFOT(Status::ReceivedBytes, uint64_t)
SPECIALIZE_CONNECTIONINFOT(Status::MessageQueueSize, int)
SPECIALIZE_CONNECTIONINFOT(Status::ObjectCount, int)
SPECIALIZE_CONNECTIONINFOT(Status::Address, std::string)
SPECIALIZE_CONNECTIONINFOT(Status::Uptime, std::string)
SPECIALIZE_CONNECTIONINFOT(Status::ResponseTime, int)
}
}
#endif