[seiscomp, scanloc] Install, add .gitignore
This commit is contained in:
83
include/seiscomp/wired/buffer.h
Normal file
83
include/seiscomp/wired/buffer.h
Normal 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
|
80
include/seiscomp/wired/buffers/file.h
Normal file
80
include/seiscomp/wired/buffers/file.h
Normal 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
|
159
include/seiscomp/wired/clientsession.h
Normal file
159
include/seiscomp/wired/clientsession.h
Normal 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
|
341
include/seiscomp/wired/device.h
Normal file
341
include/seiscomp/wired/device.h
Normal 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 ⌖
|
||||
};
|
||||
|
||||
|
||||
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
|
52
include/seiscomp/wired/devices/fd.h
Normal file
52
include/seiscomp/wired/devices/fd.h
Normal 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
|
368
include/seiscomp/wired/devices/socket.h
Normal file
368
include/seiscomp/wired/devices/socket.h
Normal 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
|
117
include/seiscomp/wired/endpoint.h
Normal file
117
include/seiscomp/wired/endpoint.h
Normal 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
|
157
include/seiscomp/wired/ipacl.h
Normal file
157
include/seiscomp/wired/ipacl.h
Normal 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
|
99
include/seiscomp/wired/mime.h
Normal file
99
include/seiscomp/wired/mime.h
Normal 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
|
551
include/seiscomp/wired/protocols/http.h
Normal file
551
include/seiscomp/wired/protocols/http.h
Normal 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
|
151
include/seiscomp/wired/protocols/websocket.h
Normal file
151
include/seiscomp/wired/protocols/websocket.h
Normal 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
|
180
include/seiscomp/wired/reactor.h
Normal file
180
include/seiscomp/wired/reactor.h
Normal 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
|
132
include/seiscomp/wired/server.h
Normal file
132
include/seiscomp/wired/server.h
Normal 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
|
112
include/seiscomp/wired/session.h
Normal file
112
include/seiscomp/wired/session.h
Normal 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
|
Reference in New Issue
Block a user