[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,83 @@
/***************************************************************************
* 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_WIRED_BUFFER_H
#define SEISCOMP_WIRED_BUFFER_H
#include <seiscomp/core/baseobject.h>
#include <seiscomp/core/datetime.h>
#include <string>
#include <list>
namespace Seiscomp {
namespace Wired {
DEFINE_SMARTPOINTER(Buffer);
typedef std::list<BufferPtr> BufferList;
struct SC_SYSTEM_CORE_API Buffer : Seiscomp::Core::BaseObject {
Buffer(int max_size = 0x7fffffff)
: encoding(Identity), format(Plain), lock(false),
maxBufferSize(max_size), lastModified(0) {}
~Buffer() override {}
enum Encoding {
Identity,
Compress,
GZip,
BZip2
};
enum Format {
Plain,
XML,
JSON,
BSON,
Octetts,
Custom
};
Seiscomp::Core::Time timestamp;
Encoding encoding;
Format format;
bool lock;
std::string header;
std::string data;
//! Maximum size of one buffer chunk when update is called
int maxBufferSize;
time_t lastModified;
// If true is returned the buffer is valid and updated
// otherwise everything has been read
virtual bool updateBuffer();
virtual size_t length() const;
};
}
}
#endif

View File

@ -0,0 +1,80 @@
/***************************************************************************
* 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_WIRED_BUFFERS_FILE_H
#define SEISCOMP_WIRED_BUFFERS_FILE_H
#include <seiscomp/wired/buffer.h>
#include <cstdio>
namespace Seiscomp {
namespace Wired {
DEFINE_SMARTPOINTER(FileBuffer);
/**
* @brief The FileBuffer transfers a file in chunked mode over a HTTP
* connection. It only supports regular files, no symlinks, no
* directories, no pipes and so on.
* Technically, S_ISREG(stat(fn).st_mode) must evaluate to true.
*/
class SC_SYSTEM_CORE_API FileBuffer : public Buffer {
public:
FileBuffer(int max_size = 0x7fffffff);
~FileBuffer() override;
public:
bool open(const std::string &fn, const char *mode = "rb");
bool open(const char *fn, const char *mode = "rb");
bool updateBuffer() override;
size_t length() const override;
public:
enum Type {
HTML,
CSS,
JS,
JSON,
PNG,
JPG,
SVG,
XML,
WOFF,
TTF,
TypeQuantity
};
static const char *mimeType(Type);
static const char *mimeType(const char *filenameExtension);
FILE *fp;
long fplen;
};
}
}
#endif

View File

