From 4f1e1fa1d777d85b8c60bb911f0b0be3da0380d5 Mon Sep 17 00:00:00 2001 From: Erik Zandvliet Date: Wed, 23 Apr 2014 13:06:17 +0200 Subject: [PATCH] Abstraction of semaphore to a class --- Doxyfile | 69 +++-- lib/converter.cpp | 39 +++ lib/converter.h | 8 + lib/dtsc.h | 4 + lib/dtscmeta.cpp | 142 ++++++++++ lib/shared_memory.cpp | 635 ++++++++++++++++++++++++++++++------------ lib/shared_memory.h | 117 +++++++- lib/stream.cpp | 11 +- 8 files changed, 809 insertions(+), 216 deletions(-) diff --git a/Doxyfile b/Doxyfile index 8cdff0d2..c7b3439b 100644 --- a/Doxyfile +++ b/Doxyfile @@ -1,4 +1,4 @@ -# Doxyfile 1.8.6 +# Doxyfile 1.8.7 # This file describes the settings to be used by the documentation system # doxygen (www.doxygen.org) for a project. @@ -70,6 +70,14 @@ OUTPUT_DIRECTORY = ./docs CREATE_SUBDIRS = NO +# If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII +# characters to appear in the names of generated files. If set to NO, non-ASCII +# characters will be escaped, for example _xE3_x81_x84 will be used for Unicode +# U+3044. +# The default value is: NO. + +ALLOW_UNICODE_NAMES = NO + # The OUTPUT_LANGUAGE tag is used to specify the language in which all # documentation generated by doxygen is written. Doxygen will use this # information to generate all constant output in the proper language. @@ -261,9 +269,12 @@ OPTIMIZE_OUTPUT_VHDL = NO # extension. Doxygen has a built-in mapping, but you can override or extend it # using this tag. The format is ext=language, where ext is a file extension, and # language is one of the parsers supported by doxygen: IDL, Java, Javascript, -# C#, C, C++, D, PHP, Objective-C, Python, Fortran, VHDL. For instance to make -# doxygen treat .inc files as Fortran files (default is PHP), and .f files as C -# (default is Fortran), use: inc=Fortran f=C. +# C#, C, C++, D, PHP, Objective-C, Python, Fortran (fixed format Fortran: +# FortranFixed, free formatted Fortran: FortranFree, unknown formatted Fortran: +# Fortran. In the later case the parser tries to guess whether the code is fixed +# or free formatted code, this is the default for Fortran type files), VHDL. For +# instance to make doxygen treat .inc files as Fortran files (default is PHP), +# and .f files as C (default is Fortran), use: inc=Fortran f=C. # # Note For files without extension you can use no_extension as a placeholder. # @@ -1230,7 +1241,8 @@ GENERATE_CHI = NO CHM_INDEX_ENCODING = # The BINARY_TOC flag controls whether a binary table of contents is generated ( -# YES) or a normal table of contents ( NO) in the .chm file. +# YES) or a normal table of contents ( NO) in the .chm file. Furthermore it +# enables the Previous and Next buttons. # The default value is: NO. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. @@ -1470,11 +1482,11 @@ SEARCHENGINE = YES # When the SERVER_BASED_SEARCH tag is enabled the search engine will be # implemented using a web server instead of a web client using Javascript. There -# are two flavours of web server based searching depending on the -# EXTERNAL_SEARCH setting. When disabled, doxygen will generate a PHP script for -# searching and an index file used by the script. When EXTERNAL_SEARCH is -# enabled the indexing and searching needs to be provided by external tools. See -# the section "External Indexing and Searching" for details. +# are two flavors of web server based searching depending on the EXTERNAL_SEARCH +# setting. When disabled, doxygen will generate a PHP script for searching and +# an index file used by the script. When EXTERNAL_SEARCH is enabled the indexing +# and searching needs to be provided by external tools. See the section +# "External Indexing and Searching" for details. # The default value is: NO. # This tag requires that the tag SEARCHENGINE is set to YES. @@ -1762,6 +1774,13 @@ MAN_OUTPUT = man MAN_EXTENSION = .3 +# The MAN_SUBDIR tag determines the name of the directory created within +# MAN_OUTPUT in which the man pages are placed. If defaults to man followed by +# MAN_EXTENSION with the initial . removed. +# This tag requires that the tag GENERATE_MAN is set to YES. + +MAN_SUBDIR = + # If the MAN_LINKS tag is set to YES and doxygen generates man output, then it # will generate one additional man file for each entity documented in the real # man page(s). These additional files only source the real man page, but without @@ -1789,18 +1808,6 @@ GENERATE_XML = NO XML_OUTPUT = xml -# The XML_SCHEMA tag can be used to specify a XML schema, which can be used by a -# validating XML parser to check the syntax of the XML files. -# This tag requires that the tag GENERATE_XML is set to YES. - -XML_SCHEMA = - -# The XML_DTD tag can be used to specify a XML DTD, which can be used by a -# validating XML parser to check the syntax of the XML files. -# This tag requires that the tag GENERATE_XML is set to YES. - -XML_DTD = - # If the XML_PROGRAMLISTING tag is set to YES doxygen will dump the program # listings (including syntax highlighting and cross-referencing information) to # the XML output. Note that enabling this will significantly increase the size @@ -1947,9 +1954,9 @@ PREDEFINED = EXPAND_AS_DEFINED = # If the SKIP_FUNCTION_MACROS tag is set to YES then doxygen's preprocessor will -# remove all refrences to function-like macros that are alone on a line, have an -# all uppercase name, and do not end with a semicolon. Such function macros are -# typically used for boiler-plate code, and will confuse the parser if not +# remove all references to function-like macros that are alone on a line, have +# an all uppercase name, and do not end with a semicolon. Such function macros +# are typically used for boiler-plate code, and will confuse the parser if not # removed. # The default value is: YES. # This tag requires that the tag ENABLE_PREPROCESSING is set to YES. @@ -1969,7 +1976,7 @@ SKIP_FUNCTION_MACROS = YES # where loc1 and loc2 can be relative or absolute paths or URLs. See the # section "Linking to external documentation" for more information about the use # of tag files. -# Note: Each tag file must have an unique name (where the name does NOT include +# Note: Each tag file must have a unique name (where the name does NOT include # the path). If a tag file is not located in the directory in which doxygen is # run, you must also specify the path to the tagfile here. @@ -2061,6 +2068,16 @@ HAVE_DOT = NO DOT_NUM_THREADS = 0 +# When you want a differently looking font n the dot files that doxygen +# generates you can specify the font name using DOT_FONTNAME. You need to make +# sure dot is able to find the font, which can be done by putting it in a +# standard location or by setting the DOTFONTPATH environment variable or by +# setting DOT_FONTPATH to the directory containing the font. +# The default value is: Helvetica. +# This tag requires that the tag HAVE_DOT is set to YES. + +DOT_FONTNAME = Helvetica + # The DOT_FONTSIZE tag can be used to set the size (in points) of the font of # dot graphs. # Minimum value: 4, maximum value: 24, default value: 10. diff --git a/lib/converter.cpp b/lib/converter.cpp index 114b50ae..5eba384d 100644 --- a/lib/converter.cpp +++ b/lib/converter.cpp @@ -12,10 +12,17 @@ namespace Converter { + ///\brief The base constructor Converter::Converter(){ fillFFMpegEncoders(); } + ///\brief A function that fill the internal variables with values provided by examing ffmpeg output + /// + ///Checks for the following encoders: + /// - AAC + /// - H264 + /// - MP3 void Converter::fillFFMpegEncoders(){ std::vector cmd; cmd.reserve(3); @@ -45,10 +52,14 @@ namespace Converter { fclose( outFile ); } + ///\brief A function to obtain all available codecs that have been obtained from the encoders. + ///\return A reference to the allCodecs member. converterInfo & Converter::getCodecs(){ return allCodecs; } + ///\brief A function to obtain the available encoders in JSON format. + ///\return A JSON::Value containing all encoder:codec pairs. JSON::Value Converter::getEncoders(){ JSON::Value result; for (converterInfo::iterator convIt = allCodecs.begin(); convIt != allCodecs.end(); convIt++){ @@ -64,6 +75,9 @@ namespace Converter { return result; } + ///\brief Looks in a given path for all files that could be converted + ///\param myPath The location to look at, this should be a folder. + ///\return A JSON::Value containing all media files in the location, with their corresponding metadata values. JSON::Value Converter::queryPath(std::string myPath){ char const * cmd[3] = {0, 0, 0}; std::string mistPath = Util::getMyPath() + "MistInfo"; @@ -89,6 +103,20 @@ namespace Converter { return result; } + ///\brief Start a conversion with the given parameters + ///\param name The name to use for logging the conversion. + ///\param parameters The parameters, accepted are the following: + /// - input The input url + /// - output The output url + /// - encoder The encoder to use + /// - video An object containing video parameters, if not existant no video will be output. Values are: + /// - width The width of the resulting video + /// - height The height of the resulting video + /// - codec The codec to encode video in, or copy to use the current codec + /// - fpks The framerate in fps * 1000 + /// - audio An object containing audio parameters, if not existant no audio will be output. Values are: + /// - codec The codec to encode audio in, or copy to use the current codec + /// - samplerate The target samplerate for the audio, in hz void Converter::startConversion(std::string name, JSON::Value parameters) { if ( !parameters.isMember("input")){ statusHistory[name] = "No input file supplied"; @@ -185,6 +213,9 @@ namespace Converter { allConversions[name]["status"]["time"] = 0; } + ///\brief Updates the internal status of the converter class. + /// + ///Will check for each running conversion whether it is still running, and update its status accordingly void Converter::updateStatus(){ if (allConversions.size()){ std::map::iterator cIt; @@ -249,6 +280,11 @@ namespace Converter { } } + ///\brief Parses a single ffmpeg status line into a JSON format + ///\param statusLine The current status of ffmpeg + ///\return A JSON::Value with the following values set: + /// - frame The current last encoded frame + /// - time The current last encoded timestamp JSON::Value Converter::parseFFMpegStatus(std::string statusLine){ JSON::Value result; int curOffset = statusLine.find("frame=") + 6; @@ -263,6 +299,8 @@ namespace Converter { return result; } + ///\brief Obtain the current internal status of the conversion class + ///\return A JSON::Value with the status of each conversion JSON::Value Converter::getStatus(){ updateStatus(); JSON::Value result; @@ -281,6 +319,7 @@ namespace Converter { return result; } + ///\brief Clears the status history of all conversions void Converter::clearStatus(){ statusHistory.clear(); } diff --git a/lib/converter.h b/lib/converter.h index 41a89170..c3a6a0bf 100644 --- a/lib/converter.h +++ b/lib/converter.h @@ -3,10 +3,15 @@ #include "json.h" +///\brief A typedef to simplify accessing all codecs typedef std::map codecInfo; +///\brief A typedef to simplify accessing all encoders typedef std::map converterInfo; +///\brief A namespace containing all functions for handling the conversion API namespace Converter { + + ///\brief A class containing the basic conversion API functionality class Converter { public: Converter(); @@ -20,8 +25,11 @@ namespace Converter { JSON::Value parseFFMpegStatus(std::string statusLine); private: void fillFFMpegEncoders(); + ///\brief Holds a list of all current known codecs converterInfo allCodecs; + ///\brief Holds a list of all the current conversions std::map allConversions; + ///\brief Stores the status of all conversions, and the history std::map statusHistory; }; } diff --git a/lib/dtsc.h b/lib/dtsc.h index 9bfc0de2..5eea2682 100644 --- a/lib/dtsc.h +++ b/lib/dtsc.h @@ -210,6 +210,7 @@ namespace DTSC { char data[11]; }; + ///\brief Basic class for storage of a read-only track class readOnlyTrack { public: readOnlyTrack(); @@ -248,6 +249,7 @@ namespace DTSC { void toPrettyString(std::ostream & str, int indent = 0, int verbosity = 0); }; + ///\brief Class for storage of track data class Track : public readOnlyTrack { public: Track(); @@ -270,6 +272,7 @@ namespace DTSC { void toPrettyString(std::ostream & str, int indent = 0, int verbosity = 0); }; + ///\brief Class for storage of read-only meta data class readOnlyMeta { public: readOnlyMeta(); @@ -291,6 +294,7 @@ namespace DTSC { void toPrettyString(std::ostream & str, int indent = 0, int verbosity = 0); }; + ///\brief Class for storage of meta data class Meta : public readOnlyMeta { public: Meta(); diff --git a/lib/dtscmeta.cpp b/lib/dtscmeta.cpp index ab850b86..5b5adb41 100644 --- a/lib/dtscmeta.cpp +++ b/lib/dtscmeta.cpp @@ -115,6 +115,7 @@ namespace DTSC { /// Internally used resize function for when operating in copy mode and the internal buffer is too small. /// It will only resize up, never down. + ///\param len The length th scale the buffer up to if necessary void Packet::resize(unsigned int len) { if (master && len > bufferLen) { char * tmp = (char *)realloc(data, len); @@ -127,6 +128,10 @@ namespace DTSC { } } + ///\brief Initializes a packet with new data + ///\param data_ The new data for the packet + ///\param len The length of the data pointed to by data_ + ///\param noCopy Determines whether to make a copy or not void Packet::reInit(const char * data_, unsigned int len, bool noCopy) { if (!data_){ DEBUG_MSG(DLVL_DEVEL, "ReInit received a null pointer with len %d, ignoring", len); @@ -240,6 +245,9 @@ namespace DTSC { return (char*)1;//out of packet! 1 == error } + ///\brief Locates an identifier within the payload + ///\param identifier The identifier to find + ///\return A pointer to the location of the identifier char * Packet::findIdentifier(const char * identifier){ char * p = data; if (version == DTSC_V2){ @@ -251,6 +259,10 @@ namespace DTSC { return ret; } + ///\brief Retrieves a single parameter as a string + ///\param identifier The name of the parameter + ///\param result A location on which the string will be returned + ///\param len An integer in which the length of the string will be returned void Packet::getString(const char * identifier, char *& result, int & len) { char * pos = findIdentifier(identifier); if (pos < (char*)2) { @@ -267,6 +279,9 @@ namespace DTSC { len = ntohl(((int *)(pos + 1))[0]); } + ///\brief Retrieves a single parameter as a string + ///\param identifier The name of the parameter + ///\param result The string in which to store the result void Packet::getString(const char * identifier, std::string & result) { char * data = NULL; int len = 0; @@ -274,6 +289,9 @@ namespace DTSC { result = std::string(data, len); } + ///\brief Retrieves a single parameter as an integer + ///\param identifier The name of the parameter + ///\param result The result is stored in this integer void Packet::getInt(const char * identifier, int & result) { char * pos = findIdentifier(identifier); if (pos < (char*)2) { @@ -287,28 +305,42 @@ namespace DTSC { result = ((long long int)pos[1] << 56) | ((long long int)pos[2] << 48) | ((long long int)pos[3] << 40) | ((long long int)pos[4] << 32) | ((long long int)pos[5] << 24) | ((long long int)pos[6] << 16) | ((long long int)pos[7] << 8) | pos[8]; } + ///\brief Retrieves a single parameter as an integer + ///\param identifier The name of the parameter + ///\result The requested parameter as an integer int Packet::getInt(const char * identifier) { int result; getInt(identifier, result); return result; } + ///\brief Retrieves a single parameter as a boolean + ///\param identifier The name of the parameter + ///\param result The result is stored in this boolean void Packet::getFlag(const char * identifier, bool & result) { int result_; getInt(identifier, result_); result = (bool)result_; } + ///\brief Retrieves a single parameter as a boolean + ///\param identifier The name of the parameter + ///\result The requested parameter as a boolean bool Packet::getFlag(const char * identifier) { bool result; getFlag(identifier, result); return result; } + ///\brief Checks whether a parameter exists + ///\param identifier The name of the parameter + ///\result Whether the parameter exists or not bool Packet::hasMember(const char * identifier) { return findIdentifier(identifier) > (char*)2; } + ///\brief Returns the timestamp of the packet. + ///\return The timestamp of this packet. long long unsigned int Packet::getTime() { if (version != DTSC_V2){ if (!data){return 0;} @@ -317,6 +349,8 @@ namespace DTSC { return ((long long int)ntohl(((int *)(data + 12))[0]) << 32) | ntohl(((int *)(data + 12))[1]); } + ///\brief Returns the track id of the packet. + ///\return The track id of this packet. long int Packet::getTrackId() { if (version != DTSC_V2){ return getInt("trackid"); @@ -324,15 +358,21 @@ namespace DTSC { return ntohl(((int *)data)[2]); } + ///\brief Returns a pointer to the payload of this packet. + ///\return A pointer to the payload of this packet. char * Packet::getData() { return data; } + ///\brief Returns the size of the payload of this packet. + ///\return The size of the payload of this packet. int Packet::getDataLen() { return dataLen; } + ///\brief Converts the packet into a JSON value + ///\return A JSON::Value representation of this packet. JSON::Value Packet::toJSON(){ JSON::Value result; unsigned int i = 8; @@ -346,44 +386,56 @@ namespace DTSC { } + ///\brief Returns the payloadsize of a part long Part::getSize() { return ((long)data[0] << 16) | ((long)data[1] << 8) | data[2]; } + ///\brief Sets the payloadsize of a part void Part::setSize(long newSize) { data[0] = (newSize & 0xFF0000) >> 16; data[1] = (newSize & 0x00FF00) >> 8; data[2] = (newSize & 0x0000FF); } + ///\brief Retruns the duration of a part short Part::getDuration() { return btohs(data + 3); } + ///\brief Sets the duration of a part void Part::setDuration(short newDuration) { htobs(data + 3, newDuration); } + ///\brief returns the offset of a part long Part::getOffset() { return btohl(data + 5); } + ///\brief Sets the offset of a part void Part::setOffset(long newOffset) { htobl(data + 5, newOffset); } + ///\brief Returns the data of a part char * Part::getData() { return data; } + ///\brief Converts a part to a human readable string + ///\param str The stringstream to append to + ///\param indent the amount of indentation needed void Part::toPrettyString(std::ostream & str, int indent){ str << std::string(indent, ' ') << "Part: Size(" << getSize() << "), Dur(" << getDuration() << "), Offset(" << getOffset() << ")" << std::endl; } + ///\brief Returns the byteposition of a keyframe long long unsigned int Key::getBpos() { return (((long long unsigned int)data[0] << 32) | (data[1] << 24) | (data[2] << 16) | (data[3] << 8) | data[4]); } + ///\brief Returns the byteposition of a keyframe void Key::setBpos(long long unsigned int newBpos) { data[4] = newBpos & 0xFF; data[3] = (newBpos >> 8) & 0xFF; @@ -392,88 +444,113 @@ namespace DTSC { data[0] = (newBpos >> 32) & 0xFF; } + ///\brief Returns the byteposition of a keyframe long Key::getLength() { return ((data[5] << 16) | (data[6] << 8) | data[7]); } + ///\brief Sets the byteposition of a keyframe void Key::setLength(long newLength) { data[7] = newLength & 0xFF; data[6] = (newLength >> 8) & 0xFF; data[5] = (newLength >> 16) & 0xFF; } + ///\brief Returns the number of a keyframe unsigned short Key::getNumber() { return btohs(data + 8); } + ///\brief Sets the number of a keyframe void Key::setNumber(unsigned short newNumber) { htobs(data + 8, newNumber); } + ///\brief Returns the number of parts of a keyframe short Key::getParts() { return btohs(data + 10); } + ///\brief Sets the number of parts of a keyframe void Key::setParts(short newParts) { htobs(data + 10, newParts); } + ///\brief Returns the timestamp of a keyframe long Key::getTime() { return btohl(data + 12); } + ///\brief Sets the timestamp of a keyframe void Key::setTime(long newTime) { htobl(data + 12, newTime); } + ///\brief Returns the data of this keyframe struct char * Key::getData() { return data; } + ///\brief Converts a keyframe to a human readable string + ///\param str The stringstream to append to + ///\param indent the amount of indentation needed void Key::toPrettyString(std::ostream & str, int indent){ str << std::string(indent, ' ') << "Key " << getNumber() << ": Pos(" << getBpos() << "), Dur(" << getLength() << "), Parts(" << getParts() << "), Time(" << getTime() << ")" << std::endl; } + ///\brief Returns the duration of this fragment long Fragment::getDuration() { return btohl(data); } + ///\brief Sets the duration of this fragment void Fragment::setDuration(long newDuration) { htobl(data, newDuration); } + ///\brief Returns the length of this fragment char Fragment::getLength() { return data[4]; } + ///\brief Sets the length of this fragment void Fragment::setLength(char newLength) { data[4] = newLength; } + ///\brief Returns the number of the first keyframe in this fragment short Fragment::getNumber() { return btohs(data + 5); } + ///\brief Sets the number of the first keyframe in this fragment void Fragment::setNumber(short newNumber) { htobs(data + 5, newNumber); } + ///\brief Returns the size of a fragment long Fragment::getSize() { return btohl(data + 7); } + ///\brief Sets the size of a fragement void Fragment::setSize(long newSize) { htobl(data + 7, newSize); } + ///\brief Returns thte data of this fragment structure char * Fragment::getData() { return data; } + ///\brief Converts a fragment to a human readable string + ///\param str The stringstream to append to + ///\param indent the amount of indentation needed void Fragment::toPrettyString(std::ostream & str, int indent){ str << std::string(indent, ' ') << "Fragment " << getNumber() << ": Dur(" << getDuration() << "), Len(" << (int)getLength() << "), Size(" << getSize() << ")" << std::endl; } + ///\brief Constructs an empty readOnlyTrack readOnlyTrack::readOnlyTrack() { fragments = NULL; fragLen = 0; @@ -493,6 +570,7 @@ namespace DTSC { fpks = 0; } + ///\brief Constructs a readOnlyTrack from a JSON::Value readOnlyTrack::readOnlyTrack(JSON::Value & trackRef) { if (trackRef.isMember("fragments") && trackRef["fragments"].isString()) { fragments = (Fragment *)trackRef["fragments"].asStringRef().data(); @@ -539,6 +617,7 @@ namespace DTSC { } } + ///\brief Constructs an empty track Track::Track() { trackID = 0; firstms = 0; @@ -553,6 +632,7 @@ namespace DTSC { fpks = 0; } + ///\brief Constructs a track from a readOnlyTrack Track::Track(const readOnlyTrack & rhs) { trackID = rhs.trackID; firstms = rhs.firstms; @@ -581,6 +661,7 @@ namespace DTSC { } } + ///\brief Constructs a track from a JSON::Value Track::Track(JSON::Value & trackRef) { if (trackRef.isMember("fragments") && trackRef["fragments"].isString()) { Fragment * tmp = (Fragment *)trackRef["fragments"].asStringRef().data(); @@ -618,6 +699,9 @@ namespace DTSC { } } + ///\brief Updates a track and its metadata given a DTSC::Packet. + /// + ///Will also insert keyframes on non-video tracks, and creates fragments void Track::update(DTSC::Packet & pack) { if (pack.getTime() < lastms) { DEBUG_MSG(DLVL_WARN, "Received packets for track %d in wrong order (%d < %d) - ignoring!", (int)trackID, (int)pack.getTime(), (int)lastms); @@ -679,6 +763,9 @@ namespace DTSC { fragments.rbegin()->setSize(fragments.rbegin()->getSize() + dataLen); } + ///\brief Updates a track and its metadata given a JSON::Value + /// + ///Will also insert keyframes on non-video tracks, and creates fragments void Track::update(JSON::Value & pack) { if (pack["time"].asInt() < lastms) { DEBUG_MSG(DLVL_WARN, "Received packets for track %d in wrong order (%d < %d) - ignoring!", (int)trackID, (int)pack["time"].asInt(), (int)lastms); @@ -737,6 +824,7 @@ namespace DTSC { fragments.rbegin()->setSize(fragments.rbegin()->getSize() + pack["data"].asStringRef().size()); } + ///\brief Returns a key given its number, or an empty key if the number is out of bounds Key & Track::getKey(unsigned int keyNum) { static Key empty; if (keyNum < keys[0].getNumber()) { @@ -748,6 +836,7 @@ namespace DTSC { return keys[keyNum - keys[0].getNumber()]; } + ///\brief Returns a unique identifier for a track std::string readOnlyTrack::getIdentifier() { std::stringstream result; if (type == "") { @@ -766,12 +855,14 @@ namespace DTSC { return result.str(); } + ///\brief Returns a writable identifier for a track, to prevent overwrites on readout std::string readOnlyTrack::getWritableIdentifier() { std::stringstream result; result << getIdentifier() << "_" << trackID; return result.str(); } + ///\brief Resets a track, clears all meta values void Track::reset() { fragments.clear(); parts.clear(); @@ -781,6 +872,7 @@ namespace DTSC { lastms = 0; } + ///\brief Creates an empty read-only meta object readOnlyMeta::readOnlyMeta() { vod = false; live = false; @@ -790,6 +882,7 @@ namespace DTSC { bufferWindow = 0; } + ///\brief Creates a read-only meta object from a given JSON::Value readOnlyMeta::readOnlyMeta(JSON::Value & meta) { vod = meta.isMember("vod") && meta["vod"]; live = meta.isMember("live") && meta["live"]; @@ -810,6 +903,10 @@ namespace DTSC { } } + ///\brief Converts a read-only track to a human readable string + ///\param str The stringstream to append to + ///\param indent the amount of indentation needed + ///\param verbosity How verbose the output needs to be void readOnlyTrack::toPrettyString(std::ostream & str, int indent, int verbosity){ str << std::string(indent, ' ') << "Track " << getWritableIdentifier() << std::endl; str << std::string(indent + 2, ' ') << "ID: " << trackID << std::endl; @@ -859,6 +956,7 @@ namespace DTSC { } } + ///\brief Creates an empty meta object Meta::Meta() { vod = false; live = false; @@ -867,6 +965,7 @@ namespace DTSC { bufferWindow = 0; } + ///\brief Creates a meta object from a read-only meta object Meta::Meta(const readOnlyMeta & rhs) { vod = rhs.vod; live = rhs.live; @@ -878,6 +977,7 @@ namespace DTSC { moreheader = rhs.moreheader; } + ///\brief Creates a meta object from a JSON::Value Meta::Meta(JSON::Value & meta) { vod = meta.isMember("vod") && meta["vod"]; live = meta.isMember("live") && meta["live"]; @@ -898,6 +998,7 @@ namespace DTSC { } } + ///\brief Updates a meta object given a JSON::Value void Meta::update(JSON::Value & pack) { vod = pack.isMember("bpos"); live = !vod; @@ -906,6 +1007,7 @@ namespace DTSC { } } + ///\brief Updates a meta object given a DTSC::Packet void Meta::update(DTSC::Packet & pack) { vod = pack.hasMember("bpos"); live = !vod; @@ -914,6 +1016,10 @@ namespace DTSC { } } + ///\brief Converts a track to a human readable string + ///\param str The stringstream to append to + ///\param indent the amount of indentation needed + ///\param verbosity How verbose the output needs to be void Track::toPrettyString(std::ostream & str, int indent, int verbosity){ str << std::string(indent, ' ') << "Track " << getWritableIdentifier() << std::endl; str << std::string(indent + 2, ' ') << "ID: " << trackID << std::endl; @@ -963,6 +1069,7 @@ namespace DTSC { } } + ///\brief Converts a short to a char* char * convertShort(short input) { static char result[2]; result[0] = (input >> 8) & 0xFF; @@ -970,6 +1077,7 @@ namespace DTSC { return result; } + ///\brief Converts an integer to a char* char * convertInt(int input) { static char result[4]; result[0] = (input >> 24) & 0xFF; @@ -979,6 +1087,7 @@ namespace DTSC { return result; } + ///\brief Converts a long long to a char* char * convertLongLong(long long int input) { static char result[8]; result[0] = (input >> 56) & 0xFF; @@ -992,6 +1101,7 @@ namespace DTSC { return result; } + ///\brief Determines the "packed" size of a read-only track int readOnlyTrack::getSendLen() { int result = 146 + init.size() + codec.size() + type.size() + getWritableIdentifier().size(); result += fragLen * 11; @@ -1012,6 +1122,7 @@ namespace DTSC { return result; } + ///\brief Determines the "packed" size of a track int Track::getSendLen() { int result = 146 + init.size() + codec.size() + type.size() + getWritableIdentifier().size(); result += fragments.size() * 11; @@ -1032,15 +1143,22 @@ namespace DTSC { return result; } + ///\brief Writes a pointer to the specified destination + /// + ///Does a memcpy and increases the destination pointer accordingly static void writePointer(char *& p, const char * src, unsigned int len){ memcpy(p, src, len); p += len; } + ///\brief Writes a pointer to the specified destination + /// + ///Does a memcpy and increases the destination pointer accordingly static void writePointer(char *& p, const std::string & src){ writePointer(p, src.data(), src.size()); } + ///\brief Writes a read-only track to a pointer void readOnlyTrack::writeTo(char *& p){ std::string iden = getWritableIdentifier(); writePointer(p, convertShort(iden.size()), 2); @@ -1102,6 +1220,7 @@ namespace DTSC { writePointer(p, "\000\000\356", 3);//End this track Object } + ///\brief Writes a read-only track to a socket void readOnlyTrack::send(Socket::Connection & conn) { conn.SendNow(convertShort(getWritableIdentifier().size()), 2); conn.SendNow(getWritableIdentifier()); @@ -1162,6 +1281,7 @@ namespace DTSC { conn.SendNow("\000\000\356", 3);//End this track Object } + ///\brief Writes a track to a pointer void Track::writeTo(char *& p){ writePointer(p, convertShort(getWritableIdentifier().size()), 2); writePointer(p, getWritableIdentifier()); @@ -1228,6 +1348,7 @@ namespace DTSC { writePointer(p, "\000\000\356", 3);//End this track Object } + ///\brief Writes a track to a socket void Track::send(Socket::Connection & conn) { conn.SendNow(convertShort(getWritableIdentifier().size()), 2); conn.SendNow(getWritableIdentifier()); @@ -1294,6 +1415,7 @@ namespace DTSC { conn.SendNow("\000\000\356", 3);//End this track Object } + ///\brief Determines the "packed" size of a read-only meta object unsigned int readOnlyMeta::getSendLen(){ unsigned int dataLen = 16 + (vod ? 14 : 0) + (live ? 15 : 0) + (merged ? 17 : 0) + (bufferWindow ? 24 : 0) + 21; for (std::map::iterator it = tracks.begin(); it != tracks.end(); it++) { @@ -1302,6 +1424,7 @@ namespace DTSC { return dataLen; } + ///\brief Writes a read-only meta object to a pointer void readOnlyMeta::writeTo(char * p){ int dataLen = getSendLen(); writePointer(p, DTSC::Magic_Header, 4); @@ -1332,6 +1455,7 @@ namespace DTSC { writePointer(p, "\000\000\356", 3);//End global object } + ///\brief Writes a read-only meta object to a socket void readOnlyMeta::send(Socket::Connection & conn) { int dataLen = getSendLen(); conn.SendNow(DTSC::Magic_Header, 4); @@ -1362,6 +1486,7 @@ namespace DTSC { conn.SendNow("\000\000\356", 3);//End global object } + ///\brief Determines the "packed" size of a meta object unsigned int Meta::getSendLen(){ unsigned int dataLen = 16 + (vod ? 14 : 0) + (live ? 15 : 0) + (merged ? 17 : 0) + (bufferWindow ? 24 : 0) + 21; for (std::map::iterator it = tracks.begin(); it != tracks.end(); it++) { @@ -1370,6 +1495,7 @@ namespace DTSC { return dataLen; } + ///\brief Writes a meta object to a pointer void Meta::writeTo(char * p){ int dataLen = getSendLen(); writePointer(p, DTSC::Magic_Header, 4); @@ -1400,6 +1526,7 @@ namespace DTSC { writePointer(p, "\000\000\356", 3);//End global object } + ///\brief Writes a meta object to a socket void Meta::send(Socket::Connection & conn) { int dataLen = getSendLen(); conn.SendNow(DTSC::Magic_Header, 4); @@ -1430,6 +1557,7 @@ namespace DTSC { conn.SendNow("\000\000\356", 3);//End global object } + ///\brief Converts a read-only track to a JSON::Value JSON::Value readOnlyTrack::toJSON() { JSON::Value result; if (fragments) { @@ -1467,6 +1595,7 @@ namespace DTSC { return result; } + ///\brief Converts a track to a JSON::Value JSON::Value Track::toJSON() { JSON::Value result; std::string tmp; @@ -1513,6 +1642,7 @@ namespace DTSC { return result; } + ///\brief Converts a meta object to a JSON::Value JSON::Value Meta::toJSON() { JSON::Value result; for (std::map::iterator it = tracks.begin(); it != tracks.end(); it++) { @@ -1534,6 +1664,10 @@ namespace DTSC { return result; } + ///\brief Converts a read-only meta object to a human readable string + ///\param str The stringstream to append to + ///\param indent the amount of indentation needed + ///\param verbosity How verbose the output needs to be void readOnlyMeta::toPrettyString(std::ostream & str, int indent, int verbosity){ for (std::map::iterator it = tracks.begin(); it != tracks.end(); it++) { it->second.toPrettyString(str, indent, verbosity); @@ -1553,6 +1687,10 @@ namespace DTSC { str << std::string(indent, ' ') << "More Header: " << moreheader << std::endl; } + ///\brief Converts a meta object to a human readable string + ///\param str The stringstream to append to + ///\param indent the amount of indentation needed + ///\param verbosity How verbose the output needs to be void Meta::toPrettyString(std::ostream & str, int indent, int verbosity){ for (std::map::iterator it = tracks.begin(); it != tracks.end(); it++) { it->second.toPrettyString(str, indent, verbosity); @@ -1572,6 +1710,7 @@ namespace DTSC { str << std::string(indent, ' ') << "More Header: " << moreheader << std::endl; } + ///\brief Converts a read-only meta object to a JSON::Value JSON::Value readOnlyMeta::toJSON() { JSON::Value result; for (std::map::iterator it = tracks.begin(); it != tracks.end(); it++) { @@ -1593,12 +1732,14 @@ namespace DTSC { return result; } + ///\brief Resets a meta object, removes all unimportant meta values void Meta::reset() { for (std::map::iterator it = tracks.begin(); it != tracks.end(); it++) { it->second.reset(); } } + ///\brief Returns whether a read-only meta object is fixed or not bool readOnlyMeta::isFixed() { for (std::map::iterator it = tracks.begin(); it != tracks.end(); it++) { if (!it->second.keyLen || !(it->second.keys[it->second.keyLen - 1].getBpos())) { @@ -1608,6 +1749,7 @@ namespace DTSC { return true; } + ///\brief Returns whether a meta object is fixed or not bool Meta::isFixed() { for (std::map::iterator it = tracks.begin(); it != tracks.end(); it++) { if (it->second.type == "meta" || it->second.type == "") { diff --git a/lib/shared_memory.cpp b/lib/shared_memory.cpp index 1fa0b056..b861bdce 100644 --- a/lib/shared_memory.cpp +++ b/lib/shared_memory.cpp @@ -7,8 +7,10 @@ #include #include +#include #include "defines.h" #include "shared_memory.h" +#include "stream.h" namespace IPC { /// Stores a long value of val in network order to the pointer p. @@ -19,6 +21,7 @@ namespace IPC { p[3] = val & 0xFF; } + /// Stores a long long value of val in network order to the pointer p. static void htobll(char * p, long long val) { p[0] = (val >> 56) & 0xFF; p[1] = (val >> 48) & 0xFF; @@ -30,24 +33,189 @@ namespace IPC { p[7] = val & 0xFF; } + /// Reads a long value of p in host order to val. static void btohl(char * p, long & val) { val = ((long)p[0] << 24) | ((long)p[1] << 16) | ((long)p[2] << 8) | p[3]; } + /// Reads a long long value of p in host order to val. static void btohll(char * p, long long & val) { val = ((long long)p[0] << 56) | ((long long)p[1] << 48) | ((long long)p[2] << 40) | ((long long)p[3] << 32) | ((long long)p[4] << 24) | ((long long)p[5] << 16) | ((long long)p[6] << 8) | p[7]; } -#if !defined __APPLE__ && !defined __CYGWIN__ + ///\brief Empty semaphore constructor, clears all values + semaphore::semaphore() { +#ifdef __CYGWIN__ + mySem = 0; +#else + mySem = SEM_FAILED; +#endif + myName = 0; + } + + ///\brief Constructs a named semaphore + ///\param name The name of the semaphore + ///\param oflag The flags with which to open the semaphore + ///\param mode The mode in which to create the semaphore, if O_CREAT is given in oflag, ignored otherwise + ///\param value The initial value of the semaphore if O_CREAT is given in oflag, ignored otherwise + semaphore::semaphore(const char * name, int oflag, mode_t mode, unsigned int value) { +#ifdef __CYGWIN__ + mySem = 0; +#else + mySem = SEM_FAILED; +#endif + open(name, oflag, mode, value); + } + + ///\brief The deconstructor + semaphore::~semaphore() {} + + ///\brief Returns whether we have a valid semaphore + semaphore::operator bool() const { +#ifdef __CYGWIN__ + return mySem != 0; +#else + return mySem != SEM_FAILED; +#endif + } + + ///\brief Opens a semaphore + /// + ///Closes currently opened semaphore if needed + ///\param name The name of the semaphore + ///\param oflag The flags with which to open the semaphore + ///\param mode The mode in which to create the semaphore, if O_CREAT is given in oflag, ignored otherwise + ///\param value The initial value of the semaphore if O_CREAT is given in oflag, ignored otherwise + void semaphore::open(const char * name, int oflag, mode_t mode, unsigned int value) { + close(); +#ifdef __CYGWIN__ + mySem = CreateSemaphore(0, value, 1 , std::string("Global\\" + std::string(name)).c_str()); +#else + if (oflag & O_CREAT) { + mySem = sem_open(name, oflag, mode, value); + } else { + mySem = sem_open(name, oflag); + } +#endif + myName = (char *)name; + } + + ///\brief Returns the current value of the semaphore + int semaphore::getVal() const { + int res; +#ifdef __CYGWIN__ + ReleaseSemaphore(mySem, 0, &res);//not really release.... just checking to see if I can get the value this way +#else + sem_getvalue(mySem, &res); +#endif + return res; + } + + ///\brief Posts to the semaphore, increases its value by one + void semaphore::post() { + if (*this) { +#ifdef __CYGWIN__ + ReleaseSemaphore(mySem, 1, 0); +#else + sem_post(mySem); +#endif + } + } + + ///\brief Waits for the semaphore, decreases its value by one + void semaphore::wait() { + if (*this) { +#ifdef __CYGWIN__ + WaitForSingleObject(mySem, INFINITE); +#else + int tmp; + do { + tmp = sem_wait(mySem); + } while (tmp == -1 && errno == EINTR); +#endif + } + } + + ///\brief Tries to wait for the semaphore, returns true if successfull, false otherwise + bool semaphore::tryWait() { + bool result; +#ifdef __CYGWIN__ + result = WaitForSingleObject(mySem, 0);//wait at most 1ms +#else + result = sem_trywait(mySem); +#endif + return (result == 0); + } + + ///\brief Closes the currently opened semaphore + void semaphore::close() { + if (*this) { +#ifdef __CYGWIN__ + CloseHandle(mySem); + mySem = 0; +#else + sem_close(mySem); + mySem = SEM_FAILED; +#endif + } + } + + ///\brief Unlinks the previously opened semaphore + void semaphore::unlink() { + close(); +#ifndef __CYGWIN__ + if (myName) { + sem_unlink(myName); + } +#endif + myName = 0; + } + + + ///\brief Unmaps a shared page if allowed + void sharedPage::unmap() { + if (mapped && len) { +#ifdef __CYGWIN__ + UnmapViewOfFile(mapped); +#else + munmap(mapped, len); +#endif + } + mapped = 0; + len = 0; + } + + ///\brief Closes a shared page if allowed + void sharedPage::close() { + if (handle > 0) { +#ifdef __CYGWIN__ + CloseHandle(handle); +#else + ::close(handle); +#endif + } + handle = 0; + } + + +#if !defined __APPLE__ + ///brief Creates a shared page + ///\param name_ The name of the page to be created + ///\param len_ The size to make the page + ///\param master_ Whether to create or merely open the page + ///\param autoBackoff When only opening the page, wait for it to appear or fail sharedPage::sharedPage(std::string name_, unsigned int len_, bool master_, bool autoBackoff) : handle(0), name(name_), len(len_), master(master_), mapped(NULL) { handle = 0; name = name_; len = len_; master = master_; mapped = 0; - init(name_,len_,master_, autoBackoff); + init(name_, len_, master_, autoBackoff); } - sharedPage::sharedPage(const sharedPage & rhs){ + + ///\brief Creates a copy of a shared page + ///\param rhs The page to copy + sharedPage::sharedPage(const sharedPage & rhs) { handle = 0; name = ""; len = 0; @@ -55,92 +223,139 @@ namespace IPC { mapped = 0; init(rhs.name, rhs.len, rhs.master); } + + ///\brief Returns whether the shared page is valid or not sharedPage::operator bool() const { return mapped != 0; } - void sharedPage::operator =(sharedPage & rhs){ + + ///\brief Assignment operator + void sharedPage::operator =(sharedPage & rhs) { init(rhs.name, rhs.len, rhs.master); rhs.master = false;//Make sure the memory does not get unlinked } - void sharedPage::init(std::string name_, unsigned int len_, bool master_, bool autoBackoff) { - if (mapped && len){ - munmap(mapped,len); - } - if(master){ - shm_unlink(name.c_str()); - } - if (handle > 0){ - close(handle); - } - handle = 0; - name = name_; - len = len_; - master = master_; - mapped = 0; - if (name.size()){ - handle = shm_open(name.c_str(), ( master ? O_CREAT | O_EXCL : 0 )| O_RDWR, ACCESSPERMS); - if (handle == -1) { + + + #ifdef __CYGWIN__ + ///\brief Initialize a page, de-initialize before if needed + ///\param name_ The name of the page to be created + ///\param len_ The size to make the page + ///\param master_ Whether to create or merely open the page + ///\param autoBackoff When only opening the page, wait for it to appear or fail + void sharedPage::init(std::string name_, unsigned int len_, bool master_, bool autoBackoff) { + unmap(); + close(); + name = name_; + len = len_; + master = master_; + mapped = 0; + if (name.size()) { if (master){ - DEBUG_MSG(DLVL_HIGH, "Overwriting old page for %s", name.c_str()); - handle = shm_open(name.c_str(), O_CREAT | O_RDWR, ACCESSPERMS); + handle = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, len, name.c_str()); }else{ - int i = 0; - while (i < 10 && handle == -1 && autoBackoff){ - i++; - Util::sleep(1000); - handle = shm_open(name.c_str(), O_RDWR, ACCESSPERMS); + handle = OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, name.c_str()); + } + if (!handle) { + DEBUG_MSG(DLVL_FAIL, "%s for page %s failed: %s", (master ? "CreateFileMapping" : "OpenFileMapping"), name.c_str(), strerror(errno)); + return; + } + mapped = (char *)MapViewOfFile(handle, FILE_MAP_ALL_ACCESS, 0, 0, 0); + if (!mapped) { + return; + } + } + } + #else + ///\brief Initialize a page, de-initialize before if needed + ///\param name_ The name of the page to be created + ///\param len_ The size to make the page + ///\param master_ Whether to create or merely open the page + ///\param autoBackoff When only opening the page, wait for it to appear or fail + void sharedPage::init(std::string name_, unsigned int len_, bool master_, bool autoBackoff) { + unmap(); + if (master) { + shm_unlink(name.c_str()); + } + close(); + name = name_; + len = len_; + master = master_; + mapped = 0; + if (name.size()) { + handle = shm_open(name.c_str(), (master ? O_CREAT | O_EXCL : 0) | O_RDWR, ACCESSPERMS); + if (handle == -1) { + if (master) { + DEBUG_MSG(DLVL_HIGH, "Overwriting old page for %s", name.c_str()); + handle = shm_open(name.c_str(), O_CREAT | O_RDWR, ACCESSPERMS); + } else { + int i = 0; + while (i < 10 && handle == -1 && autoBackoff) { + i++; + Util::sleep(1000); + handle = shm_open(name.c_str(), O_RDWR, ACCESSPERMS); + } } } - } - if (handle == -1) { - DEBUG_MSG(DLVL_FAIL, "shm_open for page %s failed: %s", name.c_str(), strerror(errno)); - return; - } - if (master){ - if (ftruncate(handle, 0) < 0) { - DEBUG_MSG(DLVL_FAIL, "truncate to zero for page %s failed: %s", name.c_str(), strerror(errno)); + if (handle == -1) { + DEBUG_MSG(DLVL_FAIL, "shm_open for page %s failed: %s", name.c_str(), strerror(errno)); return; } - if (ftruncate(handle, len) < 0) { - DEBUG_MSG(DLVL_FAIL, "truncate to %lld for page %s failed: %s", len, name.c_str(), strerror(errno)); + if (master) { + if (ftruncate(handle, 0) < 0) { + DEBUG_MSG(DLVL_FAIL, "truncate to zero for page %s failed: %s", name.c_str(), strerror(errno)); + return; + } + if (ftruncate(handle, len) < 0) { + DEBUG_MSG(DLVL_FAIL, "truncate to %lld for page %s failed: %s", len, name.c_str(), strerror(errno)); + return; + } + } else { + struct stat buffStats; + int xRes = fstat(handle, &buffStats); + if (xRes < 0) { + return; + } + len = buffStats.st_size; + } + mapped = (char *)mmap(0, len, PROT_READ | PROT_WRITE, MAP_SHARED, handle, 0); + if (mapped == MAP_FAILED) { + mapped = 0; return; } - }else{ - struct stat buffStats; - int xRes = fstat(handle, &buffStats); - if (xRes < 0){ - return; - } - len = buffStats.st_size; - } - mapped = (char*)mmap(0, len, PROT_READ | PROT_WRITE, MAP_SHARED, handle, 0); - if (mapped == MAP_FAILED){ - mapped = 0; - return; } } - } - sharedPage::~sharedPage(){ - if (mapped && len){ - munmap(mapped,len); - } - if(master){ + #endif + + ///\brief Default destructor + sharedPage::~sharedPage() { + unmap(); + if (master) { +#ifndef __CYGWIN__ shm_unlink(name.c_str()); +#endif } - if (handle > 0){ - close(handle); - } + close(); } + #else - sharedPage::sharedPage(std::string name_, unsigned int len_, bool master_, bool autoBackoff) /*: handle(0), name(name_), len(len_), master(master_), mapped(NULL) */{ + + ///brief Creates a shared page + ///\param name_ The name of the page to be created + ///\param len_ The size to make the page + ///\param master_ Whether to create or merely open the page + ///\param autoBackoff When only opening the page, wait for it to appear or fail + sharedPage::sharedPage(std::string name_, unsigned int len_, bool master_, bool autoBackoff) { handle = 0; name = name_; len = len_; master = master_; mapped = 0; - init(name_,len_,master_, autoBackoff); + init(name_, len_, master_, autoBackoff); } - sharedPage::sharedPage(const sharedPage & rhs){ + + ///\brief Creates a copy of a shared page + ///\param rhs The page to copy + sharedPage::sharedPage(const sharedPage & rhs) { handle = 0; name = ""; len = 0; @@ -148,27 +363,36 @@ namespace IPC { mapped = 0; init(rhs.name, rhs.len, rhs.master); } - sharedPage::~sharedPage(){ - if (mapped && len){ - munmap(mapped,len); - } - if(master){ + + ///\brief Default destructor + sharedPage::~sharedPage() { + unmap(); + if (master) { unlink(name.c_str()); } - if (handle > 0){ - close(handle); - } + close(handle); } + #endif + + ///brief Creates a shared file + ///\param name_ The name of the file to be created + ///\param len_ The size to make the file + ///\param master_ Whether to create or merely open the file + ///\param autoBackoff When only opening the file, wait for it to appear or fail sharedFile::sharedFile(std::string name_, unsigned int len_, bool master_, bool autoBackoff) : handle(0), name(name_), len(len_), master(master_), mapped(NULL) { handle = 0; name = name_; len = len_; master = master_; mapped = 0; - init(name_,len_,master_, autoBackoff); + init(name_, len_, master_, autoBackoff); } - sharedFile::sharedFile(const sharedPage & rhs){ + + + ///\brief Creates a copy of a shared page + ///\param rhs The page to copy + sharedFile::sharedFile(const sharedFile & rhs) { handle = 0; name = ""; len = 0; @@ -176,21 +400,38 @@ namespace IPC { mapped = 0; init(rhs.name, rhs.len, rhs.master); } + + ///\brief Returns whether the shared file is valid or not sharedFile::operator bool() const { return mapped != 0; } - void sharedFile::operator =(sharedFile & rhs){ + + ///\brief Assignment operator + void sharedFile::operator =(sharedFile & rhs) { init(rhs.name, rhs.len, rhs.master); rhs.master = false;//Make sure the memory does not get unlinked } - void sharedFile::init(std::string name_, unsigned int len_, bool master_, bool autoBackoff) { - if (mapped && len){ - munmap(mapped,len); + + ///\brief Unmaps a shared file if allowed + void sharedFile::unmap() { + if (mapped && len) { + munmap(mapped, len); + mapped = 0; + len = 0; } - if(master){ + } + + ///\brief Initialize a page, de-initialize before if needed + ///\param name_ The name of the page to be created + ///\param len_ The size to make the page + ///\param master_ Whether to create or merely open the page + ///\param autoBackoff When only opening the page, wait for it to appear or fail + void sharedFile::init(std::string name_, unsigned int len_, bool master_, bool autoBackoff) { + unmap(); + if (master) { unlink(name.c_str()); } - if (handle > 0){ + if (handle > 0) { close(handle); } handle = 0; @@ -198,19 +439,19 @@ namespace IPC { len = len_; master = master_; mapped = 0; - if (name.size()){ + if (name.size()) { /// \todo Use ACCESSPERMS instead of 0600? - handle = open(name.c_str(), ( master ? O_CREAT | O_TRUNC | O_EXCL : 0 )| O_RDWR, (mode_t)0600); + handle = open(std::string(Util::getTmpFolder() + name).c_str(), (master ? O_CREAT | O_TRUNC | O_EXCL : 0) | O_RDWR, (mode_t)0600); if (handle == -1) { - if (master){ + if (master) { DEBUG_MSG(DLVL_HIGH, "Overwriting old file for %s", name.c_str()); - handle = open(name.c_str(), O_CREAT | O_TRUNC | O_RDWR, (mode_t)0600); - }else{ + handle = open(std::string(Util::getTmpFolder() + name).c_str(), O_CREAT | O_TRUNC | O_RDWR, (mode_t)0600); + } else { int i = 0; - while (i < 10 && handle == -1 && autoBackoff){ + while (i < 10 && handle == -1 && autoBackoff) { i++; Util::sleep(1000); - handle = open(name.c_str(), O_RDWR, (mode_t)0600); + handle = open(std::string(Util::getTmpFolder() + name).c_str(), O_RDWR, (mode_t)0600); } } } @@ -218,154 +459,180 @@ namespace IPC { perror(std::string("open for file " + name + " failed").c_str()); return; } - if (master){ + if (master) { if (ftruncate(handle, len) < 0) { perror(std::string("ftruncate to len for file " + name + " failed").c_str()); return; } - }else{ + } else { struct stat buffStats; int xRes = fstat(handle, &buffStats); - if (xRes < 0){ + if (xRes < 0) { return; } len = buffStats.st_size; } - mapped = (char*)mmap(0, len, PROT_READ | PROT_WRITE, MAP_SHARED, handle, 0); - if (mapped == MAP_FAILED){ + mapped = (char *)mmap(0, len, PROT_READ | PROT_WRITE, MAP_SHARED, handle, 0); + if (mapped == MAP_FAILED) { mapped = 0; return; } } } - sharedFile::~sharedFile(){ - if (mapped && len){ - munmap(mapped,len); - } - if(master){ + + ///\brief Default destructor + sharedFile::~sharedFile() { + unmap(); + if (master) { unlink(name.c_str()); } - if (handle > 0){ + if (handle > 0) { close(handle); } } - + + + ///\brief StatExchange constructor, sets the datapointer to the given value statExchange::statExchange(char * _data) : data(_data) {} + ///\brief Sets timestamp of the current stats void statExchange::now(long long int time) { htobll(data, time); } + ///\brief Gets timestamp of the current stats long long int statExchange::now() { long long int result; btohll(data, result); return result; } + ///\brief Sets time currently connected void statExchange::time(long time) { htobl(data + 8, time); } + ///\brief Gets time currently connected long statExchange::time() { long result; btohl(data + 8, result); return result; } + ///\brief Sets the last viewing second of this user void statExchange::lastSecond(long time) { htobl(data + 12, time); } + ///\brief Gets the last viewing second of this user long statExchange::lastSecond() { long result; btohl(data + 12, result); return result; } + ///\brief Sets the amount of bytes received void statExchange::down(long long int bytes) { htobll(data + 16, bytes); } + ///\brief Gets the amount of bytes received long long int statExchange::down() { long long int result; btohll(data + 16, result); return result; } + ///\brief Sets the amount of bytes sent void statExchange::up(long long int bytes) { htobll(data + 24, bytes); } + ///\brief Gets the amount of bytes sent long long int statExchange::up() { long long int result; btohll(data + 24, result); return result; } + ///\brief Sets the host of this connection void statExchange::host(std::string name) { memcpy(data + 32, name.c_str(), std::min((int)name.size(), 16)); } + ///\brief Gets the host of this connection std::string statExchange::host() { return std::string(data + 32, std::min((int)strlen(data + 32), 16)); } + ///\brief Sets the name of the stream this user is viewing void statExchange::streamName(std::string name) { memcpy(data + 48, name.c_str(), std::min((int)name.size(), 20)); } + ///\brief Gets the name of the stream this user is viewing std::string statExchange::streamName() { return std::string(data + 48, std::min((int)strlen(data + 48), 20)); } + ///\brief Sets the name of the connector through which this user is viewing void statExchange::connector(std::string name) { memcpy(data + 68, name.c_str(), std::min((int)name.size(), 20)); } + ///\brief Gets the name of the connector through which this user is viewing std::string statExchange::connector() { return std::string(data + 68, std::min((int)strlen(data + 68), 20)); } - - semGuard::semGuard(sem_t * semaphore) : mySemaphore(semaphore) { - sem_wait(mySemaphore); + ///\brief Creates a semaphore guard, locks the semaphore on call + semGuard::semGuard(semaphore thisSemaphore) : mySemaphore(thisSemaphore) { + mySemaphore.wait(); } + ///\brief Destructs a semaphore guard, unlocks the semaphore on call semGuard::~semGuard() { - sem_post(mySemaphore); + mySemaphore.post(); } - - sharedServer::sharedServer(){ - mySemaphore = 0; + + ///\brief Default constructor, erases all the values + sharedServer::sharedServer() { payLen = 0; hasCounter = false; amount = 0; } - sharedServer::sharedServer(std::string name, int len, bool withCounter){ + ///\brief Desired constructor, initializes after cleaning. + ///\param name The basename of this server + ///\param len The lenght of the payload + ///\param withCounter Whether the content should have a counter + sharedServer::sharedServer(std::string name, int len, bool withCounter) { sharedServer(); init(name, len, withCounter); } - - - void sharedServer::init(std::string name, int len, bool withCounter){ + + ///\brief Initialize the server + ///\param name The basename of this server + ///\param len The lenght of the payload + ///\param withCounter Whether the content should have a counter + void sharedServer::init(std::string name, int len, bool withCounter) { amount = 0; - if (mySemaphore != SEM_FAILED) { - sem_close(mySemaphore); + if (mySemaphore) { + mySemaphore.close(); } - if (baseName != ""){ - sem_unlink(std::string("/" + baseName).c_str()); + if (baseName != "") { + mySemaphore.unlink(); } myPages.clear(); baseName = name; payLen = len; hasCounter = withCounter; - mySemaphore = sem_open(std::string("/" + baseName).c_str(), O_CREAT | O_EXCL | O_RDWR, ACCESSPERMS, 1); - if (mySemaphore == SEM_FAILED) { - mySemaphore = sem_open(std::string("/" + baseName).c_str(), O_CREAT | O_RDWR, ACCESSPERMS, 1); + mySemaphore.open(std::string("/" + baseName).c_str(), O_CREAT | O_EXCL | O_RDWR, ACCESSPERMS, 1); + if (!mySemaphore) { + mySemaphore.open(std::string("/" + baseName).c_str(), O_CREAT | O_RDWR, ACCESSPERMS, 1); } - if (mySemaphore == SEM_FAILED) { - DEBUG_MSG(DLVL_FAIL,"Creating semaphore failed: %s", strerror(errno)); + if (!mySemaphore) { + DEBUG_MSG(DLVL_FAIL, "Creating semaphore failed: %s", strerror(errno)); return; } newPage(); @@ -375,17 +642,18 @@ namespace IPC { newPage(); } + ///\brief The deconstructor sharedServer::~sharedServer() { - if (mySemaphore != SEM_FAILED) { - sem_close(mySemaphore); - } - sem_unlink(std::string("/" + baseName).c_str()); + mySemaphore.close(); + mySemaphore.unlink(); } + ///\brief Determines whether a sharedServer is valid sharedServer::operator bool() const { return myPages.size(); } + ///\brief Creates the next page with the correct size void sharedServer::newPage() { semGuard tmpGuard(mySemaphore); sharedPage tmp(std::string(baseName + (char)(myPages.size() + (int)'A')), (4096 << myPages.size()), true); @@ -394,6 +662,7 @@ namespace IPC { DEBUG_MSG(DLVL_MEDIUM, "Added a new page: %s", tmp.name.c_str()); } + ///\brief Deletes the highest allocated page void sharedServer::deletePage() { if (myPages.size() == 1) { DEBUG_MSG(DLVL_WARN, "Can't remove last page for %s", baseName.c_str()); @@ -403,25 +672,26 @@ namespace IPC { myPages.erase((*myPages.rbegin())); } - bool sharedServer::isInUse(unsigned int id){ + ///\brief Determines whether an id is currently in use or not + bool sharedServer::isInUse(unsigned int id) { unsigned int i = 0; for (std::set::iterator it = myPages.begin(); it != myPages.end(); it++) { //return if we reached the end - if (!it->mapped || !it->len){ + if (!it->mapped || !it->len) { return false; } //not on this page? skip to next. - if (it->len < (id - i)*payLen){ + if (it->len < (id - i)*payLen) { i += it->len / payLen; continue; } - if (hasCounter){ + if (hasCounter) { //counter? return true if it is non-zero. - return (it->mapped[(id - i)*payLen] != 0); - }else{ + return (it->mapped[(id - i) * payLen] != 0); + } else { //no counter - check the entire size for being all zeroes. - for (unsigned int j = 0; j < payLen; ++j){ - if (it->mapped[(id-i)*payLen+j]){ + for (unsigned int j = 0; j < payLen; ++j) { + if (it->mapped[(id - i)*payLen + j]) { return true; } } @@ -431,7 +701,8 @@ namespace IPC { //only happens if we run out of pages return false; } - + + ///\brief Parse each of the possible payload pieces, and runs a callback on it if in use. void sharedServer::parseEach(void (*callback)(char * data, size_t len, unsigned int id)) { char * empty = 0; if (!hasCounter) { @@ -440,18 +711,18 @@ namespace IPC { } unsigned int id = 0; for (std::set::iterator it = myPages.begin(); it != myPages.end(); it++) { - if (!it->mapped || !it->len){ + if (!it->mapped || !it->len) { DEBUG_MSG(DLVL_FAIL, "Something went terribly wrong?"); break; } unsigned int offset = 0; while (offset + payLen + (hasCounter ? 1 : 0) <= it->len) { - if (hasCounter){ + if (hasCounter) { if (it->mapped[offset] != 0) { int counter = it->mapped[offset]; //increase the count if needed - if (id >= amount){ - amount = id+1; + if (id >= amount) { + amount = id + 1; DEBUG_MSG(DLVL_VERYHIGH, "Shared memory %s is now at count %u", baseName.c_str(), amount); } callback(it->mapped + offset + 1, payLen, id); @@ -477,11 +748,11 @@ namespace IPC { } else { it->mapped[offset] ++; } - }else{ + } else { //stop if we're past the amount counted and we're empty - if (id >= amount - 1){ + if (id >= amount - 1) { //bring the counter down if this was the last element - if (id == amount - 1){ + if (id == amount - 1) { amount = id; DEBUG_MSG(DLVL_VERYHIGH, "Shared memory %s is now at count %u", baseName.c_str(), amount); } @@ -489,24 +760,24 @@ namespace IPC { return; } } - }else{ + } else { if (memcmp(empty, it->mapped + offset, payLen)) { //increase the count if needed - if (id >= amount){ - amount = id+1; + if (id >= amount) { + amount = id + 1; DEBUG_MSG(DLVL_VERYHIGH, "Shared memory %s is now at count %u", baseName.c_str(), amount); } callback(it->mapped + offset, payLen, id); - }else{ + } else { //stop if we're past the amount counted and we're empty - if (id >= amount - 1){ + if (id >= amount - 1) { //bring the counter down if this was the last element - if (id == amount - 1){ + if (id == amount - 1) { amount = id; DEBUG_MSG(DLVL_VERYHIGH, "Shared memory %s is now at count %u", baseName.c_str(), amount); } //stop, we're guaranteed no more pages are full at this point - if (empty){ + if (empty) { free(empty); } return; @@ -517,11 +788,12 @@ namespace IPC { id ++; } } - if (empty){ + if (empty) { free(empty); } } + ///\brief Creates an empty shared client sharedClient::sharedClient() { hasCounter = 0; payLen = 0; @@ -529,60 +801,67 @@ namespace IPC { mySemaphore = 0; } - sharedClient::sharedClient(const sharedClient & rhs ) { + ///\brief Copy constructor for sharedClients + ///\param rhs The client ro copy + sharedClient::sharedClient(const sharedClient & rhs) { baseName = rhs.baseName; payLen = rhs.payLen; hasCounter = rhs.hasCounter; -#ifdef __APPLE__ +#ifdef __APPLE__ //note: O_CREAT is only needed for mac, probably - mySemaphore = sem_open(std::string("/" + baseName).c_str(), O_RDWR | O_CREAT, 0); + mySemaphore.open(std::string("/" + baseName).c_str(), O_RDWR | O_CREAT, 0); #else - mySemaphore = sem_open(std::string("/" + baseName).c_str(), O_RDWR); + mySemaphore.open(std::string("/" + baseName).c_str(), O_RDWR); #endif - if (mySemaphore == SEM_FAILED) { - DEBUG_MSG(DLVL_FAIL,"Creating semaphore failed: %s", strerror(errno)); + if (!mySemaphore) { + DEBUG_MSG(DLVL_FAIL, "Creating semaphore failed: %s", strerror(errno)); return; } semGuard tmpGuard(mySemaphore); - myPage.init(rhs.myPage.name,rhs.myPage.len,rhs.myPage.master); + myPage.init(rhs.myPage.name, rhs.myPage.len, rhs.myPage.master); offsetOnPage = rhs.offsetOnPage; } - void sharedClient::operator =(const sharedClient & rhs ) { + ///\brief Assignment operator + void sharedClient::operator =(const sharedClient & rhs) { baseName = rhs.baseName; payLen = rhs.payLen; hasCounter = rhs.hasCounter; -#ifdef __APPLE__ +#ifdef __APPLE__ //note: O_CREAT is only needed for mac, probably - mySemaphore = sem_open(std::string("/" + baseName).c_str(), O_RDWR | O_CREAT, 0); + mySemaphore.open(std::string("/" + baseName).c_str(), O_RDWR | O_CREAT, 0); #else - mySemaphore = sem_open(std::string("/" + baseName).c_str(), O_RDWR); + mySemaphore.open(std::string("/" + baseName).c_str(), O_RDWR); #endif - if (mySemaphore == SEM_FAILED) { - DEBUG_MSG(DLVL_FAIL,"Creating semaphore failed: %s", strerror(errno)); + if (!mySemaphore) { + DEBUG_MSG(DLVL_FAIL, "Creating semaphore failed: %s", strerror(errno)); return; } semGuard tmpGuard(mySemaphore); - myPage.init(rhs.myPage.name,rhs.myPage.len,rhs.myPage.master); + myPage.init(rhs.myPage.name, rhs.myPage.len, rhs.myPage.master); offsetOnPage = rhs.offsetOnPage; } - + + ///\brief SharedClient Constructor, allocates space on the correct page. + ///\param name The basename of the server to connect to + ///\param len The size of the payload to allocate + ///\param withCounter Whether or not this payload has a counter sharedClient::sharedClient(std::string name, int len, bool withCounter) : baseName(name), payLen(len), offsetOnPage(-1), hasCounter(withCounter) { -#ifdef __APPLE__ +#ifdef __APPLE__ //note: O_CREAT is only needed for mac, probably - mySemaphore = sem_open(std::string("/" + baseName).c_str(), O_RDWR | O_CREAT, 0); + mySemaphore.open(std::string("/" + baseName).c_str(), O_RDWR | O_CREAT, 0); #else - mySemaphore = sem_open(std::string("/" + baseName).c_str(), O_RDWR); + mySemaphore.open(std::string("/" + baseName).c_str(), O_RDWR); #endif - if (mySemaphore == SEM_FAILED) { - DEBUG_MSG(DLVL_FAIL,"Creating semaphore failed: %s", strerror(errno)); + if (!mySemaphore) { + DEBUG_MSG(DLVL_FAIL, "Creating semaphore failed: %s", strerror(errno)); return; } semGuard tmpGuard(mySemaphore); char * empty = 0; if (!hasCounter) { empty = (char *)malloc(payLen * sizeof(char)); - if (!empty){ + if (!empty) { DEBUG_MSG(DLVL_FAIL, "Failed to allocate %u bytes for empty payload!", payLen); return; } @@ -608,15 +887,15 @@ namespace IPC { free(empty); } + ///\brief The deconstructor sharedClient::~sharedClient() { - if (hasCounter){ + if (hasCounter) { finish(); } - if (mySemaphore != SEM_FAILED) { - sem_close(mySemaphore); - } + mySemaphore.close(); } + ///\brief Writes data to the shared data void sharedClient::write(char * data, int len) { if (hasCounter) { keepAlive(); @@ -624,30 +903,36 @@ namespace IPC { memcpy(myPage.mapped + offsetOnPage + (hasCounter ? 1 : 0), data, std::min(len, payLen)); } + ///\brief Indicate that the process is done using this piece of memory, set the counter to finished void sharedClient::finish() { if (!hasCounter) { DEBUG_MSG(DLVL_WARN, "Trying to time-out an element without counters"); return; } - if (myPage.mapped){ + if (myPage.mapped) { myPage.mapped[offsetOnPage] = 127; } } + ///\brief Re-initialize the counter void sharedClient::keepAlive() { if (!hasCounter) { DEBUG_MSG(DLVL_WARN, "Trying to keep-alive an element without counters"); return; } - if (myPage.mapped[offsetOnPage] < 128){ + if (myPage.mapped[offsetOnPage] < 128) { myPage.mapped[offsetOnPage] = 1; - }else{ + } else { DEBUG_MSG(DLVL_WARN, "Trying to keep-alive an element that needs to timeout, ignoring"); } } + ///\brief Get a pointer to the data of this client char * sharedClient::getData() { - if (!myPage.mapped){return 0;} + if (!myPage.mapped) { + return 0; + } return (myPage.mapped + offsetOnPage + (hasCounter ? 1 : 0)); } } + diff --git a/lib/shared_memory.h b/lib/shared_memory.h index 29392ea9..9c448203 100644 --- a/lib/shared_memory.h +++ b/lib/shared_memory.h @@ -1,12 +1,18 @@ #pragma once #include #include -#include #include "timing.h" +#ifdef __CYGWIN__ +#include +#else +#include +#endif + namespace IPC { + ///\brief A class used for the exchange of statistics over shared memory. class statExchange { public: statExchange(char * _data); @@ -27,18 +33,53 @@ namespace IPC { void connector(std::string name); std::string connector(); 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) + /// - 20 byte - streamName (name of the stream peer is viewing) + /// - 20 byte - connector (name of the connector the peer is using) char * data; }; - class semGuard { + ///\brief A class used for the abstraction of semaphores + class semaphore { public: - semGuard(sem_t * semaphore); - ~semGuard(); + semaphore(); + semaphore(const char * name, int oflag, mode_t mode, unsigned int value); + ~semaphore(); + operator bool() const; + void open(const char * name, int oflag, mode_t mode = 0, unsigned int value = 0); + int getVal() const; + void post(); + void wait(); + bool tryWait(); + void close(); + void unlink(); private: - sem_t * mySemaphore; +#ifdef __CYGWIN__ + HANDLE mySem; +#else + sem_t * mySem; +#endif + char * myName; }; -#if !defined __APPLE__ && !defined __CYGWIN__ + ///\brief A class used as a semaphore guard + class semGuard { + public: + semGuard(semaphore thisSemaphore); + ~semGuard(); + private: + ///\brief The semaphore to guard. + semaphore mySemaphore; + }; + +#if !defined __APPLE__ + ///\brief A class for managing shared memory pages. class sharedPage{ public: sharedPage(std::string name_ = "", unsigned int len_ = 0, bool master_ = false, bool autoBackoff = true); @@ -50,20 +91,37 @@ namespace IPC { bool operator < (const sharedPage & rhs) const { return name < rhs.name; } + void unmap(); + void close(); + #ifdef __CYGWIN__ + ///\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 class sharedPage; #endif +#if !defined __APPLE__ + ///\brief A class for managing shared files in the same form as shared memory pages +#else + ///\brief A class for managing shared files. +#endif class sharedFile{ public: sharedFile(std::string name_ = "", unsigned int len_ = 0, bool master_ = false, bool autoBackoff = true); - sharedFile(const sharedPage & rhs); + sharedFile(const sharedFile & rhs); ~sharedFile(); operator bool() const; void init(std::string name_, unsigned int len_, bool master_ = false, bool autoBackoff = true); @@ -71,14 +129,23 @@ namespace IPC { bool operator < (const sharedFile & rhs) const { return name < rhs.name; } + void unmap(); + ///\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 long long int 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 __APPLE__ || defined __CYGWIN__ +#ifdef __APPLE__ + ///\brief A class for handling shared memory pages. + /// + ///Uses shared files at its backbone, defined for portability class sharedPage: public sharedFile{ public: sharedPage(std::string name_ = "", unsigned int len_ = 0, bool master_ = false, bool autoBackoff = true); @@ -87,6 +154,15 @@ namespace IPC { }; #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(); @@ -95,18 +171,33 @@ namespace IPC { ~sharedServer(); void parseEach(void (*callback)(char * data, size_t len, unsigned int id)); operator bool() const; + ///\brief The amount of connected clients unsigned int amount; 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::set myPages; - sem_t * mySemaphore; + ///\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(); @@ -119,11 +210,17 @@ namespace IPC { void keepAlive(); char * getData(); private: + ///\brief The basename of the shared pages. std::string baseName; + ///\brief The shared page this client has reserved a space on. sharedPage myPage; - sem_t * mySemaphore; + ///\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; }; } diff --git a/lib/stream.cpp b/lib/stream.cpp index 77dd6933..eb22e140 100644 --- a/lib/stream.cpp +++ b/lib/stream.cpp @@ -12,6 +12,7 @@ #include "config.h" #include "socket.h" #include "defines.h" +#include "shared_memory.h" std::string Util::getTmpFolder(){ std::string dir; @@ -119,14 +120,14 @@ bool Util::Stream::getStream(std::string streamname){ JSON::Value ServConf = JSON::fromFile(getTmpFolder() + "streamlist"); if (ServConf["streams"].isMember(streamname)){ //check if the stream is already active, if yes, don't re-activate - sem_t * playerLock = sem_open(std::string("/lock_" + streamname).c_str(), O_CREAT | O_RDWR, ACCESSPERMS, 1); - if (sem_trywait(playerLock) == -1){ - sem_close(playerLock); + IPC::semaphore playerLock(std::string("/lock_" + streamname).c_str(), O_CREAT | O_RDWR, ACCESSPERMS, 1); + if (!playerLock.tryWait()){ + playerLock.close(); DEBUG_MSG(DLVL_MEDIUM, "Playerlock for %s already active - not re-activating stream", streamname.c_str()); return true; } - sem_post(playerLock); - sem_close(playerLock); + playerLock.post(); + playerLock.close(); if (ServConf["streams"][streamname]["source"].asString()[0] == '/'){ DEBUG_MSG(DLVL_MEDIUM, "Activating VoD stream %s", streamname.c_str()); return getVod(ServConf["streams"][streamname]["source"].asString(), streamname);