mistserver/lib/shared_memory.h
2021-10-19 22:29:40 +02:00

269 lines
8.8 KiB
C++

#pragma once
#include <set>
#include <string>
#include "defines.h"
#include "timing.h"
#if defined(__CYGWIN__) || defined(_WIN32)
#include <windows.h>
#else
#include <semaphore.h>
#endif
#ifndef ACCESSPERMS
#define ACCESSPERMS (S_IRWXU | S_IRWXG | S_IRWXO)
#endif
#define STAT_EX_SIZE 177
#define PLAY_EX_SIZE 2 + 6 * SIMUL_TRACKS
namespace IPC{
///\brief A class used for the exchange of statistics over shared memory.
class statExchange{
public:
statExchange(char *_data);
void now(long long int time);
long long int now();
void time(long time);
long time();
void lastSecond(long time);
long lastSecond();
void down(long long int bytes);
long long int down();
void up(long long int bytes);
long long int up();
void host(std::string name);
std::string host();
void streamName(std::string name);
std::string streamName();
void connector(std::string name);
std::string connector();
void crc(unsigned int sum);
char getSync();
void setSync(char s);
unsigned int crc();
uint32_t getPID();
std::string getSessId();
private:
///\brief The payload for the stat exchange
/// - 8 byte - now (timestamp of last statistics)
/// - 4 byte - time (duration of the current connection)
/// - 4 byte - lastSecond (last second of content viewed)
/// - 8 byte - down (Number of bytes received from peer)
/// - 8 byte - up (Number of bytes sent to peer)
/// - 16 byte - host (ip address of the peer)
/// - 100 byte - streamName (name of the stream peer is viewing)
/// - 20 byte - connector (name of the connector the peer is using)
/// - 4 byte - CRC32 of user agent (or zero if none)
/// - 1 byte sync (was seen by controller yes/no)
/// - (implicit 4 bytes: PID)
char *data;
};
///\brief A class used for the abstraction of semaphores
class semaphore{
public:
semaphore();
semaphore(const char *name, int oflag, mode_t mode = 0, unsigned int value = 0, bool noWait = false);
~semaphore();
operator bool() const;
void open(const char *name, int oflag, mode_t mode = 0, unsigned int value = 0, bool noWait = false);
int getVal() const;
void post();
void wait();
bool tryWait();
bool tryWaitOneSecond();
void close();
void abandon();
void unlink();
private:
#if defined(__CYGWIN__) || defined(_WIN32)
///\todo Maybe sometime implement anything else than 777
static SECURITY_ATTRIBUTES getSecurityAttributes();
HANDLE mySem;
#else
sem_t *mySem;
#endif
unsigned int isLocked;
uint64_t lockTime;
std::string myName;
};
///\brief A class used as a semaphore guard
class semGuard{
public:
semGuard(semaphore *thisSemaphore);
~semGuard();
private:
///\brief The semaphore to guard.
semaphore *mySemaphore;
};
///\brief A class for managing shared files.
class sharedFile{
public:
sharedFile(const std::string &name_ = "", uint64_t len_ = 0, bool master_ = false, bool autoBackoff = true);
sharedFile(const sharedFile &rhs);
~sharedFile();
operator bool() const;
void init(const std::string &name_, uint64_t len_, bool master_ = false, bool autoBackoff = true);
void operator=(sharedFile &rhs);
bool operator<(const sharedFile &rhs) const{return name < rhs.name;}
void close();
void unmap();
bool exists();
///\brief The fd handle of the opened shared file
int handle;
///\brief The name of the opened shared file
std::string name;
///\brief The size in bytes of the opened shared file
uint64_t len;
///\brief Whether this class should unlink the shared file upon deletion or not
bool master;
///\brief A pointer to the payload of the file file
char *mapped;
};
#if defined(__CYGWIN__) || defined(_WIN32)
void preservePage(std::string);
void releasePage(std::string);
#endif
#ifdef SHM_ENABLED
///\brief A class for managing shared memory pages.
class sharedPage{
public:
sharedPage(const std::string &name_ = "", uint64_t len_ = 0, bool master_ = false, bool autoBackoff = true);
sharedPage(const sharedPage &rhs);
~sharedPage();
operator bool() const;
void init(const std::string &name_, uint64_t len_, bool master_ = false, bool autoBackoff = true);
void operator=(sharedPage &rhs);
bool operator<(const sharedPage &rhs) const{return name < rhs.name;}
void unmap();
void close();
bool exists();
#if defined(__CYGWIN__) || defined(_WIN32)
///\brief The handle of the opened shared memory page
HANDLE handle;
#else
///\brief The fd handle of the opened shared memory page
int handle;
#endif
///\brief The name of the opened shared memory page
std::string name;
///\brief The size in bytes of the opened shared memory page
long long int len;
///\brief Whether this class should unlink the shared memory upon deletion or not
bool master;
///\brief A pointer to the payload of the page
char *mapped;
};
#else
///\brief A class for handling shared memory pages.
/// Uses shared files at its backbone, defined for portability
class sharedPage : public sharedFile{
public:
sharedPage(const std::string &name_ = "", uint64_t len_ = 0, bool master_ = false, bool autoBackoff = true);
sharedPage(const sharedPage &rhs);
~sharedPage();
};
#endif
///\brief The server part of a server/client model for shared memory.
///
/// The server manages the shared memory pages, and allocates new pages when needed.
///
/// Pages are created with a basename + index, where index is in the range of 'A' - 'Z'
/// Each time a page is nearly full, the next page is created with a size double to the previous one.
///
/// Clients should allocate payLen bytes at a time, possibly with the addition of a counter.
/// If no such length can be allocated, the next page should be tried, and so on.
class sharedServer{
public:
sharedServer();
sharedServer(std::string name, int len, bool withCounter = false);
void init(std::string name, int len, bool withCounter = false);
~sharedServer();
void parseEach(void (*activeCallback)(char *data, size_t len, unsigned int id),
void (*disconCallback)(char *data, size_t len, unsigned int id) = 0);
char *getIndex(unsigned int id);
operator bool() const;
///\brief The amount of connected clients
unsigned int amount;
unsigned int connectedUsers;
void finishEach();
void abandon();
private:
bool isInUse(unsigned int id);
void newPage();
void deletePage();
///\brief The basename of the shared pages.
std::string baseName;
///\brief The length of each consecutive piece of payload
unsigned int payLen;
///\brief The set of sharedPage structures to manage the actual memory
std::deque<sharedPage> myPages;
///\brief A semaphore that is locked upon creation and deletion of the page, to ensure no new data is allocated during this step.
semaphore mySemaphore;
///\brief Whether the payload has a counter, if so, it is added in front of the payload
bool hasCounter;
};
///\brief The client part of a server/client model for shared memory.
///
/// The server manages the shared memory pages, and allocates new pages when needed.
///
/// Pages are created with a basename + index, where index is in the range of 'A' - 'Z'
/// Each time a page is nearly full, the next page is created with a size double to the previous one.
///
/// Clients should allocate payLen bytes at a time, possibly with the addition of a counter.
/// If no such length can be allocated, the next page should be tried, and so on.
class sharedClient{
public:
sharedClient();
sharedClient(const sharedClient &rhs);
sharedClient(std::string name, int len, bool withCounter = false);
void operator=(const sharedClient &rhs);
~sharedClient();
void write(char *data, int len);
void finish();
void keepAlive();
bool isAlive();
char *getData();
int getCounter();
bool countAsViewer;
private:
///\brief The basename of the shared pages.
std::string baseName;
///\brief The shared page this client has reserved a space on.
sharedPage myPage;
///\brief A semaphore that is locked upon trying to allocate space on a page
semaphore mySemaphore;
///\brief The size in bytes of the opened page
int payLen;
///\brief The offset of the payload reserved for this client within the opened page
int offsetOnPage;
///\brief Whether the payload has a counter, if so, it is added in front of the payload
bool hasCounter;
};
class userConnection{
public:
userConnection(char *_data);
unsigned long getTrackId(size_t offset) const;
void setTrackId(size_t offset, unsigned long trackId) const;
unsigned long getKeynum(size_t offset) const;
void setKeynum(size_t offset, unsigned long keynum);
private:
char *data;
};
}// namespace IPC