@ -0,0 +1,159 @@
/***************************************************************************
* 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_WIRED_CLIENTSESSION_H
#define SEISCOMP_WIRED_CLIENTSESSION_H
#include <seiscomp/wired/session.h>
#include <seiscomp/wired/buffer.h>
#include <vector>
namespace Seiscomp {
namespace Wired {
class SC_SYSTEM_CORE_API ClientSession : public Session {
public:
enum Error {
NoError = 0,
TooManyCharactersPerLine,
ErrorQuantity
};
public:
ClientSession(Device *dev, size_t maxCharactersPerLine = 200);
public:
//! Flush data still in the buffer.
virtual void flush();
//! Update the session state including flushing and
//! reading available data.
void update() override;
//! Queue data in the outbox
void send(const char *data, size_t len);
void send(const char *data);
//! Queues a buffer and returns whether the queue was empty
bool send(Buffer *);
//! Sets keepReading to false
void close() override;
bool valid() const;
bool erroneous() const;
protected:
virtual void outboxFlushed();
virtual void buffersFlushed();
virtual void bufferSent(Buffer*);
//! Sets the post data size that is read by handleReceived and
//! passed to handlePostData
void setPostDataSize(size_t len);
size_t postDataSize() const;
void setMIMEUnfoldingEnabled(bool);
//! Returns the available bytes to send.
virtual size_t inAvail() const;
void setError(const char* msg);
//! Sets the error state
void invalidate();
//! Break the reading loop to give control to other sessions. This
//! calls only makes sense if the reactor is level-triggered.
void finishReading();
//! Handles a socket read into _buffer. The default implementation
//! extracts lines and calls handleInbox/handleData.
virtual void handleReceive(const char *data, size_t len);
//! Handles a line
virtual void handleInbox(const char *data, size_t len);
//! Handles posted data that has been requested if setPOSTDataSize
//! is called with len > 0.
virtual void handlePostData(const char *data, size_t len);
virtual void handleInboxError(Error error);
private:
void flushOutbox();
protected:
enum Flags {
NoFlags = 0x0000,
MIMEUnfolding = 0x0001,
KeepReading = 0x0002,
//Future1 = 0x0004,
//Future2 = 0x0008,
//Future3 = 0x0010,
//Future4 = 0x0020,
//Future5 = 0x0040,
//Future6 = 0x0080,
Erroneous = 0x0100
};
std::vector<char> _inbox;
size_t _inboxPos;
std::vector<char> _outbox;
uint16_t _flags;
size_t _postDataSize;
Device::count_t _bytesSent;
private:
BufferPtr _currentBuffer;
size_t _currentBufferHeaderOffset;
size_t _currentBufferDataOffset;
BufferList _bufferQueue;
size_t _bufferBytesPending;
};
inline bool ClientSession::valid() const {
return !erroneous();
}
inline void ClientSession::invalidate() {
_flags |= Erroneous;
}
inline bool ClientSession::erroneous() const {
return _flags & Erroneous;
}
}
}
#endif

View File

@ -0,0 +1,341 @@
/***************************************************************************
* 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_WIRED_DEVICE_H
#define SEISCOMP_WIRED_DEVICE_H
#include <seiscomp/core/platform/platform.h>
#include <seiscomp/core/interruptible.h>
#if defined(SC_HAS_EPOLL)
#define SEISCOMP_WIRED_EPOLL
#elif defined(SC_HAS_KQUEUE)
#define SEISCOMP_WIRED_KQUEUE
#else
#error "Require either epoll or kqueue support"
#endif
#ifdef SEISCOMP_WIRED_EPOLL
#ifndef WIN32
#include <sys/epoll.h>
#endif
#endif
#ifdef SEISCOMP_WIRED_KQUEUE
#include <sys/types.h>
#include <sys/event.h>
#endif
#include <seiscomp/core/baseobject.h>
#include <list>
#include <stdint.h>
#include <functional>
namespace Seiscomp {
namespace Wired {
class DeviceGroup;
class Session;
/**
* Helper class to wrap any type of object and output it anomymized, e.g.
* IP addresses, password and so on
*/
template <typename T>
struct Anonymize {
Anonymize(const T &t) : target(t) {}
const T &target;
};
template <typename T>
Anonymize<T> anonymize(const T &t) {
return Anonymize<T>(t);
}
DEFINE_SMARTPOINTER(Device);
class SC_SYSTEM_CORE_API Device : public Core::BaseObject {
// ----------------------------------------------------------------------
// Public enumerations
// ----------------------------------------------------------------------
public:
/**
* @brief The Mode enum holds the states of a device.
*/
enum Mode {
Idle = 0x00,
Read = 0x01,
Write = 0x02,
ReadWrite = Read | Write,
Exception = 0x04,
Closed = 0x80
};
enum Status {
Success = 0,
Error,
InvalidDevice,
AllocationError
};
typedef uint64_t count_t;
// ----------------------------------------------------------------------
// X'truction
// ----------------------------------------------------------------------
public:
//! C'tor
Device();
/**
* @brief Device constructor
* @param fd The file descriptor of the device
*/
Device(int fd);
//! D'tor
~Device() override;
// ----------------------------------------------------------------------
// Public interface
// ----------------------------------------------------------------------
public:
void setSession(Session *session) { _session = session; }
Session *session() const { return _session; }
//! Returns whether the device is valid (functioning) or
//! invalid (closed or malfunctioning)
bool isValid() const;
void setMode(int m);
void addMode(int m);
void removeMode(int m);
int mode() const { return _selectMode; }
//! Sets a timeout when this device is active in a device group.
//! A negative disables the timeout. Timeouts relative values that
//! will be evaluated before the next events are checked.
//! setTimeout must not be called from a different thread in which
//! the reactor is running.
bool setTimeout(int milliseconds);
int selectMode() const { return _selectMode; }
virtual void close() = 0;
virtual ssize_t write(const char *data, size_t len) = 0;
virtual ssize_t read(char *data, size_t len) = 0;
/**
* @brief Returns the current file descriptor and sets the internal
* file descriptor to invalid
* @return The current file descriptor
*/
int takeFd();
int fd() const;
virtual Status setNonBlocking(bool nb);
// ----------------------------------------------------------------------
// Protected interface
// ----------------------------------------------------------------------
protected:
Session *_session;
int _fd;
int _selectMode;
#ifdef SEISCOMP_WIRED_KQUEUE
int _activeMode;
#endif
static int _deviceCount;
private:
DeviceGroup *_group; //<! The group the device is part of
Device *_qPrev; //<! The prev pointer used by intrusive list
Device *_qNext; //<! The next pointer used by intrusive list
// Store timeout in milliseconds.
// A negative value means no timeout.
int _timeout;
int _ticker;
friend class DeviceGroup;
};
class SC_SYSTEM_CORE_API DeviceGroup : public Core::BaseObject {
// ----------------------------------------------------------------------
// Public enumerations and types
// ----------------------------------------------------------------------
public:
/**
* @brief The TriggerMode enum defined how the device group unblocks,
* either edge triggered only when the mode changes or level
* triggered as long as the mode is not idle.
*/
enum TriggerMode {
EdgeTriggered,
LevelTriggered
};
typedef std::function<void ()> TimeoutFunc;
// ----------------------------------------------------------------------
// X'truction
// ----------------------------------------------------------------------
public:
//! C'tor
DeviceGroup();
//! D'tor
~DeviceGroup() override;
// ----------------------------------------------------------------------
// Public interface
// ----------------------------------------------------------------------
public:
/**
* @return Whether the device group is initialized or not
*/
bool isValid() const;
/**
* @brief Sets up a device group by allocating its resources.
* @return true on success, false otherwise
*/
bool setup();
//! Appends a device to a group. If the timeout of a device is
//! activated this call is not thread-safe and must not be called
//! from a different thread. Additional synchin' is required then.
bool append(Device *);
//! Removes a device from a group. If the timeout of a device is
//! activated this call is not thread-safe and must not be called
//! from a different thread. Additional synchin' is required then.
bool remove(Device *);
size_t count() const;
void clear();
bool setTimer(uint32_t seconds, uint32_t milliseconds, TimeoutFunc func);
bool clearTimer();
/**
* @brief Interrupt the blocking wait.
*/
void interrupt();
Device *wait();
Device *next();
bool readable() const;
bool writable() const;
bool timedOut() const;
bool interrupted() const { return _isInterrupted; }
//! Set the trigger mode which is only supported when epoll or kqueue
//! is used. The default trigger mode is LevelTriggered.
bool setTriggerMode(TriggerMode);
TriggerMode triggerMode() const;
// ----------------------------------------------------------------------
// Private interface
// ----------------------------------------------------------------------
private:
void applyTimeout(Device *d);
void removeFromQueue(Device *d);
void updateState(Device *);
// ----------------------------------------------------------------------
// Private members
// ----------------------------------------------------------------------
private:
TriggerMode _triggerMode;
bool _readyForRead;
bool _readyForWrite;
bool _timedOut;
bool _isInSelect;
bool _isInterrupted;
uint32_t _timerSeconds;
uint32_t _timerMilliseconds;
bool _timerSingleShot;
TimeoutFunc _fnTimeout;
int _timerFd;
int _interrupt_read_fd;
int _interrupt_write_fd;
#if defined(SEISCOMP_WIRED_EPOLL) || defined(SEISCOMP_WIRED_KQUEUE)
unsigned int _defaultOps;
size_t _count;
#ifdef SEISCOMP_WIRED_EPOLL
#define SEISCOMP_WIRED_EPOLL_EVENT_BUFFER 10
int _epoll_fd;
struct epoll_event _epoll_events[SEISCOMP_WIRED_EPOLL_EVENT_BUFFER];
#endif
#ifdef SEISCOMP_WIRED_KQUEUE
#define SEISCOMP_WIRED_KQUEUE_EVENT_BUFFER 10
int _kqueue_fd;
struct kevent _kqueue_events[SEISCOMP_WIRED_KQUEUE_EVENT_BUFFER];
#endif
size_t _selectIndex;
size_t _selectSize;
#endif
int _lastCallDuration;
Device *_queue;
Device *_nextQueue;
friend class Device;
};
inline bool DeviceGroup::readable() const {
return _readyForRead;
}
inline bool DeviceGroup::writable() const {
return _readyForWrite;
}
inline bool DeviceGroup::timedOut() const {
return _timedOut;
}
}
}
#endif

View File

@ -0,0 +1,52 @@
/***************************************************************************
* 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_WIRED_FD_H
#define SEISCOMP_WIRED_FD_H
#include <seiscomp/wired/device.h>
namespace Seiscomp {
namespace Wired {
DEFINE_SMARTPOINTER(FileDescriptor);
class FileDescriptor : public Device {
public:
FileDescriptor();
FileDescriptor(int fd);
~FileDescriptor() override;
public:
void close() override;
ssize_t write(const char *data, size_t len) override;
ssize_t read(char *data, size_t len) override;
};
}
}
#endif

View File

@ -0,0 +1,368 @@
/***************************************************************************
* 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_WIRE_SOCKET_H
#define SEISCOMP_WIRE_SOCKET_H
#include <seiscomp/wired/device.h>
#include <stdint.h>
#include <openssl/ssl.h>
#include <openssl/pkcs12.h>
#include <ostream>
namespace Seiscomp {
namespace Wired {
DEFINE_SMARTPOINTER(Socket);
class SC_SYSTEM_CORE_API Socket : public Device {
DECLARE_CASTS(Socket)
public:
enum Status {
Success = 0,
Error,
AllocationError,
ReuseAdressError,
BindError,
ListenError,
AcceptError,
ConnectError,
AddrInfoError,
Timeout,
InvalidSocket,
InvalidPort,
InvalidAddressFamily,
InvalidAddress,
InvalidHostname,
NotSupported
};
/**
* @brief The IP union holds either a IPv4 or IPv6 address.
*/
union IPAddress {
enum {
DWORDS = 4,
BYTES = 4*4,
MAX_IP_STRING_LEN = 46
};
IPAddress() { dwords[0] = dwords[1] = dwords[2] = dwords[3] = 0; }
explicit IPAddress(uint32_t addr) { dwords[0] = addr; dwords[1] = dwords[2] = dwords[3] = 0; }
explicit IPAddress(uint32_t addr[DWORDS]) { dwords[0] = addr[0]; dwords[1] = addr[1]; dwords[2] = addr[2]; dwords[3] = addr[3]; }
IPAddress(uint8_t a, uint8_t b, uint8_t c, uint8_t d) {
set(a,b,c,d);
}
bool operator==(const IPAddress &other) const {
return (dwords[0] == other.dwords[0])
&& (dwords[1] == other.dwords[1])
&& (dwords[2] == other.dwords[2])
&& (dwords[3] == other.dwords[3]);
}
bool equalV4(const IPAddress &other) const {
return dwords[0] == other.dwords[0];
}
bool equalV4(uint32_t addr) const {
return dwords[0] == addr;
}
bool equalV6(const IPAddress &other) const {
return *this == other;
}
bool zero() const {
return !dwords[0] && !dwords[1] && !dwords[2] && !dwords[3];
}
bool not_zero() const {
return dwords[0] || dwords[1] || dwords[2] || dwords[3];
}
/**
* @brief Returns whether the address is a v4 or v6 address or more
* technically, if the upper 96bits are set.
* @return flag indicating a v4 address
*/
bool isV4() const {
return !dwords[1] && !dwords[2] && !dwords[3];
}
void set(uint8_t a, uint8_t b,
uint8_t c, uint8_t d) {
v4.A = a;
v4.B = b;
v4.C = c;
v4.D = d;
dwords[1] = dwords[2] = dwords[3] = 0;
}
void set(uint32_t ipv4addr) {
dwords[0] = ipv4addr;
dwords[1] = dwords[2] = dwords[3] = 0;
}
bool fromString(const char *);
bool fromStringV4(const char *);
bool fromStringV6(const char *);
/**
* @brief Converts the IP to a string representation. The input
* string must at least have space for 46 characters.
* @return The number of bytes written including the terminating
* null byte.
*/
int toString(char *, bool anonymize = false) const;
uint32_t dwords[DWORDS];
uint8_t bytes[DWORDS*4];
struct {
uint8_t D;
uint8_t C;
uint8_t B;
uint8_t A;
} v4;
uint32_t dwordV4;
};
typedef uint16_t port_t;
public:
Socket();
Socket(int fd, const std::string &hostname = "localhost", port_t port = 0);
~Socket() override;
public:
static const char *toString(Status);
void shutdown();
void close() override;
const std::string &hostname() const;
port_t port() const;
IPAddress address() const;
ssize_t send(const char *data);
ssize_t write(const char *data, size_t len) override;
ssize_t read(char *data, size_t len) override;
//! Sets the socket timeout. This utilizes setsockopt which does not
//! work in non blocking sockets.
Status setSocketTimeout(int secs, int usecs);
Device::Status setNonBlocking(bool nb) override;
bool isNonBlocking() const { return _flags & NonBlocking; }
bool isAccepted() const { return !(_flags & InAccept); }
Status setReuseAddr(bool ra);
Status setNoDelay(bool nd);
//! Switches resolving host names when a new connection is accepted.
//! This feature is disabled by default and can significantly slow
//! down the server if enabled.
Status setResolveHostnames(bool rh);
virtual Status connect(const std::string &hostname, port_t port);
/**
* @brief Connects to an IPv6 host.
* @param hostname The hostname or IP address
* @param port The port number
* @return The status of the connect operation
*/
virtual Status connectV6(const std::string &hostname, port_t port);
virtual Status bind(IPAddress ip, port_t port);
virtual Status bindV6(IPAddress ip, port_t port);
Status listen(int backlog = 10);
virtual Socket *accept();
count_t rx() const { return _bytesReceived; }
count_t tx() const { return _bytesSent; }
protected:
Status applySocketTimeout(int secs, int usecs);
protected:
enum Flags {
NoFlags = 0x0000,
ReuseAddress = 0x0001,
NonBlocking = 0x0002,
ResolveName = 0x0004,
NoDelay = 0x0008,
//Future2 = 0x0010,
//Future3 = 0x0020,
//Future4 = 0x0040,
//Future5 = 0x0080,
InAccept = 0x0100
};
static int _socketCount;
std::string _hostname;
IPAddress _addr;
port_t _port;
uint16_t _flags;
count_t _bytesSent;
count_t _bytesReceived;
int _timeOutSecs;
int _timeOutUsecs;
friend class SSLSocket;
};
DEFINE_SMARTPOINTER(SSLSocket);
class SSLSocket : public Socket {
public:
SSLSocket();
/**
* @brief Creates an SSL socket with an SSL context. The socket will
* then re-use this context and not create a default one.
* @param ctx The SSL context pointer.
* @param shared If true then the reference count of the SSL context
* will be increased. That might be important if the
* same context is shared between many SSL sockets.
* The caller must then call SSL_CTX_free on the passed
* context to release the refence count again.
*/
SSLSocket(SSL_CTX *ctx, bool shared = false);
~SSLSocket();
public:
Status bind(IPAddress ip, port_t port) override;
Status bindV6(IPAddress ip, port_t port) override;
void close() override;
Socket *accept() override;
ssize_t write(const char *data, size_t len) override;
ssize_t read(char *data, size_t len) override;
Status connect(const std::string &hostname, port_t port) override;
Status connectV6(const std::string &hostname, port_t port) override;
/**
* @brief Takes the connection from a socket and renders the source
* socket invalid.
* @param socket The socket the connection parameters will be taken from.
* @return Status flag
*/
Status take(Socket *socket);
SSL_CTX *sslContext() const;
SSL *ssl() const;
/**
* @brief Returns the peer certificate presented by the other end.
* @return An X509 pointer which is managed by this instance. It must
* not be deleted.
*/
X509 *peerCertificate() const;
/**
* @brief Creates SSL client context from PKCS12 file
* @param pkcs12File Absolute path to pkcs12File
* @return The client SSL context
*/
static SSL_CTX *createClientContextFromFile(const std::string &pkcs12File);
/**
* @brief Creates SSL client context from Base64 encoded PKCS12 certificate
* @param cert The Base64 encoded PKCS12 certificate
* @return The client SSL context
*/
static SSL_CTX *createClientContext(const std::string &cert);
/**
* @brief Creates SSL client context from OpenSSL PKCS12 structure
* @param p12 Pointer to PKCS12 structure
* @return The client SSL context
*/
static SSL_CTX *createClientContext(PKCS12 *p12);
static SSL_CTX *createClientContext(const char *pemCert, const char *pemKey);
static SSL_CTX *createServerContext(const char *pemCert, const char *pemKey);
private:
void cleanUp();
private:
SSL *_ssl;
SSL_CTX *_ctx;
};
inline SSL_CTX *SSLSocket::sslContext() const {
return _ctx;
}
inline SSL *SSLSocket::ssl() const {
return _ssl;
}
inline X509 *SSLSocket::peerCertificate() const {
return SSL_get_peer_certificate(_ssl);
}
/**
* @brief Returns a human readable description for the last
* failed operation.
* @return The description string
*/
const char *getSystemError(Socket *socket);
/**
* @brief Returns a human readable description for the last
* failed SSL operation.
* @return The description string
*/
const char *getSSLSystemError();
std::ostream &operator<<(std::ostream &, const Socket::IPAddress &ip);
std::ostream &operator<<(std::ostream &, const Anonymize<Socket::IPAddress> &ip);
std::string toString(const Socket::IPAddress &ip);
}
}
#endif

View File

@ -0,0 +1,117 @@
/***************************************************************************
* 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_WIRED_ACCEPTOR_H
#define SEISCOMP_WIRED_ACCEPTOR_H
#include <seiscomp/wired/devices/socket.h>
#include <seiscomp/wired/session.h>
#include <seiscomp/wired/ipacl.h>
namespace Seiscomp {
namespace Wired {
class Server;
DEFINE_SMARTPOINTER(Endpoint);
class SC_SYSTEM_CORE_API Endpoint : public Session {
// ----------------------------------------------------------------------
// X'truction
// ----------------------------------------------------------------------
public:
/**
* @brief Endpoint constructor
* @param sock The socket the endpoint listens on.
*/
Endpoint(Socket *sock);
// ----------------------------------------------------------------------
// Connection interface
// ----------------------------------------------------------------------
public:
void update() override;
Socket *socket() const { return static_cast<Socket*>(_device.get()); }
Session *accept(Socket *socket);
// ----------------------------------------------------------------------
// Protected interface
// ----------------------------------------------------------------------
protected:
virtual bool checkSocket(Socket *socket) const;
virtual Session *createSession(Socket *socket);
};
class SC_SYSTEM_CORE_API AccessControlledEndpoint : public Endpoint {
// ----------------------------------------------------------------------
// X'truction
// ----------------------------------------------------------------------
public:
/**
* @brief AccessControlledEndpoint constructor
* @param sock The socket to listen on
* @param allowedIPs The list of allowed IPs to connect
* @param deniedIPs The list of blocked IPs
*/
AccessControlledEndpoint(Socket *sock,
const IPACL &allowedIPs,
const IPACL &deniedIPs);
/**
* @brief Compares the IPACL of the object with the given one
* @param allowedIPs The list of allowed IPs
* @param deniedIPs The list of blocked IPs
* @return True, if the lists are equal
*/
bool compareIPACL(const IPACL &allowedIPs, const IPACL &deniedIPs) const;
// ----------------------------------------------------------------------
// Protected Endpoint interface
// ----------------------------------------------------------------------
protected:
bool checkSocket(Socket *socket) const override;
// ----------------------------------------------------------------------
// Protected members
// ----------------------------------------------------------------------
protected:
IPACL _allowedIPs;
IPACL _deniedIPs;
};
}
}
#endif

View File

@ -0,0 +1,157 @@
/***************************************************************************
* 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_WIRED_IPACL_H
#define SEISCOMP_WIRED_IPACL_H
#include <vector>
#include <string>
#include <seiscomp/wired/devices/socket.h>
namespace Seiscomp {
namespace Wired {
/**
* @brief The IPMask struct holds an IP4/6 address and an IP4/6 mask
*/
struct SC_SYSTEM_CORE_API IPMask {
IPMask(uint32_t addr_ = 0, uint32_t mask_ = 0)
: addr(addr_), mask(mask_) {}
IPMask(Socket::IPAddress addr_, Socket::IPAddress mask_)
: addr(addr_), mask(mask_) {}
bool operator==(const IPMask &other) const {
return (addr == other.addr && mask == other.mask);
}
bool operator!=(const IPMask &other) const {
return !operator==(other);
}
Socket::IPAddress addr;
Socket::IPAddress mask;
};
std::string toString(const IPMask &mask);
bool fromString(IPMask &mask, const std::string &str);
/**
* @brief The IPACL class wraps the functionality of an IP access control list
*
* This class holds a list of IP address/mask pairs and checks if an IP matches
* or not. It does not define whether it is a whitelist or blacklist.
*/
class SC_SYSTEM_CORE_API IPACL {
public:
typedef std::vector<IPMask> IPMasks;
typedef IPMasks::const_iterator const_iterator;
// ----------------------------------------------------------------------
// Public interface
// ----------------------------------------------------------------------
public:
/**
* @brief Adds an IP mask in string representation, e.g. "192.168.0.0/24"
* @param ip The IP mask as string
* @return true on success, false otherwise
*/
bool add(const std::string &ip);
/**
* @brief Checks if an IP address matches any of the items in the ACL.
* @param ip IP address in 32bit binary representation
* @return true if it matches, false otherwise. If the ACL list is
* empty, it returns true as well
*/
bool check(const Socket::IPAddress &ip) const;
/**
* @brief Checks if an IP address does not match any of the items in
* the ACL
* @param ip IP address in 32bit binary representation
* @return true if it does not match, false otherwise. If the ACL list is
* empty, it returns true as well
*/
bool not_check(const Socket::IPAddress &ip) const;
//! Clears the ACL list
void clear();
//! Checks if ACL is empty
bool empty() const;
const_iterator begin() const;
const_iterator end() const;
/**
* @brief Merges two access lists
* @param other The other access list to be merged into this
* @return This instance
*/
IPACL &operator+=(const IPACL &other);
/**
* @brief Removes items in this which are also in other
* @param other The other access list to be removed from this
* @return This instance
*/
IPACL &operator-=(const IPACL &other);
/**
* @brief operator == Compares IPACL objects
* @param other The other IPACL object
* @return True, if both objects are equal
*/
bool operator==(const IPACL &other) const;
// ----------------------------------------------------------------------
// Private members
// ----------------------------------------------------------------------
private:
IPMasks _masks;
};
std::string toString(const IPACL &acl);
bool fromString(IPACL &acl, const std::string &str);
inline IPACL::const_iterator IPACL::begin() const {
return _masks.begin();
}
inline IPACL::const_iterator IPACL::end() const {
return _masks.end();
}
}
}
#endif

View File

@ -0,0 +1,99 @@
/***************************************************************************
* 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_WIRED_MIME_H
#define SEISCOMP_WIRED_MIME_H
#include <list>
#include <seiscomp/core/enumeration.h>
namespace Seiscomp {
namespace Wire {
namespace MIME {
// Section 7.2
class Multipart {
public:
struct CustomHeader {
CustomHeader()
: name(nullptr), name_len(0), value(nullptr), value_len(0) {}
const char *name;
size_t name_len;
const char *value;
size_t value_len;
};
typedef std::list<CustomHeader> CustomHeaders;
static bool ParseContentType(const std::string &contentType,
std::string &subtype,
std::string &boundary);
Multipart(const std::string &boundary, const std::string &s);
Multipart(const std::string &boundary, const char *src, size_t l);
bool next();
bool typeEquals(const char *s) const;
bool typeStartsWith(const char *s, size_t len) const;
bool operator==(const std::string &type) const {
return typeEquals(type.c_str());
}
const CustomHeaders &customHeaders() { return _customHeaders; }
protected:
void init(const std::string &boundary, const char *src, size_t l);
size_t findString(const char *needle, size_t len, size_t haystack_len = std::string::npos);
public:
const char *type;
size_t type_len;
const char *disposition;
size_t disposition_len;
const char *transfer_enc;
size_t transfer_enc_len;
const char *body;
size_t body_len;
protected:
std::string _boundary;
const char *_source;
size_t _source_len;
size_t _part;
CustomHeaders _customHeaders;
};
}
}
}
#endif

View File

@ -0,0 +1,551 @@
/***************************************************************************
* 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_WIRED_PROTOCOLS_HTTP_H
#define SEISCOMP_WIRED_PROTOCOLS_HTTP_H
#include <seiscomp/core/enumeration.h>
#include <seiscomp/core/datetime.h>
#include <seiscomp/core/strings.h>
#include <seiscomp/wired/clientsession.h>
#include "websocket.h"
namespace Seiscomp {
namespace Wired {
MAKEENUM(
HttpStatus,
EVALUES(
HTTP_101,
HTTP_200,
HTTP_201,
HTTP_202,
HTTP_203,
HTTP_204,
HTTP_205,
HTTP_206,
HTTP_207,
HTTP_300,
HTTP_301,
HTTP_302,
HTTP_303,
HTTP_304,
HTTP_305,
HTTP_306,
HTTP_307,
HTTP_310,
HTTP_400,
HTTP_401,
HTTP_402,
HTTP_403,
HTTP_404,
HTTP_405,
HTTP_406,
HTTP_407,
HTTP_408,
HTTP_409,
HTTP_410,
HTTP_411,
HTTP_412,
HTTP_413,
HTTP_414,
HTTP_415,
HTTP_416,
HTTP_417,
HTTP_418,
HTTP_421,
HTTP_422,
HTTP_423,
HTTP_424,
HTTP_425,
HTTP_426,
HTTP_500,
HTTP_501,
HTTP_502,
HTTP_503,
HTTP_504,
HTTP_505,
HTTP_506,
HTTP_507,
HTTP_509,
HTTP_510,
HTTP_LAST
),
ENAMES(
"101 Switching Protocols",
"200 OK",
"201 Created",
"202 Accepted",
"203 Non-Authoritative Information",
"204 No Content",
"205 Reset Content",
"206 Partial Content",
"207 Multi-Status",
"300 Multiple Choice",
"301 Moved Permanently",
"302 Found",
"303 See Other",
"304 Not Modified",
"305 Use Proxy",
"306 (reserved)",
"307 Temporary Redirect",
"310 ERR_TOO_MANY_REDIRECTS",
"400 Bad Request",
"401 Unauthorized",
"402 Payment Required",
"403 Forbidden",
"404 Not Found",
"405 Method Not Allowed",
"406 Not Acceptable",
"407 Proxy Authentication Required",
"408 Request Time-out",
"409 Conflict",
"410 Gone",
"411 Length Required",
"412 Precondition Failed",
"413 Request Entity Too Large",
"414 Request-URI Too Long",
"415 Unsupported Media Type",
"416 Requested range not satisfiable",
"417 Expectation Failed",
"418 I'm a Teapot",
"421 There are too many connections from your internet address",
"422 Unprocessable Entity",
"423 Locked",
"424 Failed Dependency",
"425 Unordered Collection",
"426 Upgrade Required",
"500 Internal Server Error",
"501 Not Implemented",
"502 Bad Gateway",
"503 Service Unavailable",
"504 Gateway Time-out",
"505 HTTP Version not supported",
"506 Variant Also Negotiates",
"507 Insufficient Storage",
"509 Bandwidth Limit Exceeded",
"510 Not Extended",
""
)
);
struct HttpRequest {
typedef Seiscomp::Core::Time Time;
MAKEENUM(
Type,
EVALUES(GET, POST, OPTIONS, HEAD, PUT, DELETE, TRACE),
ENAMES("GET", "POST", "OPTIONS", "HEAD", "PUT", "DELETE", "TRACE")
);
enum State {
WAITING, // Waiting state
ENABLED, // Request has enabled but not yet started
READING, // Still reading the request
RUNNING, // Running independently
QRUNNING, // Running by using a request queue
FINISHED // Finished
};
Type type;
State state;
std::string version;
std::string userAgent;
std::string host;
std::string path;
std::string contentType;
std::string options;
std::string cookie;
std::string referer;
std::string origin;
std::string upgradeTo;
std::string data;
std::string secWebsocketProtocol;
std::string secWebsocketKey;
int secWebsocketVersion;
Time ifModifiedSince;
bool keepAlive;
bool addKeepAliveHeader;
bool upgrade;
bool isXMLHTTP;
HttpStatus status;
Device::count_t tx;
};
struct URLOptionName {
URLOptionName(const char *s) : name(s) {}
const char *name;
};
struct URLOptionValue {
URLOptionValue(const char *s) : value(s) {}
const char *value;
};
struct URLOptions {
URLOptions(const std::string &s) : _source(s.data()), _source_len(s.size()) {}
URLOptions(const char *src, size_t l) : _source(src), _source_len(l) {}
bool next();
bool nameEquals(const char *s) const;
bool valueEquals(const char *s) const;
bool operator==(const URLOptionName &wrapper) const {
return nameEquals(wrapper.name);
}
bool operator==(const URLOptionValue &wrapper) const {
return valueEquals(wrapper.value);
}
const char *_source;
size_t _source_len;
const char *name_start;
size_t name_len;
const char *val_start;
size_t val_len;
};
struct URLInsituOptions {
URLInsituOptions(std::string &s) : _source(&s[0]), _source_len(s.size()) {}
URLInsituOptions(char *src, size_t l) : _source(src), _source_len(l) {}
bool next();
bool nameEquals(const char *s) const;
bool valueEquals(const char *s) const;
bool operator==(const URLOptionName &wrapper) const {
return nameEquals(wrapper.name);
}
bool operator==(const URLOptionValue &wrapper) const {
return valueEquals(wrapper.value);
}
const char *_source;
size_t _source_len;
char *name;
size_t name_len;
char *val;
size_t val_len;
};
class URLPath {
public:
URLPath(const std::string &s);
URLPath(const char *src, size_t l);
public:
bool empty() const { return part_len == 0; }
bool next();
bool partEquals(const char *s) const;
const char *remainder() const;
size_t remainderLength() const;
// Checks a sub path for equality
bool operator==(const char *s) const { return partEquals(s); }
bool operator!=(const char *s) const { return !partEquals(s); }
public:
const char *part_start;
size_t part_len;
private:
const char *_source;
size_t _source_len;
};
class URLInsituPath {
public:
URLInsituPath(std::string &s);
URLInsituPath(char *src, size_t l);
public:
bool empty() const { return part_len == 0; }
bool next();
bool partEquals(const char *s) const;
char *savePart();
char *remainder() const;
size_t remainderLength() const;
// Checks a sub path for equality
bool operator==(const char *s) const { return partEquals(s); }
bool operator!=(const char *s) const { return !partEquals(s); }
public:
char *part_start;
size_t part_len;
private:
char *_source;
size_t _source_len;
};
DEFINE_SMARTPOINTER(HttpSession);
class SC_SYSTEM_CORE_API HttpSession : public ClientSession {
public:
static std::string EmptyString;
public:
HttpSession(Device *sock, const char *protocol,
const char *server = nullptr);
~HttpSession() override;
public:
void sendResponse(HttpStatus status);
void sendResponse(const std::string &,
HttpStatus status,
const char *contentType,
const char *cookie = nullptr);
void sendResponse(const char *, size_t len,
HttpStatus status,
const char *contentType,
const char *cookie = nullptr);
/*
* additionalHeader must contain a trailing newline (\r\n) for
* each line.
*/
void sendResponse(Buffer*,
HttpStatus status,
const char *contentType,
const char *cookie = nullptr,
const char *additionalHeader = nullptr);
void sendStatus(HttpStatus status, const std::string &content = EmptyString,
const char *contentType = "text/plain");
void close() override;
void redirect(const char *path);
//! Resets a connection to its default state. Return false if
//! an error should be raised and to terminate the session.
//! reset is used if a waiting connection is reused and receives
//! a new request.
virtual bool reset();
virtual void handleHeader(const char *name, size_t nlen,
const char *value, size_t vlen);
virtual bool handleRequest(HttpRequest &req);
virtual bool handleGETRequest(HttpRequest &req);
virtual bool handlePOSTRequest(HttpRequest &req);
virtual bool handleOPTIONSRequest(HttpRequest &req);
virtual bool handleHEADRequest(HttpRequest &req);
virtual bool handlePUTRequest(HttpRequest &req);
virtual bool handleDELETERequest(HttpRequest &req);
virtual bool handleTRACERequest(HttpRequest &req);
// Websocket functions
void upgradeToWebsocket(HttpRequest &req, const char *protocol,
uint64_t maxPayloadSize = 0);
virtual void handleWebsocketFrame(Websocket::Frame &frame);
//! Send a response as Websocket frame. If status is not NoStatus
//! the connection is closed and the close parameter is ignored.
void sendWebsocketResponse(const char *data, int len,
Websocket::Frame::Type type,
Websocket::Status statusCode =
Websocket::NoStatus,
bool close = false);
static std::string urlencode(const std::string &s);
static std::string urlencode(const char *s, int len);
static std::string urldecode(const std::string &s);
static std::string urldecode(const char *s, int len);
static int urldecode(char *s, int len);
protected:
//! Handles a socket read for Websockets
void handleReceive(const char *data, size_t len) override;
void handleInbox(const char *data, size_t len) override;
void handleInboxError(Error error) override;
void handlePostData(const char *data, size_t len) override;
void outboxFlushed() override;
virtual bool validatePostDataSize(size_t postDataSize);
virtual void requestFinished();
protected:
//! const char reference that needs to be managed by the application
const char *_protocol;
const char *_server;
bool _requestStarted;
size_t _dataSize;
bool _dataStarted;
bool _acceptGzip;
bool _upgradedToWebsocket;
Websocket::FramePtr _websocketFrame;
HttpRequest _request;
};
inline URLPath::URLPath(const std::string &s)
: _source(&s[0])
, _source_len(s.size())
{
while ( _source_len && (*_source == '/') ) {
++_source;
--_source_len;
}
}
inline URLPath::URLPath(const char *src, size_t l)
: _source(src)
, _source_len(l)
{
while ( _source_len && (*_source == '/') ) {
++_source;
--_source_len;
}
}
inline bool URLPath::next() {
size_t len;
const char *data = Core::tokenize(_source, "/", _source_len, len);
if ( data != nullptr ) {
Core::trim(data, len);
part_start = data;
part_len = len;
return true;
}
part_start = nullptr;
part_len = 0;
return false;
}
inline bool URLPath::partEquals(const char *s) const {
if ( strlen(s) != part_len ) return false;
return !strncmp(s, part_start, part_len);
}
inline const char *URLPath::remainder() const {
return _source;
}
inline size_t URLPath::remainderLength() const {
return _source_len;
}
inline URLInsituPath::URLInsituPath(std::string &s)
: part_start(&s[0])
, part_len(0)
, _source(part_start)
, _source_len(s.size())
{
while ( _source_len && (*_source == '/') ) {
++_source;
--_source_len;
}
}
inline URLInsituPath::URLInsituPath(char *src, size_t l)
: part_start(src)
, part_len(0)
, _source(part_start)
, _source_len(l)
{
while ( _source_len && (*_source == '/') ) {
++_source;
--_source_len;
}
}
inline bool URLInsituPath::next() {
size_t len;
char *data = Core::tokenize2(_source, "/", _source_len, len);
if ( data != nullptr ) {
Core::trim(data,len);
part_start = data;
part_len = len;
return true;
}
part_start = nullptr;
part_len = 0;
return false;
}
inline bool URLInsituPath::partEquals(const char *s) const {
if ( strlen(s) != part_len ) return false;
return !strncmp(s, part_start, part_len);
}
inline char *URLInsituPath::savePart() {
part_start[part_len] = '\0';
return part_start;
}
inline char *URLInsituPath::remainder() const {
return _source;
}
inline size_t URLInsituPath::remainderLength() const {
return _source_len;
}
}
}
#endif

View File

@ -0,0 +1,151 @@
/***************************************************************************
* 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_WIRED_PROTOCOLS_WEBSOCKET_H
#define SEISCOMP_WIRED_PROTOCOLS_WEBSOCKET_H
#include <string>
#include <stdint.h>
#include <seiscomp/wired/buffer.h>
namespace Seiscomp {
namespace Wired {
namespace Websocket {
enum Status {
// No status set
NoStatus = 0,
// Normal closure; the connection successfully completed whatever
// purpose for which it was created.
CloseNormal = 1000,
// The endpoint is going away, either because of a server failure
// or because the browser is navigating away from the page that
// opened the connection.
CloseGoingAway = 1001,
// The endpoint is terminating the connection due to a protocol
// error.
CloseProtocolError = 1002,
// The connection is being terminated because the endpoint received
// data of a type it cannot accept (for example, a text-only
// endpoint received binary data).
CloseUnsupported = 1003,
// Reserved. Indicates that no status code was provided even though
// one was expected.
CloseNoStatus = 1005,
// Reserved. Used to indicate that a connection was closed
// abnormally (that is, with no close frame being sent) when a
// status code is expected.
CloseAbnormal = 1006,
// The endpoint is terminating the connection because a message
// was received that contained inconsistent data (e.g., non-UTF-8
// data within a text message).
CloseInconsistentData = 1007,
// The endpoint is terminating the connection because it received
// a message that violates its policy. This is a generic status code,
// used when codes 1003 and 1009 are not suitable.
CloseViolatePolicy = 1008,
// The endpoint is terminating the connection because a data frame
// was received that is too large.
CloseTooLarge = 1009,
// The client is terminating the connection because it expected
// the server to negotiate one or more extension, but the server
// didn't.
CloseExpectedExts = 1010,
// The server is terminating the connection because it encountered
// an unexpected condition that prevented it from fulfilling the
// request.
CloseUnexpectedCondition = 1011
};
DEFINE_SMARTPOINTER(Frame);
class Frame : public Seiscomp::Core::BaseObject {
public:
enum Type {
ContinuationFrame = 0x00,
TextFrame = 0x01,
BinaryFrame = 0x02,
ConnectionClose = 0x08,
Ping = 0x09,
Pong = 0x0A
};
public:
Frame();
//! Resets the header
void reset();
void setMaxPayloadSize(uint64_t size);
//! Returns the number of bytes read from the input buffer
//! If an protocol error occured, -1 is returned.
ssize_t feed(const char *data, size_t len);
bool isFinished() { return _isFinished; }
static void finalizeBuffer(Buffer *buf, Type type, Status statusCode = NoStatus);
private:
typedef bool (Frame::*ItemCallback)();
bool next(size_t nBytes, void *dst, ItemCallback cb);
bool readControl();
bool readPayload1();
bool readPayload16();
bool readPayload64();
bool readMask();
bool dataComplete();
bool readStatus();
bool readData();
private:
size_t _bytesToRead;
uint8_t *_buffer;
ItemCallback _func;
bool _isFinished;
uint8_t _control;
uint64_t _maxPayloadSize;
public:
Type type;
uint16_t status;
bool isMasked;
bool finalFragment;
uint64_t payloadLength;
uint32_t mask;
std::string data;
};
}
}
}
#endif

View File

@ -0,0 +1,180 @@
/***************************************************************************
* 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_WIRED_REACTOR_H
#define SEISCOMP_WIRED_REACTOR_H
#include <seiscomp/wired/devices/socket.h>
#include <seiscomp/core/list.h>
#include <mutex>
namespace Seiscomp {
namespace Wired {
DEFINE_SMARTPOINTER(Session);
DEFINE_SMARTPOINTER(Reactor);
typedef Core::Generic::IntrusiveList<SessionPtr> SessionList;
/**
* @brief The Reactor class is the core event loop.
*
* The reactor waits for activity on any of its managed devices and dispatches
* the events. It basically calls the update() method on a session thats device
* is ready to read or write. In case of an exception the device is closed and
* the session is being removed.
*
* The underlying implementation uses either epoll on Linux or kqueue on BSD
* or OSX.
*/
class SC_SYSTEM_CORE_API Reactor : public Seiscomp::Core::BaseObject {
// ----------------------------------------------------------------------
// Public enumerations
// ----------------------------------------------------------------------
public:
typedef DeviceGroup::TriggerMode TriggerMode;
// ----------------------------------------------------------------------
// X'truction
// ----------------------------------------------------------------------
public:
//! C'tor
Reactor();
// ----------------------------------------------------------------------
// Public interface
// ----------------------------------------------------------------------
public:
//! Adds a session to the reactor.
virtual bool addSession(Session *session);
//! Schedules adding a session to the reactor. The session will be added
//! in the same thread the reactors run loop is running. Call interrupt
//! after all sessions have been added.
//! @note This method is only useful when adding a session from a different
//! thread.
virtual bool addSessionDeferred(Session *session);
//! Removes a session from the reactor
virtual bool removeSession(Session *session);
//! Moves a session from this to another reactor. The session
//! is going to be removed from this reactor and will be scheduled
//! in the target reactor. Call interrupt afterwards on the
//! target reactor.
//! @note This method is only useful when both reactors are running
//! in different threads.
void moveTo(Reactor *target, Session *session);
//! Returns the number of sessions in this reactor
size_t count() const;
bool setTimer(uint32_t seconds, uint32_t milliseconds, DeviceGroup::TimeoutFunc func);
bool clearTimer();
//! Sets up the device polling infrastructure and returns a success
//! flag.
bool setup();
//! Run the reactor blocking
virtual bool run();
bool isRunning() const { return _isRunning; }
virtual Device *wait();
//! Returns if the reactor has been interrupted or not
bool interrupted() const { return _devices.interrupted(); }
//! The method is called between DeviceGroup::wait
virtual void idle();
//! Shutdown the reactor causing to terminate
//! the run loop and closing all handled sessions
virtual void shutdown();
//! Clean up all sessions and sockets
virtual void clear();
//! Synchronizes a release of a session smart pointer in
//! a threaded environment and sets the passed ptr to nullptr.
void release(SessionPtr &ptr);
//! Interrupts the reactors wait causing to idle method to be called
void interrupt();
//! Interrupts the reactor causing the run loop to terminate.
//! The session sockets are not closed and resume can
//! be used to continue operation.
void stop();
//! Clears the stop state and allows run to be called again.
void resume();
bool setTriggerMode(TriggerMode);
TriggerMode triggerMode() const;
const SessionList &sessions() const;
const DeviceGroup *devices() const;
/**
* @brief getBuffer returns a temporary buffer that sessions can use
* to read from device.
* @param buf Address that is populated with the buffer address
* @param len Length will hold the length of the buffer
*/
void getBuffer(char *&buf, size_t &len);
// ----------------------------------------------------------------------
// Protected events
// ----------------------------------------------------------------------
protected:
virtual void sessionAdded(Session *session);
virtual void sessionRemoved(Session *session);
virtual void sessionTagged(Session *session);
// ----------------------------------------------------------------------
// Protected members
// ----------------------------------------------------------------------
protected:
mutable std::mutex _mutex;
mutable std::mutex _sessionMutex;
std::vector<char> _buffer;
bool _shouldRun;
bool _isRunning;
SessionList _sessions;
SessionList _deferredSession;
DeviceGroup _devices;
};
}
}
#endif

View File

@ -0,0 +1,132 @@
/***************************************************************************
* 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_WIRED_SERVER_H
#define SEISCOMP_WIRED_SERVER_H
#include <seiscomp/wired/reactor.h>
#include <seiscomp/wired/endpoint.h>
namespace Seiscomp {
namespace Wired {
DEFINE_SMARTPOINTER(Server);
class SC_SYSTEM_CORE_API Server : public Reactor {
// ----------------------------------------------------------------------
// X'truction
// ----------------------------------------------------------------------
public:
//! C'tor
Server();
//! D'tor
~Server() override;
// ----------------------------------------------------------------------
// Public interface
// ----------------------------------------------------------------------
public:
void setCertificate(const std::string&);
void setPrivateKey(const std::string&);
//! Initializes the server and starts listening
//! on all defined ports
virtual bool init();
//! Shutdown the server causing the run loop to terminate.
virtual void shutdown() override;
//! Clean up all sessions and sockets
virtual void clear() override;
//! Adds a session to a server
virtual bool addSession(Session *session) override;
virtual bool removeSession(Session *session) override;
/**
* @brief Adds an endpoint session to the server. It will create a
* corresponding socket (either unencrypted or SSL) and attach
* it to the session.
* @param ip The bind address
* @param port The port to listen on
* @param useSSL Whether to use SSL or not
* @param endpoint The endpoint instance
* @return Status flag
*/
bool addEndpoint(Socket::IPAddress ip, Socket::port_t port, bool useSSL,
Endpoint *endpoint);
/**
* @brief Adds an endpoint session to the server. This function
* requires a socket to be present for the endpoint. It will
* set the socket to non-blocking and call bind on it with the
* respective IP address and port.
* @param ip The bind address
* @param port The port to listen on
* @param endpoint The endpoint instance
* @return Status flag
*/
bool addEndpoint(Socket::IPAddress ip, Socket::port_t port, Endpoint *endpoint);
/**
* @brief Adds an IPv6 endpoint bound to a port to the server.
* @param ip The bind IP mask
* @param port The port number to accept incoming connections.
* @param useSSL Flag if SSL should be used or not
* @param endpoint The implementation of the endpoint
* @return Success flag
*/
bool addEndpointV6(Socket::IPAddress ip, Socket::port_t port,
bool useSSL, Endpoint *endpoint);
bool removeEndpoint(Endpoint *endpoint);
bool clearEndpoints();
const SessionList &endpoints() const;
// ----------------------------------------------------------------------
// Protected interface
// ----------------------------------------------------------------------
protected:
virtual void endpointRemoved(Endpoint *endpoint);
// ----------------------------------------------------------------------
// Private members
// ----------------------------------------------------------------------
private:
std::string _certificate;
std::string _privateKey;
SessionList _endpoints;
};
}
}
#endif

View File

@ -0,0 +1,112 @@
/***************************************************************************
* 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_WIRED_SESSION_H
#define SEISCOMP_WIRED_SESSION_H
#include <seiscomp/wired/devices/socket.h>
#include <seiscomp/core/list.h>
namespace Seiscomp {
namespace Wired {
class Reactor;
class Server;
DEFINE_SMARTPOINTER(Session);
class SC_SYSTEM_CORE_API Session : public Core::BaseObject,
public Core::Generic::IntrusiveListItem<SessionPtr> {
// ----------------------------------------------------------------------
// X'truction
// ----------------------------------------------------------------------
protected:
//! Protected c'tor
Session(Device *dev);
public:
~Session() override;
// ----------------------------------------------------------------------
// Public interface
// ----------------------------------------------------------------------
public:
void setDevice(Device *dev);
Device *device() const;
Reactor *parent() const { return _parent; }
/**
* @brief Called if the underlying device completed the handshake with
* the remote end and is ready to receive and send data.
* The default implementation does nothing.
*/
virtual void accepted();
//! Update the session state.
virtual void update() = 0;
//! Close the session and terminate the connection.
virtual void close();
/**
* @brief Called if the underlying device times out.
* The default implementation return false.
* @return Whether to close the connection (false) or to keep it (true).
*/
virtual bool handleTimeout();
void setTag(bool t) { _tagged = t; }
bool isTagged() const { return _tagged; }
// ----------------------------------------------------------------------
// Protected members
// ----------------------------------------------------------------------
protected:
DevicePtr _device;
Reactor *_parent;
// ----------------------------------------------------------------------
// Private members
// ----------------------------------------------------------------------
private:
bool _tagged;
// ----------------------------------------------------------------------
// Friends
// ----------------------------------------------------------------------
friend class Reactor;
friend class Server;
};
}
}
#endif