mirror of
https://github.com/EQEmu/Server.git
synced 2025-12-26 19:21:28 +00:00
Merge branch 'web_interface' of github.com:EQEmu/Server into web_interface
This commit is contained in:
commit
7359eb01d4
@ -255,7 +255,7 @@ OPTION(EQEMU_BUILD_LOGIN "Build the login server." OFF)
|
||||
OPTION(EQEMU_BUILD_TESTS "Build utility tests." OFF)
|
||||
OPTION(EQEMU_BUILD_PERL "Build Perl parser." ON)
|
||||
OPTION(EQEMU_BUILD_LUA "Build Lua parser." ON)
|
||||
OPTION(EQEMU_BUILD_CLIENT_FILES "Build Client Import/Export Data Programs." ON)
|
||||
OPTION(EQEMU_BUILD_CLIENT_FILES "Build Client Inport/Export Data Programs." ON)
|
||||
|
||||
#C++11 stuff
|
||||
IF(NOT MSVC)
|
||||
@ -312,7 +312,7 @@ IF(EQEMU_BUILD_LUA)
|
||||
SET(BOOST_ROOT "${CMAKE_CURRENT_SOURCE_DIR}/dependencies/boost")
|
||||
|
||||
FIND_PACKAGE(Boost REQUIRED)
|
||||
INCLUDE_DIRECTORIES("${LUA_INCLUDE_DIR}" "${Boost_INCLUDE_DIRS}" "luabind")
|
||||
INCLUDE_DIRECTORIES("${LUA_INCLUDE_DIR}" "${Boost_INCLUDE_DIRS}" "dependencies/luabind")
|
||||
|
||||
OPTION(EQEMU_SANITIZE_LUA_LIBS "Sanitize Lua Libraries (Remove OS and IO standard libraries from being able to run)." ON)
|
||||
IF(EQEMU_SANITIZE_LUA_LIBS)
|
||||
@ -320,11 +320,7 @@ IF(EQEMU_BUILD_LUA)
|
||||
ENDIF(EQEMU_SANITIZE_LUA_LIBS)
|
||||
ENDIF(EQEMU_BUILD_LUA)
|
||||
|
||||
INCLUDE_DIRECTORIES("${ZLIB_INCLUDE_DIRS}" "${MySQL_INCLUDE_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}/common/glm/glm")
|
||||
|
||||
IF(EQEMU_BUILD_LUA)
|
||||
ADD_SUBDIRECTORY(luabind)
|
||||
ENDIF(EQEMU_BUILD_LUA)
|
||||
INCLUDE_DIRECTORIES("${ZLIB_INCLUDE_DIRS}" "${MySQL_INCLUDE_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}/common/glm/glm" "${CMAKE_CURRENT_SOURCE_DIR}/dependencies/libwebsockets" "${CMAKE_CURRENT_SOURCE_DIR}/common/rapidjson")
|
||||
|
||||
IF(EQEMU_BUILD_SERVER OR EQEMU_BUILD_LOGIN OR EQEMU_BUILD_TESTS)
|
||||
ADD_SUBDIRECTORY(common)
|
||||
@ -336,6 +332,8 @@ IF(EQEMU_BUILD_SERVER)
|
||||
ADD_SUBDIRECTORY(ucs)
|
||||
ADD_SUBDIRECTORY(queryserv)
|
||||
ADD_SUBDIRECTORY(eqlaunch)
|
||||
ADD_SUBDIRECTORY(dependencies)
|
||||
ADD_SUBDIRECTORY(web_interface)
|
||||
ENDIF(EQEMU_BUILD_SERVER)
|
||||
IF(EQEMU_BUILD_LOGIN)
|
||||
ADD_SUBDIRECTORY(loginserver)
|
||||
|
||||
@ -64,6 +64,7 @@ SET(common_sources
|
||||
timeoutmgr.cpp
|
||||
timer.cpp
|
||||
unix.cpp
|
||||
uuid.cpp
|
||||
worldconn.cpp
|
||||
XMLParser.cpp
|
||||
platform.cpp
|
||||
@ -90,6 +91,7 @@ SET(common_sources
|
||||
tinyxml/tinyxml.cpp
|
||||
tinyxml/tinyxmlerror.cpp
|
||||
tinyxml/tinyxmlparser.cpp
|
||||
web_interface_utils.cpp
|
||||
)
|
||||
|
||||
SET(common_headers
|
||||
@ -184,6 +186,7 @@ SET(common_headers
|
||||
timer.h
|
||||
types.h
|
||||
unix.h
|
||||
uuid.h
|
||||
useperl.h
|
||||
version.h
|
||||
worldconn.h
|
||||
@ -234,6 +237,7 @@ SET(common_headers
|
||||
StackWalker/StackWalker.h
|
||||
tinyxml/tinystr.h
|
||||
tinyxml/tinyxml.h
|
||||
web_interface_utils.h
|
||||
)
|
||||
|
||||
SOURCE_GROUP(Patches FILES
|
||||
|
||||
@ -26,7 +26,7 @@ EQEmuConfig *EQEmuConfig::_config = nullptr;
|
||||
|
||||
void EQEmuConfig::do_world(TiXmlElement *ele) {
|
||||
const char *text;
|
||||
TiXmlElement * sub_ele;;
|
||||
TiXmlElement * sub_ele;
|
||||
|
||||
text= ParseTextBlock(ele,"shortname");
|
||||
if (text)
|
||||
@ -217,6 +217,27 @@ void EQEmuConfig::do_qsdatabase(TiXmlElement *ele) {
|
||||
QSDatabaseDB=text;
|
||||
}
|
||||
|
||||
void EQEmuConfig::do_web_interface(TiXmlElement *ele) {
|
||||
const char *text;
|
||||
|
||||
text = ParseTextBlock(ele, "port", true);
|
||||
if (text)
|
||||
WebInterfacePort = atoi(text);
|
||||
|
||||
text = ParseTextBlock(ele, "cert", true);
|
||||
if (text)
|
||||
WebInterfaceCert = text;
|
||||
|
||||
text = ParseTextBlock(ele, "priv_key", true);
|
||||
if (text)
|
||||
WebInterfacePrivKey = text;
|
||||
|
||||
TiXmlElement *sub_ele = ele->FirstChildElement("ssl");
|
||||
if (sub_ele != nullptr) {
|
||||
WebInterfaceUseSSL = true;
|
||||
}
|
||||
}
|
||||
|
||||
void EQEmuConfig::do_zones(TiXmlElement *ele) {
|
||||
const char *text;
|
||||
TiXmlElement *sub_ele;
|
||||
@ -372,6 +393,14 @@ std::string EQEmuConfig::GetByName(const std::string &var_name) const {
|
||||
return(QSDatabaseDB);
|
||||
if(var_name == "QSDatabasePort")
|
||||
return(itoa(QSDatabasePort));
|
||||
if (var_name == "WebInterfacePort")
|
||||
return(itoa(WebInterfacePort));
|
||||
if (var_name == "WebInterfaceUseSSL")
|
||||
return(itoa(WebInterfaceUseSSL));
|
||||
if (var_name == "WebInterfaceCert")
|
||||
return(WebInterfaceCert);
|
||||
if (var_name == "WebInterfacePrivKey")
|
||||
return(WebInterfacePrivKey);
|
||||
if(var_name == "SpellsFile")
|
||||
return(SpellsFile);
|
||||
if(var_name == "OpCodesFile")
|
||||
@ -433,6 +462,10 @@ void EQEmuConfig::Dump() const
|
||||
std::cout << "QSDatabasePassword = " << QSDatabasePassword << std::endl;
|
||||
std::cout << "QSDatabaseDB = " << QSDatabaseDB << std::endl;
|
||||
std::cout << "QSDatabasePort = " << QSDatabasePort << std::endl;
|
||||
std::cout << "WebInterfacePort = " << WebInterfacePort << std::endl;
|
||||
std::cout << "WebInterfaceUseSSL = " << WebInterfaceUseSSL << std::endl;
|
||||
std::cout << "WebInterfaceCert = " << WebInterfaceCert << std::endl;
|
||||
std::cout << "WebInterfacePrivKey = " << WebInterfacePrivKey << std::endl;
|
||||
std::cout << "SpellsFile = " << SpellsFile << std::endl;
|
||||
std::cout << "OpCodesFile = " << OpCodesFile << std::endl;
|
||||
std::cout << "EQTimeFile = " << EQTimeFile << std::endl;
|
||||
@ -443,6 +476,5 @@ void EQEmuConfig::Dump() const
|
||||
std::cout << "ZonePortLow = " << ZonePortLow << std::endl;
|
||||
std::cout << "ZonePortHigh = " << ZonePortHigh << std::endl;
|
||||
std::cout << "DefaultStatus = " << (int)DefaultStatus << std::endl;
|
||||
// std::cout << "DynamicCount = " << DynamicCount << std::endl;
|
||||
}
|
||||
|
||||
|
||||
@ -75,6 +75,12 @@ public:
|
||||
std::string QSDatabaseDB;
|
||||
uint16 QSDatabasePort;
|
||||
|
||||
// from <web_interface>
|
||||
uint16 WebInterfacePort;
|
||||
bool WebInterfaceUseSSL;
|
||||
std::string WebInterfaceCert;
|
||||
std::string WebInterfacePrivKey;
|
||||
|
||||
// From <files/>
|
||||
std::string SpellsFile;
|
||||
std::string OpCodesFile;
|
||||
@ -158,6 +164,12 @@ protected:
|
||||
QSDatabasePassword="eq";
|
||||
QSDatabaseDB="eq";
|
||||
|
||||
// web_interface
|
||||
WebInterfacePort = 9081;
|
||||
WebInterfaceUseSSL = false;
|
||||
WebInterfaceCert = "";
|
||||
WebInterfacePrivKey = "";
|
||||
|
||||
// Files
|
||||
SpellsFile="spells_us.txt";
|
||||
OpCodesFile="opcodes.conf";
|
||||
|
||||
@ -4,6 +4,7 @@ ELEMENT(mailserver)
|
||||
ELEMENT(zones)
|
||||
ELEMENT(database)
|
||||
ELEMENT(qsdatabase)
|
||||
ELEMENT(web_interface)
|
||||
ELEMENT(files)
|
||||
ELEMENT(directories)
|
||||
ELEMENT(launcher)
|
||||
|
||||
@ -366,6 +366,22 @@ bool EmuTCPConnection::LineOutQueuePush(char* line) {
|
||||
safe_delete_array(line);
|
||||
return(true);
|
||||
}
|
||||
if (strcmp(line, "**PACKETMODEWI**") == 0) {
|
||||
MSendQueue.lock();
|
||||
safe_delete_array(sendbuf);
|
||||
if (TCPMode == modeConsole)
|
||||
Send((const uchar*) "\0**PACKETMODEWI**\r", 18);
|
||||
TCPMode = modePacket;
|
||||
PacketMode = packetModeWebInterface;
|
||||
EmuTCPNetPacket_Struct* tnps = 0;
|
||||
while ((tnps = InModeQueue.pop())) {
|
||||
SendPacket(tnps);
|
||||
safe_delete_array(tnps);
|
||||
}
|
||||
MSendQueue.unlock();
|
||||
safe_delete_array(line);
|
||||
return(true);
|
||||
}
|
||||
}
|
||||
|
||||
return(TCPConnection::LineOutQueuePush(line));
|
||||
@ -419,6 +435,13 @@ bool EmuTCPConnection::ConnectIP(uint32 irIP, uint16 irPort, char* errbuf) {
|
||||
sendbuf = new uchar[sendbuf_size];
|
||||
memcpy(sendbuf, "\0**PACKETMODEQS**\r", sendbuf_size);
|
||||
}
|
||||
else if (PacketMode == packetModeWebInterface) {
|
||||
safe_delete_array(sendbuf);
|
||||
sendbuf_size = 18;
|
||||
sendbuf_used = sendbuf_size;
|
||||
sendbuf = new uchar[sendbuf_size];
|
||||
memcpy(sendbuf, "\0**PACKETMODEWI**\r", sendbuf_size);
|
||||
}
|
||||
else {
|
||||
//default: packetModeZone
|
||||
safe_delete_array(sendbuf);
|
||||
|
||||
@ -30,7 +30,7 @@ class EmuTCPServer;
|
||||
class EmuTCPConnection : public TCPConnection {
|
||||
public:
|
||||
enum eTCPMode { modeConsole, modeTransition, modePacket };
|
||||
enum ePacketMode { packetModeZone, packetModeLauncher, packetModeLogin, packetModeUCS, packetModeQueryServ };
|
||||
enum ePacketMode { packetModeZone, packetModeLauncher, packetModeLogin, packetModeUCS, packetModeQueryServ, packetModeWebInterface };
|
||||
|
||||
EmuTCPConnection(uint32 ID, EmuTCPServer* iServer, SOCKET iSock, uint32 irIP, uint16 irPort, bool iOldFormat = false);
|
||||
EmuTCPConnection(bool iOldFormat = false, EmuTCPServer* iRelayServer = 0, eTCPMode iMode = modePacket); // for outgoing connections
|
||||
|
||||
@ -65,12 +65,12 @@ LOG_TYPE( QUERYSERV, CLIENT, DISABLED )
|
||||
LOG_TYPE( QUERYSERV, TRACE, DISABLED )
|
||||
LOG_TYPE( QUERYSERV, PACKETS, DISABLED)
|
||||
|
||||
LOG_CATEGORY(SOCKET_SERVER)
|
||||
LOG_TYPE(SOCKET_SERVER, INIT, ENABLED)
|
||||
LOG_TYPE(SOCKET_SERVER, ERROR, ENABLED)
|
||||
LOG_TYPE(SOCKET_SERVER, CLIENT, DISABLED)
|
||||
LOG_TYPE(SOCKET_SERVER, TRACE, DISABLED)
|
||||
LOG_TYPE(SOCKET_SERVER, PACKETS, DISABLED)
|
||||
LOG_CATEGORY( WEB_INTERFACE )
|
||||
LOG_TYPE( WEB_INTERFACE, INIT, ENABLED )
|
||||
LOG_TYPE( WEB_INTERFACE, ERROR, ENABLED )
|
||||
LOG_TYPE( WEB_INTERFACE, CLIENT, DISABLED )
|
||||
LOG_TYPE( WEB_INTERFACE, TRACE, DISABLED )
|
||||
LOG_TYPE( WEB_INTERFACE, PACKETS, DISABLED )
|
||||
|
||||
LOG_CATEGORY( SPAWNS )
|
||||
LOG_TYPE( SPAWNS, MAIN, DISABLED )
|
||||
|
||||
@ -8,7 +8,7 @@ enum EQEmuExePlatform
|
||||
ExePlatformWorld,
|
||||
ExePlatformLogin,
|
||||
ExePlatformQueryServ,
|
||||
ExePlatformSocket_Server,
|
||||
ExePlatformWebInterface,
|
||||
ExePlatformUCS,
|
||||
ExePlatformLaunch,
|
||||
ExePlatformSharedMemory,
|
||||
|
||||
226
common/rapidjson/rapidjson/allocators.h
Normal file
226
common/rapidjson/rapidjson/allocators.h
Normal file
@ -0,0 +1,226 @@
|
||||
#ifndef RAPIDJSON_ALLOCATORS_H_
|
||||
#define RAPIDJSON_ALLOCATORS_H_
|
||||
|
||||
#include "rapidjson.h"
|
||||
|
||||
namespace rapidjson {
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Allocator
|
||||
|
||||
/*! \class rapidjson::Allocator
|
||||
\brief Concept for allocating, resizing and freeing memory block.
|
||||
|
||||
Note that Malloc() and Realloc() are non-static but Free() is static.
|
||||
|
||||
So if an allocator need to support Free(), it needs to put its pointer in
|
||||
the header of memory block.
|
||||
|
||||
\code
|
||||
concept Allocator {
|
||||
static const bool kNeedFree; //!< Whether this allocator needs to call Free().
|
||||
|
||||
// Allocate a memory block.
|
||||
// \param size of the memory block in bytes.
|
||||
// \returns pointer to the memory block.
|
||||
void* Malloc(size_t size);
|
||||
|
||||
// Resize a memory block.
|
||||
// \param originalPtr The pointer to current memory block. Null pointer is permitted.
|
||||
// \param originalSize The current size in bytes. (Design issue: since some allocator may not book-keep this, explicitly pass to it can save memory.)
|
||||
// \param newSize the new size in bytes.
|
||||
void* Realloc(void* originalPtr, size_t originalSize, size_t newSize);
|
||||
|
||||
// Free a memory block.
|
||||
// \param pointer to the memory block. Null pointer is permitted.
|
||||
static void Free(void *ptr);
|
||||
};
|
||||
\endcode
|
||||
*/
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// CrtAllocator
|
||||
|
||||
//! C-runtime library allocator.
|
||||
/*! This class is just wrapper for standard C library memory routines.
|
||||
\note implements Allocator concept
|
||||
*/
|
||||
class CrtAllocator {
|
||||
public:
|
||||
static const bool kNeedFree = true;
|
||||
void* Malloc(size_t size) { return malloc(size); }
|
||||
void* Realloc(void* originalPtr, size_t originalSize, size_t newSize) { (void)originalSize; return realloc(originalPtr, newSize); }
|
||||
static void Free(void *ptr) { free(ptr); }
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// MemoryPoolAllocator
|
||||
|
||||
//! Default memory allocator used by the parser and DOM.
|
||||
/*! This allocator allocate memory blocks from pre-allocated memory chunks.
|
||||
|
||||
It does not free memory blocks. And Realloc() only allocate new memory.
|
||||
|
||||
The memory chunks are allocated by BaseAllocator, which is CrtAllocator by default.
|
||||
|
||||
User may also supply a buffer as the first chunk.
|
||||
|
||||
If the user-buffer is full then additional chunks are allocated by BaseAllocator.
|
||||
|
||||
The user-buffer is not deallocated by this allocator.
|
||||
|
||||
\tparam BaseAllocator the allocator type for allocating memory chunks. Default is CrtAllocator.
|
||||
\note implements Allocator concept
|
||||
*/
|
||||
template <typename BaseAllocator = CrtAllocator>
|
||||
class MemoryPoolAllocator {
|
||||
public:
|
||||
static const bool kNeedFree = false; //!< Tell users that no need to call Free() with this allocator. (concept Allocator)
|
||||
|
||||
//! Constructor with chunkSize.
|
||||
/*! \param chunkSize The size of memory chunk. The default is kDefaultChunkSize.
|
||||
\param baseAllocator The allocator for allocating memory chunks.
|
||||
*/
|
||||
MemoryPoolAllocator(size_t chunkSize = kDefaultChunkCapacity, BaseAllocator* baseAllocator = 0) :
|
||||
chunkHead_(0), chunk_capacity_(chunkSize), userBuffer_(0), baseAllocator_(baseAllocator), ownBaseAllocator_(0)
|
||||
{
|
||||
if (!baseAllocator_)
|
||||
ownBaseAllocator_ = baseAllocator_ = new BaseAllocator();
|
||||
AddChunk(chunk_capacity_);
|
||||
}
|
||||
|
||||
//! Constructor with user-supplied buffer.
|
||||
/*! The user buffer will be used firstly. When it is full, memory pool allocates new chunk with chunk size.
|
||||
|
||||
The user buffer will not be deallocated when this allocator is destructed.
|
||||
|
||||
\param buffer User supplied buffer.
|
||||
\param size Size of the buffer in bytes. It must at least larger than sizeof(ChunkHeader).
|
||||
\param chunkSize The size of memory chunk. The default is kDefaultChunkSize.
|
||||
\param baseAllocator The allocator for allocating memory chunks.
|
||||
*/
|
||||
MemoryPoolAllocator(void *buffer, size_t size, size_t chunkSize = kDefaultChunkCapacity, BaseAllocator* baseAllocator = 0) :
|
||||
chunkHead_(0), chunk_capacity_(chunkSize), userBuffer_(buffer), baseAllocator_(baseAllocator), ownBaseAllocator_(0)
|
||||
{
|
||||
RAPIDJSON_ASSERT(buffer != 0);
|
||||
RAPIDJSON_ASSERT(size > sizeof(ChunkHeader));
|
||||
chunkHead_ = reinterpret_cast<ChunkHeader*>(buffer);
|
||||
chunkHead_->capacity = size - sizeof(ChunkHeader);
|
||||
chunkHead_->size = 0;
|
||||
chunkHead_->next = 0;
|
||||
}
|
||||
|
||||
//! Destructor.
|
||||
/*! This deallocates all memory chunks, excluding the user-supplied buffer.
|
||||
*/
|
||||
~MemoryPoolAllocator() {
|
||||
Clear();
|
||||
delete ownBaseAllocator_;
|
||||
}
|
||||
|
||||
//! Deallocates all memory chunks, excluding the user-supplied buffer.
|
||||
void Clear() {
|
||||
while(chunkHead_ != 0 && chunkHead_ != userBuffer_) {
|
||||
ChunkHeader* next = chunkHead_->next;
|
||||
baseAllocator_->Free(chunkHead_);
|
||||
chunkHead_ = next;
|
||||
}
|
||||
}
|
||||
|
||||
//! Computes the total capacity of allocated memory chunks.
|
||||
/*! \return total capacity in bytes.
|
||||
*/
|
||||
size_t Capacity() const {
|
||||
size_t capacity = 0;
|
||||
for (ChunkHeader* c = chunkHead_; c != 0; c = c->next)
|
||||
capacity += c->capacity;
|
||||
return capacity;
|
||||
}
|
||||
|
||||
//! Computes the memory blocks allocated.
|
||||
/*! \return total used bytes.
|
||||
*/
|
||||
size_t Size() const {
|
||||
size_t size = 0;
|
||||
for (ChunkHeader* c = chunkHead_; c != 0; c = c->next)
|
||||
size += c->size;
|
||||
return size;
|
||||
}
|
||||
|
||||
//! Allocates a memory block. (concept Allocator)
|
||||
void* Malloc(size_t size) {
|
||||
size = RAPIDJSON_ALIGN(size);
|
||||
if (chunkHead_->size + size > chunkHead_->capacity)
|
||||
AddChunk(chunk_capacity_ > size ? chunk_capacity_ : size);
|
||||
|
||||
void *buffer = reinterpret_cast<char *>(chunkHead_ + 1) + chunkHead_->size;
|
||||
chunkHead_->size += size;
|
||||
return buffer;
|
||||
}
|
||||
|
||||
//! Resizes a memory block (concept Allocator)
|
||||
void* Realloc(void* originalPtr, size_t originalSize, size_t newSize) {
|
||||
if (originalPtr == 0)
|
||||
return Malloc(newSize);
|
||||
|
||||
// Do not shrink if new size is smaller than original
|
||||
if (originalSize >= newSize)
|
||||
return originalPtr;
|
||||
|
||||
// Simply expand it if it is the last allocation and there is sufficient space
|
||||
if (originalPtr == (char *)(chunkHead_ + 1) + chunkHead_->size - originalSize) {
|
||||
size_t increment = static_cast<size_t>(newSize - originalSize);
|
||||
increment = RAPIDJSON_ALIGN(increment);
|
||||
if (chunkHead_->size + increment <= chunkHead_->capacity) {
|
||||
chunkHead_->size += increment;
|
||||
return originalPtr;
|
||||
}
|
||||
}
|
||||
|
||||
// Realloc process: allocate and copy memory, do not free original buffer.
|
||||
void* newBuffer = Malloc(newSize);
|
||||
RAPIDJSON_ASSERT(newBuffer != 0); // Do not handle out-of-memory explicitly.
|
||||
return memcpy(newBuffer, originalPtr, originalSize);
|
||||
}
|
||||
|
||||
//! Frees a memory block (concept Allocator)
|
||||
static void Free(void *ptr) { (void)ptr; } // Do nothing
|
||||
|
||||
private:
|
||||
//! Copy constructor is not permitted.
|
||||
MemoryPoolAllocator(const MemoryPoolAllocator& rhs) /* = delete */;
|
||||
//! Copy assignment operator is not permitted.
|
||||
MemoryPoolAllocator& operator=(const MemoryPoolAllocator& rhs) /* = delete */;
|
||||
|
||||
//! Creates a new chunk.
|
||||
/*! \param capacity Capacity of the chunk in bytes.
|
||||
*/
|
||||
void AddChunk(size_t capacity) {
|
||||
ChunkHeader* chunk = reinterpret_cast<ChunkHeader*>(baseAllocator_->Malloc(sizeof(ChunkHeader) + capacity));
|
||||
chunk->capacity = capacity;
|
||||
chunk->size = 0;
|
||||
chunk->next = chunkHead_;
|
||||
chunkHead_ = chunk;
|
||||
}
|
||||
|
||||
static const int kDefaultChunkCapacity = 64 * 1024; //!< Default chunk capacity.
|
||||
|
||||
//! Chunk header for perpending to each chunk.
|
||||
/*! Chunks are stored as a singly linked list.
|
||||
*/
|
||||
struct ChunkHeader {
|
||||
size_t capacity; //!< Capacity of the chunk in bytes (excluding the header itself).
|
||||
size_t size; //!< Current size of allocated memory in bytes.
|
||||
ChunkHeader *next; //!< Next chunk in the linked list.
|
||||
};
|
||||
|
||||
ChunkHeader *chunkHead_; //!< Head of the chunk linked-list. Only the head chunk serves allocation.
|
||||
size_t chunk_capacity_; //!< The minimum capacity of chunk when they are allocated.
|
||||
void *userBuffer_; //!< User supplied buffer.
|
||||
BaseAllocator* baseAllocator_; //!< base allocator for allocating memory chunks.
|
||||
BaseAllocator* ownBaseAllocator_; //!< base allocator created by this object.
|
||||
};
|
||||
|
||||
} // namespace rapidjson
|
||||
|
||||
#endif // RAPIDJSON_ENCODINGS_H_
|
||||
1441
common/rapidjson/rapidjson/document.h
Normal file
1441
common/rapidjson/rapidjson/document.h
Normal file
File diff suppressed because it is too large
Load Diff
270
common/rapidjson/rapidjson/encodedstream.h
Normal file
270
common/rapidjson/rapidjson/encodedstream.h
Normal file
@ -0,0 +1,270 @@
|
||||
#ifndef RAPIDJSON_ENCODEDSTREAM_H_
|
||||
#define RAPIDJSON_ENCODEDSTREAM_H_
|
||||
|
||||
#include "rapidjson.h"
|
||||
|
||||
#ifdef __GNUC__
|
||||
RAPIDJSON_DIAG_PUSH
|
||||
RAPIDJSON_DIAG_OFF(effc++)
|
||||
#endif
|
||||
|
||||
namespace rapidjson {
|
||||
|
||||
//! Input byte stream wrapper with a statically bound encoding.
|
||||
/*!
|
||||
\tparam Encoding The interpretation of encoding of the stream. Either UTF8, UTF16LE, UTF16BE, UTF32LE, UTF32BE.
|
||||
\tparam InputByteStream Type of input byte stream. For example, FileReadStream.
|
||||
*/
|
||||
template <typename Encoding, typename InputByteStream>
|
||||
class EncodedInputStream {
|
||||
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
|
||||
public:
|
||||
typedef typename Encoding::Ch Ch;
|
||||
|
||||
EncodedInputStream(InputByteStream& is) : is_(is) {
|
||||
current_ = Encoding::TakeBOM(is_);
|
||||
}
|
||||
|
||||
Ch Peek() const { return current_; }
|
||||
Ch Take() { Ch c = current_; current_ = Encoding::Take(is_); return c; }
|
||||
size_t Tell() const { return is_.Tell(); }
|
||||
|
||||
// Not implemented
|
||||
void Put(Ch) { RAPIDJSON_ASSERT(false); }
|
||||
void Flush() { RAPIDJSON_ASSERT(false); }
|
||||
Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
|
||||
size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; }
|
||||
|
||||
private:
|
||||
EncodedInputStream(const EncodedInputStream&);
|
||||
EncodedInputStream& operator=(const EncodedInputStream&);
|
||||
|
||||
InputByteStream& is_;
|
||||
Ch current_;
|
||||
};
|
||||
|
||||
//! Output byte stream wrapper with statically bound encoding.
|
||||
/*!
|
||||
\tparam Encoding The interpretation of encoding of the stream. Either UTF8, UTF16LE, UTF16BE, UTF32LE, UTF32BE.
|
||||
\tparam InputByteStream Type of input byte stream. For example, FileWriteStream.
|
||||
*/
|
||||
template <typename Encoding, typename OutputByteStream>
|
||||
class EncodedOutputStream {
|
||||
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
|
||||
public:
|
||||
typedef typename Encoding::Ch Ch;
|
||||
|
||||
EncodedOutputStream(OutputByteStream& os, bool putBOM = true) : os_(os) {
|
||||
if (putBOM)
|
||||
Encoding::PutBOM(os_);
|
||||
}
|
||||
|
||||
void Put(Ch c) { Encoding::Put(os_, c); }
|
||||
void Flush() { os_.Flush(); }
|
||||
|
||||
// Not implemented
|
||||
Ch Peek() const { RAPIDJSON_ASSERT(false); }
|
||||
Ch Take() { RAPIDJSON_ASSERT(false); }
|
||||
size_t Tell() const { RAPIDJSON_ASSERT(false); return 0; }
|
||||
Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
|
||||
size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; }
|
||||
|
||||
private:
|
||||
EncodedOutputStream(const EncodedOutputStream&);
|
||||
EncodedOutputStream& operator=(const EncodedOutputStream&);
|
||||
|
||||
OutputByteStream& os_;
|
||||
};
|
||||
|
||||
#define RAPIDJSON_ENCODINGS_FUNC(x) UTF8<Ch>::x, UTF16LE<Ch>::x, UTF16BE<Ch>::x, UTF32LE<Ch>::x, UTF32BE<Ch>::x
|
||||
|
||||
//! Input stream wrapper with dynamically bound encoding and automatic encoding detection.
|
||||
/*!
|
||||
\tparam CharType Type of character for reading.
|
||||
\tparam InputByteStream type of input byte stream to be wrapped.
|
||||
*/
|
||||
template <typename CharType, typename InputByteStream>
|
||||
class AutoUTFInputStream {
|
||||
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
|
||||
public:
|
||||
typedef CharType Ch;
|
||||
|
||||
//! Constructor.
|
||||
/*!
|
||||
\param is input stream to be wrapped.
|
||||
\param type UTF encoding type if it is not detected from the stream.
|
||||
*/
|
||||
AutoUTFInputStream(InputByteStream& is, UTFType type = kUTF8) : is_(&is), type_(type), hasBOM_(false) {
|
||||
DetectType();
|
||||
static const TakeFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Take) };
|
||||
takeFunc_ = f[type_];
|
||||
current_ = takeFunc_(*is_);
|
||||
}
|
||||
|
||||
UTFType GetType() const { return type_; }
|
||||
bool HasBOM() const { return hasBOM_; }
|
||||
|
||||
Ch Peek() const { return current_; }
|
||||
Ch Take() { Ch c = current_; current_ = takeFunc_(*is_); return c; }
|
||||
size_t Tell() const { return is_->Tell(); }
|
||||
|
||||
// Not implemented
|
||||
void Put(Ch) { RAPIDJSON_ASSERT(false); }
|
||||
void Flush() { RAPIDJSON_ASSERT(false); }
|
||||
Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
|
||||
size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; }
|
||||
|
||||
private:
|
||||
AutoUTFInputStream(const AutoUTFInputStream&);
|
||||
AutoUTFInputStream& operator=(const AutoUTFInputStream&);
|
||||
|
||||
// Detect encoding type with BOM or RFC 4627
|
||||
void DetectType() {
|
||||
// BOM (Byte Order Mark):
|
||||
// 00 00 FE FF UTF-32BE
|
||||
// FF FE 00 00 UTF-32LE
|
||||
// FE FF UTF-16BE
|
||||
// FF FE UTF-16LE
|
||||
// EF BB BF UTF-8
|
||||
|
||||
const unsigned char* c = (const unsigned char *)is_->Peek4();
|
||||
if (!c)
|
||||
return;
|
||||
|
||||
unsigned bom = c[0] | (c[1] << 8) | (c[2] << 16) | (c[3] << 24);
|
||||
hasBOM_ = false;
|
||||
if (bom == 0xFFFE0000) { type_ = kUTF32BE; hasBOM_ = true; is_->Take(); is_->Take(); is_->Take(); is_->Take(); }
|
||||
else if (bom == 0x0000FEFF) { type_ = kUTF32LE; hasBOM_ = true; is_->Take(); is_->Take(); is_->Take(); is_->Take(); }
|
||||
else if ((bom & 0xFFFF) == 0xFFFE) { type_ = kUTF16BE; hasBOM_ = true; is_->Take(); is_->Take(); }
|
||||
else if ((bom & 0xFFFF) == 0xFEFF) { type_ = kUTF16LE; hasBOM_ = true; is_->Take(); is_->Take(); }
|
||||
else if ((bom & 0xFFFFFF) == 0xBFBBEF) { type_ = kUTF8; hasBOM_ = true; is_->Take(); is_->Take(); is_->Take(); }
|
||||
|
||||
// RFC 4627: Section 3
|
||||
// "Since the first two characters of a JSON text will always be ASCII
|
||||
// characters [RFC0020], it is possible to determine whether an octet
|
||||
// stream is UTF-8, UTF-16 (BE or LE), or UTF-32 (BE or LE) by looking
|
||||
// at the pattern of nulls in the first four octets."
|
||||
// 00 00 00 xx UTF-32BE
|
||||
// 00 xx 00 xx UTF-16BE
|
||||
// xx 00 00 00 UTF-32LE
|
||||
// xx 00 xx 00 UTF-16LE
|
||||
// xx xx xx xx UTF-8
|
||||
|
||||
if (!hasBOM_) {
|
||||
unsigned pattern = (c[0] ? 1 : 0) | (c[1] ? 2 : 0) | (c[2] ? 4 : 0) | (c[3] ? 8 : 0);
|
||||
switch (pattern) {
|
||||
case 0x08: type_ = kUTF32BE; break;
|
||||
case 0x0A: type_ = kUTF16BE; break;
|
||||
case 0x01: type_ = kUTF32LE; break;
|
||||
case 0x05: type_ = kUTF16LE; break;
|
||||
case 0x0F: type_ = kUTF8; break;
|
||||
default: break; // Use type defined by user.
|
||||
}
|
||||
}
|
||||
|
||||
// Runtime check whether the size of character type is sufficient. It only perform checks with assertion.
|
||||
switch (type_) {
|
||||
case kUTF8:
|
||||
// Do nothing
|
||||
break;
|
||||
case kUTF16LE:
|
||||
case kUTF16BE:
|
||||
RAPIDJSON_ASSERT(sizeof(Ch) >= 2);
|
||||
break;
|
||||
case kUTF32LE:
|
||||
case kUTF32BE:
|
||||
RAPIDJSON_ASSERT(sizeof(Ch) >= 4);
|
||||
break;
|
||||
default:
|
||||
RAPIDJSON_ASSERT(false); // Invalid type
|
||||
}
|
||||
}
|
||||
|
||||
typedef Ch (*TakeFunc)(InputByteStream& is);
|
||||
InputByteStream* is_;
|
||||
UTFType type_;
|
||||
Ch current_;
|
||||
TakeFunc takeFunc_;
|
||||
bool hasBOM_;
|
||||
};
|
||||
|
||||
//! Output stream wrapper with dynamically bound encoding and automatic encoding detection.
|
||||
/*!
|
||||
\tparam CharType Type of character for writing.
|
||||
\tparam InputByteStream type of output byte stream to be wrapped.
|
||||
*/
|
||||
template <typename CharType, typename OutputByteStream>
|
||||
class AutoUTFOutputStream {
|
||||
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
|
||||
public:
|
||||
typedef CharType Ch;
|
||||
|
||||
//! Constructor.
|
||||
/*!
|
||||
\param os output stream to be wrapped.
|
||||
\param type UTF encoding type.
|
||||
\param putBOM Whether to write BOM at the beginning of the stream.
|
||||
*/
|
||||
AutoUTFOutputStream(OutputByteStream& os, UTFType type, bool putBOM) : os_(&os), type_(type) {
|
||||
// RUntime check whether the size of character type is sufficient. It only perform checks with assertion.
|
||||
switch (type_) {
|
||||
case kUTF16LE:
|
||||
case kUTF16BE:
|
||||
RAPIDJSON_ASSERT(sizeof(Ch) >= 2);
|
||||
break;
|
||||
case kUTF32LE:
|
||||
case kUTF32BE:
|
||||
RAPIDJSON_ASSERT(sizeof(Ch) >= 4);
|
||||
break;
|
||||
case kUTF8:
|
||||
// Do nothing
|
||||
break;
|
||||
default:
|
||||
RAPIDJSON_ASSERT(false); // Invalid UTFType
|
||||
}
|
||||
|
||||
static const PutFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Put) };
|
||||
putFunc_ = f[type_];
|
||||
|
||||
if (putBOM)
|
||||
PutBOM();
|
||||
}
|
||||
|
||||
UTFType GetType() const { return type_; }
|
||||
|
||||
void Put(Ch c) { putFunc_(*os_, c); }
|
||||
void Flush() { os_->Flush(); }
|
||||
|
||||
// Not implemented
|
||||
Ch Peek() const { RAPIDJSON_ASSERT(false); }
|
||||
Ch Take() { RAPIDJSON_ASSERT(false); }
|
||||
size_t Tell() const { RAPIDJSON_ASSERT(false); return 0; }
|
||||
Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
|
||||
size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; }
|
||||
|
||||
private:
|
||||
AutoUTFOutputStream(const AutoUTFOutputStream&);
|
||||
AutoUTFOutputStream& operator=(const AutoUTFOutputStream&);
|
||||
|
||||
void PutBOM() {
|
||||
typedef void (*PutBOMFunc)(OutputByteStream&);
|
||||
static const PutBOMFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(PutBOM) };
|
||||
f[type_](*os_);
|
||||
}
|
||||
|
||||
typedef void (*PutFunc)(OutputByteStream&, Ch);
|
||||
|
||||
OutputByteStream* os_;
|
||||
UTFType type_;
|
||||
PutFunc putFunc_;
|
||||
};
|
||||
|
||||
#undef RAPIDJSON_ENCODINGS_FUNC
|
||||
|
||||
} // namespace rapidjson
|
||||
|
||||
#ifdef __GNUC__
|
||||
RAPIDJSON_DIAG_POP
|
||||
#endif
|
||||
|
||||
#endif // RAPIDJSON_FILESTREAM_H_
|
||||
610
common/rapidjson/rapidjson/encodings.h
Normal file
610
common/rapidjson/rapidjson/encodings.h
Normal file
@ -0,0 +1,610 @@
|
||||
#ifndef RAPIDJSON_ENCODINGS_H_
|
||||
#define RAPIDJSON_ENCODINGS_H_
|
||||
|
||||
#include "rapidjson.h"
|
||||
|
||||
#ifdef _MSC_VER
|
||||
RAPIDJSON_DIAG_PUSH
|
||||
RAPIDJSON_DIAG_OFF(4244) // conversion from 'type1' to 'type2', possible loss of data
|
||||
RAPIDJSON_DIAG_OFF(4702) // unreachable code
|
||||
#elif defined(__GNUC__)
|
||||
RAPIDJSON_DIAG_PUSH
|
||||
RAPIDJSON_DIAG_OFF(effc++)
|
||||
#endif
|
||||
|
||||
namespace rapidjson {
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Encoding
|
||||
|
||||
/*! \class rapidjson::Encoding
|
||||
\brief Concept for encoding of Unicode characters.
|
||||
|
||||
\code
|
||||
concept Encoding {
|
||||
typename Ch; //! Type of character. A "character" is actually a code unit in unicode's definition.
|
||||
|
||||
enum { supportUnicode = 1 }; // or 0 if not supporting unicode
|
||||
|
||||
//! \brief Encode a Unicode codepoint to an output stream.
|
||||
//! \param os Output stream.
|
||||
//! \param codepoint An unicode codepoint, ranging from 0x0 to 0x10FFFF inclusively.
|
||||
template<typename OutputStream>
|
||||
static void Encode(OutputStream& os, unsigned codepoint);
|
||||
|
||||
//! \brief Decode a Unicode codepoint from an input stream.
|
||||
//! \param is Input stream.
|
||||
//! \param codepoint Output of the unicode codepoint.
|
||||
//! \return true if a valid codepoint can be decoded from the stream.
|
||||
template <typename InputStream>
|
||||
static bool Decode(InputStream& is, unsigned* codepoint);
|
||||
|
||||
//! \brief Validate one Unicode codepoint from an encoded stream.
|
||||
//! \param is Input stream to obtain codepoint.
|
||||
//! \param os Output for copying one codepoint.
|
||||
//! \return true if it is valid.
|
||||
//! \note This function just validating and copying the codepoint without actually decode it.
|
||||
template <typename InputStream, typename OutputStream>
|
||||
static bool Validate(InputStream& is, OutputStream& os);
|
||||
|
||||
// The following functions are deal with byte streams.
|
||||
|
||||
//! Take a character from input byte stream, skip BOM if exist.
|
||||
template <typename InputByteStream>
|
||||
static CharType TakeBOM(InputByteStream& is);
|
||||
|
||||
//! Take a character from input byte stream.
|
||||
template <typename InputByteStream>
|
||||
static Ch Take(InputByteStream& is);
|
||||
|
||||
//! Put BOM to output byte stream.
|
||||
template <typename OutputByteStream>
|
||||
static void PutBOM(OutputByteStream& os);
|
||||
|
||||
//! Put a character to output byte stream.
|
||||
template <typename OutputByteStream>
|
||||
static void Put(OutputByteStream& os, Ch c);
|
||||
};
|
||||
\endcode
|
||||
*/
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// UTF8
|
||||
|
||||
//! UTF-8 encoding.
|
||||
/*! http://en.wikipedia.org/wiki/UTF-8
|
||||
http://tools.ietf.org/html/rfc3629
|
||||
\tparam CharType Code unit for storing 8-bit UTF-8 data. Default is char.
|
||||
\note implements Encoding concept
|
||||
*/
|
||||
template<typename CharType = char>
|
||||
struct UTF8 {
|
||||
typedef CharType Ch;
|
||||
|
||||
enum { supportUnicode = 1 };
|
||||
|
||||
template<typename OutputStream>
|
||||
static void Encode(OutputStream& os, unsigned codepoint) {
|
||||
if (codepoint <= 0x7F)
|
||||
os.Put(static_cast<Ch>(codepoint & 0xFF));
|
||||
else if (codepoint <= 0x7FF) {
|
||||
os.Put(static_cast<Ch>(0xC0 | ((codepoint >> 6) & 0xFF)));
|
||||
os.Put(static_cast<Ch>(0x80 | ((codepoint & 0x3F))));
|
||||
}
|
||||
else if (codepoint <= 0xFFFF) {
|
||||
os.Put(static_cast<Ch>(0xE0 | ((codepoint >> 12) & 0xFF)));
|
||||
os.Put(static_cast<Ch>(0x80 | ((codepoint >> 6) & 0x3F)));
|
||||
os.Put(static_cast<Ch>(0x80 | (codepoint & 0x3F)));
|
||||
}
|
||||
else {
|
||||
RAPIDJSON_ASSERT(codepoint <= 0x10FFFF);
|
||||
os.Put(static_cast<Ch>(0xF0 | ((codepoint >> 18) & 0xFF)));
|
||||
os.Put(static_cast<Ch>(0x80 | ((codepoint >> 12) & 0x3F)));
|
||||
os.Put(static_cast<Ch>(0x80 | ((codepoint >> 6) & 0x3F)));
|
||||
os.Put(static_cast<Ch>(0x80 | (codepoint & 0x3F)));
|
||||
}
|
||||
}
|
||||
|
||||
template <typename InputStream>
|
||||
static bool Decode(InputStream& is, unsigned* codepoint) {
|
||||
#define COPY() c = is.Take(); *codepoint = (*codepoint << 6) | ((unsigned char)c & 0x3Fu)
|
||||
#define TRANS(mask) result &= ((GetRange((unsigned char)c) & mask) != 0)
|
||||
#define TAIL() COPY(); TRANS(0x70)
|
||||
Ch c = is.Take();
|
||||
if (!(c & 0x80)) {
|
||||
*codepoint = (unsigned char)c;
|
||||
return true;
|
||||
}
|
||||
|
||||
unsigned char type = GetRange((unsigned char)c);
|
||||
*codepoint = (0xFF >> type) & (unsigned char)c;
|
||||
bool result = true;
|
||||
switch (type) {
|
||||
case 2: TAIL(); return result;
|
||||
case 3: TAIL(); TAIL(); return result;
|
||||
case 4: COPY(); TRANS(0x50); TAIL(); return result;
|
||||
case 5: COPY(); TRANS(0x10); TAIL(); TAIL(); return result;
|
||||
case 6: TAIL(); TAIL(); TAIL(); return result;
|
||||
case 10: COPY(); TRANS(0x20); TAIL(); return result;
|
||||
case 11: COPY(); TRANS(0x60); TAIL(); TAIL(); return result;
|
||||
default: return false;
|
||||
}
|
||||
#undef COPY
|
||||
#undef TRANS
|
||||
#undef TAIL
|
||||
}
|
||||
|
||||
template <typename InputStream, typename OutputStream>
|
||||
static bool Validate(InputStream& is, OutputStream& os) {
|
||||
#define COPY() os.Put(c = is.Take())
|
||||
#define TRANS(mask) result &= ((GetRange((unsigned char)c) & mask) != 0)
|
||||
#define TAIL() COPY(); TRANS(0x70)
|
||||
Ch c;
|
||||
COPY();
|
||||
if (!(c & 0x80))
|
||||
return true;
|
||||
|
||||
bool result = true;
|
||||
switch (GetRange((unsigned char)c)) {
|
||||
case 2: TAIL(); return result;
|
||||
case 3: TAIL(); TAIL(); return result;
|
||||
case 4: COPY(); TRANS(0x50); TAIL(); return result;
|
||||
case 5: COPY(); TRANS(0x10); TAIL(); TAIL(); return result;
|
||||
case 6: TAIL(); TAIL(); TAIL(); return result;
|
||||
case 10: COPY(); TRANS(0x20); TAIL(); return result;
|
||||
case 11: COPY(); TRANS(0x60); TAIL(); TAIL(); return result;
|
||||
default: return false;
|
||||
}
|
||||
#undef COPY
|
||||
#undef TRANS
|
||||
#undef TAIL
|
||||
}
|
||||
|
||||
static unsigned char GetRange(unsigned char c) {
|
||||
// Referring to DFA of http://bjoern.hoehrmann.de/utf-8/decoder/dfa/
|
||||
// With new mapping 1 -> 0x10, 7 -> 0x20, 9 -> 0x40, such that AND operation can test multiple types.
|
||||
static const unsigned char type[] = {
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,
|
||||
0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,
|
||||
0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
|
||||
0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
|
||||
8,8,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
|
||||
10,3,3,3,3,3,3,3,3,3,3,3,3,4,3,3, 11,6,6,6,5,8,8,8,8,8,8,8,8,8,8,8,
|
||||
};
|
||||
return type[c];
|
||||
}
|
||||
|
||||
template <typename InputByteStream>
|
||||
static CharType TakeBOM(InputByteStream& is) {
|
||||
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
|
||||
Ch c = Take(is);
|
||||
if ((unsigned char)c != 0xEFu) return c;
|
||||
c = is.Take();
|
||||
if ((unsigned char)c != 0xBBu) return c;
|
||||
c = is.Take();
|
||||
if ((unsigned char)c != 0xBFu) return c;
|
||||
c = is.Take();
|
||||
return c;
|
||||
}
|
||||
|
||||
template <typename InputByteStream>
|
||||
static Ch Take(InputByteStream& is) {
|
||||
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
|
||||
return is.Take();
|
||||
}
|
||||
|
||||
template <typename OutputByteStream>
|
||||
static void PutBOM(OutputByteStream& os) {
|
||||
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
|
||||
os.Put(0xEFu); os.Put(0xBBu); os.Put(0xBFu);
|
||||
}
|
||||
|
||||
template <typename OutputByteStream>
|
||||
static void Put(OutputByteStream& os, Ch c) {
|
||||
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
|
||||
os.Put(static_cast<typename OutputByteStream::Ch>(c));
|
||||
}
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// UTF16
|
||||
|
||||
//! UTF-16 encoding.
|
||||
/*! http://en.wikipedia.org/wiki/UTF-16
|
||||
http://tools.ietf.org/html/rfc2781
|
||||
\tparam CharType Type for storing 16-bit UTF-16 data. Default is wchar_t. C++11 may use char16_t instead.
|
||||
\note implements Encoding concept
|
||||
|
||||
\note For in-memory access, no need to concern endianness. The code units and code points are represented by CPU's endianness.
|
||||
For streaming, use UTF16LE and UTF16BE, which handle endianness.
|
||||
*/
|
||||
template<typename CharType = wchar_t>
|
||||
struct UTF16 {
|
||||
typedef CharType Ch;
|
||||
RAPIDJSON_STATIC_ASSERT(sizeof(Ch) >= 2);
|
||||
|
||||
enum { supportUnicode = 1 };
|
||||
|
||||
template<typename OutputStream>
|
||||
static void Encode(OutputStream& os, unsigned codepoint) {
|
||||
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 2);
|
||||
if (codepoint <= 0xFFFF) {
|
||||
RAPIDJSON_ASSERT(codepoint < 0xD800 || codepoint > 0xDFFF); // Code point itself cannot be surrogate pair
|
||||
os.Put(static_cast<typename OutputStream::Ch>(codepoint));
|
||||
}
|
||||
else {
|
||||
RAPIDJSON_ASSERT(codepoint <= 0x10FFFF);
|
||||
unsigned v = codepoint - 0x10000;
|
||||
os.Put(static_cast<typename OutputStream::Ch>((v >> 10) | 0xD800));
|
||||
os.Put((v & 0x3FF) | 0xDC00);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename InputStream>
|
||||
static bool Decode(InputStream& is, unsigned* codepoint) {
|
||||
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 2);
|
||||
Ch c = is.Take();
|
||||
if (c < 0xD800 || c > 0xDFFF) {
|
||||
*codepoint = c;
|
||||
return true;
|
||||
}
|
||||
else if (c <= 0xDBFF) {
|
||||
*codepoint = (c & 0x3FF) << 10;
|
||||
c = is.Take();
|
||||
*codepoint |= (c & 0x3FF);
|
||||
*codepoint += 0x10000;
|
||||
return c >= 0xDC00 && c <= 0xDFFF;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
template <typename InputStream, typename OutputStream>
|
||||
static bool Validate(InputStream& is, OutputStream& os) {
|
||||
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 2);
|
||||
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 2);
|
||||
Ch c;
|
||||
os.Put(c = is.Take());
|
||||
if (c < 0xD800 || c > 0xDFFF)
|
||||
return true;
|
||||
else if (c <= 0xDBFF) {
|
||||
os.Put(c = is.Take());
|
||||
return c >= 0xDC00 && c <= 0xDFFF;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
//! UTF-16 little endian encoding.
|
||||
template<typename CharType = wchar_t>
|
||||
struct UTF16LE : UTF16<CharType> {
|
||||
template <typename InputByteStream>
|
||||
static CharType TakeBOM(InputByteStream& is) {
|
||||
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
|
||||
CharType c = Take(is);
|
||||
return (unsigned short)c == 0xFEFFu ? Take(is) : c;
|
||||
}
|
||||
|
||||
template <typename InputByteStream>
|
||||
static CharType Take(InputByteStream& is) {
|
||||
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
|
||||
CharType c = (unsigned char)is.Take();
|
||||
c |= (unsigned char)is.Take() << 8;
|
||||
return c;
|
||||
}
|
||||
|
||||
template <typename OutputByteStream>
|
||||
static void PutBOM(OutputByteStream& os) {
|
||||
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
|
||||
os.Put(0xFFu); os.Put(0xFEu);
|
||||
}
|
||||
|
||||
template <typename OutputByteStream>
|
||||
static void Put(OutputByteStream& os, CharType c) {
|
||||
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
|
||||
os.Put(c & 0xFFu);
|
||||
os.Put((c >> 8) & 0xFFu);
|
||||
}
|
||||
};
|
||||
|
||||
//! UTF-16 big endian encoding.
|
||||
template<typename CharType = wchar_t>
|
||||
struct UTF16BE : UTF16<CharType> {
|
||||
template <typename InputByteStream>
|
||||
static CharType TakeBOM(InputByteStream& is) {
|
||||
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
|
||||
CharType c = Take(is);
|
||||
return (unsigned short)c == 0xFEFFu ? Take(is) : c;
|
||||
}
|
||||
|
||||
template <typename InputByteStream>
|
||||
static CharType Take(InputByteStream& is) {
|
||||
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
|
||||
CharType c = (unsigned char)is.Take() << 8;
|
||||
c |= (unsigned char)is.Take();
|
||||
return c;
|
||||
}
|
||||
|
||||
template <typename OutputByteStream>
|
||||
static void PutBOM(OutputByteStream& os) {
|
||||
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
|
||||
os.Put(0xFEu); os.Put(0xFFu);
|
||||
}
|
||||
|
||||
template <typename OutputByteStream>
|
||||
static void Put(OutputByteStream& os, CharType c) {
|
||||
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
|
||||
os.Put((c >> 8) & 0xFFu);
|
||||
os.Put(c & 0xFFu);
|
||||
}
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// UTF32
|
||||
|
||||
//! UTF-32 encoding.
|
||||
/*! http://en.wikipedia.org/wiki/UTF-32
|
||||
\tparam CharType Type for storing 32-bit UTF-32 data. Default is unsigned. C++11 may use char32_t instead.
|
||||
\note implements Encoding concept
|
||||
|
||||
\note For in-memory access, no need to concern endianness. The code units and code points are represented by CPU's endianness.
|
||||
For streaming, use UTF32LE and UTF32BE, which handle endianness.
|
||||
*/
|
||||
template<typename CharType = unsigned>
|
||||
struct UTF32 {
|
||||
typedef CharType Ch;
|
||||
RAPIDJSON_STATIC_ASSERT(sizeof(Ch) >= 4);
|
||||
|
||||
enum { supportUnicode = 1 };
|
||||
|
||||
template<typename OutputStream>
|
||||
static void Encode(OutputStream& os, unsigned codepoint) {
|
||||
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 4);
|
||||
RAPIDJSON_ASSERT(codepoint <= 0x10FFFF);
|
||||
os.Put(codepoint);
|
||||
}
|
||||
|
||||
template <typename InputStream>
|
||||
static bool Decode(InputStream& is, unsigned* codepoint) {
|
||||
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 4);
|
||||
Ch c = is.Take();
|
||||
*codepoint = c;
|
||||
return c <= 0x10FFFF;
|
||||
}
|
||||
|
||||
template <typename InputStream, typename OutputStream>
|
||||
static bool Validate(InputStream& is, OutputStream& os) {
|
||||
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 4);
|
||||
Ch c;
|
||||
os.Put(c = is.Take());
|
||||
return c <= 0x10FFFF;
|
||||
}
|
||||
};
|
||||
|
||||
//! UTF-32 little endian enocoding.
|
||||
template<typename CharType = unsigned>
|
||||
struct UTF32LE : UTF32<CharType> {
|
||||
template <typename InputByteStream>
|
||||
static CharType TakeBOM(InputByteStream& is) {
|
||||
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
|
||||
CharType c = Take(is);
|
||||
return (unsigned)c == 0x0000FEFFu ? Take(is) : c;
|
||||
}
|
||||
|
||||
template <typename InputByteStream>
|
||||
static CharType Take(InputByteStream& is) {
|
||||
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
|
||||
CharType c = (unsigned char)is.Take();
|
||||
c |= (unsigned char)is.Take() << 8;
|
||||
c |= (unsigned char)is.Take() << 16;
|
||||
c |= (unsigned char)is.Take() << 24;
|
||||
return c;
|
||||
}
|
||||
|
||||
template <typename OutputByteStream>
|
||||
static void PutBOM(OutputByteStream& os) {
|
||||
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
|
||||
os.Put(0xFFu); os.Put(0xFEu); os.Put(0x00u); os.Put(0x00u);
|
||||
}
|
||||
|
||||
template <typename OutputByteStream>
|
||||
static void Put(OutputByteStream& os, CharType c) {
|
||||
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
|
||||
os.Put(c & 0xFFu);
|
||||
os.Put((c >> 8) & 0xFFu);
|
||||
os.Put((c >> 16) & 0xFFu);
|
||||
os.Put((c >> 24) & 0xFFu);
|
||||
}
|
||||
};
|
||||
|
||||
//! UTF-32 big endian encoding.
|
||||
template<typename CharType = unsigned>
|
||||
struct UTF32BE : UTF32<CharType> {
|
||||
template <typename InputByteStream>
|
||||
static CharType TakeBOM(InputByteStream& is) {
|
||||
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
|
||||
CharType c = Take(is);
|
||||
return (unsigned)c == 0x0000FEFFu ? Take(is) : c;
|
||||
}
|
||||
|
||||
template <typename InputByteStream>
|
||||
static CharType Take(InputByteStream& is) {
|
||||
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
|
||||
CharType c = (unsigned char)is.Take() << 24;
|
||||
c |= (unsigned char)is.Take() << 16;
|
||||
c |= (unsigned char)is.Take() << 8;
|
||||
c |= (unsigned char)is.Take();
|
||||
return c;
|
||||
}
|
||||
|
||||
template <typename OutputByteStream>
|
||||
static void PutBOM(OutputByteStream& os) {
|
||||
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
|
||||
os.Put(0x00u); os.Put(0x00u); os.Put(0xFEu); os.Put(0xFFu);
|
||||
}
|
||||
|
||||
template <typename OutputByteStream>
|
||||
static void Put(OutputByteStream& os, CharType c) {
|
||||
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
|
||||
os.Put((c >> 24) & 0xFFu);
|
||||
os.Put((c >> 16) & 0xFFu);
|
||||
os.Put((c >> 8) & 0xFFu);
|
||||
os.Put(c & 0xFFu);
|
||||
}
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// ASCII
|
||||
|
||||
//! ASCII encoding.
|
||||
/*! http://en.wikipedia.org/wiki/ASCII
|
||||
\tparam CharType Code unit for storing 7-bit ASCII data. Default is char.
|
||||
\note implements Encoding concept
|
||||
*/
|
||||
template<typename CharType = char>
|
||||
struct ASCII {
|
||||
typedef CharType Ch;
|
||||
|
||||
enum { supportUnicode = 0 };
|
||||
|
||||
template<typename OutputStream>
|
||||
static void Encode(OutputStream& os, unsigned codepoint) {
|
||||
RAPIDJSON_ASSERT(codepoint <= 0x7F);
|
||||
os.Put(static_cast<Ch>(codepoint & 0xFF));
|
||||
}
|
||||
|
||||
template <typename InputStream>
|
||||
static bool Decode(InputStream& is, unsigned* codepoint) {
|
||||
unsigned char c = static_cast<unsigned char>(is.Take());
|
||||
*codepoint = c;
|
||||
return c <= 0X7F;
|
||||
}
|
||||
|
||||
template <typename InputStream, typename OutputStream>
|
||||
static bool Validate(InputStream& is, OutputStream& os) {
|
||||
unsigned char c = is.Take();
|
||||
os.Put(c);
|
||||
return c <= 0x7F;
|
||||
}
|
||||
|
||||
template <typename InputByteStream>
|
||||
static CharType TakeBOM(InputByteStream& is) {
|
||||
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
|
||||
Ch c = Take(is);
|
||||
return c;
|
||||
}
|
||||
|
||||
template <typename InputByteStream>
|
||||
static Ch Take(InputByteStream& is) {
|
||||
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
|
||||
return is.Take();
|
||||
}
|
||||
|
||||
template <typename OutputByteStream>
|
||||
static void PutBOM(OutputByteStream& os) {
|
||||
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
|
||||
(void)os;
|
||||
}
|
||||
|
||||
template <typename OutputByteStream>
|
||||
static void Put(OutputByteStream& os, Ch c) {
|
||||
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
|
||||
os.Put(static_cast<typename OutputByteStream::Ch>(c));
|
||||
}
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// AutoUTF
|
||||
|
||||
//! Runtime-specified UTF encoding type of a stream.
|
||||
enum UTFType {
|
||||
kUTF8 = 0, //!< UTF-8.
|
||||
kUTF16LE = 1, //!< UTF-16 little endian.
|
||||
kUTF16BE = 2, //!< UTF-16 big endian.
|
||||
kUTF32LE = 3, //!< UTF-32 little endian.
|
||||
kUTF32BE = 4 //!< UTF-32 big endian.
|
||||
};
|
||||
|
||||
//! Dynamically select encoding according to stream's runtime-specified UTF encoding type.
|
||||
/*! \note This class can be used with AutoUTFInputtStream and AutoUTFOutputStream, which provides GetType().
|
||||
*/
|
||||
template<typename CharType>
|
||||
struct AutoUTF {
|
||||
typedef CharType Ch;
|
||||
|
||||
enum { supportUnicode = 1 };
|
||||
|
||||
#define RAPIDJSON_ENCODINGS_FUNC(x) UTF8<Ch>::x, UTF16LE<Ch>::x, UTF16BE<Ch>::x, UTF32LE<Ch>::x, UTF32BE<Ch>::x
|
||||
|
||||
template<typename OutputStream>
|
||||
RAPIDJSON_FORCEINLINE static void Encode(OutputStream& os, unsigned codepoint) {
|
||||
typedef void (*EncodeFunc)(OutputStream&, unsigned);
|
||||
static const EncodeFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Encode) };
|
||||
(*f[os.GetType()])(os, codepoint);
|
||||
}
|
||||
|
||||
template <typename InputStream>
|
||||
RAPIDJSON_FORCEINLINE static bool Decode(InputStream& is, unsigned* codepoint) {
|
||||
typedef bool (*DecodeFunc)(InputStream&, unsigned*);
|
||||
static const DecodeFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Decode) };
|
||||
return (*f[is.GetType()])(is, codepoint);
|
||||
}
|
||||
|
||||
template <typename InputStream, typename OutputStream>
|
||||
RAPIDJSON_FORCEINLINE static bool Validate(InputStream& is, OutputStream& os) {
|
||||
typedef bool (*ValidateFunc)(InputStream&, OutputStream&);
|
||||
static const ValidateFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Validate) };
|
||||
return (*f[is.GetType()])(is, os);
|
||||
}
|
||||
|
||||
#undef RAPIDJSON_ENCODINGS_FUNC
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Transcoder
|
||||
|
||||
//! Encoding conversion.
|
||||
template<typename SourceEncoding, typename TargetEncoding>
|
||||
struct Transcoder {
|
||||
//! Take one Unicode codepoint from source encoding, convert it to target encoding and put it to the output stream.
|
||||
template<typename InputStream, typename OutputStream>
|
||||
RAPIDJSON_FORCEINLINE static bool Transcode(InputStream& is, OutputStream& os) {
|
||||
unsigned codepoint;
|
||||
if (!SourceEncoding::Decode(is, &codepoint))
|
||||
return false;
|
||||
TargetEncoding::Encode(os, codepoint);
|
||||
return true;
|
||||
}
|
||||
|
||||
//! Validate one Unicode codepoint from an encoded stream.
|
||||
template<typename InputStream, typename OutputStream>
|
||||
RAPIDJSON_FORCEINLINE static bool Validate(InputStream& is, OutputStream& os) {
|
||||
return Transcode(is, os); // Since source/target encoding is different, must transcode.
|
||||
}
|
||||
};
|
||||
|
||||
//! Specialization of Transcoder with same source and target encoding.
|
||||
template<typename Encoding>
|
||||
struct Transcoder<Encoding, Encoding> {
|
||||
template<typename InputStream, typename OutputStream>
|
||||
RAPIDJSON_FORCEINLINE static bool Transcode(InputStream& is, OutputStream& os) {
|
||||
os.Put(is.Take()); // Just copy one code unit. This semantic is different from primary template class.
|
||||
return true;
|
||||
}
|
||||
|
||||
template<typename InputStream, typename OutputStream>
|
||||
RAPIDJSON_FORCEINLINE static bool Validate(InputStream& is, OutputStream& os) {
|
||||
return Encoding::Validate(is, os); // source/target encoding are the same
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace rapidjson
|
||||
|
||||
#if defined(__GNUC__) || defined(_MSV_VER)
|
||||
RAPIDJSON_DIAG_POP
|
||||
#endif
|
||||
|
||||
#endif // RAPIDJSON_ENCODINGS_H_
|
||||
52
common/rapidjson/rapidjson/error/en.h
Normal file
52
common/rapidjson/rapidjson/error/en.h
Normal file
@ -0,0 +1,52 @@
|
||||
#ifndef RAPIDJSON_ERROR_EN_H__
|
||||
#define RAPIDJSON_ERROR_EN_H__
|
||||
|
||||
#include "error.h"
|
||||
|
||||
namespace rapidjson {
|
||||
|
||||
//! Maps error code of parsing into error message.
|
||||
/*!
|
||||
\param parseErrorCode Error code obtained in parsing.
|
||||
\return the error message.
|
||||
\note User can make a copy of this function for localization.
|
||||
Using switch-case is safer for future modification of error codes.
|
||||
*/
|
||||
inline const RAPIDJSON_ERROR_CHARTYPE* GetParseError_En(ParseErrorCode parseErrorCode) {
|
||||
switch (parseErrorCode) {
|
||||
case kParseErrorNone: return RAPIDJSON_ERROR_STRING("No error.");
|
||||
|
||||
case kParseErrorDocumentEmpty: return RAPIDJSON_ERROR_STRING("The document is empty.");
|
||||
case kParseErrorDocumentRootNotObjectOrArray: return RAPIDJSON_ERROR_STRING("The document root must be either object or array.");
|
||||
case kParseErrorDocumentRootNotSingular: return RAPIDJSON_ERROR_STRING("The document root must not follow by other values.");
|
||||
|
||||
case kParseErrorValueInvalid: return RAPIDJSON_ERROR_STRING("Invalid value.");
|
||||
|
||||
case kParseErrorObjectMissName: return RAPIDJSON_ERROR_STRING("Missing a name for object member.");
|
||||
case kParseErrorObjectMissColon: return RAPIDJSON_ERROR_STRING("Missing a colon after a name of object member.");
|
||||
case kParseErrorObjectMissCommaOrCurlyBracket: return RAPIDJSON_ERROR_STRING("Missing a comma or '}' after an object member.");
|
||||
|
||||
case kParseErrorArrayMissCommaOrSquareBracket: return RAPIDJSON_ERROR_STRING("Missing a comma or ']' after an array element.");
|
||||
|
||||
case kParseErrorStringUnicodeEscapeInvalidHex: return RAPIDJSON_ERROR_STRING("Incorrect hex digit after \\u escape in string.");
|
||||
case kParseErrorStringUnicodeSurrogateInvalid: return RAPIDJSON_ERROR_STRING("The surrogate pair in string is invalid.");
|
||||
case kParseErrorStringEscapeInvalid: return RAPIDJSON_ERROR_STRING("Invalid escape character in string.");
|
||||
case kParseErrorStringMissQuotationMark: return RAPIDJSON_ERROR_STRING("Missing a closing quotation mark in string.");
|
||||
case kParseErrorStringInvalidEncoding: return RAPIDJSON_ERROR_STRING("Invalid encoding in string.");
|
||||
|
||||
case kParseErrorNumberTooBig: return RAPIDJSON_ERROR_STRING("Number too big to be stored in double.");
|
||||
case kParseErrorNumberMissFraction: return RAPIDJSON_ERROR_STRING("Miss fraction part in number.");
|
||||
case kParseErrorNumberMissExponent: return RAPIDJSON_ERROR_STRING("Miss exponent in number.");
|
||||
|
||||
case kParseErrorTermination: return RAPIDJSON_ERROR_STRING("Terminate parsing due to Handler error.");
|
||||
case kParseErrorUnspecificSyntaxError: return RAPIDJSON_ERROR_STRING("Unspecific syntax error.");
|
||||
case kParseErrorStackSizeLimitExceeded: return RAPIDJSON_ERROR_STRING("Parsing stack size limit is exceeded.");
|
||||
|
||||
default:
|
||||
return RAPIDJSON_ERROR_STRING("Unknown error.");
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace rapidjson
|
||||
|
||||
#endif // RAPIDJSON_ERROR_EN_H__
|
||||
124
common/rapidjson/rapidjson/error/error.h
Normal file
124
common/rapidjson/rapidjson/error/error.h
Normal file
@ -0,0 +1,124 @@
|
||||
#ifndef RAPIDJSON_ERROR_ERROR_H__
|
||||
#define RAPIDJSON_ERROR_ERROR_H__
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// RAPIDJSON_ERROR_CHARTYPE
|
||||
|
||||
//! Character type of error messages.
|
||||
/*! The default charater type is char.
|
||||
On Windows, user can define this macro as TCHAR for supporting both
|
||||
unicode/non-unicode settings.
|
||||
*/
|
||||
#ifndef RAPIDJSON_ERROR_CHARTYPE
|
||||
#define RAPIDJSON_ERROR_CHARTYPE char
|
||||
#endif
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// RAPIDJSON_ERROR_STRING
|
||||
|
||||
//! Macro for converting string literial to RAPIDJSON_ERROR_CHARTYPE[].
|
||||
/*! By default this conversion macro does nothing.
|
||||
On Windows, user can define this macro as _T(x) for supporting both
|
||||
unicode/non-unicode settings.
|
||||
*/
|
||||
#ifndef RAPIDJSON_ERROR_STRING
|
||||
#define RAPIDJSON_ERROR_STRING(x) x
|
||||
#endif
|
||||
|
||||
namespace rapidjson {
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// ParseErrorCode
|
||||
|
||||
//! Error code of parsing.
|
||||
/*! \see GenericReader::Parse, GenericReader::GetParseErrorCode
|
||||
*/
|
||||
enum ParseErrorCode {
|
||||
kParseErrorNone = 0, //!< No error.
|
||||
|
||||
kParseErrorDocumentEmpty, //!< The document is empty.
|
||||
kParseErrorDocumentRootNotObjectOrArray, //!< The document root must be either object or array.
|
||||
kParseErrorDocumentRootNotSingular, //!< The document root must not follow by other values.
|
||||
|
||||
kParseErrorValueInvalid, //!< Invalid value.
|
||||
|
||||
kParseErrorObjectMissName, //!< Missing a name for object member.
|
||||
kParseErrorObjectMissColon, //!< Missing a colon after a name of object member.
|
||||
kParseErrorObjectMissCommaOrCurlyBracket, //!< Missing a comma or '}' after an object member.
|
||||
|
||||
kParseErrorArrayMissCommaOrSquareBracket, //!< Missing a comma or ']' after an array element.
|
||||
|
||||
kParseErrorStringUnicodeEscapeInvalidHex, //!< Incorrect hex digit after \\u escape in string.
|
||||
kParseErrorStringUnicodeSurrogateInvalid, //!< The surrogate pair in string is invalid.
|
||||
kParseErrorStringEscapeInvalid, //!< Invalid escape character in string.
|
||||
kParseErrorStringMissQuotationMark, //!< Missing a closing quotation mark in string.
|
||||
kParseErrorStringInvalidEncoding, //!< Invalid encoding in string.
|
||||
|
||||
kParseErrorNumberTooBig, //!< Number too big to be stored in double.
|
||||
kParseErrorNumberMissFraction, //!< Miss fraction part in number.
|
||||
kParseErrorNumberMissExponent, //!< Miss exponent in number.
|
||||
|
||||
kParseErrorTermination, //!< Parsing was terminated.
|
||||
kParseErrorUnspecificSyntaxError, //!< Unspecific syntax error.
|
||||
kParseErrorStackSizeLimitExceeded //!< Parsing stack size limit is exceeded.
|
||||
};
|
||||
|
||||
//! Result of parsing (wraps ParseErrorCode)
|
||||
/*!
|
||||
\code
|
||||
Document doc;
|
||||
ParseResult ok = doc.Parse("[42]");
|
||||
if (!ok) {
|
||||
fprintf(stderr, "JSON parse error: %s (%u)",
|
||||
GetParseError_En(ok.Code()), ok.Offset());
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
\endcode
|
||||
\see GenericReader::Parse, GenericDocument::Parse
|
||||
*/
|
||||
struct ParseResult {
|
||||
|
||||
//! Default constructor, no error.
|
||||
ParseResult() : code_(kParseErrorNone), offset_(0) {}
|
||||
//! Constructor to set an error.
|
||||
ParseResult(ParseErrorCode code, size_t offset) : code_(code), offset_(offset) {}
|
||||
|
||||
//! Get the error code.
|
||||
ParseErrorCode Code() const { return code_; }
|
||||
//! Get the error offset, if \ref IsError(), 0 otherwise.
|
||||
size_t Offset() const { return offset_; }
|
||||
|
||||
//! Conversion to \c bool, returns \c true, iff !\ref IsError().
|
||||
operator bool() const { return !IsError(); }
|
||||
//! Whether the result is an error.
|
||||
bool IsError() const { return code_ != kParseErrorNone; }
|
||||
|
||||
bool operator==(const ParseResult& that) const { return code_ == that.code_; }
|
||||
bool operator==(ParseErrorCode code) const { return code_ == code; }
|
||||
friend bool operator==(ParseErrorCode code, const ParseResult & err) { return code == err.code_; }
|
||||
|
||||
//! Reset error code.
|
||||
void Clear() { Set(kParseErrorNone); }
|
||||
//! Update error code and offset.
|
||||
void Set(ParseErrorCode code, size_t offset = 0) { code_ = code; offset_ = offset; }
|
||||
|
||||
private:
|
||||
ParseErrorCode code_;
|
||||
size_t offset_;
|
||||
};
|
||||
|
||||
//! Function pointer type of GetParseError().
|
||||
/*! This is the prototype for GetParseError_X(), where X is a locale.
|
||||
User can dynamically change locale in runtime, e.g.:
|
||||
|
||||
\code
|
||||
GetParseErrorFunc GetParseError = GetParseError_En; // or whatever
|
||||
const RAPIDJSON_ERROR_CHARTYPE* s = GetParseError(document.GetParseErrorCode());
|
||||
\endcode
|
||||
*/
|
||||
|
||||
typedef const RAPIDJSON_ERROR_CHARTYPE* (*GetParseErrorFunc)(ParseErrorCode);
|
||||
|
||||
} // namespace rapidjson
|
||||
|
||||
#endif // RAPIDJSON_ERROR_ERROR_H__
|
||||
74
common/rapidjson/rapidjson/filereadstream.h
Normal file
74
common/rapidjson/rapidjson/filereadstream.h
Normal file
@ -0,0 +1,74 @@
|
||||
#ifndef RAPIDJSON_FILEREADSTREAM_H_
|
||||
#define RAPIDJSON_FILEREADSTREAM_H_
|
||||
|
||||
#include "rapidjson.h"
|
||||
#include <cstdio>
|
||||
|
||||
namespace rapidjson {
|
||||
|
||||
//! File byte stream for input using fread().
|
||||
/*!
|
||||
\note implements Stream concept
|
||||
*/
|
||||
class FileReadStream {
|
||||
public:
|
||||
typedef char Ch; //!< Character type (byte).
|
||||
|
||||
//! Constructor.
|
||||
/*!
|
||||
\param fp File pointer opened for read.
|
||||
\param buffer user-supplied buffer.
|
||||
\param bufferSize size of buffer in bytes. Must >=4 bytes.
|
||||
*/
|
||||
FileReadStream(FILE* fp, char* buffer, size_t bufferSize) : fp_(fp), buffer_(buffer), bufferSize_(bufferSize), bufferLast_(0), current_(buffer_), readCount_(0), count_(0), eof_(false) {
|
||||
RAPIDJSON_ASSERT(fp_ != 0);
|
||||
RAPIDJSON_ASSERT(bufferSize >= 4);
|
||||
Read();
|
||||
}
|
||||
|
||||
Ch Peek() const { return *current_; }
|
||||
Ch Take() { Ch c = *current_; Read(); return c; }
|
||||
size_t Tell() const { return count_ + static_cast<size_t>(current_ - buffer_); }
|
||||
|
||||
// Not implemented
|
||||
void Put(Ch) { RAPIDJSON_ASSERT(false); }
|
||||
void Flush() { RAPIDJSON_ASSERT(false); }
|
||||
Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
|
||||
size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; }
|
||||
|
||||
// For encoding detection only.
|
||||
const Ch* Peek4() const {
|
||||
return (current_ + 4 <= bufferLast_) ? current_ : 0;
|
||||
}
|
||||
|
||||
private:
|
||||
void Read() {
|
||||
if (current_ < bufferLast_)
|
||||
++current_;
|
||||
else if (!eof_) {
|
||||
count_ += readCount_;
|
||||
readCount_ = fread(buffer_, 1, bufferSize_, fp_);
|
||||
bufferLast_ = buffer_ + readCount_ - 1;
|
||||
current_ = buffer_;
|
||||
|
||||
if (readCount_ < bufferSize_) {
|
||||
buffer_[readCount_] = '\0';
|
||||
++bufferLast_;
|
||||
eof_ = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
FILE* fp_;
|
||||
Ch *buffer_;
|
||||
size_t bufferSize_;
|
||||
Ch *bufferLast_;
|
||||
Ch *current_;
|
||||
size_t readCount_;
|
||||
size_t count_; //!< Number of characters read
|
||||
bool eof_;
|
||||
};
|
||||
|
||||
} // namespace rapidjson
|
||||
|
||||
#endif // RAPIDJSON_FILESTREAM_H_
|
||||
53
common/rapidjson/rapidjson/filestream.h
Normal file
53
common/rapidjson/rapidjson/filestream.h
Normal file
@ -0,0 +1,53 @@
|
||||
#ifndef RAPIDJSON_FILESTREAM_H_
|
||||
#define RAPIDJSON_FILESTREAM_H_
|
||||
|
||||
#include "rapidjson.h"
|
||||
#include <cstdio>
|
||||
|
||||
namespace rapidjson {
|
||||
|
||||
//! (Depreciated) Wrapper of C file stream for input or output.
|
||||
/*!
|
||||
This simple wrapper does not check the validity of the stream.
|
||||
\note implements Stream concept
|
||||
\note deprecated: This was only for basic testing in version 0.1, it is found that the performance is very low by using fgetc(). Use FileReadStream instead.
|
||||
*/
|
||||
class FileStream {
|
||||
public:
|
||||
typedef char Ch; //!< Character type. Only support char.
|
||||
|
||||
FileStream(FILE* fp) : fp_(fp), current_('\0'), count_(0) { Read(); }
|
||||
char Peek() const { return current_; }
|
||||
char Take() { char c = current_; Read(); return c; }
|
||||
size_t Tell() const { return count_; }
|
||||
void Put(char c) { fputc(c, fp_); }
|
||||
void Flush() { fflush(fp_); }
|
||||
|
||||
// Not implemented
|
||||
char* PutBegin() { return 0; }
|
||||
size_t PutEnd(char*) { return 0; }
|
||||
|
||||
private:
|
||||
// Prohibit copy constructor & assignment operator.
|
||||
FileStream(const FileStream&);
|
||||
FileStream& operator=(const FileStream&);
|
||||
|
||||
void Read() {
|
||||
RAPIDJSON_ASSERT(fp_ != 0);
|
||||
int c = fgetc(fp_);
|
||||
if (c != EOF) {
|
||||
current_ = (char)c;
|
||||
count_++;
|
||||
}
|
||||
else if (current_ != '\0')
|
||||
current_ = '\0';
|
||||
}
|
||||
|
||||
FILE* fp_;
|
||||
char current_;
|
||||
size_t count_;
|
||||
};
|
||||
|
||||
} // namespace rapidjson
|
||||
|
||||
#endif // RAPIDJSON_FILESTREAM_H_
|
||||
77
common/rapidjson/rapidjson/filewritestream.h
Normal file
77
common/rapidjson/rapidjson/filewritestream.h
Normal file
@ -0,0 +1,77 @@
|
||||
#ifndef RAPIDJSON_FILEWRITESTREAM_H_
|
||||
#define RAPIDJSON_FILEWRITESTREAM_H_
|
||||
|
||||
#include "rapidjson.h"
|
||||
#include <cstdio>
|
||||
|
||||
namespace rapidjson {
|
||||
|
||||
//! Wrapper of C file stream for input using fread().
|
||||
/*!
|
||||
\note implements Stream concept
|
||||
*/
|
||||
class FileWriteStream {
|
||||
public:
|
||||
typedef char Ch; //!< Character type. Only support char.
|
||||
|
||||
FileWriteStream(FILE* fp, char* buffer, size_t bufferSize) : fp_(fp), buffer_(buffer), bufferEnd_(buffer + bufferSize), current_(buffer_) {
|
||||
RAPIDJSON_ASSERT(fp_ != 0);
|
||||
}
|
||||
|
||||
void Put(char c) {
|
||||
if (current_ >= bufferEnd_)
|
||||
Flush();
|
||||
|
||||
*current_++ = c;
|
||||
}
|
||||
|
||||
void PutN(char c, size_t n) {
|
||||
size_t avail = static_cast<size_t>(bufferEnd_ - current_);
|
||||
while (n > avail) {
|
||||
memset(current_, c, avail);
|
||||
current_ += avail;
|
||||
Flush();
|
||||
n -= avail;
|
||||
avail = static_cast<size_t>(bufferEnd_ - current_);
|
||||
}
|
||||
|
||||
if (n > 0) {
|
||||
memset(current_, c, n);
|
||||
current_ += n;
|
||||
}
|
||||
}
|
||||
|
||||
void Flush() {
|
||||
if (current_ != buffer_) {
|
||||
fwrite(buffer_, 1, static_cast<size_t>(current_ - buffer_), fp_);
|
||||
current_ = buffer_;
|
||||
}
|
||||
}
|
||||
|
||||
// Not implemented
|
||||
char Peek() const { RAPIDJSON_ASSERT(false); return 0; }
|
||||
char Take() { RAPIDJSON_ASSERT(false); return 0; }
|
||||
size_t Tell() const { RAPIDJSON_ASSERT(false); return 0; }
|
||||
char* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
|
||||
size_t PutEnd(char*) { RAPIDJSON_ASSERT(false); return 0; }
|
||||
|
||||
private:
|
||||
// Prohibit copy constructor & assignment operator.
|
||||
FileWriteStream(const FileWriteStream&);
|
||||
FileWriteStream& operator=(const FileWriteStream&);
|
||||
|
||||
FILE* fp_;
|
||||
char *buffer_;
|
||||
char *bufferEnd_;
|
||||
char *current_;
|
||||
};
|
||||
|
||||
//! Implement specialized version of PutN() with memset() for better performance.
|
||||
template<>
|
||||
inline void PutN(FileWriteStream& stream, char c, size_t n) {
|
||||
stream.PutN(c, n);
|
||||
}
|
||||
|
||||
} // namespace rapidjson
|
||||
|
||||
#endif // RAPIDJSON_FILESTREAM_H_
|
||||
77
common/rapidjson/rapidjson/internal/meta.h
Normal file
77
common/rapidjson/rapidjson/internal/meta.h
Normal file
@ -0,0 +1,77 @@
|
||||
#ifndef RAPIDJSON_INTERNAL_META_H_
|
||||
#define RAPIDJSON_INTERNAL_META_H_
|
||||
|
||||
//@cond RAPIDJSON_INTERNAL
|
||||
namespace rapidjson {
|
||||
namespace internal {
|
||||
|
||||
template <int N> struct IntegralC { enum { Value = N }; };
|
||||
template <bool Cond> struct BoolType : IntegralC<Cond> {};
|
||||
struct TrueType : BoolType<true> {};
|
||||
struct FalseType : BoolType<false> {};
|
||||
|
||||
template <typename T> struct AddConst { typedef const T Type; };
|
||||
template <typename T> struct RemoveConst { typedef T Type; };
|
||||
template <typename T> struct RemoveConst<const T> { typedef T Type; };
|
||||
|
||||
template <bool Condition, typename T1, typename T2> struct SelectIfCond;
|
||||
template <typename T1, typename T2> struct SelectIfCond<true,T1,T2> { typedef T1 Type; };
|
||||
template <typename T1, typename T2> struct SelectIfCond<false,T1,T2> { typedef T2 Type; };
|
||||
|
||||
template <typename Condition, typename T1, typename T2>
|
||||
struct SelectIf : SelectIfCond<Condition::Value,T1,T2> {};
|
||||
|
||||
template <bool Constify, typename T>
|
||||
struct MaybeAddConst : SelectIfCond<Constify, const T, T> {};
|
||||
|
||||
template <typename T, typename U> struct IsSame : FalseType {};
|
||||
template <typename T> struct IsSame<T,T> : TrueType {};
|
||||
|
||||
template <typename T> struct IsConst : FalseType {};
|
||||
template <typename T> struct IsConst<const T> : TrueType {};
|
||||
|
||||
template <typename T> struct IsPointer : FalseType {};
|
||||
template <typename T> struct IsPointer<T*> : TrueType {};
|
||||
|
||||
template <typename CT, typename T>
|
||||
struct IsMoreConst {
|
||||
enum { Value =
|
||||
( IsSame< typename RemoveConst<CT>::Type, typename RemoveConst<T>::Type>::Value
|
||||
&& ( IsConst<CT>::Value >= IsConst<T>::Value ) )
|
||||
};
|
||||
};
|
||||
|
||||
template <bool Condition, typename T = void> struct EnableIfCond;
|
||||
template <typename T> struct EnableIfCond<true, T> { typedef T Type; };
|
||||
template <typename T> struct EnableIfCond<false, T> { /* empty */ };
|
||||
|
||||
template <bool Condition, typename T = void>
|
||||
struct DisableIfCond : EnableIfCond<!Condition, T> {};
|
||||
|
||||
template <typename Condition, typename T = void>
|
||||
struct EnableIf : EnableIfCond<Condition::Value, T> {};
|
||||
|
||||
template <typename Condition, typename T = void>
|
||||
struct DisableIf : DisableIfCond<Condition::Value, T> {};
|
||||
|
||||
// SFINAE helpers
|
||||
struct SfinaeResultTag {};
|
||||
template <typename T> struct RemoveSfinaeFptr {};
|
||||
template <typename T> struct RemoveSfinaeFptr<SfinaeResultTag&(*)(T)> { typedef T Type; };
|
||||
|
||||
#define RAPIDJSON_REMOVEFPTR_(type) \
|
||||
typename ::rapidjson::internal::RemoveSfinaeFptr \
|
||||
< ::rapidjson::internal::SfinaeResultTag&(*) type>::Type
|
||||
|
||||
#define RAPIDJSON_ENABLEIF(cond) \
|
||||
typename ::rapidjson::internal::EnableIf \
|
||||
<RAPIDJSON_REMOVEFPTR_(cond)>::Type * = NULL
|
||||
|
||||
#define RAPIDJSON_DISABLEIF_RETURN(cond,returntype) \
|
||||
typename ::rapidjson::internal::DisableIf<cond,returntype>::Type
|
||||
|
||||
} // namespace internal
|
||||
} // namespace rapidjson
|
||||
//@endcond
|
||||
|
||||
#endif // RAPIDJSON_INTERNAL_META_H_
|
||||
54
common/rapidjson/rapidjson/internal/pow10.h
Normal file
54
common/rapidjson/rapidjson/internal/pow10.h
Normal file
@ -0,0 +1,54 @@
|
||||
#ifndef RAPIDJSON_POW10_
|
||||
#define RAPIDJSON_POW10_
|
||||
|
||||
namespace rapidjson {
|
||||
namespace internal {
|
||||
|
||||
//! Computes integer powers of 10 in double (10.0^n).
|
||||
/*! This function uses lookup table for fast and accurate results.
|
||||
\param n positive/negative exponent. Must <= 308.
|
||||
\return 10.0^n
|
||||
*/
|
||||
inline double Pow10(int n) {
|
||||
static const double e[] = { // 1e-308...1e308: 617 * 8 bytes = 4936 bytes
|
||||
1e-308,1e-307,1e-306,1e-305,1e-304,1e-303,1e-302,1e-301,1e-300,
|
||||
1e-299,1e-298,1e-297,1e-296,1e-295,1e-294,1e-293,1e-292,1e-291,1e-290,1e-289,1e-288,1e-287,1e-286,1e-285,1e-284,1e-283,1e-282,1e-281,1e-280,
|
||||
1e-279,1e-278,1e-277,1e-276,1e-275,1e-274,1e-273,1e-272,1e-271,1e-270,1e-269,1e-268,1e-267,1e-266,1e-265,1e-264,1e-263,1e-262,1e-261,1e-260,
|
||||
1e-259,1e-258,1e-257,1e-256,1e-255,1e-254,1e-253,1e-252,1e-251,1e-250,1e-249,1e-248,1e-247,1e-246,1e-245,1e-244,1e-243,1e-242,1e-241,1e-240,
|
||||
1e-239,1e-238,1e-237,1e-236,1e-235,1e-234,1e-233,1e-232,1e-231,1e-230,1e-229,1e-228,1e-227,1e-226,1e-225,1e-224,1e-223,1e-222,1e-221,1e-220,
|
||||
1e-219,1e-218,1e-217,1e-216,1e-215,1e-214,1e-213,1e-212,1e-211,1e-210,1e-209,1e-208,1e-207,1e-206,1e-205,1e-204,1e-203,1e-202,1e-201,1e-200,
|
||||
1e-199,1e-198,1e-197,1e-196,1e-195,1e-194,1e-193,1e-192,1e-191,1e-190,1e-189,1e-188,1e-187,1e-186,1e-185,1e-184,1e-183,1e-182,1e-181,1e-180,
|
||||
1e-179,1e-178,1e-177,1e-176,1e-175,1e-174,1e-173,1e-172,1e-171,1e-170,1e-169,1e-168,1e-167,1e-166,1e-165,1e-164,1e-163,1e-162,1e-161,1e-160,
|
||||
1e-159,1e-158,1e-157,1e-156,1e-155,1e-154,1e-153,1e-152,1e-151,1e-150,1e-149,1e-148,1e-147,1e-146,1e-145,1e-144,1e-143,1e-142,1e-141,1e-140,
|
||||
1e-139,1e-138,1e-137,1e-136,1e-135,1e-134,1e-133,1e-132,1e-131,1e-130,1e-129,1e-128,1e-127,1e-126,1e-125,1e-124,1e-123,1e-122,1e-121,1e-120,
|
||||
1e-119,1e-118,1e-117,1e-116,1e-115,1e-114,1e-113,1e-112,1e-111,1e-110,1e-109,1e-108,1e-107,1e-106,1e-105,1e-104,1e-103,1e-102,1e-101,1e-100,
|
||||
1e-99, 1e-98, 1e-97, 1e-96, 1e-95, 1e-94, 1e-93, 1e-92, 1e-91, 1e-90, 1e-89, 1e-88, 1e-87, 1e-86, 1e-85, 1e-84, 1e-83, 1e-82, 1e-81, 1e-80,
|
||||
1e-79, 1e-78, 1e-77, 1e-76, 1e-75, 1e-74, 1e-73, 1e-72, 1e-71, 1e-70, 1e-69, 1e-68, 1e-67, 1e-66, 1e-65, 1e-64, 1e-63, 1e-62, 1e-61, 1e-60,
|
||||
1e-59, 1e-58, 1e-57, 1e-56, 1e-55, 1e-54, 1e-53, 1e-52, 1e-51, 1e-50, 1e-49, 1e-48, 1e-47, 1e-46, 1e-45, 1e-44, 1e-43, 1e-42, 1e-41, 1e-40,
|
||||
1e-39, 1e-38, 1e-37, 1e-36, 1e-35, 1e-34, 1e-33, 1e-32, 1e-31, 1e-30, 1e-29, 1e-28, 1e-27, 1e-26, 1e-25, 1e-24, 1e-23, 1e-22, 1e-21, 1e-20,
|
||||
1e-19, 1e-18, 1e-17, 1e-16, 1e-15, 1e-14, 1e-13, 1e-12, 1e-11, 1e-10, 1e-9, 1e-8, 1e-7, 1e-6, 1e-5, 1e-4, 1e-3, 1e-2, 1e-1, 1e+0,
|
||||
1e+1, 1e+2, 1e+3, 1e+4, 1e+5, 1e+6, 1e+7, 1e+8, 1e+9, 1e+10, 1e+11, 1e+12, 1e+13, 1e+14, 1e+15, 1e+16, 1e+17, 1e+18, 1e+19, 1e+20,
|
||||
1e+21, 1e+22, 1e+23, 1e+24, 1e+25, 1e+26, 1e+27, 1e+28, 1e+29, 1e+30, 1e+31, 1e+32, 1e+33, 1e+34, 1e+35, 1e+36, 1e+37, 1e+38, 1e+39, 1e+40,
|
||||
1e+41, 1e+42, 1e+43, 1e+44, 1e+45, 1e+46, 1e+47, 1e+48, 1e+49, 1e+50, 1e+51, 1e+52, 1e+53, 1e+54, 1e+55, 1e+56, 1e+57, 1e+58, 1e+59, 1e+60,
|
||||
1e+61, 1e+62, 1e+63, 1e+64, 1e+65, 1e+66, 1e+67, 1e+68, 1e+69, 1e+70, 1e+71, 1e+72, 1e+73, 1e+74, 1e+75, 1e+76, 1e+77, 1e+78, 1e+79, 1e+80,
|
||||
1e+81, 1e+82, 1e+83, 1e+84, 1e+85, 1e+86, 1e+87, 1e+88, 1e+89, 1e+90, 1e+91, 1e+92, 1e+93, 1e+94, 1e+95, 1e+96, 1e+97, 1e+98, 1e+99, 1e+100,
|
||||
1e+101,1e+102,1e+103,1e+104,1e+105,1e+106,1e+107,1e+108,1e+109,1e+110,1e+111,1e+112,1e+113,1e+114,1e+115,1e+116,1e+117,1e+118,1e+119,1e+120,
|
||||
1e+121,1e+122,1e+123,1e+124,1e+125,1e+126,1e+127,1e+128,1e+129,1e+130,1e+131,1e+132,1e+133,1e+134,1e+135,1e+136,1e+137,1e+138,1e+139,1e+140,
|
||||
1e+141,1e+142,1e+143,1e+144,1e+145,1e+146,1e+147,1e+148,1e+149,1e+150,1e+151,1e+152,1e+153,1e+154,1e+155,1e+156,1e+157,1e+158,1e+159,1e+160,
|
||||
1e+161,1e+162,1e+163,1e+164,1e+165,1e+166,1e+167,1e+168,1e+169,1e+170,1e+171,1e+172,1e+173,1e+174,1e+175,1e+176,1e+177,1e+178,1e+179,1e+180,
|
||||
1e+181,1e+182,1e+183,1e+184,1e+185,1e+186,1e+187,1e+188,1e+189,1e+190,1e+191,1e+192,1e+193,1e+194,1e+195,1e+196,1e+197,1e+198,1e+199,1e+200,
|
||||
1e+201,1e+202,1e+203,1e+204,1e+205,1e+206,1e+207,1e+208,1e+209,1e+210,1e+211,1e+212,1e+213,1e+214,1e+215,1e+216,1e+217,1e+218,1e+219,1e+220,
|
||||
1e+221,1e+222,1e+223,1e+224,1e+225,1e+226,1e+227,1e+228,1e+229,1e+230,1e+231,1e+232,1e+233,1e+234,1e+235,1e+236,1e+237,1e+238,1e+239,1e+240,
|
||||
1e+241,1e+242,1e+243,1e+244,1e+245,1e+246,1e+247,1e+248,1e+249,1e+250,1e+251,1e+252,1e+253,1e+254,1e+255,1e+256,1e+257,1e+258,1e+259,1e+260,
|
||||
1e+261,1e+262,1e+263,1e+264,1e+265,1e+266,1e+267,1e+268,1e+269,1e+270,1e+271,1e+272,1e+273,1e+274,1e+275,1e+276,1e+277,1e+278,1e+279,1e+280,
|
||||
1e+281,1e+282,1e+283,1e+284,1e+285,1e+286,1e+287,1e+288,1e+289,1e+290,1e+291,1e+292,1e+293,1e+294,1e+295,1e+296,1e+297,1e+298,1e+299,1e+300,
|
||||
1e+301,1e+302,1e+303,1e+304,1e+305,1e+306,1e+307,1e+308
|
||||
};
|
||||
RAPIDJSON_ASSERT(n <= 308);
|
||||
return n < -308 ? 0.0 : e[n + 308];
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace rapidjson
|
||||
|
||||
#endif // RAPIDJSON_POW10_
|
||||
87
common/rapidjson/rapidjson/internal/stack.h
Normal file
87
common/rapidjson/rapidjson/internal/stack.h
Normal file
@ -0,0 +1,87 @@
|
||||
#ifndef RAPIDJSON_INTERNAL_STACK_H_
|
||||
#define RAPIDJSON_INTERNAL_STACK_H_
|
||||
|
||||
namespace rapidjson {
|
||||
namespace internal {
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Stack
|
||||
|
||||
//! A type-unsafe stack for storing different types of data.
|
||||
/*! \tparam Allocator Allocator for allocating stack memory.
|
||||
*/
|
||||
template <typename Allocator>
|
||||
class Stack {
|
||||
public:
|
||||
Stack(Allocator* allocator, size_t stack_capacity) : allocator_(allocator), own_allocator_(0), stack_(0), stack_top_(0), stack_end_(0), stack_capacity_(stack_capacity) {
|
||||
RAPIDJSON_ASSERT(stack_capacity_ > 0);
|
||||
if (!allocator_)
|
||||
own_allocator_ = allocator_ = new Allocator();
|
||||
stack_top_ = stack_ = (char*)allocator_->Malloc(stack_capacity_);
|
||||
stack_end_ = stack_ + stack_capacity_;
|
||||
}
|
||||
|
||||
~Stack() {
|
||||
Allocator::Free(stack_);
|
||||
delete own_allocator_; // Only delete if it is owned by the stack
|
||||
}
|
||||
|
||||
void Clear() { /*stack_top_ = 0;*/ stack_top_ = stack_; }
|
||||
|
||||
template<typename T>
|
||||
T* Push(size_t count = 1) {
|
||||
// Expand the stack if needed
|
||||
if (stack_top_ + sizeof(T) * count >= stack_end_) {
|
||||
size_t new_capacity = stack_capacity_ * 2;
|
||||
size_t size = GetSize();
|
||||
size_t new_size = GetSize() + sizeof(T) * count;
|
||||
if (new_capacity < new_size)
|
||||
new_capacity = new_size;
|
||||
stack_ = (char*)allocator_->Realloc(stack_, stack_capacity_, new_capacity);
|
||||
stack_capacity_ = new_capacity;
|
||||
stack_top_ = stack_ + size;
|
||||
stack_end_ = stack_ + stack_capacity_;
|
||||
}
|
||||
T* ret = reinterpret_cast<T*>(stack_top_);
|
||||
stack_top_ += sizeof(T) * count;
|
||||
return ret;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T* Pop(size_t count) {
|
||||
RAPIDJSON_ASSERT(GetSize() >= count * sizeof(T));
|
||||
stack_top_ -= count * sizeof(T);
|
||||
return reinterpret_cast<T*>(stack_top_);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T* Top() {
|
||||
RAPIDJSON_ASSERT(GetSize() >= sizeof(T));
|
||||
return reinterpret_cast<T*>(stack_top_ - sizeof(T));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T* Bottom() { return (T*)stack_; }
|
||||
|
||||
Allocator& GetAllocator() { return *allocator_; }
|
||||
bool Empty() const { return stack_top_ == stack_; }
|
||||
size_t GetSize() const { return static_cast<size_t>(stack_top_ - stack_); }
|
||||
size_t GetCapacity() const { return stack_capacity_; }
|
||||
|
||||
private:
|
||||
// Prohibit copy constructor & assignment operator.
|
||||
Stack(const Stack&);
|
||||
Stack& operator=(const Stack&);
|
||||
|
||||
Allocator* allocator_;
|
||||
Allocator* own_allocator_;
|
||||
char *stack_;
|
||||
char *stack_top_;
|
||||
char *stack_end_;
|
||||
size_t stack_capacity_;
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
} // namespace rapidjson
|
||||
|
||||
#endif // RAPIDJSON_STACK_H_
|
||||
23
common/rapidjson/rapidjson/internal/strfunc.h
Normal file
23
common/rapidjson/rapidjson/internal/strfunc.h
Normal file
@ -0,0 +1,23 @@
|
||||
#ifndef RAPIDJSON_INTERNAL_STRFUNC_H_
|
||||
#define RAPIDJSON_INTERNAL_STRFUNC_H_
|
||||
|
||||
namespace rapidjson {
|
||||
namespace internal {
|
||||
|
||||
//! Custom strlen() which works on different character types.
|
||||
/*! \tparam Ch Character type (e.g. char, wchar_t, short)
|
||||
\param s Null-terminated input string.
|
||||
\return Number of characters in the string.
|
||||
\note This has the same semantics as strlen(), the return value is not number of Unicode codepoints.
|
||||
*/
|
||||
template <typename Ch>
|
||||
inline SizeType StrLen(const Ch* s) {
|
||||
const Ch* p = s;
|
||||
while (*p) ++p;
|
||||
return SizeType(p - s);
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace rapidjson
|
||||
|
||||
#endif // RAPIDJSON_INTERNAL_STRFUNC_H_
|
||||
306
common/rapidjson/rapidjson/msinttypes/inttypes.h
Normal file
306
common/rapidjson/rapidjson/msinttypes/inttypes.h
Normal file
@ -0,0 +1,306 @@
|
||||
// ISO C9x compliant inttypes.h for Microsoft Visual Studio
|
||||
// Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124
|
||||
//
|
||||
// Copyright (c) 2006-2013 Alexander Chemeris
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
//
|
||||
// 3. Neither the name of the product nor the names of its contributors may
|
||||
// be used to endorse or promote products derived from this software
|
||||
// without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
||||
// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||
// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef _MSC_VER // [
|
||||
#error "Use this header only with Microsoft Visual C++ compilers!"
|
||||
#endif // _MSC_VER ]
|
||||
|
||||
#ifndef _MSC_INTTYPES_H_ // [
|
||||
#define _MSC_INTTYPES_H_
|
||||
|
||||
#if _MSC_VER > 1000
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include "stdint.h"
|
||||
|
||||
// 7.8 Format conversion of integer types
|
||||
|
||||
typedef struct {
|
||||
intmax_t quot;
|
||||
intmax_t rem;
|
||||
} imaxdiv_t;
|
||||
|
||||
// 7.8.1 Macros for format specifiers
|
||||
|
||||
#if !defined(__cplusplus) || defined(__STDC_FORMAT_MACROS) // [ See footnote 185 at page 198
|
||||
|
||||
// The fprintf macros for signed integers are:
|
||||
#define PRId8 "d"
|
||||
#define PRIi8 "i"
|
||||
#define PRIdLEAST8 "d"
|
||||
#define PRIiLEAST8 "i"
|
||||
#define PRIdFAST8 "d"
|
||||
#define PRIiFAST8 "i"
|
||||
|
||||
#define PRId16 "hd"
|
||||
#define PRIi16 "hi"
|
||||
#define PRIdLEAST16 "hd"
|
||||
#define PRIiLEAST16 "hi"
|
||||
#define PRIdFAST16 "hd"
|
||||
#define PRIiFAST16 "hi"
|
||||
|
||||
#define PRId32 "I32d"
|
||||
#define PRIi32 "I32i"
|
||||
#define PRIdLEAST32 "I32d"
|
||||
#define PRIiLEAST32 "I32i"
|
||||
#define PRIdFAST32 "I32d"
|
||||
#define PRIiFAST32 "I32i"
|
||||
|
||||
#define PRId64 "I64d"
|
||||
#define PRIi64 "I64i"
|
||||
#define PRIdLEAST64 "I64d"
|
||||
#define PRIiLEAST64 "I64i"
|
||||
#define PRIdFAST64 "I64d"
|
||||
#define PRIiFAST64 "I64i"
|
||||
|
||||
#define PRIdMAX "I64d"
|
||||
#define PRIiMAX "I64i"
|
||||
|
||||
#define PRIdPTR "Id"
|
||||
#define PRIiPTR "Ii"
|
||||
|
||||
// The fprintf macros for unsigned integers are:
|
||||
#define PRIo8 "o"
|
||||
#define PRIu8 "u"
|
||||
#define PRIx8 "x"
|
||||
#define PRIX8 "X"
|
||||
#define PRIoLEAST8 "o"
|
||||
#define PRIuLEAST8 "u"
|
||||
#define PRIxLEAST8 "x"
|
||||
#define PRIXLEAST8 "X"
|
||||
#define PRIoFAST8 "o"
|
||||
#define PRIuFAST8 "u"
|
||||
#define PRIxFAST8 "x"
|
||||
#define PRIXFAST8 "X"
|
||||
|
||||
#define PRIo16 "ho"
|
||||
#define PRIu16 "hu"
|
||||
#define PRIx16 "hx"
|
||||
#define PRIX16 "hX"
|
||||
#define PRIoLEAST16 "ho"
|
||||
#define PRIuLEAST16 "hu"
|
||||
#define PRIxLEAST16 "hx"
|
||||
#define PRIXLEAST16 "hX"
|
||||
#define PRIoFAST16 "ho"
|
||||
#define PRIuFAST16 "hu"
|
||||
#define PRIxFAST16 "hx"
|
||||
#define PRIXFAST16 "hX"
|
||||
|
||||
#define PRIo32 "I32o"
|
||||
#define PRIu32 "I32u"
|
||||
#define PRIx32 "I32x"
|
||||
#define PRIX32 "I32X"
|
||||
#define PRIoLEAST32 "I32o"
|
||||
#define PRIuLEAST32 "I32u"
|
||||
#define PRIxLEAST32 "I32x"
|
||||
#define PRIXLEAST32 "I32X"
|
||||
#define PRIoFAST32 "I32o"
|
||||
#define PRIuFAST32 "I32u"
|
||||
#define PRIxFAST32 "I32x"
|
||||
#define PRIXFAST32 "I32X"
|
||||
|
||||
#define PRIo64 "I64o"
|
||||
#define PRIu64 "I64u"
|
||||
#define PRIx64 "I64x"
|
||||
#define PRIX64 "I64X"
|
||||
#define PRIoLEAST64 "I64o"
|
||||
#define PRIuLEAST64 "I64u"
|
||||
#define PRIxLEAST64 "I64x"
|
||||
#define PRIXLEAST64 "I64X"
|
||||
#define PRIoFAST64 "I64o"
|
||||
#define PRIuFAST64 "I64u"
|
||||
#define PRIxFAST64 "I64x"
|
||||
#define PRIXFAST64 "I64X"
|
||||
|
||||
#define PRIoMAX "I64o"
|
||||
#define PRIuMAX "I64u"
|
||||
#define PRIxMAX "I64x"
|
||||
#define PRIXMAX "I64X"
|
||||
|
||||
#define PRIoPTR "Io"
|
||||
#define PRIuPTR "Iu"
|
||||
#define PRIxPTR "Ix"
|
||||
#define PRIXPTR "IX"
|
||||
|
||||
// The fscanf macros for signed integers are:
|
||||
#define SCNd8 "d"
|
||||
#define SCNi8 "i"
|
||||
#define SCNdLEAST8 "d"
|
||||
#define SCNiLEAST8 "i"
|
||||
#define SCNdFAST8 "d"
|
||||
#define SCNiFAST8 "i"
|
||||
|
||||
#define SCNd16 "hd"
|
||||
#define SCNi16 "hi"
|
||||
#define SCNdLEAST16 "hd"
|
||||
#define SCNiLEAST16 "hi"
|
||||
#define SCNdFAST16 "hd"
|
||||
#define SCNiFAST16 "hi"
|
||||
|
||||
#define SCNd32 "ld"
|
||||
#define SCNi32 "li"
|
||||
#define SCNdLEAST32 "ld"
|
||||
#define SCNiLEAST32 "li"
|
||||
#define SCNdFAST32 "ld"
|
||||
#define SCNiFAST32 "li"
|
||||
|
||||
#define SCNd64 "I64d"
|
||||
#define SCNi64 "I64i"
|
||||
#define SCNdLEAST64 "I64d"
|
||||
#define SCNiLEAST64 "I64i"
|
||||
#define SCNdFAST64 "I64d"
|
||||
#define SCNiFAST64 "I64i"
|
||||
|
||||
#define SCNdMAX "I64d"
|
||||
#define SCNiMAX "I64i"
|
||||
|
||||
#ifdef _WIN64 // [
|
||||
# define SCNdPTR "I64d"
|
||||
# define SCNiPTR "I64i"
|
||||
#else // _WIN64 ][
|
||||
# define SCNdPTR "ld"
|
||||
# define SCNiPTR "li"
|
||||
#endif // _WIN64 ]
|
||||
|
||||
// The fscanf macros for unsigned integers are:
|
||||
#define SCNo8 "o"
|
||||
#define SCNu8 "u"
|
||||
#define SCNx8 "x"
|
||||
#define SCNX8 "X"
|
||||
#define SCNoLEAST8 "o"
|
||||
#define SCNuLEAST8 "u"
|
||||
#define SCNxLEAST8 "x"
|
||||
#define SCNXLEAST8 "X"
|
||||
#define SCNoFAST8 "o"
|
||||
#define SCNuFAST8 "u"
|
||||
#define SCNxFAST8 "x"
|
||||
#define SCNXFAST8 "X"
|
||||
|
||||
#define SCNo16 "ho"
|
||||
#define SCNu16 "hu"
|
||||
#define SCNx16 "hx"
|
||||
#define SCNX16 "hX"
|
||||
#define SCNoLEAST16 "ho"
|
||||
#define SCNuLEAST16 "hu"
|
||||
#define SCNxLEAST16 "hx"
|
||||
#define SCNXLEAST16 "hX"
|
||||
#define SCNoFAST16 "ho"
|
||||
#define SCNuFAST16 "hu"
|
||||
#define SCNxFAST16 "hx"
|
||||
#define SCNXFAST16 "hX"
|
||||
|
||||
#define SCNo32 "lo"
|
||||
#define SCNu32 "lu"
|
||||
#define SCNx32 "lx"
|
||||
#define SCNX32 "lX"
|
||||
#define SCNoLEAST32 "lo"
|
||||
#define SCNuLEAST32 "lu"
|
||||
#define SCNxLEAST32 "lx"
|
||||
#define SCNXLEAST32 "lX"
|
||||
#define SCNoFAST32 "lo"
|
||||
#define SCNuFAST32 "lu"
|
||||
#define SCNxFAST32 "lx"
|
||||
#define SCNXFAST32 "lX"
|
||||
|
||||
#define SCNo64 "I64o"
|
||||
#define SCNu64 "I64u"
|
||||
#define SCNx64 "I64x"
|
||||
#define SCNX64 "I64X"
|
||||
#define SCNoLEAST64 "I64o"
|
||||
#define SCNuLEAST64 "I64u"
|
||||
#define SCNxLEAST64 "I64x"
|
||||
#define SCNXLEAST64 "I64X"
|
||||
#define SCNoFAST64 "I64o"
|
||||
#define SCNuFAST64 "I64u"
|
||||
#define SCNxFAST64 "I64x"
|
||||
#define SCNXFAST64 "I64X"
|
||||
|
||||
#define SCNoMAX "I64o"
|
||||
#define SCNuMAX "I64u"
|
||||
#define SCNxMAX "I64x"
|
||||
#define SCNXMAX "I64X"
|
||||
|
||||
#ifdef _WIN64 // [
|
||||
# define SCNoPTR "I64o"
|
||||
# define SCNuPTR "I64u"
|
||||
# define SCNxPTR "I64x"
|
||||
# define SCNXPTR "I64X"
|
||||
#else // _WIN64 ][
|
||||
# define SCNoPTR "lo"
|
||||
# define SCNuPTR "lu"
|
||||
# define SCNxPTR "lx"
|
||||
# define SCNXPTR "lX"
|
||||
#endif // _WIN64 ]
|
||||
|
||||
#endif // __STDC_FORMAT_MACROS ]
|
||||
|
||||
// 7.8.2 Functions for greatest-width integer types
|
||||
|
||||
// 7.8.2.1 The imaxabs function
|
||||
#define imaxabs _abs64
|
||||
|
||||
// 7.8.2.2 The imaxdiv function
|
||||
|
||||
// This is modified version of div() function from Microsoft's div.c found
|
||||
// in %MSVC.NET%\crt\src\div.c
|
||||
#ifdef STATIC_IMAXDIV // [
|
||||
static
|
||||
#else // STATIC_IMAXDIV ][
|
||||
_inline
|
||||
#endif // STATIC_IMAXDIV ]
|
||||
imaxdiv_t __cdecl imaxdiv(intmax_t numer, intmax_t denom)
|
||||
{
|
||||
imaxdiv_t result;
|
||||
|
||||
result.quot = numer / denom;
|
||||
result.rem = numer % denom;
|
||||
|
||||
if (numer < 0 && result.rem > 0) {
|
||||
// did division wrong; must fix up
|
||||
++result.quot;
|
||||
result.rem -= denom;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// 7.8.2.3 The strtoimax and strtoumax functions
|
||||
#define strtoimax _strtoi64
|
||||
#define strtoumax _strtoui64
|
||||
|
||||
// 7.8.2.4 The wcstoimax and wcstoumax functions
|
||||
#define wcstoimax _wcstoi64
|
||||
#define wcstoumax _wcstoui64
|
||||
|
||||
|
||||
#endif // _MSC_INTTYPES_H_ ]
|
||||
260
common/rapidjson/rapidjson/msinttypes/stdint.h
Normal file
260
common/rapidjson/rapidjson/msinttypes/stdint.h
Normal file
@ -0,0 +1,260 @@
|
||||
// ISO C9x compliant stdint.h for Microsoft Visual Studio
|
||||
// Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124
|
||||
//
|
||||
// Copyright (c) 2006-2013 Alexander Chemeris
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
//
|
||||
// 3. Neither the name of the product nor the names of its contributors may
|
||||
// be used to endorse or promote products derived from this software
|
||||
// without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
||||
// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||
// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef _MSC_VER // [
|
||||
#error "Use this header only with Microsoft Visual C++ compilers!"
|
||||
#endif // _MSC_VER ]
|
||||
|
||||
#ifndef _MSC_STDINT_H_ // [
|
||||
#define _MSC_STDINT_H_
|
||||
|
||||
#if _MSC_VER > 1000
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
// miloyip: Originally Visual Studio 2010 uses its own stdint.h. However it generates warning with INT64_C(), so change to use this file for vs2010.
|
||||
#if _MSC_VER >= 1700 // [
|
||||
#include <stdint.h>
|
||||
#else // ] _MSC_VER >= 1700 [
|
||||
|
||||
#include <limits.h>
|
||||
|
||||
// For Visual Studio 6 in C++ mode and for many Visual Studio versions when
|
||||
// compiling for ARM we should wrap <wchar.h> include with 'extern "C++" {}'
|
||||
// or compiler give many errors like this:
|
||||
// error C2733: second C linkage of overloaded function 'wmemchr' not allowed
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
# include <wchar.h>
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
// Define _W64 macros to mark types changing their size, like intptr_t.
|
||||
#ifndef _W64
|
||||
# if !defined(__midl) && (defined(_X86_) || defined(_M_IX86)) && _MSC_VER >= 1300
|
||||
# define _W64 __w64
|
||||
# else
|
||||
# define _W64
|
||||
# endif
|
||||
#endif
|
||||
|
||||
|
||||
// 7.18.1 Integer types
|
||||
|
||||
// 7.18.1.1 Exact-width integer types
|
||||
|
||||
// Visual Studio 6 and Embedded Visual C++ 4 doesn't
|
||||
// realize that, e.g. char has the same size as __int8
|
||||
// so we give up on __intX for them.
|
||||
#if (_MSC_VER < 1300)
|
||||
typedef signed char int8_t;
|
||||
typedef signed short int16_t;
|
||||
typedef signed int int32_t;
|
||||
typedef unsigned char uint8_t;
|
||||
typedef unsigned short uint16_t;
|
||||
typedef unsigned int uint32_t;
|
||||
#else
|
||||
typedef signed __int8 int8_t;
|
||||
typedef signed __int16 int16_t;
|
||||
typedef signed __int32 int32_t;
|
||||
typedef unsigned __int8 uint8_t;
|
||||
typedef unsigned __int16 uint16_t;
|
||||
typedef unsigned __int32 uint32_t;
|
||||
#endif
|
||||
typedef signed __int64 int64_t;
|
||||
typedef unsigned __int64 uint64_t;
|
||||
|
||||
|
||||
// 7.18.1.2 Minimum-width integer types
|
||||
typedef int8_t int_least8_t;
|
||||
typedef int16_t int_least16_t;
|
||||
typedef int32_t int_least32_t;
|
||||
typedef int64_t int_least64_t;
|
||||
typedef uint8_t uint_least8_t;
|
||||
typedef uint16_t uint_least16_t;
|
||||
typedef uint32_t uint_least32_t;
|
||||
typedef uint64_t uint_least64_t;
|
||||
|
||||
// 7.18.1.3 Fastest minimum-width integer types
|
||||
typedef int8_t int_fast8_t;
|
||||
typedef int16_t int_fast16_t;
|
||||
typedef int32_t int_fast32_t;
|
||||
typedef int64_t int_fast64_t;
|
||||
typedef uint8_t uint_fast8_t;
|
||||
typedef uint16_t uint_fast16_t;
|
||||
typedef uint32_t uint_fast32_t;
|
||||
typedef uint64_t uint_fast64_t;
|
||||
|
||||
// 7.18.1.4 Integer types capable of holding object pointers
|
||||
#ifdef _WIN64 // [
|
||||
typedef signed __int64 intptr_t;
|
||||
typedef unsigned __int64 uintptr_t;
|
||||
#else // _WIN64 ][
|
||||
typedef _W64 signed int intptr_t;
|
||||
typedef _W64 unsigned int uintptr_t;
|
||||
#endif // _WIN64 ]
|
||||
|
||||
// 7.18.1.5 Greatest-width integer types
|
||||
typedef int64_t intmax_t;
|
||||
typedef uint64_t uintmax_t;
|
||||
|
||||
|
||||
// 7.18.2 Limits of specified-width integer types
|
||||
|
||||
#if !defined(__cplusplus) || defined(__STDC_LIMIT_MACROS) // [ See footnote 220 at page 257 and footnote 221 at page 259
|
||||
|
||||
// 7.18.2.1 Limits of exact-width integer types
|
||||
#define INT8_MIN ((int8_t)_I8_MIN)
|
||||
#define INT8_MAX _I8_MAX
|
||||
#define INT16_MIN ((int16_t)_I16_MIN)
|
||||
#define INT16_MAX _I16_MAX
|
||||
#define INT32_MIN ((int32_t)_I32_MIN)
|
||||
#define INT32_MAX _I32_MAX
|
||||
#define INT64_MIN ((int64_t)_I64_MIN)
|
||||
#define INT64_MAX _I64_MAX
|
||||
#define UINT8_MAX _UI8_MAX
|
||||
#define UINT16_MAX _UI16_MAX
|
||||
#define UINT32_MAX _UI32_MAX
|
||||
#define UINT64_MAX _UI64_MAX
|
||||
|
||||
// 7.18.2.2 Limits of minimum-width integer types
|
||||
#define INT_LEAST8_MIN INT8_MIN
|
||||
#define INT_LEAST8_MAX INT8_MAX
|
||||
#define INT_LEAST16_MIN INT16_MIN
|
||||
#define INT_LEAST16_MAX INT16_MAX
|
||||
#define INT_LEAST32_MIN INT32_MIN
|
||||
#define INT_LEAST32_MAX INT32_MAX
|
||||
#define INT_LEAST64_MIN INT64_MIN
|
||||
#define INT_LEAST64_MAX INT64_MAX
|
||||
#define UINT_LEAST8_MAX UINT8_MAX
|
||||
#define UINT_LEAST16_MAX UINT16_MAX
|
||||
#define UINT_LEAST32_MAX UINT32_MAX
|
||||
#define UINT_LEAST64_MAX UINT64_MAX
|
||||
|
||||
// 7.18.2.3 Limits of fastest minimum-width integer types
|
||||
#define INT_FAST8_MIN INT8_MIN
|
||||
#define INT_FAST8_MAX INT8_MAX
|
||||
#define INT_FAST16_MIN INT16_MIN
|
||||
#define INT_FAST16_MAX INT16_MAX
|
||||
#define INT_FAST32_MIN INT32_MIN
|
||||
#define INT_FAST32_MAX INT32_MAX
|
||||
#define INT_FAST64_MIN INT64_MIN
|
||||
#define INT_FAST64_MAX INT64_MAX
|
||||
#define UINT_FAST8_MAX UINT8_MAX
|
||||
#define UINT_FAST16_MAX UINT16_MAX
|
||||
#define UINT_FAST32_MAX UINT32_MAX
|
||||
#define UINT_FAST64_MAX UINT64_MAX
|
||||
|
||||
// 7.18.2.4 Limits of integer types capable of holding object pointers
|
||||
#ifdef _WIN64 // [
|
||||
# define INTPTR_MIN INT64_MIN
|
||||
# define INTPTR_MAX INT64_MAX
|
||||
# define UINTPTR_MAX UINT64_MAX
|
||||
#else // _WIN64 ][
|
||||
# define INTPTR_MIN INT32_MIN
|
||||
# define INTPTR_MAX INT32_MAX
|
||||
# define UINTPTR_MAX UINT32_MAX
|
||||
#endif // _WIN64 ]
|
||||
|
||||
// 7.18.2.5 Limits of greatest-width integer types
|
||||
#define INTMAX_MIN INT64_MIN
|
||||
#define INTMAX_MAX INT64_MAX
|
||||
#define UINTMAX_MAX UINT64_MAX
|
||||
|
||||
// 7.18.3 Limits of other integer types
|
||||
|
||||
#ifdef _WIN64 // [
|
||||
# define PTRDIFF_MIN _I64_MIN
|
||||
# define PTRDIFF_MAX _I64_MAX
|
||||
#else // _WIN64 ][
|
||||
# define PTRDIFF_MIN _I32_MIN
|
||||
# define PTRDIFF_MAX _I32_MAX
|
||||
#endif // _WIN64 ]
|
||||
|
||||
#define SIG_ATOMIC_MIN INT_MIN
|
||||
#define SIG_ATOMIC_MAX INT_MAX
|
||||
|
||||
#ifndef SIZE_MAX // [
|
||||
# ifdef _WIN64 // [
|
||||
# define SIZE_MAX _UI64_MAX
|
||||
# else // _WIN64 ][
|
||||
# define SIZE_MAX _UI32_MAX
|
||||
# endif // _WIN64 ]
|
||||
#endif // SIZE_MAX ]
|
||||
|
||||
// WCHAR_MIN and WCHAR_MAX are also defined in <wchar.h>
|
||||
#ifndef WCHAR_MIN // [
|
||||
# define WCHAR_MIN 0
|
||||
#endif // WCHAR_MIN ]
|
||||
#ifndef WCHAR_MAX // [
|
||||
# define WCHAR_MAX _UI16_MAX
|
||||
#endif // WCHAR_MAX ]
|
||||
|
||||
#define WINT_MIN 0
|
||||
#define WINT_MAX _UI16_MAX
|
||||
|
||||
#endif // __STDC_LIMIT_MACROS ]
|
||||
|
||||
|
||||
// 7.18.4 Limits of other integer types
|
||||
|
||||
#if !defined(__cplusplus) || defined(__STDC_CONSTANT_MACROS) // [ See footnote 224 at page 260
|
||||
|
||||
// 7.18.4.1 Macros for minimum-width integer constants
|
||||
|
||||
#define INT8_C(val) val##i8
|
||||
#define INT16_C(val) val##i16
|
||||
#define INT32_C(val) val##i32
|
||||
#define INT64_C(val) val##i64
|
||||
|
||||
#define UINT8_C(val) val##ui8
|
||||
#define UINT16_C(val) val##ui16
|
||||
#define UINT32_C(val) val##ui32
|
||||
#define UINT64_C(val) val##ui64
|
||||
|
||||
// 7.18.4.2 Macros for greatest-width integer constants
|
||||
// These #ifndef's are needed to prevent collisions with <boost/cstdint.hpp>.
|
||||
// Check out Issue 9 for the details.
|
||||
#ifndef INTMAX_C // [
|
||||
# define INTMAX_C INT64_C
|
||||
#endif // INTMAX_C ]
|
||||
#ifndef UINTMAX_C // [
|
||||
# define UINTMAX_C UINT64_C
|
||||
#endif // UINTMAX_C ]
|
||||
|
||||
#endif // __STDC_CONSTANT_MACROS ]
|
||||
|
||||
#endif // _MSC_VER >= 1600 ]
|
||||
|
||||
#endif // _MSC_STDINT_H_ ]
|
||||
195
common/rapidjson/rapidjson/prettywriter.h
Normal file
195
common/rapidjson/rapidjson/prettywriter.h
Normal file
@ -0,0 +1,195 @@
|
||||
#ifndef RAPIDJSON_PRETTYWRITER_H_
|
||||
#define RAPIDJSON_PRETTYWRITER_H_
|
||||
|
||||
#include "writer.h"
|
||||
|
||||
#ifdef __GNUC__
|
||||
RAPIDJSON_DIAG_PUSH
|
||||
RAPIDJSON_DIAG_OFF(effc++)
|
||||
#endif
|
||||
|
||||
namespace rapidjson {
|
||||
|
||||
//! Writer with indentation and spacing.
|
||||
/*!
|
||||
\tparam OutputStream Type of ouptut os.
|
||||
\tparam SourceEncoding Encoding of source string.
|
||||
\tparam TargetEncoding Encoding of output stream.
|
||||
\tparam Allocator Type of allocator for allocating memory of stack.
|
||||
*/
|
||||
template<typename OutputStream, typename SourceEncoding = UTF8<>, typename TargetEncoding = UTF8<>, typename Allocator = MemoryPoolAllocator<> >
|
||||
class PrettyWriter : public Writer<OutputStream, SourceEncoding, TargetEncoding, Allocator> {
|
||||
public:
|
||||
typedef Writer<OutputStream, SourceEncoding, TargetEncoding, Allocator> Base;
|
||||
typedef typename Base::Ch Ch;
|
||||
|
||||
//! Constructor
|
||||
/*! \param os Output stream.
|
||||
\param allocator User supplied allocator. If it is null, it will create a private one.
|
||||
\param levelDepth Initial capacity of stack.
|
||||
*/
|
||||
PrettyWriter(OutputStream& os, Allocator* allocator = 0, size_t levelDepth = Base::kDefaultLevelDepth) :
|
||||
Base(os, allocator, levelDepth), indentChar_(' '), indentCharCount_(4) {}
|
||||
|
||||
//! Overridden for fluent API, see \ref Writer::SetDoublePrecision()
|
||||
PrettyWriter& SetDoublePrecision(int p) { Base::SetDoublePrecision(p); return *this; }
|
||||
|
||||
//! Set custom indentation.
|
||||
/*! \param indentChar Character for indentation. Must be whitespace character (' ', '\\t', '\\n', '\\r').
|
||||
\param indentCharCount Number of indent characters for each indentation level.
|
||||
\note The default indentation is 4 spaces.
|
||||
*/
|
||||
PrettyWriter& SetIndent(Ch indentChar, unsigned indentCharCount) {
|
||||
RAPIDJSON_ASSERT(indentChar == ' ' || indentChar == '\t' || indentChar == '\n' || indentChar == '\r');
|
||||
indentChar_ = indentChar;
|
||||
indentCharCount_ = indentCharCount;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/*! @name Implementation of Handler
|
||||
\see Handler
|
||||
*/
|
||||
//@{
|
||||
|
||||
bool Null() { PrettyPrefix(kNullType); return Base::WriteNull(); }
|
||||
bool Bool(bool b) { PrettyPrefix(b ? kTrueType : kFalseType); return Base::WriteBool(b); }
|
||||
bool Int(int i) { PrettyPrefix(kNumberType); return Base::WriteInt(i); }
|
||||
bool Uint(unsigned u) { PrettyPrefix(kNumberType); return Base::WriteUint(u); }
|
||||
bool Int64(int64_t i64) { PrettyPrefix(kNumberType); return Base::WriteInt64(i64); }
|
||||
bool Uint64(uint64_t u64) { PrettyPrefix(kNumberType); return Base::WriteUint64(u64); }
|
||||
bool Double(double d) { PrettyPrefix(kNumberType); return Base::WriteDouble(d); }
|
||||
|
||||
bool String(const Ch* str, SizeType length, bool copy = false) {
|
||||
(void)copy;
|
||||
PrettyPrefix(kStringType);
|
||||
return Base::WriteString(str, length);
|
||||
}
|
||||
|
||||
bool StartObject() {
|
||||
PrettyPrefix(kObjectType);
|
||||
new (Base::level_stack_.template Push<typename Base::Level>()) typename Base::Level(false);
|
||||
return Base::WriteStartObject();
|
||||
}
|
||||
|
||||
bool EndObject(SizeType memberCount = 0) {
|
||||
(void)memberCount;
|
||||
RAPIDJSON_ASSERT(Base::level_stack_.GetSize() >= sizeof(typename Base::Level));
|
||||
RAPIDJSON_ASSERT(!Base::level_stack_.template Top<typename Base::Level>()->inArray);
|
||||
bool empty = Base::level_stack_.template Pop<typename Base::Level>(1)->valueCount == 0;
|
||||
|
||||
if (!empty) {
|
||||
Base::os_->Put('\n');
|
||||
WriteIndent();
|
||||
}
|
||||
if (!Base::WriteEndObject())
|
||||
return false;
|
||||
if (Base::level_stack_.Empty()) // end of json text
|
||||
Base::os_->Flush();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool StartArray() {
|
||||
PrettyPrefix(kArrayType);
|
||||
new (Base::level_stack_.template Push<typename Base::Level>()) typename Base::Level(true);
|
||||
return Base::WriteStartArray();
|
||||
}
|
||||
|
||||
bool EndArray(SizeType memberCount = 0) {
|
||||
(void)memberCount;
|
||||
RAPIDJSON_ASSERT(Base::level_stack_.GetSize() >= sizeof(typename Base::Level));
|
||||
RAPIDJSON_ASSERT(Base::level_stack_.template Top<typename Base::Level>()->inArray);
|
||||
bool empty = Base::level_stack_.template Pop<typename Base::Level>(1)->valueCount == 0;
|
||||
|
||||
if (!empty) {
|
||||
Base::os_->Put('\n');
|
||||
WriteIndent();
|
||||
}
|
||||
if (!Base::WriteEndArray())
|
||||
return false;
|
||||
if (Base::level_stack_.Empty()) // end of json text
|
||||
Base::os_->Flush();
|
||||
return true;
|
||||
}
|
||||
|
||||
//@}
|
||||
|
||||
/*! @name Convenience extensions */
|
||||
//@{
|
||||
|
||||
//! Simpler but slower overload.
|
||||
bool String(const Ch* str) { return String(str, internal::StrLen(str)); }
|
||||
|
||||
//! Overridden for fluent API, see \ref Writer::Double()
|
||||
bool Double(double d, int precision) {
|
||||
int oldPrecision = Base::GetDoublePrecision();
|
||||
SetDoublePrecision(precision);
|
||||
bool ret = Double(d);
|
||||
SetDoublePrecision(oldPrecision);
|
||||
return ret;
|
||||
}
|
||||
|
||||
//@}
|
||||
protected:
|
||||
void PrettyPrefix(Type type) {
|
||||
(void)type;
|
||||
if (Base::level_stack_.GetSize() != 0) { // this value is not at root
|
||||
typename Base::Level* level = Base::level_stack_.template Top<typename Base::Level>();
|
||||
|
||||
if (level->inArray) {
|
||||
if (level->valueCount > 0) {
|
||||
Base::os_->Put(','); // add comma if it is not the first element in array
|
||||
Base::os_->Put('\n');
|
||||
}
|
||||
else
|
||||
Base::os_->Put('\n');
|
||||
WriteIndent();
|
||||
}
|
||||
else { // in object
|
||||
if (level->valueCount > 0) {
|
||||
if (level->valueCount % 2 == 0) {
|
||||
Base::os_->Put(',');
|
||||
Base::os_->Put('\n');
|
||||
}
|
||||
else {
|
||||
Base::os_->Put(':');
|
||||
Base::os_->Put(' ');
|
||||
}
|
||||
}
|
||||
else
|
||||
Base::os_->Put('\n');
|
||||
|
||||
if (level->valueCount % 2 == 0)
|
||||
WriteIndent();
|
||||
}
|
||||
if (!level->inArray && level->valueCount % 2 == 0)
|
||||
RAPIDJSON_ASSERT(type == kStringType); // if it's in object, then even number should be a name
|
||||
level->valueCount++;
|
||||
}
|
||||
else {
|
||||
RAPIDJSON_ASSERT(type == kObjectType || type == kArrayType);
|
||||
RAPIDJSON_ASSERT(!Base::hasRoot_); // Should only has one and only one root.
|
||||
Base::hasRoot_ = true;
|
||||
}
|
||||
}
|
||||
|
||||
void WriteIndent() {
|
||||
size_t count = (Base::level_stack_.GetSize() / sizeof(typename Base::Level)) * indentCharCount_;
|
||||
PutN(*Base::os_, indentChar_, count);
|
||||
}
|
||||
|
||||
Ch indentChar_;
|
||||
unsigned indentCharCount_;
|
||||
|
||||
private:
|
||||
// Prohibit copy constructor & assignment operator.
|
||||
PrettyWriter(const PrettyWriter&);
|
||||
PrettyWriter& operator=(const PrettyWriter&);
|
||||
};
|
||||
|
||||
} // namespace rapidjson
|
||||
|
||||
#ifdef __GNUC__
|
||||
RAPIDJSON_DIAG_POP
|
||||
#endif
|
||||
|
||||
#endif // RAPIDJSON_RAPIDJSON_H_
|
||||
397
common/rapidjson/rapidjson/rapidjson.h
Normal file
397
common/rapidjson/rapidjson/rapidjson.h
Normal file
@ -0,0 +1,397 @@
|
||||
#ifndef RAPIDJSON_RAPIDJSON_H_
|
||||
#define RAPIDJSON_RAPIDJSON_H_
|
||||
|
||||
// Copyright (c) 2011 Milo Yip (miloyip@gmail.com)
|
||||
// Version 0.1
|
||||
|
||||
/*!\file rapidjson.h
|
||||
\brief common definitions and configuration
|
||||
|
||||
\todo Complete Doxygen documentation for configure macros.
|
||||
*/
|
||||
|
||||
#include <cstdlib> // malloc(), realloc(), free()
|
||||
#include <cstring> // memcpy()
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// RAPIDJSON_NO_INT64DEFINE
|
||||
|
||||
// Here defines int64_t and uint64_t types in global namespace as well as the
|
||||
// (U)INT64_C constant macros.
|
||||
// If user have their own definition, can define RAPIDJSON_NO_INT64DEFINE to disable this.
|
||||
#ifndef RAPIDJSON_NO_INT64DEFINE
|
||||
//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN
|
||||
#ifndef __STDC_CONSTANT_MACROS
|
||||
# define __STDC_CONSTANT_MACROS 1 // required by C++ standard
|
||||
#endif
|
||||
#ifdef _MSC_VER
|
||||
#include "msinttypes/stdint.h"
|
||||
#include "msinttypes/inttypes.h"
|
||||
#else
|
||||
// Other compilers should have this.
|
||||
#include <stdint.h>
|
||||
#include <inttypes.h>
|
||||
#endif
|
||||
//!@endcond
|
||||
#endif // RAPIDJSON_NO_INT64TYPEDEF
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// RAPIDJSON_FORCEINLINE
|
||||
|
||||
#ifndef RAPIDJSON_FORCEINLINE
|
||||
#ifdef _MSC_VER
|
||||
#define RAPIDJSON_FORCEINLINE __forceinline
|
||||
#else
|
||||
#define RAPIDJSON_FORCEINLINE
|
||||
#endif
|
||||
#endif // RAPIDJSON_FORCEINLINE
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// RAPIDJSON_ENDIAN
|
||||
#define RAPIDJSON_LITTLEENDIAN 0 //!< Little endian machine
|
||||
#define RAPIDJSON_BIGENDIAN 1 //!< Big endian machine
|
||||
|
||||
//! Endianness of the machine.
|
||||
/*! GCC 4.6 provided macro for detecting endianness of the target machine. But other
|
||||
compilers may not have this. User can define RAPIDJSON_ENDIAN to either
|
||||
\ref RAPIDJSON_LITTLEENDIAN or \ref RAPIDJSON_BIGENDIAN.
|
||||
|
||||
Implemented with reference to
|
||||
https://gcc.gnu.org/onlinedocs/gcc-4.6.0/cpp/Common-Predefined-Macros.html
|
||||
http://www.boost.org/doc/libs/1_42_0/boost/detail/endian.hpp
|
||||
*/
|
||||
#ifndef RAPIDJSON_ENDIAN
|
||||
// Detect with GCC 4.6's macro
|
||||
# ifdef __BYTE_ORDER__
|
||||
# if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
|
||||
# define RAPIDJSON_ENDIAN RAPIDJSON_LITTLEENDIAN
|
||||
# elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
|
||||
# define RAPIDJSON_ENDIAN RAPIDJSON_BIGENDIAN
|
||||
# else
|
||||
# error Unknown machine endianess detected. User needs to define RAPIDJSON_ENDIAN.
|
||||
# endif // __BYTE_ORDER__
|
||||
// Detect with GLIBC's endian.h
|
||||
# elif defined(__GLIBC__)
|
||||
# include <endian.h>
|
||||
# if (__BYTE_ORDER == __LITTLE_ENDIAN)
|
||||
# define RAPIDJSON_ENDIAN RAPIDJSON_LITTLEENDIAN
|
||||
# elif (__BYTE_ORDER == __BIG_ENDIAN)
|
||||
# define RAPIDJSON_ENDIAN RAPIDJSON_BIGENDIAN
|
||||
# else
|
||||
# error Unknown machine endianess detected. User needs to define RAPIDJSON_ENDIAN.
|
||||
# endif // __GLIBC__
|
||||
// Detect with _LITTLE_ENDIAN and _BIG_ENDIAN macro
|
||||
# elif defined(_LITTLE_ENDIAN) && !defined(_BIG_ENDIAN)
|
||||
# define RAPIDJSON_ENDIAN RAPIDJSON_LITTLEENDIAN
|
||||
# elif defined(_BIG_ENDIAN) && !defined(_LITTLE_ENDIAN)
|
||||
# define RAPIDJSON_ENDIAN RAPIDJSON_BIGENDIAN
|
||||
// Detect with architecture macros
|
||||
# elif defined(__sparc) || defined(__sparc__) || defined(_POWER) || defined(__powerpc__) || defined(__ppc__) || defined(__hpux) || defined(__hppa) || defined(_MIPSEB) || defined(_POWER) || defined(__s390__)
|
||||
# define RAPIDJSON_ENDIAN RAPIDJSON_BIGENDIAN
|
||||
# elif defined(__i386__) || defined(__alpha__) || defined(__ia64) || defined(__ia64__) || defined(_M_IX86) || defined(_M_IA64) || defined(_M_ALPHA) || defined(__amd64) || defined(__amd64__) || defined(_M_AMD64) || defined(__x86_64) || defined(__x86_64__) || defined(_M_X64) || defined(__bfin__)
|
||||
# define RAPIDJSON_ENDIAN RAPIDJSON_LITTLEENDIAN
|
||||
# else
|
||||
# error Unknown machine endianess detected. User needs to define RAPIDJSON_ENDIAN.
|
||||
# endif
|
||||
#endif // RAPIDJSON_ENDIAN
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// RAPIDJSON_ALIGNSIZE
|
||||
|
||||
//! Data alignment of the machine.
|
||||
/*!
|
||||
Some machine requires strict data alignment.
|
||||
Currently the default uses 4 bytes alignment. User can customize this.
|
||||
*/
|
||||
#ifndef RAPIDJSON_ALIGN
|
||||
#define RAPIDJSON_ALIGN(x) ((x + 3u) & ~3u)
|
||||
#endif
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// RAPIDJSON_SSE2/RAPIDJSON_SSE42/RAPIDJSON_SIMD
|
||||
|
||||
// Enable SSE2 optimization.
|
||||
//#define RAPIDJSON_SSE2
|
||||
|
||||
// Enable SSE4.2 optimization.
|
||||
//#define RAPIDJSON_SSE42
|
||||
|
||||
#if defined(RAPIDJSON_SSE2) || defined(RAPIDJSON_SSE42)
|
||||
#define RAPIDJSON_SIMD
|
||||
#endif
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// RAPIDJSON_NO_SIZETYPEDEFINE
|
||||
|
||||
#ifndef RAPIDJSON_NO_SIZETYPEDEFINE
|
||||
namespace rapidjson {
|
||||
//! Use 32-bit array/string indices even for 64-bit platform, instead of using size_t.
|
||||
/*! User may override the SizeType by defining RAPIDJSON_NO_SIZETYPEDEFINE.
|
||||
*/
|
||||
typedef unsigned SizeType;
|
||||
} // namespace rapidjson
|
||||
#endif
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// RAPIDJSON_ASSERT
|
||||
|
||||
//! Assertion.
|
||||
/*! By default, rapidjson uses C assert() for assertion.
|
||||
User can override it by defining RAPIDJSON_ASSERT(x) macro.
|
||||
*/
|
||||
#ifndef RAPIDJSON_ASSERT
|
||||
#include <cassert>
|
||||
#define RAPIDJSON_ASSERT(x) assert(x)
|
||||
#endif // RAPIDJSON_ASSERT
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// RAPIDJSON_STATIC_ASSERT
|
||||
|
||||
// Adopt from boost
|
||||
#ifndef RAPIDJSON_STATIC_ASSERT
|
||||
//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN
|
||||
namespace rapidjson {
|
||||
|
||||
template <bool x> struct STATIC_ASSERTION_FAILURE;
|
||||
template <> struct STATIC_ASSERTION_FAILURE<true> { enum { value = 1 }; };
|
||||
template<int x> struct StaticAssertTest {};
|
||||
} // namespace rapidjson
|
||||
|
||||
#define RAPIDJSON_JOIN(X, Y) RAPIDJSON_DO_JOIN(X, Y)
|
||||
#define RAPIDJSON_DO_JOIN(X, Y) RAPIDJSON_DO_JOIN2(X, Y)
|
||||
#define RAPIDJSON_DO_JOIN2(X, Y) X##Y
|
||||
|
||||
#if defined(__GNUC__)
|
||||
#define RAPIDJSON_STATIC_ASSERT_UNUSED_ATTRIBUTE __attribute__((unused))
|
||||
#else
|
||||
#define RAPIDJSON_STATIC_ASSERT_UNUSED_ATTRIBUTE
|
||||
#endif
|
||||
//!@endcond
|
||||
|
||||
/*! \def RAPIDJSON_STATIC_ASSERT
|
||||
\brief (internal) macro to check for conditions at compile-time
|
||||
\param x compile-time condition
|
||||
\hideinitializer
|
||||
*/
|
||||
#define RAPIDJSON_STATIC_ASSERT(x) typedef ::rapidjson::StaticAssertTest<\
|
||||
sizeof(::rapidjson::STATIC_ASSERTION_FAILURE<bool(x) >)>\
|
||||
RAPIDJSON_JOIN(StaticAssertTypedef, __LINE__) RAPIDJSON_STATIC_ASSERT_UNUSED_ATTRIBUTE
|
||||
#endif
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Helpers
|
||||
|
||||
//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN
|
||||
|
||||
#define RAPIDJSON_MULTILINEMACRO_BEGIN do {
|
||||
#define RAPIDJSON_MULTILINEMACRO_END \
|
||||
} while((void)0, 0)
|
||||
|
||||
// adopted from Boost
|
||||
#define RAPIDJSON_VERSION_CODE(x,y,z) \
|
||||
(((x)*100000) + ((y)*100) + (z))
|
||||
|
||||
// token stringification
|
||||
#define RAPIDJSON_STRINGIFY(x) RAPIDJSON_DO_STRINGIFY(x)
|
||||
#define RAPIDJSON_DO_STRINGIFY(x) #x
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// RAPIDJSON_DIAG_PUSH/POP, RAPIDJSON_DIAG_OFF
|
||||
|
||||
#if defined(__clang__) || (defined(__GNUC__) && RAPIDJSON_VERSION_CODE(__GNUC__,__GNUC_MINOR__,__GNUC_PATCHLEVEL__) >= RAPIDJSON_VERSION_CODE(4,2,0))
|
||||
|
||||
#define RAPIDJSON_PRAGMA(x) _Pragma(RAPIDJSON_STRINGIFY(x))
|
||||
#define RAPIDJSON_DIAG_PRAGMA(x) RAPIDJSON_PRAGMA(GCC diagnostic x)
|
||||
#define RAPIDJSON_DIAG_OFF(x) \
|
||||
RAPIDJSON_DIAG_PRAGMA(ignored RAPIDJSON_STRINGIFY(RAPIDJSON_JOIN(-W,x)))
|
||||
|
||||
// push/pop support in Clang and GCC>=4.6
|
||||
#if defined(__clang__) || (defined(__GNUC__) && RAPIDJSON_VERSION_CODE(__GNUC__,__GNUC_MINOR__,__GNUC_PATCHLEVEL__) >= RAPIDJSON_VERSION_CODE(4,6,0))
|
||||
#define RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_PRAGMA(push)
|
||||
#define RAPIDJSON_DIAG_POP RAPIDJSON_DIAG_PRAGMA(pop)
|
||||
#else // GCC >= 4.2, < 4.6
|
||||
#define RAPIDJSON_DIAG_PUSH /* ignored */
|
||||
#define RAPIDJSON_DIAG_POP /* ignored */
|
||||
#endif
|
||||
|
||||
#elif defined(_MSC_VER)
|
||||
|
||||
// pragma (MSVC specific)
|
||||
#define RAPIDJSON_PRAGMA(x) __pragma(x)
|
||||
#define RAPIDJSON_DIAG_PRAGMA(x) RAPIDJSON_PRAGMA(warning(x))
|
||||
|
||||
#define RAPIDJSON_DIAG_OFF(x) RAPIDJSON_DIAG_PRAGMA(disable: x)
|
||||
#define RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_PRAGMA(push)
|
||||
#define RAPIDJSON_DIAG_POP RAPIDJSON_DIAG_PRAGMA(pop)
|
||||
|
||||
#else
|
||||
|
||||
#define RAPIDJSON_DIAG_OFF(x) /* ignored */
|
||||
#define RAPIDJSON_DIAG_PUSH /* ignored */
|
||||
#define RAPIDJSON_DIAG_POP /* ignored */
|
||||
|
||||
#endif // RAPIDJSON_DIAG_*
|
||||
|
||||
//!@endcond
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Allocators and Encodings
|
||||
|
||||
#include "allocators.h"
|
||||
#include "encodings.h"
|
||||
|
||||
//! main RapidJSON namespace
|
||||
namespace rapidjson {
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Stream
|
||||
|
||||
/*! \class rapidjson::Stream
|
||||
\brief Concept for reading and writing characters.
|
||||
|
||||
For read-only stream, no need to implement PutBegin(), Put(), Flush() and PutEnd().
|
||||
|
||||
For write-only stream, only need to implement Put() and Flush().
|
||||
|
||||
\code
|
||||
concept Stream {
|
||||
typename Ch; //!< Character type of the stream.
|
||||
|
||||
//! Read the current character from stream without moving the read cursor.
|
||||
Ch Peek() const;
|
||||
|
||||
//! Read the current character from stream and moving the read cursor to next character.
|
||||
Ch Take();
|
||||
|
||||
//! Get the current read cursor.
|
||||
//! \return Number of characters read from start.
|
||||
size_t Tell();
|
||||
|
||||
//! Begin writing operation at the current read pointer.
|
||||
//! \return The begin writer pointer.
|
||||
Ch* PutBegin();
|
||||
|
||||
//! Write a character.
|
||||
void Put(Ch c);
|
||||
|
||||
//! Flush the buffer.
|
||||
void Flush();
|
||||
|
||||
//! End the writing operation.
|
||||
//! \param begin The begin write pointer returned by PutBegin().
|
||||
//! \return Number of characters written.
|
||||
size_t PutEnd(Ch* begin);
|
||||
}
|
||||
\endcode
|
||||
*/
|
||||
|
||||
//! Provides additional information for stream.
|
||||
/*!
|
||||
By using traits pattern, this type provides a default configuration for stream.
|
||||
For custom stream, this type can be specialized for other configuration.
|
||||
See TEST(Reader, CustomStringStream) in readertest.cpp for example.
|
||||
*/
|
||||
template<typename Stream>
|
||||
struct StreamTraits {
|
||||
//! Whether to make local copy of stream for optimization during parsing.
|
||||
/*!
|
||||
By default, for safety, streams do not use local copy optimization.
|
||||
Stream that can be copied fast should specialize this, like StreamTraits<StringStream>.
|
||||
*/
|
||||
enum { copyOptimization = 0 };
|
||||
};
|
||||
|
||||
//! Put N copies of a character to a stream.
|
||||
template<typename Stream, typename Ch>
|
||||
inline void PutN(Stream& stream, Ch c, size_t n) {
|
||||
for (size_t i = 0; i < n; i++)
|
||||
stream.Put(c);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// StringStream
|
||||
|
||||
//! Read-only string stream.
|
||||
/*! \note implements Stream concept
|
||||
*/
|
||||
template <typename Encoding>
|
||||
struct GenericStringStream {
|
||||
typedef typename Encoding::Ch Ch;
|
||||
|
||||
GenericStringStream(const Ch *src) : src_(src), head_(src) {}
|
||||
|
||||
Ch Peek() const { return *src_; }
|
||||
Ch Take() { return *src_++; }
|
||||
size_t Tell() const { return static_cast<size_t>(src_ - head_); }
|
||||
|
||||
Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
|
||||
void Put(Ch) { RAPIDJSON_ASSERT(false); }
|
||||
void Flush() { RAPIDJSON_ASSERT(false); }
|
||||
size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; }
|
||||
|
||||
const Ch* src_; //!< Current read position.
|
||||
const Ch* head_; //!< Original head of the string.
|
||||
};
|
||||
|
||||
template <typename Encoding>
|
||||
struct StreamTraits<GenericStringStream<Encoding> > {
|
||||
enum { copyOptimization = 1 };
|
||||
};
|
||||
|
||||
//! String stream with UTF8 encoding.
|
||||
typedef GenericStringStream<UTF8<> > StringStream;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// InsituStringStream
|
||||
|
||||
//! A read-write string stream.
|
||||
/*! This string stream is particularly designed for in-situ parsing.
|
||||
\note implements Stream concept
|
||||
*/
|
||||
template <typename Encoding>
|
||||
struct GenericInsituStringStream {
|
||||
typedef typename Encoding::Ch Ch;
|
||||
|
||||
GenericInsituStringStream(Ch *src) : src_(src), dst_(0), head_(src) {}
|
||||
|
||||
// Read
|
||||
Ch Peek() { return *src_; }
|
||||
Ch Take() { return *src_++; }
|
||||
size_t Tell() { return static_cast<size_t>(src_ - head_); }
|
||||
|
||||
// Write
|
||||
Ch* PutBegin() { return dst_ = src_; }
|
||||
void Put(Ch c) { RAPIDJSON_ASSERT(dst_ != 0); *dst_++ = c; }
|
||||
void Flush() {}
|
||||
size_t PutEnd(Ch* begin) { return static_cast<size_t>(dst_ - begin); }
|
||||
|
||||
Ch* src_;
|
||||
Ch* dst_;
|
||||
Ch* head_;
|
||||
};
|
||||
|
||||
template <typename Encoding>
|
||||
struct StreamTraits<GenericInsituStringStream<Encoding> > {
|
||||
enum { copyOptimization = 1 };
|
||||
};
|
||||
|
||||
//! Insitu string stream with UTF8 encoding.
|
||||
typedef GenericInsituStringStream<UTF8<> > InsituStringStream;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Type
|
||||
|
||||
//! Type of JSON value
|
||||
enum Type {
|
||||
kNullType = 0, //!< null
|
||||
kFalseType = 1, //!< false
|
||||
kTrueType = 2, //!< true
|
||||
kObjectType = 3, //!< object
|
||||
kArrayType = 4, //!< array
|
||||
kStringType = 5, //!< string
|
||||
kNumberType = 6 //!< number
|
||||
};
|
||||
|
||||
} // namespace rapidjson
|
||||
|
||||
#endif // RAPIDJSON_RAPIDJSON_H_
|
||||
1246
common/rapidjson/rapidjson/reader.h
Normal file
1246
common/rapidjson/rapidjson/reader.h
Normal file
File diff suppressed because it is too large
Load Diff
51
common/rapidjson/rapidjson/stringbuffer.h
Normal file
51
common/rapidjson/rapidjson/stringbuffer.h
Normal file
@ -0,0 +1,51 @@
|
||||
#ifndef RAPIDJSON_STRINGBUFFER_H_
|
||||
#define RAPIDJSON_STRINGBUFFER_H_
|
||||
|
||||
#include "rapidjson.h"
|
||||
#include "internal/stack.h"
|
||||
|
||||
namespace rapidjson {
|
||||
|
||||
//! Represents an in-memory output stream.
|
||||
/*!
|
||||
\tparam Encoding Encoding of the stream.
|
||||
\tparam Allocator type for allocating memory buffer.
|
||||
\note implements Stream concept
|
||||
*/
|
||||
template <typename Encoding, typename Allocator = CrtAllocator>
|
||||
struct GenericStringBuffer {
|
||||
typedef typename Encoding::Ch Ch;
|
||||
|
||||
GenericStringBuffer(Allocator* allocator = 0, size_t capacity = kDefaultCapacity) : stack_(allocator, capacity) {}
|
||||
|
||||
void Put(Ch c) { *stack_.template Push<Ch>() = c; }
|
||||
void Flush() {}
|
||||
|
||||
void Clear() { stack_.Clear(); }
|
||||
|
||||
const Ch* GetString() const {
|
||||
// Push and pop a null terminator. This is safe.
|
||||
*stack_.template Push<Ch>() = '\0';
|
||||
stack_.template Pop<Ch>(1);
|
||||
|
||||
return stack_.template Bottom<Ch>();
|
||||
}
|
||||
|
||||
size_t GetSize() const { return stack_.GetSize(); }
|
||||
|
||||
static const size_t kDefaultCapacity = 256;
|
||||
mutable internal::Stack<Allocator> stack_;
|
||||
};
|
||||
|
||||
//! String buffer with UTF8 encoding
|
||||
typedef GenericStringBuffer<UTF8<> > StringBuffer;
|
||||
|
||||
//! Implement specialized version of PutN() with memset() for better performance.
|
||||
template<>
|
||||
inline void PutN(GenericStringBuffer<UTF8<> >& stream, char c, size_t n) {
|
||||
memset(stream.stack_.Push<char>(n), c, n * sizeof(c));
|
||||
}
|
||||
|
||||
} // namespace rapidjson
|
||||
|
||||
#endif // RAPIDJSON_STRINGBUFFER_H_
|
||||
387
common/rapidjson/rapidjson/writer.h
Normal file
387
common/rapidjson/rapidjson/writer.h
Normal file
@ -0,0 +1,387 @@
|
||||
#ifndef RAPIDJSON_WRITER_H_
|
||||
#define RAPIDJSON_WRITER_H_
|
||||
|
||||
#include "rapidjson.h"
|
||||
#include "internal/stack.h"
|
||||
#include "internal/strfunc.h"
|
||||
#include <cstdio> // snprintf() or _sprintf_s()
|
||||
#include <new> // placement new
|
||||
|
||||
#ifdef _MSC_VER
|
||||
RAPIDJSON_DIAG_PUSH
|
||||
RAPIDJSON_DIAG_OFF(4127) // conditional expression is constant
|
||||
#endif
|
||||
|
||||
namespace rapidjson {
|
||||
|
||||
//! JSON writer
|
||||
/*! Writer implements the concept Handler.
|
||||
It generates JSON text by events to an output os.
|
||||
|
||||
User may programmatically calls the functions of a writer to generate JSON text.
|
||||
|
||||
On the other side, a writer can also be passed to objects that generates events,
|
||||
|
||||
for example Reader::Parse() and Document::Accept().
|
||||
|
||||
\tparam OutputStream Type of output stream.
|
||||
\tparam SourceEncoding Encoding of source string.
|
||||
\tparam TargetEncoding Encoding of output stream.
|
||||
\tparam Allocator Type of allocator for allocating memory of stack.
|
||||
\note implements Handler concept
|
||||
*/
|
||||
template<typename OutputStream, typename SourceEncoding = UTF8<>, typename TargetEncoding = UTF8<>, typename Allocator = MemoryPoolAllocator<> >
|
||||
class Writer {
|
||||
public:
|
||||
typedef typename SourceEncoding::Ch Ch;
|
||||
|
||||
//! Constructor
|
||||
/*! \param os Output stream.
|
||||
\param allocator User supplied allocator. If it is null, it will create a private one.
|
||||
\param levelDepth Initial capacity of stack.
|
||||
*/
|
||||
Writer(OutputStream& os, Allocator* allocator = 0, size_t levelDepth = kDefaultLevelDepth) :
|
||||
os_(&os), level_stack_(allocator, levelDepth * sizeof(Level)),
|
||||
doublePrecision_(kDefaultDoublePrecision), hasRoot_(false) {}
|
||||
|
||||
//! Reset the writer with a new stream.
|
||||
/*!
|
||||
This function reset the writer with a new stream and default settings,
|
||||
in order to make a Writer object reusable for output multiple JSONs.
|
||||
|
||||
\param os New output stream.
|
||||
\code
|
||||
Writer<OutputStream> writer(os1);
|
||||
writer.StartObject();
|
||||
// ...
|
||||
writer.EndObject();
|
||||
|
||||
writer.Reset(os2);
|
||||
writer.StartObject();
|
||||
// ...
|
||||
writer.EndObject();
|
||||
\endcode
|
||||
*/
|
||||
void Reset(OutputStream& os) {
|
||||
os_ = &os;
|
||||
doublePrecision_ = kDefaultDoublePrecision;
|
||||
hasRoot_ = false;
|
||||
level_stack_.Clear();
|
||||
}
|
||||
|
||||
//! Checks whether the output is a complete JSON.
|
||||
/*!
|
||||
A complete JSON has a complete root object or array.
|
||||
*/
|
||||
bool IsComplete() const {
|
||||
return hasRoot_ && level_stack_.Empty();
|
||||
}
|
||||
|
||||
//! Set the number of significant digits for \c double values
|
||||
/*! When writing a \c double value to the \c OutputStream, the number
|
||||
of significant digits is limited to 6 by default.
|
||||
\param p maximum number of significant digits (default: 6)
|
||||
\return The Writer itself for fluent API.
|
||||
*/
|
||||
Writer& SetDoublePrecision(int p = kDefaultDoublePrecision) {
|
||||
if (p < 0) p = kDefaultDoublePrecision; // negative precision is ignored
|
||||
doublePrecision_ = p;
|
||||
return *this;
|
||||
}
|
||||
|
||||
//! \see SetDoublePrecision()
|
||||
int GetDoublePrecision() const { return doublePrecision_; }
|
||||
|
||||
/*!@name Implementation of Handler
|
||||
\see Handler
|
||||
*/
|
||||
//@{
|
||||
|
||||
bool Null() { Prefix(kNullType); return WriteNull(); }
|
||||
bool Bool(bool b) { Prefix(b ? kTrueType : kFalseType); return WriteBool(b); }
|
||||
bool Int(int i) { Prefix(kNumberType); return WriteInt(i); }
|
||||
bool Uint(unsigned u) { Prefix(kNumberType); return WriteUint(u); }
|
||||
bool Int64(int64_t i64) { Prefix(kNumberType); return WriteInt64(i64); }
|
||||
bool Uint64(uint64_t u64) { Prefix(kNumberType); return WriteUint64(u64); }
|
||||
|
||||
//! Writes the given \c double value to the stream
|
||||
/*!
|
||||
The number of significant digits (the precision) to be written
|
||||
can be set by \ref SetDoublePrecision() for the Writer:
|
||||
\code
|
||||
Writer<...> writer(...);
|
||||
writer.SetDoublePrecision(12).Double(M_PI);
|
||||
\endcode
|
||||
\param d The value to be written.
|
||||
\return Whether it is succeed.
|
||||
*/
|
||||
bool Double(double d) { Prefix(kNumberType); return WriteDouble(d); }
|
||||
|
||||
bool String(const Ch* str, SizeType length, bool copy = false) {
|
||||
(void)copy;
|
||||
Prefix(kStringType);
|
||||
return WriteString(str, length);
|
||||
}
|
||||
|
||||
bool StartObject() {
|
||||
Prefix(kObjectType);
|
||||
new (level_stack_.template Push<Level>()) Level(false);
|
||||
return WriteStartObject();
|
||||
}
|
||||
|
||||
bool EndObject(SizeType memberCount = 0) {
|
||||
(void)memberCount;
|
||||
RAPIDJSON_ASSERT(level_stack_.GetSize() >= sizeof(Level));
|
||||
RAPIDJSON_ASSERT(!level_stack_.template Top<Level>()->inArray);
|
||||
level_stack_.template Pop<Level>(1);
|
||||
bool ret = WriteEndObject();
|
||||
if (level_stack_.Empty()) // end of json text
|
||||
os_->Flush();
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool StartArray() {
|
||||
Prefix(kArrayType);
|
||||
new (level_stack_.template Push<Level>()) Level(true);
|
||||
return WriteStartArray();
|
||||
}
|
||||
|
||||
bool EndArray(SizeType elementCount = 0) {
|
||||
(void)elementCount;
|
||||
RAPIDJSON_ASSERT(level_stack_.GetSize() >= sizeof(Level));
|
||||
RAPIDJSON_ASSERT(level_stack_.template Top<Level>()->inArray);
|
||||
level_stack_.template Pop<Level>(1);
|
||||
bool ret = WriteEndArray();
|
||||
if (level_stack_.Empty()) // end of json text
|
||||
os_->Flush();
|
||||
return ret;
|
||||
}
|
||||
//@}
|
||||
|
||||
/*! @name Convenience extensions */
|
||||
//@{
|
||||
|
||||
//! Writes the given \c double value to the stream (explicit precision)
|
||||
/*!
|
||||
The currently set double precision is ignored in favor of the explicitly
|
||||
given precision for this value.
|
||||
\see Double(), SetDoublePrecision(), GetDoublePrecision()
|
||||
\param d The value to be written
|
||||
\param precision The number of significant digits for this value
|
||||
\return Whether it is succeeded.
|
||||
*/
|
||||
bool Double(double d, int precision) {
|
||||
int oldPrecision = GetDoublePrecision();
|
||||
SetDoublePrecision(precision);
|
||||
bool ret = Double(d);
|
||||
SetDoublePrecision(oldPrecision);
|
||||
return ret;
|
||||
}
|
||||
|
||||
//! Simpler but slower overload.
|
||||
bool String(const Ch* str) { return String(str, internal::StrLen(str)); }
|
||||
|
||||
//@}
|
||||
|
||||
protected:
|
||||
//! Information for each nested level
|
||||
struct Level {
|
||||
Level(bool inArray_) : valueCount(0), inArray(inArray_) {}
|
||||
size_t valueCount; //!< number of values in this level
|
||||
bool inArray; //!< true if in array, otherwise in object
|
||||
};
|
||||
|
||||
static const size_t kDefaultLevelDepth = 32;
|
||||
|
||||
bool WriteNull() {
|
||||
os_->Put('n'); os_->Put('u'); os_->Put('l'); os_->Put('l'); return true;
|
||||
}
|
||||
|
||||
bool WriteBool(bool b) {
|
||||
if (b) {
|
||||
os_->Put('t'); os_->Put('r'); os_->Put('u'); os_->Put('e');
|
||||
}
|
||||
else {
|
||||
os_->Put('f'); os_->Put('a'); os_->Put('l'); os_->Put('s'); os_->Put('e');
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WriteInt(int i) {
|
||||
if (i < 0) {
|
||||
os_->Put('-');
|
||||
i = -i;
|
||||
}
|
||||
return WriteUint((unsigned)i);
|
||||
}
|
||||
|
||||
bool WriteUint(unsigned u) {
|
||||
char buffer[10];
|
||||
char *p = buffer;
|
||||
do {
|
||||
*p++ = char(u % 10) + '0';
|
||||
u /= 10;
|
||||
} while (u > 0);
|
||||
|
||||
do {
|
||||
--p;
|
||||
os_->Put(*p);
|
||||
} while (p != buffer);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WriteInt64(int64_t i64) {
|
||||
if (i64 < 0) {
|
||||
os_->Put('-');
|
||||
i64 = -i64;
|
||||
}
|
||||
WriteUint64((uint64_t)i64);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WriteUint64(uint64_t u64) {
|
||||
char buffer[20];
|
||||
char *p = buffer;
|
||||
do {
|
||||
*p++ = char(u64 % 10) + '0';
|
||||
u64 /= 10;
|
||||
} while (u64 > 0);
|
||||
|
||||
do {
|
||||
--p;
|
||||
os_->Put(*p);
|
||||
} while (p != buffer);
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#define RAPIDJSON_SNPRINTF sprintf_s
|
||||
#else
|
||||
#define RAPIDJSON_SNPRINTF snprintf
|
||||
#endif
|
||||
|
||||
//! \todo Optimization with custom double-to-string converter.
|
||||
bool WriteDouble(double d) {
|
||||
char buffer[100];
|
||||
int ret = RAPIDJSON_SNPRINTF(buffer, sizeof(buffer), "%.*g", doublePrecision_, d);
|
||||
RAPIDJSON_ASSERT(ret >= 1);
|
||||
for (int i = 0; i < ret; i++)
|
||||
os_->Put(buffer[i]);
|
||||
return true;
|
||||
}
|
||||
#undef RAPIDJSON_SNPRINTF
|
||||
|
||||
bool WriteString(const Ch* str, SizeType length) {
|
||||
static const char hexDigits[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
|
||||
static const char escape[256] = {
|
||||
#define Z16 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
//0 1 2 3 4 5 6 7 8 9 A B C D E F
|
||||
'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'b', 't', 'n', 'u', 'f', 'r', 'u', 'u', // 00
|
||||
'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', // 10
|
||||
0, 0, '"', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 20
|
||||
Z16, Z16, // 30~4F
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,'\\', 0, 0, 0, // 50
|
||||
Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16 // 60~FF
|
||||
#undef Z16
|
||||
};
|
||||
|
||||
os_->Put('\"');
|
||||
GenericStringStream<SourceEncoding> is(str);
|
||||
while (is.Tell() < length) {
|
||||
const Ch c = is.Peek();
|
||||
if (!TargetEncoding::supportUnicode && (unsigned)c >= 0x80) {
|
||||
// Unicode escaping
|
||||
unsigned codepoint;
|
||||
if (!SourceEncoding::Decode(is, &codepoint))
|
||||
return false;
|
||||
os_->Put('\\');
|
||||
os_->Put('u');
|
||||
if (codepoint <= 0xD7FF || (codepoint >= 0xE000 && codepoint <= 0xFFFF)) {
|
||||
os_->Put(hexDigits[(codepoint >> 12) & 15]);
|
||||
os_->Put(hexDigits[(codepoint >> 8) & 15]);
|
||||
os_->Put(hexDigits[(codepoint >> 4) & 15]);
|
||||
os_->Put(hexDigits[(codepoint ) & 15]);
|
||||
}
|
||||
else if (codepoint >= 0x010000 && codepoint <= 0x10FFFF) {
|
||||
// Surrogate pair
|
||||
unsigned s = codepoint - 0x010000;
|
||||
unsigned lead = (s >> 10) + 0xD800;
|
||||
unsigned trail = (s & 0x3FF) + 0xDC00;
|
||||
os_->Put(hexDigits[(lead >> 12) & 15]);
|
||||
os_->Put(hexDigits[(lead >> 8) & 15]);
|
||||
os_->Put(hexDigits[(lead >> 4) & 15]);
|
||||
os_->Put(hexDigits[(lead ) & 15]);
|
||||
os_->Put('\\');
|
||||
os_->Put('u');
|
||||
os_->Put(hexDigits[(trail >> 12) & 15]);
|
||||
os_->Put(hexDigits[(trail >> 8) & 15]);
|
||||
os_->Put(hexDigits[(trail >> 4) & 15]);
|
||||
os_->Put(hexDigits[(trail ) & 15]);
|
||||
}
|
||||
else
|
||||
return false; // invalid code point
|
||||
}
|
||||
else if ((sizeof(Ch) == 1 || (unsigned)c < 256) && escape[(unsigned char)c]) {
|
||||
is.Take();
|
||||
os_->Put('\\');
|
||||
os_->Put(escape[(unsigned char)c]);
|
||||
if (escape[(unsigned char)c] == 'u') {
|
||||
os_->Put('0');
|
||||
os_->Put('0');
|
||||
os_->Put(hexDigits[(unsigned char)c >> 4]);
|
||||
os_->Put(hexDigits[(unsigned char)c & 0xF]);
|
||||
}
|
||||
}
|
||||
else
|
||||
Transcoder<SourceEncoding, TargetEncoding>::Transcode(is, *os_);
|
||||
}
|
||||
os_->Put('\"');
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WriteStartObject() { os_->Put('{'); return true; }
|
||||
bool WriteEndObject() { os_->Put('}'); return true; }
|
||||
bool WriteStartArray() { os_->Put('['); return true; }
|
||||
bool WriteEndArray() { os_->Put(']'); return true; }
|
||||
|
||||
void Prefix(Type type) {
|
||||
(void)type;
|
||||
if (level_stack_.GetSize() != 0) { // this value is not at root
|
||||
Level* level = level_stack_.template Top<Level>();
|
||||
if (level->valueCount > 0) {
|
||||
if (level->inArray)
|
||||
os_->Put(','); // add comma if it is not the first element in array
|
||||
else // in object
|
||||
os_->Put((level->valueCount % 2 == 0) ? ',' : ':');
|
||||
}
|
||||
if (!level->inArray && level->valueCount % 2 == 0)
|
||||
RAPIDJSON_ASSERT(type == kStringType); // if it's in object, then even number should be a name
|
||||
level->valueCount++;
|
||||
}
|
||||
else {
|
||||
RAPIDJSON_ASSERT(type == kObjectType || type == kArrayType);
|
||||
RAPIDJSON_ASSERT(!hasRoot_); // Should only has one and only one root.
|
||||
hasRoot_ = true;
|
||||
}
|
||||
}
|
||||
|
||||
OutputStream* os_;
|
||||
internal::Stack<Allocator> level_stack_;
|
||||
int doublePrecision_;
|
||||
bool hasRoot_;
|
||||
|
||||
static const int kDefaultDoublePrecision = 6;
|
||||
|
||||
private:
|
||||
// Prohibit copy constructor & assignment operator.
|
||||
Writer(const Writer&);
|
||||
Writer& operator=(const Writer&);
|
||||
};
|
||||
|
||||
} // namespace rapidjson
|
||||
|
||||
#ifdef _MSC_VER
|
||||
RAPIDJSON_DIAG_POP
|
||||
#endif
|
||||
|
||||
#endif // RAPIDJSON_RAPIDJSON_H_
|
||||
@ -186,6 +186,10 @@
|
||||
#define ServerOP_QSPlayerLogMoves 0x4014
|
||||
#define ServerOP_QSMerchantLogTransactions 0x4015
|
||||
|
||||
#define ServerOP_WIServGeneric 0x5001
|
||||
#define ServerOP_WIWorldResponse 0x5002
|
||||
#define ServerOP_WIClientRequest 0x5003
|
||||
|
||||
enum { QSG_LFGuild = 0 };
|
||||
enum { QSG_LFGuild_PlayerMatches = 0, QSG_LFGuild_UpdatePlayerInfo, QSG_LFGuild_RequestPlayerInfo, QSG_LFGuild_UpdateGuildInfo, QSG_LFGuild_GuildMatches,
|
||||
QSG_LFGuild_RequestGuildInfo };
|
||||
@ -1229,6 +1233,17 @@ struct ReloadWorld_Struct{
|
||||
uint32 Option;
|
||||
};
|
||||
|
||||
struct WI_Client_Request_Struct{
|
||||
char Client_UUID[64];
|
||||
char JSON_Data[0];
|
||||
};
|
||||
|
||||
struct WI_Client_Response_Struct{
|
||||
char Client_UUID[64];
|
||||
char JSON_Data[0];
|
||||
};
|
||||
|
||||
|
||||
#pragma pack()
|
||||
|
||||
#endif
|
||||
|
||||
44
common/uuid.cpp
Normal file
44
common/uuid.cpp
Normal file
@ -0,0 +1,44 @@
|
||||
/*
|
||||
EQEMu: Everquest Server Emulator
|
||||
Copyright (C) 2001-2014 EQEMu Development Team (http://eqemulator.net)
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; version 2 of the License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY except by those people which sell it, which
|
||||
are required to give you total support for your newly bought product;
|
||||
without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "uuid.h"
|
||||
|
||||
#ifdef WIN32
|
||||
#include <rpc.h>
|
||||
#else
|
||||
#include <uuid/uuid.h>
|
||||
#endif
|
||||
|
||||
std::string CreateUUID() {
|
||||
#ifdef WIN32
|
||||
UUID uuid;
|
||||
UuidCreate(&uuid);
|
||||
unsigned char *str = nullptr;
|
||||
UuidToStringA(&uuid, &str);
|
||||
std::string s((char*)str);
|
||||
RpcStringFreeA(&str);
|
||||
return s;
|
||||
#else
|
||||
char str[64] = { 0 };
|
||||
uuid_t uuid;
|
||||
uuid_generate_random(uuid);
|
||||
uuid_unparse(uuid, str);
|
||||
return str;
|
||||
#endif
|
||||
}
|
||||
@ -1,28 +1,27 @@
|
||||
/* EQEMu: Everquest Server Emulator
|
||||
Copyright (C) 2001-2008 EQEMu Development Team (http://eqemulator.net)
|
||||
|
||||
/*
|
||||
EQEMu: Everquest Server Emulator
|
||||
Copyright (C) 2001-2014 EQEMu Development Team (http://eqemulator.net)
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; version 2 of the License.
|
||||
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY except by those people which sell it, which
|
||||
are required to give you total support for your newly bought product;
|
||||
without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
*/
|
||||
#ifndef COMMON_UUID_H
|
||||
#define COMMON_UUID_H
|
||||
|
||||
#include "../common/debug.h"
|
||||
#include "socket_server_config.h"
|
||||
#include <string>
|
||||
|
||||
socket_server_config *socket_server_config::_chat_config = nullptr;
|
||||
std::string CreateUUID();
|
||||
|
||||
std::string socket_server_config::GetByName(const std::string &var_name) const {
|
||||
return(EQEmuConfig::GetByName(var_name));
|
||||
}
|
||||
#endif
|
||||
|
||||
77
common/web_interface_utils.cpp
Normal file
77
common/web_interface_utils.cpp
Normal file
@ -0,0 +1,77 @@
|
||||
/* EQEMu: Everquest Server Emulator
|
||||
Copyright (C) 2001-2014 EQEMu Development Team (http://eqemulator.net)
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; version 2 of the License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY except by those people which sell it, which
|
||||
are required to give you total support for your newly bought product;
|
||||
without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "../common/debug.h"
|
||||
#include "web_interface_utils.h"
|
||||
#include "rapidjson/writer.h"
|
||||
#include "rapidjson/stringbuffer.h"
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <vector>
|
||||
#include <utility>
|
||||
|
||||
|
||||
using namespace rapidjson;
|
||||
using namespace std;
|
||||
|
||||
std::vector<std::string> explode(std::string const & s, char delim)
|
||||
{
|
||||
std::vector<std::string> result;
|
||||
std::istringstream iss(s);
|
||||
|
||||
for (std::string token; std::getline(iss, token, delim);)
|
||||
{
|
||||
result.push_back(std::move(token));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string MakeJSON(std::string json)
|
||||
{
|
||||
StringBuffer s;
|
||||
Writer<StringBuffer> writer(s);
|
||||
writer.StartObject();
|
||||
|
||||
auto arg_c = explode(json, ',');
|
||||
if (arg_c.size() == 0)
|
||||
{
|
||||
auto arg_v = explode(json, ':');
|
||||
if (arg_v.size() > 0)
|
||||
{
|
||||
for (int j = 0; j < arg_v.size(); j++)
|
||||
{
|
||||
writer.String(arg_v[j].c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < arg_c.size(); i++)
|
||||
{
|
||||
auto arg_v = explode(arg_c[i], ':');
|
||||
for (int j = 0; j < arg_v.size(); j++)
|
||||
{
|
||||
writer.String(arg_v[j].c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
writer.EndObject();
|
||||
return s.GetString();
|
||||
}
|
||||
32
common/web_interface_utils.h
Normal file
32
common/web_interface_utils.h
Normal file
@ -0,0 +1,32 @@
|
||||
/* EQEMu: Everquest Server Emulator
|
||||
Copyright (C) 2001-2014 EQEMu Development Team (http://eqemulator.net)
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; version 2 of the License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY except by those people which sell it, which
|
||||
are required to give you total support for your newly bought product;
|
||||
without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
#ifndef COMMON_WEBINTUTIL_H
|
||||
#define COMMON_WEBINTUTIL_H
|
||||
|
||||
#include "../common/debug.h"
|
||||
#include "rapidjson/writer.h"
|
||||
#include "rapidjson/stringbuffer.h"
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <vector>
|
||||
#include <utility>
|
||||
|
||||
std::string MakeJSON(std::string json);
|
||||
|
||||
#endif
|
||||
|
||||
11
dependencies/.gitignore
vendored
11
dependencies/.gitignore
vendored
@ -1,2 +1,9 @@
|
||||
*.*
|
||||
*
|
||||
boost/
|
||||
luaj_x86/
|
||||
luaj_x64/
|
||||
mysql_x86/
|
||||
mysql_x64/
|
||||
zlib_x86/
|
||||
zlib_x64/
|
||||
cyassl/
|
||||
websocketpp/
|
||||
7
dependencies/CMakeLists.txt
vendored
Normal file
7
dependencies/CMakeLists.txt
vendored
Normal file
@ -0,0 +1,7 @@
|
||||
CMAKE_MINIMUM_REQUIRED(VERSION 2.8)
|
||||
|
||||
IF(EQEMU_BUILD_LUA)
|
||||
ADD_SUBDIRECTORY(luabind)
|
||||
ENDIF(EQEMU_BUILD_LUA)
|
||||
|
||||
ADD_SUBDIRECTORY(libwebsockets)
|
||||
38
dependencies/libwebsockets/.gitignore
vendored
Normal file
38
dependencies/libwebsockets/.gitignore
vendored
Normal file
@ -0,0 +1,38 @@
|
||||
#Ignore build files
|
||||
Makefile
|
||||
config.h
|
||||
config.log
|
||||
config.status
|
||||
libtool
|
||||
stamp-h1
|
||||
output/
|
||||
win32port/ipch/
|
||||
win32port/Debug*/
|
||||
win32port/Release*/
|
||||
win32port/server/Debug*/
|
||||
win32port/server/Release*/
|
||||
win32port/client/Debug*/
|
||||
win32port/client/Release*/
|
||||
win32port/libwebsocketswin32/Debug*/
|
||||
win32port/libwebsocketswin32/Release*/
|
||||
win32port/zlib/Debug*/
|
||||
win32port/zlib/Release*/
|
||||
*.vcxproj.user
|
||||
*.opensdf
|
||||
*.sdf
|
||||
*.suo
|
||||
*.su
|
||||
*.m4
|
||||
missing
|
||||
depcomp
|
||||
install-sh
|
||||
configure
|
||||
compile
|
||||
config.guess
|
||||
*~
|
||||
*.orig
|
||||
autom4te.cache/
|
||||
ltmain.sh
|
||||
config.sub
|
||||
ar-lib
|
||||
libwebsockets.pc
|
||||
29
dependencies/libwebsockets/Android.mk
vendored
Normal file
29
dependencies/libwebsockets/Android.mk
vendored
Normal file
@ -0,0 +1,29 @@
|
||||
# example Android Native Library makefile
|
||||
# contributed by Gregory Junker <ggjunker@gmail.com>
|
||||
|
||||
LOCAL_PATH:= $(call my-dir)
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
LOCAL_MODULE := libwebsockets
|
||||
LOCAL_CFLAGS := -DLWS_BUILTIN_GETIFADDRS
|
||||
LWS_LIB_PATH := ../../../shared/libwebsockets/lib
|
||||
LOCAL_C_INCLUDES:= $(LOCAL_PATH)/$(LWS_LIB_PATH)
|
||||
LOCAL_SRC_FILES := \
|
||||
$(LWS_LIB_PATH)/base64-decode.c \
|
||||
$(LWS_LIB_PATH)/client.c \
|
||||
$(LWS_LIB_PATH)/client-handshake.c \
|
||||
$(LWS_LIB_PATH)/client-parser.c \
|
||||
$(LWS_LIB_PATH)/daemonize.c \
|
||||
$(LWS_LIB_PATH)/extension.c \
|
||||
$(LWS_LIB_PATH)/extension-deflate-frame.c \
|
||||
$(LWS_LIB_PATH)/extension-deflate-stream.c \
|
||||
$(LWS_LIB_PATH)/getifaddrs.c \
|
||||
$(LWS_LIB_PATH)/handshake.c \
|
||||
$(LWS_LIB_PATH)/libwebsockets.c \
|
||||
$(LWS_LIB_PATH)/md5.c \
|
||||
$(LWS_LIB_PATH)/output.c \
|
||||
$(LWS_LIB_PATH)/parsers.c \
|
||||
$(LWS_LIB_PATH)/sha-1.c
|
||||
|
||||
include $(BUILD_STATIC_LIBRARY)
|
||||
914
dependencies/libwebsockets/CMakeLists.txt
vendored
Normal file
914
dependencies/libwebsockets/CMakeLists.txt
vendored
Normal file
@ -0,0 +1,914 @@
|
||||
cmake_minimum_required(VERSION 2.6)
|
||||
|
||||
project(libwebsockets)
|
||||
|
||||
set(PACKAGE "libwebsockets")
|
||||
set(CPACK_PACKAGE_NAME "${PACKAGE}")
|
||||
set(CPACK_PACKAGE_VERSION_MAJOR "1")
|
||||
set(CPACK_PACKAGE_VERSION_MINOR "3")
|
||||
set(CPACK_PACKAGE_VERSION "${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}")
|
||||
set(CPACK_PACKAGE_VENDOR "andy@warmcat.com")
|
||||
set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "${PACKAGE} ${PACKAGE_VERSION}")
|
||||
set(SOVERSION "4.0.0")
|
||||
set(CPACK_SOURCE_GENERATOR "TGZ")
|
||||
set(CPACK_SOURCE_PACKAGE_FILE_NAME "${CPACK_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION}")
|
||||
set(VERSION "${CPACK_PACKAGE_VERSION}")
|
||||
|
||||
set(LWS_LIBRARY_VERSION ${CPACK_PACKAGE_VERSION})
|
||||
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${PROJECT_SOURCE_DIR}/cmake/")
|
||||
|
||||
message(STATUS "CMAKE_TOOLCHAIN_FILE='${CMAKE_TOOLCHAIN_FILE}'")
|
||||
|
||||
# Try to find the current Git hash.
|
||||
find_package(Git)
|
||||
if(GIT_EXECUTABLE)
|
||||
execute_process(
|
||||
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
|
||||
COMMAND "${GIT_EXECUTABLE}" log -n 1 --pretty=%h
|
||||
OUTPUT_VARIABLE GIT_HASH
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
)
|
||||
|
||||
set(LWS_BUILD_HASH ${GIT_HASH})
|
||||
message("Git commit hash: ${LWS_BUILD_HASH}")
|
||||
endif()
|
||||
|
||||
option(LWS_WITH_SSL "Include SSL support (default OpenSSL, CyaSSL if LWS_USE_CYASSL is set)" OFF)
|
||||
option(LWS_SSL_CLIENT_USE_OS_CA_CERTS "SSL support should make use of OS installed CA root certs" ON)
|
||||
option(LWS_USE_EXTERNAL_ZLIB "Search the system for ZLib instead of using the included one (on Windows)" OFF)
|
||||
option(LWS_USE_CYASSL "Use CyaSSL replacement for OpenSSL. When settings this, you also need to specify LWS_CYASSL_LIB and LWS_CYASSL_INCLUDE_DIRS" OFF)
|
||||
option(LWS_WITHOUT_BUILTIN_GETIFADDRS "Don't use BSD getifaddrs implementation from libwebsockets if it is missing (this will result in a compilation error) ... Default is your libc provides it. On some systems such as uclibc it doesn't exist." OFF)
|
||||
option(LWS_WITHOUT_CLIENT "Don't build the client part of the library" ON)
|
||||
option(LWS_WITHOUT_SERVER "Don't build the server part of the library" OFF)
|
||||
option(LWS_LINK_TESTAPPS_DYNAMIC "Link the test apps to the shared version of the library. Default is to link statically" ON)
|
||||
option(LWS_WITHOUT_TESTAPPS "Don't build the libwebsocket-test-apps" ON)
|
||||
option(LWS_WITHOUT_TEST_SERVER "Don't build the test server" ON)
|
||||
option(LWS_WITHOUT_TEST_SERVER_EXTPOLL "Don't build the test server version that uses external poll" ON)
|
||||
option(LWS_WITHOUT_TEST_PING "Don't build the ping test application" ON)
|
||||
option(LWS_WITHOUT_TEST_CLIENT "Don't build the client test application" ON)
|
||||
option(LWS_WITHOUT_TEST_FRAGGLE "Don't build the ping test application" ON)
|
||||
option(LWS_WITHOUT_DEBUG "Don't compile debug related code" OFF)
|
||||
option(LWS_WITHOUT_EXTENSIONS "Don't compile with extensions" OFF)
|
||||
option(LWS_WITH_LATENCY "Build latency measuring code into the library" OFF)
|
||||
option(LWS_WITHOUT_DAEMONIZE "Don't build the daemonization api" OFF)
|
||||
option(LWS_WITH_LIBEV "Compile with support for libev" OFF)
|
||||
option(LWS_IPV6 "Compile with support for ipv6" ON)
|
||||
option(LWS_WITH_HTTP2 "Compile with support for http2" OFF)
|
||||
|
||||
# Allow the user to override installation directories.
|
||||
set(LWS_INSTALL_LIB_DIR lib CACHE PATH "Installation directory for libraries")
|
||||
set(LWS_INSTALL_BIN_DIR "." CACHE PATH "Installation directory for executables")
|
||||
set(LWS_INSTALL_INCLUDE_DIR include CACHE PATH "Installation directory for header files")
|
||||
set(LWS_INSTALL_EXAMPLES_DIR "." CACHE PATH "Installation directory for example files")
|
||||
|
||||
if (LWS_WITHOUT_CLIENT AND LWS_WITHOUT_SERVER)
|
||||
message(FATAL_ERROR "Makes no sense to compile without both client or server.")
|
||||
endif()
|
||||
|
||||
# The base dir where the test-apps look for the SSL certs.
|
||||
set(LWS_OPENSSL_CLIENT_CERTS ../share CACHE PATH "Server SSL certificate directory")
|
||||
if (WIN32)
|
||||
set(LWS_OPENSSL_CLIENT_CERTS . CACHE PATH "Client SSL certificate directory")
|
||||
|
||||
if (LWS_IPV6)
|
||||
set(LWS_IPV6 OFF)
|
||||
message(WARNING "IPv6 does currently not work on Windows!")
|
||||
endif()
|
||||
else()
|
||||
set(LWS_OPENSSL_CLIENT_CERTS /etc/pki/tls/certs/ CACHE PATH "Client SSL certificate directory")
|
||||
endif()
|
||||
|
||||
set(LWS_CYASSL_LIB CACHE PATH "Path to the CyaSSL library")
|
||||
set(LWS_CYASSL_INCLUDE_DIRS CACHE PATH "Path to the CyaSSL include directory")
|
||||
|
||||
if (LWS_USE_CYASSL)
|
||||
if ("${LWS_CYASSL_LIB}" STREQUAL "" OR "${LWS_CYASSL_INCLUDE_DIRS}" STREQUAL "")
|
||||
message(FATAL_ERROR "You must set LWS_CYASSL_LIB and LWS_CYASSL_INCLUDE_DIRS when LWS_USE_CYASSL is turned on")
|
||||
endif()
|
||||
set(USE_CYASSL 1)
|
||||
endif()
|
||||
|
||||
if (LWS_WITHOUT_EXTENSIONS)
|
||||
set(LWS_NO_EXTENSIONS 1)
|
||||
endif()
|
||||
|
||||
if (LWS_WITH_SSL)
|
||||
set(LWS_OPENSSL_SUPPORT 1)
|
||||
endif()
|
||||
|
||||
if (LWS_SSL_CLIENT_USE_OS_CA_CERTS)
|
||||
set(LWS_SSL_CLIENT_USE_OS_CA_CERTS 1)
|
||||
endif()
|
||||
|
||||
if (LWS_WITH_LATENCY)
|
||||
set(LWS_LATENCY 1)
|
||||
endif()
|
||||
|
||||
if (LWS_WITHOUT_DAEMONIZE OR WIN32)
|
||||
set(LWS_NO_DAEMONIZE 1)
|
||||
endif()
|
||||
|
||||
if (LWS_WITHOUT_SERVER)
|
||||
set(LWS_NO_SERVER 1)
|
||||
endif()
|
||||
|
||||
if (LWS_WITHOUT_CLIENT)
|
||||
set(LWS_NO_CLIENT 1)
|
||||
endif()
|
||||
|
||||
if (LWS_WITHOUT_DEBUG)
|
||||
set(_DEBUG 0)
|
||||
else()
|
||||
set(_DEBUG 1)
|
||||
endif()
|
||||
|
||||
if (LWS_WITH_LIBEV)
|
||||
set(LWS_USE_LIBEV 1)
|
||||
set(LWS_NO_EXTERNAL_POLL 1)
|
||||
endif()
|
||||
|
||||
if (LWS_IPV6)
|
||||
set(LWS_USE_IPV6 1)
|
||||
endif()
|
||||
|
||||
if (LWS_WITH_HTTP2)
|
||||
set(LWS_USE_HTTP2 1)
|
||||
endif()
|
||||
|
||||
if (MINGW)
|
||||
set(LWS_MINGW_SUPPORT 1)
|
||||
endif()
|
||||
|
||||
include_directories("${PROJECT_BINARY_DIR}")
|
||||
|
||||
include(CheckCSourceCompiles)
|
||||
|
||||
# Check for different inline keyword versions.
|
||||
foreach(KEYWORD "inline" "__inline__" "__inline")
|
||||
set(CMAKE_REQUIRED_DEFINITIONS "-DKEYWORD=${KEYWORD}")
|
||||
CHECK_C_SOURCE_COMPILES(
|
||||
"
|
||||
#include <stdio.h>
|
||||
KEYWORD void a() {}
|
||||
int main(int argc, char **argv) { a(); return 0; }
|
||||
" HAVE_${KEYWORD})
|
||||
endforeach()
|
||||
|
||||
if (NOT HAVE_inline)
|
||||
if (HAVE___inline__)
|
||||
set(inline __inline__)
|
||||
elseif(HAVE___inline)
|
||||
set(inline __inline)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Put the libaries and binaries that get built into directories at the
|
||||
# top of the build tree rather than in hard-to-find leaf directories.
|
||||
SET(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/bin")
|
||||
SET(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/lib")
|
||||
SET(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/lib")
|
||||
|
||||
# Put absolute path of dynamic libraries into the object code. Some
|
||||
# architectures, notably Mac OS X, need this.
|
||||
SET(CMAKE_INSTALL_NAME_DIR "${CMAKE_INSTALL_PREFIX}/${LWS_INSTALL_LIB_DIR}${LIB_SUFFIX}")
|
||||
|
||||
# So we can include the CMake generated config file only when
|
||||
# building with CMAKE.
|
||||
add_definitions(-DCMAKE_BUILD)
|
||||
|
||||
include(CheckFunctionExists)
|
||||
include(CheckIncludeFile)
|
||||
include(CheckIncludeFiles)
|
||||
include(CheckLibraryExists)
|
||||
include(CheckTypeSize)
|
||||
|
||||
CHECK_FUNCTION_EXISTS(bzero HAVE_BZERO)
|
||||
CHECK_FUNCTION_EXISTS(fork HAVE_FORK)
|
||||
CHECK_FUNCTION_EXISTS(getenv HAVE_GETENV)
|
||||
CHECK_FUNCTION_EXISTS(malloc HAVE_MALLOC)
|
||||
CHECK_FUNCTION_EXISTS(memset HAVE_MEMSET)
|
||||
CHECK_FUNCTION_EXISTS(realloc HAVE_REALLOC)
|
||||
CHECK_FUNCTION_EXISTS(socket HAVE_SOCKET)
|
||||
CHECK_FUNCTION_EXISTS(strerror HAVE_STRERROR)
|
||||
CHECK_FUNCTION_EXISTS(vfork HAVE_VFORK)
|
||||
CHECK_FUNCTION_EXISTS(getifaddrs HAVE_GETIFADDRS)
|
||||
|
||||
if (NOT HAVE_GETIFADDRS)
|
||||
if (LWS_WITHOUT_BUILTIN_GETIFADDRS)
|
||||
message(FATAL_ERROR "No getifaddrs was found on the system. Turn off the LWS_WITHOUT_BUILTIN_GETIFADDRS compile option to use the supplied BSD version.")
|
||||
endif()
|
||||
|
||||
set(LWS_BUILTIN_GETIFADDRS 1)
|
||||
endif()
|
||||
|
||||
CHECK_INCLUDE_FILE(dlfcn.h HAVE_DLFCN_H)
|
||||
CHECK_INCLUDE_FILE(fcntl.h HAVE_FCNTL_H)
|
||||
CHECK_INCLUDE_FILE(in6addr.h HAVE_IN6ADDR_H)
|
||||
CHECK_INCLUDE_FILE(inttypes.h HAVE_INTTYPES_H)
|
||||
CHECK_INCLUDE_FILE(memory.h HAVE_MEMORY_H)
|
||||
CHECK_INCLUDE_FILE(netinet/in.h HAVE_NETINET_IN_H)
|
||||
CHECK_INCLUDE_FILE(stdint.h HAVE_STDINT_H)
|
||||
CHECK_INCLUDE_FILE(stdlib.h HAVE_STDLIB_H)
|
||||
CHECK_INCLUDE_FILE(strings.h HAVE_STRINGS_H)
|
||||
CHECK_INCLUDE_FILE(string.h HAVE_STRING_H)
|
||||
CHECK_INCLUDE_FILE(sys/prctl.h HAVE_SYS_PRCTL_H)
|
||||
CHECK_INCLUDE_FILE(sys/socket.h HAVE_SYS_SOCKET_H)
|
||||
CHECK_INCLUDE_FILE(sys/stat.h HAVE_SYS_STAT_H)
|
||||
CHECK_INCLUDE_FILE(sys/types.h HAVE_SYS_TYPES_H)
|
||||
CHECK_INCLUDE_FILE(unistd.h HAVE_UNISTD_H)
|
||||
CHECK_INCLUDE_FILE(vfork.h HAVE_VFORK_H)
|
||||
CHECK_INCLUDE_FILE(zlib.h HAVE_ZLIB_H)
|
||||
|
||||
# TODO: These can be tested if they actually work also...
|
||||
set(HAVE_WORKING_FORK HAVE_FORK)
|
||||
set(HAVE_WORKING_VFORK HAVE_VFORK)
|
||||
|
||||
CHECK_INCLUDE_FILES("stdlib.h;stdarg.h;string.h;float.h" STDC_HEADERS)
|
||||
|
||||
CHECK_TYPE_SIZE(pid_t PID_T_SIZE)
|
||||
CHECK_TYPE_SIZE(size_t SIZE_T_SIZE)
|
||||
|
||||
if (NOT PID_T_SIZE)
|
||||
set(pid_t int)
|
||||
endif()
|
||||
|
||||
if (NOT SIZE_T_SIZE)
|
||||
set(size_t "unsigned int")
|
||||
endif()
|
||||
|
||||
if (NOT HAVE_MALLOC)
|
||||
set(malloc rpl_malloc)
|
||||
endif()
|
||||
|
||||
if (NOT HAVE_REALLOC)
|
||||
set(realloc rpl_realloc)
|
||||
endif()
|
||||
|
||||
# Generate the config.h that includes all the compilation settings.
|
||||
configure_file(
|
||||
"${PROJECT_SOURCE_DIR}/config.h.cmake"
|
||||
"${PROJECT_BINARY_DIR}/lws_config.h")
|
||||
|
||||
if (MSVC)
|
||||
# Turn off stupid microsoft security warnings.
|
||||
add_definitions(-D_CRT_SECURE_NO_DEPRECATE -D_CRT_NONSTDC_NO_DEPRECATE)
|
||||
endif(MSVC)
|
||||
|
||||
include_directories("${PROJECT_SOURCE_DIR}/lib")
|
||||
|
||||
# Group headers and sources.
|
||||
# Some IDEs use this for nicer file structure.
|
||||
set(HDR_PRIVATE
|
||||
lib/private-libwebsockets.h
|
||||
"${PROJECT_BINARY_DIR}/lws_config.h"
|
||||
)
|
||||
|
||||
set(HDR_PUBLIC
|
||||
"${PROJECT_SOURCE_DIR}/lib/libwebsockets.h"
|
||||
)
|
||||
|
||||
set(SOURCES
|
||||
lib/base64-decode.c
|
||||
lib/handshake.c
|
||||
lib/libwebsockets.c
|
||||
lib/service.c
|
||||
lib/pollfd.c
|
||||
lib/output.c
|
||||
lib/parsers.c
|
||||
lib/context.c
|
||||
lib/sha-1.c
|
||||
)
|
||||
|
||||
if (NOT LWS_WITHOUT_CLIENT)
|
||||
list(APPEND SOURCES
|
||||
lib/client.c
|
||||
lib/client-handshake.c
|
||||
lib/client-parser.c
|
||||
)
|
||||
endif()
|
||||
|
||||
if (LWS_WITH_SSL)
|
||||
list(APPEND SOURCES
|
||||
lib/ssl.c
|
||||
)
|
||||
endif()
|
||||
|
||||
if (LWS_WITH_HTTP2)
|
||||
list(APPEND SOURCES
|
||||
lib/ssl-http2.c
|
||||
)
|
||||
endif()
|
||||
# select the active platform files
|
||||
|
||||
if (WIN32)
|
||||
list(APPEND SOURCES
|
||||
lib/lws-plat-win.c
|
||||
)
|
||||
else()
|
||||
list(APPEND SOURCES
|
||||
lib/lws-plat-unix.c
|
||||
)
|
||||
endif()
|
||||
|
||||
if (NOT LWS_WITHOUT_SERVER)
|
||||
list(APPEND SOURCES
|
||||
lib/server.c
|
||||
lib/server-handshake.c
|
||||
)
|
||||
endif()
|
||||
|
||||
if (NOT LWS_WITHOUT_EXTENSIONS)
|
||||
list(APPEND HDR_PRIVATE
|
||||
lib/extension-deflate-frame.h
|
||||
lib/extension-deflate-stream.h
|
||||
)
|
||||
|
||||
list(APPEND SOURCES
|
||||
lib/extension.c
|
||||
lib/extension-deflate-frame.c
|
||||
lib/extension-deflate-stream.c
|
||||
)
|
||||
endif()
|
||||
|
||||
if (LWS_WITH_LIBEV)
|
||||
list(APPEND SOURCES
|
||||
lib/libev.c
|
||||
)
|
||||
endif(LWS_WITH_LIBEV)
|
||||
|
||||
# Add helper files for Windows.
|
||||
if (WIN32)
|
||||
set(WIN32_HELPERS_PATH win32port/win32helpers)
|
||||
include_directories(${WIN32_HELPERS_PATH})
|
||||
else(WIN32)
|
||||
# Unix.
|
||||
if (NOT LWS_WITHOUT_DAEMONIZE)
|
||||
list(APPEND SOURCES
|
||||
lib/daemonize.c
|
||||
)
|
||||
endif()
|
||||
endif(WIN32)
|
||||
|
||||
if (UNIX)
|
||||
if (NOT HAVE_GETIFADDRS)
|
||||
list(APPEND HDR_PRIVATE lib/getifaddrs.h)
|
||||
list(APPEND SOURCES lib/getifaddrs.c)
|
||||
endif()
|
||||
endif(UNIX)
|
||||
|
||||
|
||||
if (CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX)
|
||||
if (UNIX)
|
||||
set( CMAKE_C_FLAGS "-Wall -Werror -O4 -fvisibility=hidden ${CMAKE_C_FLAGS}" )
|
||||
else(UNIX)
|
||||
set( CMAKE_C_FLAGS "-Wall -O4 -fvisibility=hidden ${CMAKE_C_FLAGS}" )
|
||||
endif(UNIX)
|
||||
endif ()
|
||||
|
||||
source_group("Headers Private" FILES ${HDR_PRIVATE})
|
||||
source_group("Headers Public" FILES ${HDR_PUBLIC})
|
||||
source_group("Sources" FILES ${SOURCES})
|
||||
|
||||
#
|
||||
# Create the lib.
|
||||
#
|
||||
add_library(websockets STATIC
|
||||
${HDR_PRIVATE}
|
||||
${HDR_PUBLIC}
|
||||
${SOURCES})
|
||||
add_library(websockets_shared SHARED
|
||||
${HDR_PRIVATE}
|
||||
${HDR_PUBLIC}
|
||||
${SOURCES})
|
||||
|
||||
if (WIN32)
|
||||
# On Windows libs have the same file ending (.lib)
|
||||
# for both static and shared libraries, so we
|
||||
# need a unique name for the static one.
|
||||
set_target_properties(websockets
|
||||
PROPERTIES
|
||||
OUTPUT_NAME websockets_static)
|
||||
|
||||
# Compile as DLL (export function declarations)
|
||||
set_property(
|
||||
TARGET websockets_shared
|
||||
PROPERTY COMPILE_DEFINITIONS
|
||||
LWS_DLL
|
||||
LWS_INTERNAL
|
||||
)
|
||||
endif(WIN32)
|
||||
|
||||
# We want the shared lib to be named "libwebsockets"
|
||||
# not "libwebsocket_shared".
|
||||
set_target_properties(websockets_shared
|
||||
PROPERTIES
|
||||
OUTPUT_NAME websockets)
|
||||
|
||||
# Set the so version of the lib.
|
||||
# Equivalent to LDFLAGS=-version-info x:x:x
|
||||
if(CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX)
|
||||
foreach(lib websockets websockets_shared)
|
||||
set_target_properties(${lib}
|
||||
PROPERTIES
|
||||
SOVERSION ${SOVERSION})
|
||||
endforeach()
|
||||
endif()
|
||||
|
||||
set(LIB_LIST)
|
||||
|
||||
#
|
||||
# Find libraries.
|
||||
#
|
||||
|
||||
#
|
||||
# ZLIB (Only needed for deflate extensions).
|
||||
#
|
||||
if (NOT LWS_WITHOUT_EXTENSIONS)
|
||||
if (WIN32 AND NOT LWS_USE_EXTERNAL_ZLIB)
|
||||
message("Using included Zlib version")
|
||||
|
||||
# Compile ZLib if needed.
|
||||
set(WIN32_ZLIB_PATH "win32port/zlib")
|
||||
set(ZLIB_SRCS
|
||||
${WIN32_ZLIB_PATH}/adler32.c
|
||||
${WIN32_ZLIB_PATH}/compress.c
|
||||
${WIN32_ZLIB_PATH}/crc32.c
|
||||
${WIN32_ZLIB_PATH}/deflate.c
|
||||
${WIN32_ZLIB_PATH}/gzclose.c
|
||||
${WIN32_ZLIB_PATH}/gzio.c
|
||||
${WIN32_ZLIB_PATH}/gzlib.c
|
||||
${WIN32_ZLIB_PATH}/gzread.c
|
||||
${WIN32_ZLIB_PATH}/gzwrite.c
|
||||
${WIN32_ZLIB_PATH}/infback.c
|
||||
${WIN32_ZLIB_PATH}/inffast.c
|
||||
${WIN32_ZLIB_PATH}/inflate.c
|
||||
${WIN32_ZLIB_PATH}/inftrees.c
|
||||
${WIN32_ZLIB_PATH}/trees.c
|
||||
${WIN32_ZLIB_PATH}/uncompr.c
|
||||
${WIN32_ZLIB_PATH}/zutil.c
|
||||
)
|
||||
|
||||
# Create the library.
|
||||
add_library(ZLIB STATIC ${ZLIB_SRCS})
|
||||
|
||||
# Set the same variables as find_package would.
|
||||
set(ZLIB_INCLUDE_DIRS ${WIN32_ZLIB_PATH})
|
||||
get_property(ZLIB_LIBRARIES TARGET ZLIB PROPERTY LOCATION)
|
||||
set(ZLIB_FOUND 1)
|
||||
else()
|
||||
find_package(ZLIB REQUIRED)
|
||||
endif()
|
||||
|
||||
# Make sure ZLib is compiled before the libs.
|
||||
foreach (lib websockets websockets_shared)
|
||||
add_dependencies(${lib} ZLIB)
|
||||
endforeach()
|
||||
|
||||
message("ZLib include dirs: ${ZLIB_INCLUDE_DIRS}")
|
||||
message("ZLib libraries: ${ZLIB_LIBRARIES}")
|
||||
include_directories(${ZLIB_INCLUDE_DIRS})
|
||||
list(APPEND LIB_LIST ${ZLIB_LIBRARIES})
|
||||
endif(NOT LWS_WITHOUT_EXTENSIONS)
|
||||
|
||||
#
|
||||
# OpenSSL
|
||||
#
|
||||
if (LWS_WITH_SSL)
|
||||
message("Compiling with SSL support")
|
||||
|
||||
if (LWS_USE_CYASSL)
|
||||
# Use CyaSSL as OpenSSL replacement.
|
||||
# TODO: Add a find_package command for this also.
|
||||
message("CyaSSL include dir: ${LWS_CYASSL_INCLUDE_DIRS}")
|
||||
message("CyaSSL libraries: ${LWS_CYASSL_LIB}")
|
||||
|
||||
# Additional to the root directory we need to include
|
||||
# the cyassl/ subdirectory which contains the OpenSSL
|
||||
# compatability layer headers.
|
||||
foreach(inc ${LWS_CYASSL_INCLUDE_DIRS})
|
||||
include_directories("${inc}" "${inc}/cyassl")
|
||||
endforeach()
|
||||
|
||||
list(APPEND LIB_LIST "${LWS_CYASSL_LIB}")
|
||||
else()
|
||||
# TODO: Add support for STATIC also.
|
||||
find_package(OpenSSL REQUIRED)
|
||||
|
||||
message("OpenSSL include dir: ${OPENSSL_INCLUDE_DIR}")
|
||||
message("OpenSSL libraries: ${OPENSSL_LIBRARIES}")
|
||||
|
||||
include_directories("${OPENSSL_INCLUDE_DIR}")
|
||||
list(APPEND LIB_LIST ${OPENSSL_LIBRARIES})
|
||||
|
||||
# Link against dynamic linking functions.
|
||||
# (Don't link directly to libdl since it is not needed on all platforms, it's now a part of libc).
|
||||
list(APPEND LIB_LIST ${CMAKE_DL_LIBS})
|
||||
endif()
|
||||
endif(LWS_WITH_SSL)
|
||||
|
||||
if (LWS_WITH_LIBEV)
|
||||
list(APPEND LIB_LIST "ev")
|
||||
endif(LWS_WITH_LIBEV)
|
||||
|
||||
#
|
||||
# Platform specific libs.
|
||||
#
|
||||
if (WINCE)
|
||||
list(APPEND LIB_LIST ws2.lib)
|
||||
elseif (WIN32)
|
||||
list(APPEND LIB_LIST ws2_32.lib)
|
||||
endif()
|
||||
|
||||
if (UNIX)
|
||||
list(APPEND LIB_LIST m)
|
||||
endif()
|
||||
|
||||
# Setup the linking for all libs.
|
||||
foreach (lib websockets websockets_shared)
|
||||
target_link_libraries(${lib} ${LIB_LIST})
|
||||
endforeach()
|
||||
|
||||
#
|
||||
# Test applications
|
||||
#
|
||||
set(TEST_APP_LIST)
|
||||
if (NOT LWS_WITHOUT_TESTAPPS)
|
||||
#
|
||||
# Helper function for adding a test app.
|
||||
#
|
||||
macro(create_test_app TEST_NAME MAIN_SRC)
|
||||
|
||||
set(TEST_SRCS ${MAIN_SRC})
|
||||
set(TEST_HDR)
|
||||
|
||||
if (WIN32)
|
||||
list(APPEND TEST_SRCS
|
||||
${WIN32_HELPERS_PATH}/getopt.c
|
||||
${WIN32_HELPERS_PATH}/getopt_long.c
|
||||
${WIN32_HELPERS_PATH}/gettimeofday.c
|
||||
)
|
||||
|
||||
list(APPEND TEST_HDR
|
||||
${WIN32_HELPERS_PATH}/getopt.h
|
||||
${WIN32_HELPERS_PATH}/gettimeofday.h
|
||||
)
|
||||
endif(WIN32)
|
||||
|
||||
source_group("Headers Private" FILES ${TEST_HDR})
|
||||
source_group("Sources" FILES ${TEST_SRCS})
|
||||
add_executable(${TEST_NAME} ${TEST_SRCS} ${TEST_HDR})
|
||||
|
||||
if (LWS_LINK_TESTAPPS_DYNAMIC)
|
||||
target_link_libraries(${TEST_NAME} websockets_shared)
|
||||
add_dependencies(${TEST_NAME} websockets_shared)
|
||||
else(LWS_LINK_TESTAPPS_DYNAMIC)
|
||||
target_link_libraries(${TEST_NAME} websockets)
|
||||
add_dependencies(${TEST_NAME} websockets)
|
||||
endif(LWS_LINK_TESTAPPS_DYNAMIC)
|
||||
|
||||
# Set test app specific defines.
|
||||
set_property(TARGET ${TEST_NAME}
|
||||
PROPERTY COMPILE_DEFINITIONS
|
||||
INSTALL_DATADIR="${CMAKE_INSTALL_PREFIX}/share"
|
||||
)
|
||||
|
||||
# Prefix the binary names with libwebsockets.
|
||||
set_target_properties(${TEST_NAME}
|
||||
PROPERTIES
|
||||
OUTPUT_NAME libwebsockets-${TEST_NAME})
|
||||
|
||||
# Add to the list of tests.
|
||||
list(APPEND TEST_APP_LIST ${TEST_NAME})
|
||||
endmacro()
|
||||
|
||||
if (LWS_WITH_SSL AND NOT LWS_USE_CYASSL)
|
||||
message("Searching for OpenSSL executable and dlls")
|
||||
find_package(OpenSSLbins)
|
||||
message("OpenSSL executable: ${OPENSSL_EXECUTABLE}")
|
||||
endif()
|
||||
|
||||
if (NOT LWS_WITHOUT_SERVER)
|
||||
#
|
||||
# test-server
|
||||
#
|
||||
if (NOT LWS_WITHOUT_TEST_SERVER)
|
||||
create_test_app(test-server "test-server/test-server.c")
|
||||
endif()
|
||||
|
||||
#
|
||||
# test-server-extpoll
|
||||
#
|
||||
if (NOT LWS_WITHOUT_TEST_SERVER_EXTPOLL)
|
||||
create_test_app(test-server-extpoll "test-server/test-server.c")
|
||||
# Set defines for this executable only.
|
||||
set_property(
|
||||
TARGET test-server-extpoll
|
||||
PROPERTY COMPILE_DEFINITIONS
|
||||
EXTERNAL_POLL
|
||||
INSTALL_DATADIR="${CMAKE_INSTALL_PREFIX}/share"
|
||||
)
|
||||
|
||||
# We need to link against winsock code.
|
||||
if (WIN32)
|
||||
target_link_libraries(test-server-extpoll ws2_32.lib)
|
||||
endif(WIN32)
|
||||
endif()
|
||||
|
||||
# Data files for running the test server.
|
||||
set(TEST_SERVER_DATA
|
||||
"${PROJECT_SOURCE_DIR}/test-server/favicon.ico"
|
||||
"${PROJECT_SOURCE_DIR}/test-server/leaf.jpg"
|
||||
"${PROJECT_SOURCE_DIR}/test-server/libwebsockets.org-logo.png"
|
||||
"${PROJECT_SOURCE_DIR}/test-server/test.html")
|
||||
|
||||
# Generate self-signed SSL certs for the test-server.
|
||||
if (LWS_WITH_SSL AND OPENSSL_EXECUTABLE AND NOT LWS_WITHOUT_TEST_SERVER)
|
||||
message("Generating SSL Certificates for the test-server...")
|
||||
|
||||
set(TEST_SERVER_SSL_KEY "${PROJECT_BINARY_DIR}/libwebsockets-test-server.key.pem")
|
||||
set(TEST_SERVER_SSL_CERT "${PROJECT_BINARY_DIR}/libwebsockets-test-server.pem")
|
||||
|
||||
if (WIN32)
|
||||
file(WRITE "${PROJECT_BINARY_DIR}/openssl_input.txt"
|
||||
"GB\n"
|
||||
"Erewhon\n"
|
||||
"All around\n"
|
||||
"libwebsockets-test\n"
|
||||
"localhost\n"
|
||||
"none@invalid.org\n\n"
|
||||
)
|
||||
|
||||
# The "type" command is a bit picky with paths.
|
||||
file(TO_NATIVE_PATH "${PROJECT_BINARY_DIR}/openssl_input.txt" OPENSSL_INPUT_WIN_PATH)
|
||||
message("OPENSSL_INPUT_WIN_PATH = ${OPENSSL_INPUT_WIN_PATH}")
|
||||
message("cmd = \"${OPENSSL_EXECUTABLE}\" req -new -newkey rsa:1024 -days 10000 -nodes -x509 -keyout \"${TEST_SERVER_SSL_KEY}\" -out \"${TEST_SERVER_SSL_CERT}\"")
|
||||
|
||||
execute_process(
|
||||
COMMAND cmd /c type "${OPENSSL_INPUT_WIN_PATH}"
|
||||
COMMAND "${OPENSSL_EXECUTABLE}" req -new -newkey rsa:1024 -days 10000 -nodes -x509 -keyout "${TEST_SERVER_SSL_KEY}" -out "${TEST_SERVER_SSL_CERT}"
|
||||
RESULT_VARIABLE OPENSSL_RETURN_CODE)
|
||||
|
||||
message("\n")
|
||||
|
||||
if (OPENSSL_RETURN_CODE)
|
||||
message(WARNING "!!! Failed to generate SSL certificate for Test Server using cmd.exe !!!:\nOpenSSL return code = ${OPENSSL_RETURN_CODE}")
|
||||
else()
|
||||
message("SUCCSESFULLY generated SSL certificate")
|
||||
endif()
|
||||
else()
|
||||
# Unix.
|
||||
execute_process(
|
||||
COMMAND printf "GB\\nErewhon\\nAll around\\nlibwebsockets-test\\n\\nlocalhost\\nnone@invalid.org\\n"
|
||||
COMMAND "${OPENSSL_EXECUTABLE}"
|
||||
req -new -newkey rsa:1024 -days 10000 -nodes -x509 -keyout "${TEST_SERVER_SSL_KEY}" -out "${TEST_SERVER_SSL_CERT}"
|
||||
RESULT_VARIABLE OPENSSL_RETURN_CODE)
|
||||
|
||||
if (OPENSSL_RETURN_CODE)
|
||||
message(WARNING "!!! Failed to generate SSL certificate for Test Server!!!:\nOpenSSL return code = ${OPENSSL_RETURN_CODE}")
|
||||
else()
|
||||
message("SUCCSESFULLY generated SSL certificate")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
list(APPEND TEST_SERVER_DATA
|
||||
"${TEST_SERVER_SSL_KEY}"
|
||||
"${TEST_SERVER_SSL_CERT}")
|
||||
endif()
|
||||
|
||||
add_custom_command(TARGET test-server
|
||||
POST_BUILD
|
||||
COMMAND "${CMAKE_COMMAND}" -E make_directory "$<TARGET_FILE_DIR:test-server>/../share/libwebsockets-test-server")
|
||||
|
||||
# Copy the file needed to run the server so that the test apps can
|
||||
# reach them from their default output location
|
||||
foreach (TEST_FILE ${TEST_SERVER_DATA})
|
||||
if (EXISTS ${TEST_FILE})
|
||||
add_custom_command(TARGET test-server
|
||||
POST_BUILD
|
||||
COMMAND "${CMAKE_COMMAND}" -E copy "${TEST_FILE}" "$<TARGET_FILE_DIR:test-server>/../share/libwebsockets-test-server" VERBATIM)
|
||||
endif()
|
||||
endforeach()
|
||||
endif(NOT LWS_WITHOUT_SERVER)
|
||||
|
||||
if (NOT LWS_WITHOUT_CLIENT)
|
||||
#
|
||||
# test-client
|
||||
#
|
||||
if (NOT LWS_WITHOUT_TEST_CLIENT)
|
||||
create_test_app(test-client "test-server/test-client.c")
|
||||
endif()
|
||||
|
||||
#
|
||||
# test-fraggle
|
||||
#
|
||||
if (NOT LWS_WITHOUT_TEST_FRAGGLE)
|
||||
create_test_app(test-fraggle "test-server/test-fraggle.c")
|
||||
endif()
|
||||
|
||||
#
|
||||
# test-ping
|
||||
#
|
||||
if (NOT LWS_WITHOUT_TEST_PING)
|
||||
create_test_app(test-ping "test-server/test-ping.c")
|
||||
endif()
|
||||
#
|
||||
# test-echo
|
||||
#
|
||||
if (NOT WITHOUT_TEST_ECHO)
|
||||
create_test_app(test-echo "test-server/test-echo.c")
|
||||
endif()
|
||||
|
||||
endif(NOT LWS_WITHOUT_CLIENT)
|
||||
|
||||
#
|
||||
# Copy OpenSSL dlls to the output directory on Windows.
|
||||
# (Otherwise we'll get an error when trying to run)
|
||||
#
|
||||
if (WIN32 AND LWS_WITH_SSL AND NOT LWS_USE_CYASSL)
|
||||
if(OPENSSL_BIN_FOUND)
|
||||
message("OpenSSL dlls found:")
|
||||
message(" Libeay: ${LIBEAY_BIN}")
|
||||
message(" SSLeay: ${SSLEAY_BIN}")
|
||||
|
||||
foreach(TARGET_BIN ${TEST_APP_LIST})
|
||||
add_custom_command(TARGET ${TARGET_BIN}
|
||||
POST_BUILD
|
||||
COMMAND "${CMAKE_COMMAND}" -E copy "${LIBEAY_BIN}" "$<TARGET_FILE_DIR:${TARGET_BIN}>" VERBATIM)
|
||||
|
||||
add_custom_command(TARGET ${TARGET_BIN}
|
||||
POST_BUILD
|
||||
COMMAND "${CMAKE_COMMAND}" -E copy "${SSLEAY_BIN}" "$<TARGET_FILE_DIR:${TARGET_BIN}>" VERBATIM)
|
||||
endforeach()
|
||||
endif()
|
||||
endif()
|
||||
endif(NOT LWS_WITHOUT_TESTAPPS)
|
||||
|
||||
if (UNIX)
|
||||
# Generate documentation.
|
||||
# TODO: Fix this on Windows.
|
||||
message("Generating API documentation")
|
||||
file(GLOB C_FILES "${PROJECT_SOURCE_DIR}/lib/*.c")
|
||||
execute_process(COMMAND "${CMAKE_COMMAND}" -E make_directory "${PROJECT_BINARY_DIR}/doc/")
|
||||
|
||||
execute_process(
|
||||
COMMAND "${PROJECT_SOURCE_DIR}/scripts/kernel-doc" -html ${C_FILES} ${HDR_PUBLIC}
|
||||
OUTPUT_FILE "${PROJECT_BINARY_DIR}/doc/libwebsockets-api-doc.html"
|
||||
ERROR_QUIET)
|
||||
|
||||
execute_process(
|
||||
COMMAND "${PROJECT_SOURCE_DIR}/scripts/kernel-doc" -text ${C_FILES} ${HDR_PUBLIC}
|
||||
OUTPUT_FILE "${PROJECT_BINARY_DIR}/doc/libwebsockets-api-doc.txt"
|
||||
ERROR_QUIET)
|
||||
|
||||
# Generate and install pkgconfig.
|
||||
# (This is not indented, because the tabs will be part of the output)
|
||||
file(WRITE "${PROJECT_BINARY_DIR}/libwebsockets.pc"
|
||||
"prefix=\"${CMAKE_INSTALL_PREFIX}\"
|
||||
exec_prefix=\${prefix}
|
||||
libdir=\${exec_prefix}/lib${LIB_SUFFIX}
|
||||
includedir=\${prefix}/include
|
||||
|
||||
Name: libwebsockets
|
||||
Description: Websockets server and client library
|
||||
Version: ${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}
|
||||
|
||||
Libs: -L\${libdir} -lwebsockets
|
||||
Cflags: -I\${includedir}"
|
||||
)
|
||||
|
||||
install(FILES "${PROJECT_BINARY_DIR}/libwebsockets.pc"
|
||||
DESTINATION lib${LIB_SUFFIX}/pkgconfig)
|
||||
endif(UNIX)
|
||||
|
||||
#
|
||||
# Installation preparations.
|
||||
#
|
||||
|
||||
if(WIN32 AND NOT CYGWIN)
|
||||
set(DEF_INSTALL_CMAKE_DIR cmake)
|
||||
else()
|
||||
set(DEF_INSTALL_CMAKE_DIR lib/cmake/libwebsockets)
|
||||
endif()
|
||||
|
||||
set(LWS_INSTALL_CMAKE_DIR ${DEF_INSTALL_CMAKE_DIR} CACHE PATH "Installation directory for CMake files")
|
||||
|
||||
# Export targets (This is used for other CMake projects to easily find the libraries and include files).
|
||||
export(TARGETS websockets websockets_shared
|
||||
FILE "${PROJECT_BINARY_DIR}/LibwebsocketsTargets.cmake")
|
||||
export(PACKAGE libwebsockets)
|
||||
|
||||
# Generate the config file for the build-tree.
|
||||
set(LWS__INCLUDE_DIRS
|
||||
"${PROJECT_SOURCE_DIR}/lib"
|
||||
"${PROJECT_BINARY_DIR}")
|
||||
set(LIBWEBSOCKETS_INCLUDE_DIRS ${LWS__INCLUDE_DIRS} CACHE PATH "Libwebsockets include directories")
|
||||
configure_file(${PROJECT_SOURCE_DIR}/cmake/LibwebsocketsConfig.cmake.in
|
||||
${PROJECT_BINARY_DIR}/LibwebsocketsConfig.cmake
|
||||
@ONLY)
|
||||
|
||||
# Generate the config file for the installation tree.
|
||||
get_filename_component(LWS_ABSOLUTE_INSTALL_CMAKE_DIR ${LWS_INSTALL_CMAKE_DIR} ABSOLUTE)
|
||||
get_filename_component(LWS_ABSOLUTE_INSTALL_INCLUDE_DIR ${LWS_INSTALL_INCLUDE_DIR} ABSOLUTE)
|
||||
file(RELATIVE_PATH
|
||||
REL_INCLUDE_DIR
|
||||
"${LWS_ABSOLUTE_INSTALL_CMAKE_DIR}"
|
||||
"${LWS_ABSOLUTE_INSTALL_INCLUDE_DIR}") # Calculate the relative directory from the cmake dir.
|
||||
|
||||
# Note the EVENT_CMAKE_DIR is defined in JanssonConfig.cmake.in,
|
||||
# we escape it here so it's evaluated when it is included instead
|
||||
# so that the include dirs are given relative to where the
|
||||
# config file is located.
|
||||
set(LWS__INCLUDE_DIRS
|
||||
"\${LWS_CMAKE_DIR}/${REL_INCLUDE_DIR}")
|
||||
configure_file(${PROJECT_SOURCE_DIR}/cmake/LibwebsocketsConfig.cmake.in
|
||||
${PROJECT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/LibwebsocketsConfig.cmake
|
||||
@ONLY)
|
||||
|
||||
# Generate version info for both build-tree and install-tree.
|
||||
configure_file(${PROJECT_SOURCE_DIR}/cmake/LibwebsocketsConfigVersion.cmake.in
|
||||
${PROJECT_BINARY_DIR}/LibwebsocketsConfigVersion.cmake
|
||||
@ONLY)
|
||||
|
||||
set_target_properties(websockets websockets_shared
|
||||
PROPERTIES PUBLIC_HEADER "${HDR_PUBLIC}")
|
||||
|
||||
#
|
||||
# Installation.
|
||||
#
|
||||
|
||||
# Install libs and headers.
|
||||
install(TARGETS websockets websockets_shared
|
||||
EXPORT LibwebsocketsTargets
|
||||
LIBRARY DESTINATION "${LWS_INSTALL_LIB_DIR}${LIB_SUFFIX}" COMPONENT libraries
|
||||
ARCHIVE DESTINATION "${LWS_INSTALL_LIB_DIR}${LIB_SUFFIX}" COMPONENT libraries
|
||||
RUNTIME DESTINATION "${LWS_INSTALL_BIN_DIR}" COMPONENT libraries # Windows DLLs
|
||||
PUBLIC_HEADER DESTINATION "${LWS_INSTALL_INCLUDE_DIR}" COMPONENT dev)
|
||||
set(CPACK_COMPONENT_LIBRARIES_DISPLAY_NAME "Libraries")
|
||||
set(CPACK_COMPONENT_DEV_DISPLAY_NAME "Development files")
|
||||
|
||||
# Install test apps.
|
||||
if (NOT LWS_WITHOUT_TESTAPPS AND NOT LWS_WITHOUT_CLIENT)
|
||||
install(TARGETS test-client ${TEST_APP_LIST}
|
||||
RUNTIME DESTINATION ${LWS_INSTALL_EXAMPLES_DIR}
|
||||
COMPONENT examples)
|
||||
set(CPACK_COMPONENT_EXAMPLES_DISPLAY_NAME "Example files")
|
||||
endif()
|
||||
|
||||
# Programs shared files used by the test-server.
|
||||
if (NOT LWS_WITHOUT_TESTAPPS AND NOT LWS_WITHOUT_SERVER)
|
||||
install(FILES ${TEST_SERVER_DATA}
|
||||
DESTINATION share/libwebsockets-test-server
|
||||
COMPONENT examples)
|
||||
endif()
|
||||
|
||||
# Install exports for the install-tree.
|
||||
install(EXPORT LibwebsocketsTargets
|
||||
DESTINATION "${LWS_INSTALL_CMAKE_DIR}" COMPONENT dev)
|
||||
|
||||
# build subdir is not part of sources
|
||||
set(CPACK_SOURCE_IGNORE_FILES $(CPACK_SOURCE_IGNORE_FILES) ".git" "build" "tgz" "tar.gz")
|
||||
|
||||
# Most people are more used to "make dist" compared to "make package_source"
|
||||
add_custom_target(dist COMMAND "${CMAKE_MAKE_PROGRAM}" package_source)
|
||||
|
||||
include(UseRPMTools)
|
||||
if (RPMTools_FOUND)
|
||||
RPMTools_ADD_RPM_TARGETS(libwebsockets libwebsockets.spec)
|
||||
endif()
|
||||
|
||||
message("---------------------------------------------------------------------")
|
||||
message(" Settings: (For more help do cmake -LH <srcpath>")
|
||||
message("---------------------------------------------------------------------")
|
||||
message(" LWS_WITH_SSL = ${LWS_WITH_SSL} (SSL Support)")
|
||||
message(" LWS_SSL_CLIENT_USE_OS_CA_CERTS = ${LWS_SSL_CLIENT_USE_OS_CA_CERTS}")
|
||||
message(" LWS_USE_CYASSL = ${LWS_USE_CYASSL} (CyaSSL replacement for OpenSSL)")
|
||||
if (LWS_USE_CYASSL)
|
||||
message(" LWS_CYASSL_LIB = ${LWS_CYASSL_LIB}")
|
||||
message(" LWS_CYASSL_INCLUDE_DIRS = ${LWS_CYASSL_INCLUDE_DIRS}")
|
||||
endif()
|
||||
message(" LWS_WITHOUT_BUILTIN_GETIFADDRS = ${LWS_WITHOUT_BUILTIN_GETIFADDRS}")
|
||||
message(" LWS_WITHOUT_CLIENT = ${LWS_WITHOUT_CLIENT}")
|
||||
message(" LWS_WITHOUT_SERVER = ${LWS_WITHOUT_SERVER}")
|
||||
message(" LWS_LINK_TESTAPPS_DYNAMIC = ${LWS_LINK_TESTAPPS_DYNAMIC}")
|
||||
message(" LWS_WITHOUT_TESTAPPS = ${LWS_WITHOUT_TESTAPPS}")
|
||||
message(" LWS_WITHOUT_TEST_SERVER = ${LWS_WITHOUT_TEST_SERVER}")
|
||||
message(" LWS_WITHOUT_TEST_SERVER_EXTPOLL = ${LWS_WITHOUT_TEST_SERVER_EXTPOLL}")
|
||||
message(" LWS_WITHOUT_TEST_PING = ${LWS_WITHOUT_TEST_PING}")
|
||||
message(" LWS_WITHOUT_TEST_CLIENT = ${LWS_WITHOUT_TEST_CLIENT}")
|
||||
message(" LWS_WITHOUT_TEST_FRAGGLE = ${LWS_WITHOUT_TEST_FRAGGLE}")
|
||||
message(" LWS_WITHOUT_DEBUG = ${LWS_WITHOUT_DEBUG}")
|
||||
message(" LWS_WITHOUT_EXTENSIONS = ${LWS_WITHOUT_EXTENSIONS}")
|
||||
message(" LWS_WITH_LATENCY = ${LWS_WITH_LATENCY}")
|
||||
message(" LWS_WITHOUT_DAEMONIZE = ${LWS_WITHOUT_DAEMONIZE}")
|
||||
message(" LWS_USE_LIBEV = ${LWS_USE_LIBEV}")
|
||||
message(" LWS_IPV6 = ${LWS_IPV6}")
|
||||
message(" LWS_WITH_HTTP2 = ${LWS_WITH_HTTP2}")
|
||||
message("---------------------------------------------------------------------")
|
||||
|
||||
# These will be available to parent projects including libwebsockets using add_subdirectory()
|
||||
set(LIBWEBSOCKETS_LIBRARIES websocket websockets_shared CACHE STRING "Libwebsocket libraries")
|
||||
set(LIBWEBSOCKETS_LIBRARIES_STATIC websocket CACHE STRING "Libwebsocket static library")
|
||||
set(LIBWEBSOCKETS_LIBRARIES_SHARED websockets_shared CACHE STRING "Libwebsocket shared library")
|
||||
|
||||
# This must always be last!
|
||||
include(CPack)
|
||||
526
dependencies/libwebsockets/LICENSE
vendored
Normal file
526
dependencies/libwebsockets/LICENSE
vendored
Normal file
@ -0,0 +1,526 @@
|
||||
Libwebsockets and included programs are provided under the terms of the GNU
|
||||
Library General Public License (LGPL) 2.1, with the following exceptions:
|
||||
|
||||
1) Static linking of programs with the libwebsockets library does not
|
||||
constitute a derivative work and does not require the author to provide
|
||||
source code for the program, use the shared libwebsockets libraries, or
|
||||
link their program against a user-supplied version of libwebsockets.
|
||||
|
||||
If you link the program to a modified version of libwebsockets, then the
|
||||
changes to libwebsockets must be provided under the terms of the LGPL in
|
||||
sections 1, 2, and 4.
|
||||
|
||||
2) You do not have to provide a copy of the libwebsockets license with
|
||||
programs that are linked to the libwebsockets library, nor do you have to
|
||||
identify the libwebsockets license in your program or documentation as
|
||||
required by section 6 of the LGPL.
|
||||
|
||||
However, programs must still identify their use of libwebsockets. The
|
||||
following example statement can be included in user documentation to
|
||||
satisfy this requirement:
|
||||
|
||||
"[program] is based in part on the work of the libwebsockets project
|
||||
(http://libwebsockets.org)"
|
||||
|
||||
GNU LESSER GENERAL PUBLIC LICENSE
|
||||
Version 2.1, February 1999
|
||||
|
||||
Copyright (C) 1991, 1999 Free Software Foundation, Inc.
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
[This is the first released version of the Lesser GPL. It also counts
|
||||
as the successor of the GNU Library Public License, version 2, hence
|
||||
the version number 2.1.]
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
Licenses are intended to guarantee your freedom to share and change
|
||||
free software--to make sure the software is free for all its users.
|
||||
|
||||
This license, the Lesser General Public License, applies to some
|
||||
specially designated software packages--typically libraries--of the
|
||||
Free Software Foundation and other authors who decide to use it. You
|
||||
can use it too, but we suggest you first think carefully about whether
|
||||
this license or the ordinary General Public License is the better
|
||||
strategy to use in any particular case, based on the explanations below.
|
||||
|
||||
When we speak of free software, we are referring to freedom of use,
|
||||
not price. Our General Public Licenses are designed to make sure that
|
||||
you have the freedom to distribute copies of free software (and charge
|
||||
for this service if you wish); that you receive source code or can get
|
||||
it if you want it; that you can change the software and use pieces of
|
||||
it in new free programs; and that you are informed that you can do
|
||||
these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
distributors to deny you these rights or to ask you to surrender these
|
||||
rights. These restrictions translate to certain responsibilities for
|
||||
you if you distribute copies of the library or if you modify it.
|
||||
|
||||
For example, if you distribute copies of the library, whether gratis
|
||||
or for a fee, you must give the recipients all the rights that we gave
|
||||
you. You must make sure that they, too, receive or can get the source
|
||||
code. If you link other code with the library, you must provide
|
||||
complete object files to the recipients, so that they can relink them
|
||||
with the library after making changes to the library and recompiling
|
||||
it. And you must show them these terms so they know their rights.
|
||||
|
||||
We protect your rights with a two-step method: (1) we copyright the
|
||||
library, and (2) we offer you this license, which gives you legal
|
||||
permission to copy, distribute and/or modify the library.
|
||||
|
||||
To protect each distributor, we want to make it very clear that
|
||||
there is no warranty for the free library. Also, if the library is
|
||||
modified by someone else and passed on, the recipients should know
|
||||
that what they have is not the original version, so that the original
|
||||
author's reputation will not be affected by problems that might be
|
||||
introduced by others.
|
||||
|
||||
Finally, software patents pose a constant threat to the existence of
|
||||
any free program. We wish to make sure that a company cannot
|
||||
effectively restrict the users of a free program by obtaining a
|
||||
restrictive license from a patent holder. Therefore, we insist that
|
||||
any patent license obtained for a version of the library must be
|
||||
consistent with the full freedom of use specified in this license.
|
||||
|
||||
Most GNU software, including some libraries, is covered by the
|
||||
ordinary GNU General Public License. This license, the GNU Lesser
|
||||
General Public License, applies to certain designated libraries, and
|
||||
is quite different from the ordinary General Public License. We use
|
||||
this license for certain libraries in order to permit linking those
|
||||
libraries into non-free programs.
|
||||
|
||||
When a program is linked with a library, whether statically or using
|
||||
a shared library, the combination of the two is legally speaking a
|
||||
combined work, a derivative of the original library. The ordinary
|
||||
General Public License therefore permits such linking only if the
|
||||
entire combination fits its criteria of freedom. The Lesser General
|
||||
Public License permits more lax criteria for linking other code with
|
||||
the library.
|
||||
|
||||
We call this license the "Lesser" General Public License because it
|
||||
does Less to protect the user's freedom than the ordinary General
|
||||
Public License. It also provides other free software developers Less
|
||||
of an advantage over competing non-free programs. These disadvantages
|
||||
are the reason we use the ordinary General Public License for many
|
||||
libraries. However, the Lesser license provides advantages in certain
|
||||
special circumstances.
|
||||
|
||||
For example, on rare occasions, there may be a special need to
|
||||
encourage the widest possible use of a certain library, so that it becomes
|
||||
a de-facto standard. To achieve this, non-free programs must be
|
||||
allowed to use the library. A more frequent case is that a free
|
||||
library does the same job as widely used non-free libraries. In this
|
||||
case, there is little to gain by limiting the free library to free
|
||||
software only, so we use the Lesser General Public License.
|
||||
|
||||
In other cases, permission to use a particular library in non-free
|
||||
programs enables a greater number of people to use a large body of
|
||||
free software. For example, permission to use the GNU C Library in
|
||||
non-free programs enables many more people to use the whole GNU
|
||||
operating system, as well as its variant, the GNU/Linux operating
|
||||
system.
|
||||
|
||||
Although the Lesser General Public License is Less protective of the
|
||||
users' freedom, it does ensure that the user of a program that is
|
||||
linked with the Library has the freedom and the wherewithal to run
|
||||
that program using a modified version of the Library.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow. Pay close attention to the difference between a
|
||||
"work based on the library" and a "work that uses the library". The
|
||||
former contains code derived from the library, whereas the latter must
|
||||
be combined with the library in order to run.
|
||||
|
||||
GNU LESSER GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License Agreement applies to any software library or other
|
||||
program which contains a notice placed by the copyright holder or
|
||||
other authorized party saying it may be distributed under the terms of
|
||||
this Lesser General Public License (also called "this License").
|
||||
Each licensee is addressed as "you".
|
||||
|
||||
A "library" means a collection of software functions and/or data
|
||||
prepared so as to be conveniently linked with application programs
|
||||
(which use some of those functions and data) to form executables.
|
||||
|
||||
The "Library", below, refers to any such software library or work
|
||||
which has been distributed under these terms. A "work based on the
|
||||
Library" means either the Library or any derivative work under
|
||||
copyright law: that is to say, a work containing the Library or a
|
||||
portion of it, either verbatim or with modifications and/or translated
|
||||
straightforwardly into another language. (Hereinafter, translation is
|
||||
included without limitation in the term "modification".)
|
||||
|
||||
"Source code" for a work means the preferred form of the work for
|
||||
making modifications to it. For a library, complete source code means
|
||||
all the source code for all modules it contains, plus any associated
|
||||
interface definition files, plus the scripts used to control compilation
|
||||
and installation of the library.
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running a program using the Library is not restricted, and output from
|
||||
such a program is covered only if its contents constitute a work based
|
||||
on the Library (independent of the use of the Library in a tool for
|
||||
writing it). Whether that is true depends on what the Library does
|
||||
and what the program that uses the Library does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Library's
|
||||
complete source code as you receive it, in any medium, provided that
|
||||
you conspicuously and appropriately publish on each copy an
|
||||
appropriate copyright notice and disclaimer of warranty; keep intact
|
||||
all the notices that refer to this License and to the absence of any
|
||||
warranty; and distribute a copy of this License along with the
|
||||
Library.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy,
|
||||
and you may at your option offer warranty protection in exchange for a
|
||||
fee.
|
||||
|
||||
2. You may modify your copy or copies of the Library or any portion
|
||||
of it, thus forming a work based on the Library, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) The modified work must itself be a software library.
|
||||
|
||||
b) You must cause the files modified to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
c) You must cause the whole of the work to be licensed at no
|
||||
charge to all third parties under the terms of this License.
|
||||
|
||||
d) If a facility in the modified Library refers to a function or a
|
||||
table of data to be supplied by an application program that uses
|
||||
the facility, other than as an argument passed when the facility
|
||||
is invoked, then you must make a good faith effort to ensure that,
|
||||
in the event an application does not supply such function or
|
||||
table, the facility still operates, and performs whatever part of
|
||||
its purpose remains meaningful.
|
||||
|
||||
(For example, a function in a library to compute square roots has
|
||||
a purpose that is entirely well-defined independent of the
|
||||
application. Therefore, Subsection 2d requires that any
|
||||
application-supplied function or table used by this function must
|
||||
be optional: if the application does not supply it, the square
|
||||
root function must still compute square roots.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Library,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Library, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote
|
||||
it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Library.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Library
|
||||
with the Library (or with a work based on the Library) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may opt to apply the terms of the ordinary GNU General Public
|
||||
License instead of this License to a given copy of the Library. To do
|
||||
this, you must alter all the notices that refer to this License, so
|
||||
that they refer to the ordinary GNU General Public License, version 2,
|
||||
instead of to this License. (If a newer version than version 2 of the
|
||||
ordinary GNU General Public License has appeared, then you can specify
|
||||
that version instead if you wish.) Do not make any other change in
|
||||
these notices.
|
||||
|
||||
Once this change is made in a given copy, it is irreversible for
|
||||
that copy, so the ordinary GNU General Public License applies to all
|
||||
subsequent copies and derivative works made from that copy.
|
||||
|
||||
This option is useful when you wish to copy part of the code of
|
||||
the Library into a program that is not a library.
|
||||
|
||||
4. You may copy and distribute the Library (or a portion or
|
||||
derivative of it, under Section 2) in object code or executable form
|
||||
under the terms of Sections 1 and 2 above provided that you accompany
|
||||
it with the complete corresponding machine-readable source code, which
|
||||
must be distributed under the terms of Sections 1 and 2 above on a
|
||||
medium customarily used for software interchange.
|
||||
|
||||
If distribution of object code is made by offering access to copy
|
||||
from a designated place, then offering equivalent access to copy the
|
||||
source code from the same place satisfies the requirement to
|
||||
distribute the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
5. A program that contains no derivative of any portion of the
|
||||
Library, but is designed to work with the Library by being compiled or
|
||||
linked with it, is called a "work that uses the Library". Such a
|
||||
work, in isolation, is not a derivative work of the Library, and
|
||||
therefore falls outside the scope of this License.
|
||||
|
||||
However, linking a "work that uses the Library" with the Library
|
||||
creates an executable that is a derivative of the Library (because it
|
||||
contains portions of the Library), rather than a "work that uses the
|
||||
library". The executable is therefore covered by this License.
|
||||
Section 6 states terms for distribution of such executables.
|
||||
|
||||
When a "work that uses the Library" uses material from a header file
|
||||
that is part of the Library, the object code for the work may be a
|
||||
derivative work of the Library even though the source code is not.
|
||||
Whether this is true is especially significant if the work can be
|
||||
linked without the Library, or if the work is itself a library. The
|
||||
threshold for this to be true is not precisely defined by law.
|
||||
|
||||
If such an object file uses only numerical parameters, data
|
||||
structure layouts and accessors, and small macros and small inline
|
||||
functions (ten lines or less in length), then the use of the object
|
||||
file is unrestricted, regardless of whether it is legally a derivative
|
||||
work. (Executables containing this object code plus portions of the
|
||||
Library will still fall under Section 6.)
|
||||
|
||||
Otherwise, if the work is a derivative of the Library, you may
|
||||
distribute the object code for the work under the terms of Section 6.
|
||||
Any executables containing that work also fall under Section 6,
|
||||
whether or not they are linked directly with the Library itself.
|
||||
|
||||
6. As an exception to the Sections above, you may also combine or
|
||||
link a "work that uses the Library" with the Library to produce a
|
||||
work containing portions of the Library, and distribute that work
|
||||
under terms of your choice, provided that the terms permit
|
||||
modification of the work for the customer's own use and reverse
|
||||
engineering for debugging such modifications.
|
||||
|
||||
You must give prominent notice with each copy of the work that the
|
||||
Library is used in it and that the Library and its use are covered by
|
||||
this License. You must supply a copy of this License. If the work
|
||||
during execution displays copyright notices, you must include the
|
||||
copyright notice for the Library among them, as well as a reference
|
||||
directing the user to the copy of this License. Also, you must do one
|
||||
of these things:
|
||||
|
||||
a) Accompany the work with the complete corresponding
|
||||
machine-readable source code for the Library including whatever
|
||||
changes were used in the work (which must be distributed under
|
||||
Sections 1 and 2 above); and, if the work is an executable linked
|
||||
with the Library, with the complete machine-readable "work that
|
||||
uses the Library", as object code and/or source code, so that the
|
||||
user can modify the Library and then relink to produce a modified
|
||||
executable containing the modified Library. (It is understood
|
||||
that the user who changes the contents of definitions files in the
|
||||
Library will not necessarily be able to recompile the application
|
||||
to use the modified definitions.)
|
||||
|
||||
b) Use a suitable shared library mechanism for linking with the
|
||||
Library. A suitable mechanism is one that (1) uses at run time a
|
||||
copy of the library already present on the user's computer system,
|
||||
rather than copying library functions into the executable, and (2)
|
||||
will operate properly with a modified version of the library, if
|
||||
the user installs one, as long as the modified version is
|
||||
interface-compatible with the version that the work was made with.
|
||||
|
||||
c) Accompany the work with a written offer, valid for at
|
||||
least three years, to give the same user the materials
|
||||
specified in Subsection 6a, above, for a charge no more
|
||||
than the cost of performing this distribution.
|
||||
|
||||
d) If distribution of the work is made by offering access to copy
|
||||
from a designated place, offer equivalent access to copy the above
|
||||
specified materials from the same place.
|
||||
|
||||
e) Verify that the user has already received a copy of these
|
||||
materials or that you have already sent this user a copy.
|
||||
|
||||
For an executable, the required form of the "work that uses the
|
||||
Library" must include any data and utility programs needed for
|
||||
reproducing the executable from it. However, as a special exception,
|
||||
the materials to be distributed need not include anything that is
|
||||
normally distributed (in either source or binary form) with the major
|
||||
components (compiler, kernel, and so on) of the operating system on
|
||||
which the executable runs, unless that component itself accompanies
|
||||
the executable.
|
||||
|
||||
It may happen that this requirement contradicts the license
|
||||
restrictions of other proprietary libraries that do not normally
|
||||
accompany the operating system. Such a contradiction means you cannot
|
||||
use both them and the Library together in an executable that you
|
||||
distribute.
|
||||
|
||||
7. You may place library facilities that are a work based on the
|
||||
Library side-by-side in a single library together with other library
|
||||
facilities not covered by this License, and distribute such a combined
|
||||
library, provided that the separate distribution of the work based on
|
||||
the Library and of the other library facilities is otherwise
|
||||
permitted, and provided that you do these two things:
|
||||
|
||||
a) Accompany the combined library with a copy of the same work
|
||||
based on the Library, uncombined with any other library
|
||||
facilities. This must be distributed under the terms of the
|
||||
Sections above.
|
||||
|
||||
b) Give prominent notice with the combined library of the fact
|
||||
that part of it is a work based on the Library, and explaining
|
||||
where to find the accompanying uncombined form of the same work.
|
||||
|
||||
8. You may not copy, modify, sublicense, link with, or distribute
|
||||
the Library except as expressly provided under this License. Any
|
||||
attempt otherwise to copy, modify, sublicense, link with, or
|
||||
distribute the Library is void, and will automatically terminate your
|
||||
rights under this License. However, parties who have received copies,
|
||||
or rights, from you under this License will not have their licenses
|
||||
terminated so long as such parties remain in full compliance.
|
||||
|
||||
9. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Library or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Library (or any work based on the
|
||||
Library), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Library or works based on it.
|
||||
|
||||
10. Each time you redistribute the Library (or any work based on the
|
||||
Library), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute, link with or modify the Library
|
||||
subject to these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties with
|
||||
this License.
|
||||
|
||||
11. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Library at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Library by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Library.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under any
|
||||
particular circumstance, the balance of the section is intended to apply,
|
||||
and the section as a whole is intended to apply in other circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
12. If the distribution and/or use of the Library is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Library under this License may add
|
||||
an explicit geographical distribution limitation excluding those countries,
|
||||
so that distribution is permitted only in or among countries not thus
|
||||
excluded. In such case, this License incorporates the limitation as if
|
||||
written in the body of this License.
|
||||
|
||||
13. The Free Software Foundation may publish revised and/or new
|
||||
versions of the Lesser General Public License from time to time.
|
||||
Such new versions will be similar in spirit to the present version,
|
||||
but may differ in detail to address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Library
|
||||
specifies a version number of this License which applies to it and
|
||||
"any later version", you have the option of following the terms and
|
||||
conditions either of that version or of any later version published by
|
||||
the Free Software Foundation. If the Library does not specify a
|
||||
license version number, you may choose any version ever published by
|
||||
the Free Software Foundation.
|
||||
|
||||
14. If you wish to incorporate parts of the Library into other free
|
||||
programs whose distribution conditions are incompatible with these,
|
||||
write to the author to ask for permission. For software which is
|
||||
copyrighted by the Free Software Foundation, write to the Free
|
||||
Software Foundation; we sometimes make exceptions for this. Our
|
||||
decision will be guided by the two goals of preserving the free status
|
||||
of all derivatives of our free software and of promoting the sharing
|
||||
and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
|
||||
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
|
||||
EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
|
||||
OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
|
||||
KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
|
||||
LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
|
||||
THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||
|
||||
16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
|
||||
WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
|
||||
AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
|
||||
FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
|
||||
CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
|
||||
LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
|
||||
RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
|
||||
FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
|
||||
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
||||
DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Libraries
|
||||
|
||||
If you develop a new library, and you want it to be of the greatest
|
||||
possible use to the public, we recommend making it free software that
|
||||
everyone can redistribute and change. You can do so by permitting
|
||||
redistribution under these terms (or, alternatively, under the terms of the
|
||||
ordinary General Public License).
|
||||
|
||||
To apply these terms, attach the following notices to the library. It is
|
||||
safest to attach them to the start of each source file to most effectively
|
||||
convey the exclusion of warranty; and each file should have at least the
|
||||
"copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the library's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the library, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the
|
||||
library `Frob' (a library for tweaking knobs) written by James Random Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1990
|
||||
Ty Coon, President of Vice
|
||||
|
||||
That's all there is to it!
|
||||
20
dependencies/libwebsockets/README
vendored
Normal file
20
dependencies/libwebsockets/README
vendored
Normal file
@ -0,0 +1,20 @@
|
||||
This is the libwebsockets C library for lightweight websocket clients and
|
||||
servers. For support, visit
|
||||
|
||||
http://libwebsockets.org
|
||||
|
||||
and consider joining the project mailing list at
|
||||
|
||||
http://ml.libwebsockets.org/mailman/listinfo/libwebsockets
|
||||
|
||||
You can get the latest version of the library from git
|
||||
|
||||
http://git.libwebsockets.org
|
||||
https://github.com/warmcat/libwebsockets
|
||||
|
||||
for more information:
|
||||
|
||||
README.build - information on building the library
|
||||
README.coding - information for writing code using the library
|
||||
README.test-apps - information about the test apps built with the library
|
||||
|
||||
225
dependencies/libwebsockets/README.build
vendored
Normal file
225
dependencies/libwebsockets/README.build
vendored
Normal file
@ -0,0 +1,225 @@
|
||||
Introduction to CMake
|
||||
---------------------
|
||||
|
||||
CMake is a multi-platform build tool that can generate build files for many
|
||||
different target platforms. See more info at http://www.cmake.org
|
||||
|
||||
CMake also allows/recommends you to do "out of source"-builds, that is,
|
||||
the build files are separated from your sources, so there is no need to
|
||||
create elaborate clean scripts to get a clean source tree, instead you
|
||||
simply remove your build directory.
|
||||
|
||||
Libwebsockets has been tested to build successfully on the following platforms
|
||||
with SSL support (both OpenSSL/CyaSSL):
|
||||
|
||||
- Windows
|
||||
- Linux (x86 and ARM)
|
||||
- OSX
|
||||
- NetBSD
|
||||
|
||||
Building the library and test apps
|
||||
----------------------------------
|
||||
|
||||
The project settings used by CMake to generate the platform specific build
|
||||
files is called CMakeLists.txt. CMake then uses one of its "Generators" to
|
||||
output a Visual Studio project or Make file for instance. To see a list of
|
||||
the available generators for your platform, simply run the "cmake" command.
|
||||
|
||||
Note that by default OpenSSL will be linked, if you don't want SSL support
|
||||
see below on how to toggle compile options.
|
||||
|
||||
Building on Unix:
|
||||
-----------------
|
||||
|
||||
1. Install CMake 2.6 or greater: http://cmake.org/cmake/resources/software.html
|
||||
(Most Unix distributions comes with a packaged version also)
|
||||
|
||||
2. Install OpenSSL.
|
||||
|
||||
3. Generate the build files (default is Make files):
|
||||
|
||||
cd /path/to/src
|
||||
mkdir build
|
||||
cd build
|
||||
cmake ..
|
||||
|
||||
(NOTE: The build/ directory can have any name and be located anywhere
|
||||
on your filesystem, and that the argument ".." given to cmake is simply
|
||||
the source directory of libwebsockets containing the CMakeLists.txt
|
||||
project file. All examples in this file assumes you use "..")
|
||||
|
||||
NOTE2
|
||||
A common option you may want to give is to set the install path, same
|
||||
as --prefix= with autotools. It defaults to /usr/local.
|
||||
You can do this by, eg
|
||||
|
||||
cmake .. -DCMAKE_INSTALL_PREFIX:PATH=/usr
|
||||
|
||||
NOTE3
|
||||
On machines that want libraries in lib64, you can also add the
|
||||
following to the cmake line
|
||||
|
||||
-DLIB_SUFFIX=64
|
||||
|
||||
NOTE4
|
||||
If you are building against a non-distro OpenSSL (eg, in order to get
|
||||
access to ALPN support only in newer OpenSSL versions) the nice way to
|
||||
express that in one cmake command is eg,
|
||||
|
||||
-DOPENSSL_ROOT_DIR=/usr/local/ssl
|
||||
|
||||
4. Finally you can build using the generated Makefile:
|
||||
|
||||
make
|
||||
|
||||
|
||||
Quirk of cmake
|
||||
--------------
|
||||
|
||||
When changing cmake options, for some reason the only way to get it to see the
|
||||
changes sometimes is delete the contents of your build directory and do the
|
||||
cmake from scratch.
|
||||
|
||||
|
||||
Building on Windows (Visual Studio)
|
||||
-----------------------------------
|
||||
1. Install CMake 2.6 or greater: http://cmake.org/cmake/resources/software.html
|
||||
|
||||
2. Install OpenSSL binaries. http://www.openssl.org/related/binaries.html
|
||||
(Preferably in the default location to make it easier for CMake to find them)
|
||||
|
||||
3. Generate the Visual studio project by opening the Visual Studio cmd prompt:
|
||||
|
||||
cd <path to src>
|
||||
md build
|
||||
cd build
|
||||
cmake -G "Visual Studio 10" ..
|
||||
|
||||
(NOTE: There is also a cmake-gui available on Windows if you prefer that)
|
||||
|
||||
4. Now you should have a generated Visual Studio Solution in your
|
||||
<path to src>/build directory, which can be used to build.
|
||||
|
||||
Setting compile options
|
||||
-----------------------
|
||||
|
||||
To set compile time flags you can either use one of the CMake gui applications
|
||||
or do it via command line.
|
||||
|
||||
Command line
|
||||
------------
|
||||
To list avaialable options (ommit the H if you don't want the help text):
|
||||
|
||||
cmake -LH ..
|
||||
|
||||
Then to set an option and build (for example turn off SSL support):
|
||||
|
||||
cmake -DLWS_WITH_SSL=0 ..
|
||||
or
|
||||
cmake -DLWS_WITH_SSL:BOOL=OFF ..
|
||||
|
||||
Unix GUI
|
||||
--------
|
||||
If you have a curses enabled build you simply type:
|
||||
(not all packages include this, my debian install does not for example).
|
||||
|
||||
ccmake
|
||||
|
||||
Windows GUI
|
||||
-----------
|
||||
On windows CMake comes with a gui application:
|
||||
Start -> Programs -> CMake -> CMake (cmake-gui)
|
||||
|
||||
CyaSSL replacement for OpenSSL
|
||||
------------------------------
|
||||
CyaSSL is a lightweight SSL library targeted at embedded system:
|
||||
http://www.yassl.com/yaSSL/Products-cyassl.html
|
||||
|
||||
It contains a OpenSSL compatability layer which makes it possible to pretty
|
||||
much link to it instead of OpenSSL, giving a much smaller footprint.
|
||||
|
||||
NOTE: cyassl needs to be compiled using the --enable-opensslextra flag for
|
||||
this to work.
|
||||
|
||||
Compiling libwebsockets with CyaSSL
|
||||
-----------------------------------
|
||||
|
||||
cmake .. -DLWS_USE_CYASSL=1 \
|
||||
-DLWS_CYASSL_INCLUDE_DIRS=/path/to/cyassl \
|
||||
-DLWS_CYASSL_LIB=/path/to/cyassl/cyassl.a ..
|
||||
|
||||
NOTE: On windows use the .lib file extension for LWS_CYASSL_LIB instead.
|
||||
|
||||
Cross compiling
|
||||
---------------
|
||||
To enable cross compiling libwebsockets using CMake you need to create
|
||||
a "Toolchain file" that you supply to CMake when generating your build files.
|
||||
CMake will then use the cross compilers and build paths specified in this file
|
||||
to look for dependencies and such.
|
||||
|
||||
Libwebsockets includes an example toolchain file cross-arm-linux-gnueabihf.cmake
|
||||
you can use as a starting point.
|
||||
|
||||
The commandline to configure for cross with this would look like
|
||||
|
||||
cmake .. -DCMAKE_INSTALL_PREFIX:PATH=/usr \
|
||||
-DCMAKE_TOOLCHAIN_FILE=../cross-arm-linux-gnueabihf.cmake \
|
||||
-DWITHOUT_EXTENSIONS=1 -DWITH_SSL=0
|
||||
|
||||
The example shows how to build with no external cross lib dependencies, you
|
||||
need to proide the cross libraries otherwise.
|
||||
|
||||
NOTE: start from an EMPTY build directory if you had a non-cross build in there
|
||||
before the settings will be cached and your changes ignored.
|
||||
|
||||
Additional information on cross compilation with CMake:
|
||||
http://www.vtk.org/Wiki/CMake_Cross_Compiling
|
||||
|
||||
|
||||
Memory efficiency
|
||||
-----------------
|
||||
|
||||
Embedded server-only configuration without extensions (ie, no compression
|
||||
on websocket connections), but with full v13 websocket features and http
|
||||
server, built on ARM Cortex-A9:
|
||||
|
||||
Update at 8dac94d (2013-02-18)
|
||||
|
||||
./configure --without-client --without-extensions --disable-debug --without-daemonize
|
||||
|
||||
Context Creation, 1024 fd limit[2]: 16720 (includes 12 bytes per fd)
|
||||
Per-connection [3]: 72 bytes, +1328 during headers
|
||||
|
||||
.text .rodata .data .bss
|
||||
11512 2784 288 4
|
||||
|
||||
This shows the impact of the major configuration with/without options at
|
||||
13ba5bbc633ea962d46d using Ubuntu ARM on a PandaBoard ES.
|
||||
|
||||
These are accounting for static allocations from the library elf, there are
|
||||
additional dynamic allocations via malloc. These are a bit old now but give
|
||||
the right idea for relative "expense" of features.
|
||||
|
||||
Static allocations, ARM9
|
||||
.text .rodata .data .bss
|
||||
All (no without) 35024 9940 336 4104
|
||||
without client 25684 7144 336 4104
|
||||
without client, exts 21652 6288 288 4104
|
||||
without client, exts, debug[1] 19756 3768 288 4104
|
||||
without server 30304 8160 336 4104
|
||||
without server, exts 25382 7204 288 4104
|
||||
without server, exts, debug[1] 23712 4256 288 4104
|
||||
|
||||
[1] --disable-debug only removes messages below lwsl_notice. Since that is
|
||||
the default logging level the impact is not noticable, error, warn and notice
|
||||
logs are all still there.
|
||||
|
||||
[2] 1024 fd per process is the default limit (set by ulimit) in at least Fedora
|
||||
and Ubuntu. You can make significant savings tailoring this to actual expected
|
||||
peak fds, ie, at a limit of 20, context creation allocation reduces to 4432 +
|
||||
240 = 4672)
|
||||
|
||||
[3] known header content is freed after connection establishment
|
||||
|
||||
|
||||
|
||||
267
dependencies/libwebsockets/README.coding
vendored
Normal file
267
dependencies/libwebsockets/README.coding
vendored
Normal file
@ -0,0 +1,267 @@
|
||||
Daemonization
|
||||
-------------
|
||||
|
||||
There's a helper api lws_daemonize built by default that does everything you
|
||||
need to daemonize well, including creating a lock file. If you're making
|
||||
what's basically a daemon, just call this early in your init to fork to a
|
||||
headless background process and exit the starting process.
|
||||
|
||||
Notice stdout, stderr, stdin are all redirected to /dev/null to enforce your
|
||||
daemon is headless, so you'll need to sort out alternative logging, by, eg,
|
||||
syslog.
|
||||
|
||||
|
||||
Maximum number of connections
|
||||
-----------------------------
|
||||
|
||||
The maximum number of connections the library can deal with is decided when
|
||||
it starts by querying the OS to find out how many file descriptors it is
|
||||
allowed to open (1024 on Fedora for example). It then allocates arrays that
|
||||
allow up to that many connections, minus whatever other file descriptors are
|
||||
in use by the user code.
|
||||
|
||||
If you want to restrict that allocation, or increase it, you can use ulimit or
|
||||
similar to change the avaiable number of file descriptors, and when restarted
|
||||
libwebsockets will adapt accordingly.
|
||||
|
||||
|
||||
Libwebsockets is singlethreaded
|
||||
-------------------------------
|
||||
|
||||
Directly performing websocket actions from other threads is not allowed.
|
||||
Aside from the internal data being inconsistent in forked() processes,
|
||||
the scope of a wsi (struct websocket) can end at any time during service
|
||||
with the socket closing and the wsi freed.
|
||||
|
||||
Websocket write activities should only take place in the
|
||||
"LWS_CALLBACK_SERVER_WRITEABLE" callback as described below.
|
||||
|
||||
Only live connections appear in the user callbacks, so this removes any
|
||||
possibility of trying to used closed and freed wsis.
|
||||
|
||||
If you need to service other socket or file descriptors as well as the
|
||||
websocket ones, you can combine them together with the websocket ones
|
||||
in one poll loop, see "External Polling Loop support" below, and
|
||||
still do it all in one thread / process context.
|
||||
|
||||
|
||||
Only send data when socket writeable
|
||||
------------------------------------
|
||||
|
||||
You should only send data on a websocket connection from the user callback
|
||||
"LWS_CALLBACK_SERVER_WRITEABLE" (or "LWS_CALLBACK_CLIENT_WRITEABLE" for
|
||||
clients).
|
||||
|
||||
If you want to send something, do not just send it but request a callback
|
||||
when the socket is writeable using
|
||||
|
||||
- libwebsocket_callback_on_writable(context, wsi) for a specific wsi, or
|
||||
- libwebsocket_callback_on_writable_all_protocol(protocol) for all connections
|
||||
using that protocol to get a callback when next writeable.
|
||||
|
||||
Usually you will get called back immediately next time around the service
|
||||
loop, but if your peer is slow or temporarily inactive the callback will be
|
||||
delayed accordingly. Generating what to write and sending it should be done
|
||||
in the ...WRITEABLE callback.
|
||||
|
||||
See the test server code for an example of how to do this.
|
||||
|
||||
|
||||
Do not rely on only your own WRITEABLE requests appearing
|
||||
---------------------------------------------------------
|
||||
|
||||
Libwebsockets may generate additional LWS_CALLBACK_CLIENT_WRITEABLE events
|
||||
if it met network conditions where it had to buffer your send data internally.
|
||||
|
||||
So your code for LWS_CALLBACK_CLIENT_WRITEABLE needs to own the decision
|
||||
about what to send, it can't assume that just because the writeable callback
|
||||
came it really is time to send something.
|
||||
|
||||
It's quite possible you get an 'extra' writeable callback at any time and
|
||||
just need to return 0 and wait for the expected callback later.
|
||||
|
||||
|
||||
Closing connections from the user side
|
||||
--------------------------------------
|
||||
|
||||
When you want to close a connection, you do it by returning -1 from a
|
||||
callback for that connection.
|
||||
|
||||
You can provoke a callback by calling libwebsocket_callback_on_writable on
|
||||
the wsi, then notice in the callback you want to close it and just return -1.
|
||||
But usually, the decision to close is made in a callback already and returning
|
||||
-1 is simple.
|
||||
|
||||
If the socket knows the connection is dead, because the peer closed or there
|
||||
was an affirmitive network error like a FIN coming, then libwebsockets will
|
||||
take care of closing the connection automatically.
|
||||
|
||||
If you have a silently dead connection, it's possible to enter a state where
|
||||
the send pipe on the connection is choked but no ack will ever come, so the
|
||||
dead connection will never become writeable. To cover that, you can use TCP
|
||||
keepalives (see later in this document)
|
||||
|
||||
|
||||
Fragmented messages
|
||||
-------------------
|
||||
|
||||
To support fragmented messages you need to check for the final
|
||||
frame of a message with libwebsocket_is_final_fragment. This
|
||||
check can be combined with libwebsockets_remaining_packet_payload
|
||||
to gather the whole contents of a message, eg:
|
||||
|
||||
case LWS_CALLBACK_RECEIVE:
|
||||
{
|
||||
Client * const client = (Client *)user;
|
||||
const size_t remaining = libwebsockets_remaining_packet_payload(wsi);
|
||||
|
||||
if (!remaining && libwebsocket_is_final_fragment(wsi)) {
|
||||
if (client->HasFragments()) {
|
||||
client->AppendMessageFragment(in, len, 0);
|
||||
in = (void *)client->GetMessage();
|
||||
len = client->GetMessageLength();
|
||||
}
|
||||
|
||||
client->ProcessMessage((char *)in, len, wsi);
|
||||
client->ResetMessage();
|
||||
} else
|
||||
client->AppendMessageFragment(in, len, remaining);
|
||||
}
|
||||
break;
|
||||
|
||||
The test app llibwebsockets-test-fraggle sources also show how to
|
||||
deal with fragmented messages.
|
||||
|
||||
|
||||
Debug Logging
|
||||
-------------
|
||||
|
||||
Also using lws_set_log_level api you may provide a custom callback to actually
|
||||
emit the log string. By default, this points to an internal emit function
|
||||
that sends to stderr. Setting it to NULL leaves it as it is instead.
|
||||
|
||||
A helper function lwsl_emit_syslog() is exported from the library to simplify
|
||||
logging to syslog. You still need to use setlogmask, openlog and closelog
|
||||
in your user code.
|
||||
|
||||
The logging apis are made available for user code.
|
||||
|
||||
lwsl_err(...)
|
||||
lwsl_warn(...)
|
||||
lwsl_notice(...)
|
||||
lwsl_info(...)
|
||||
lwsl_debug(...)
|
||||
|
||||
The difference between notice and info is that notice will be logged by default
|
||||
whereas info is ignored by default.
|
||||
|
||||
|
||||
External Polling Loop support
|
||||
-----------------------------
|
||||
|
||||
libwebsockets maintains an internal poll() array for all of its
|
||||
sockets, but you can instead integrate the sockets into an
|
||||
external polling array. That's needed if libwebsockets will
|
||||
cooperate with an existing poll array maintained by another
|
||||
server.
|
||||
|
||||
Four callbacks LWS_CALLBACK_ADD_POLL_FD, LWS_CALLBACK_DEL_POLL_FD,
|
||||
LWS_CALLBACK_SET_MODE_POLL_FD and LWS_CALLBACK_CLEAR_MODE_POLL_FD
|
||||
appear in the callback for protocol 0 and allow interface code to
|
||||
manage socket descriptors in other poll loops.
|
||||
|
||||
You can pass all pollfds that need service to libwebsocket_service_fd(), even
|
||||
if the socket or file does not belong to libwebsockets it is safe.
|
||||
|
||||
If libwebsocket handled it, it zeros the pollfd revents field before returning.
|
||||
So you can let libwebsockets try and if pollfd->revents is nonzero on return,
|
||||
you know it needs handling by your code.
|
||||
|
||||
|
||||
Using with in c++ apps
|
||||
----------------------
|
||||
|
||||
The library is ready for use by C++ apps. You can get started quickly by
|
||||
copying the test server
|
||||
|
||||
$ cp test-server/test-server.c test.cpp
|
||||
|
||||
and building it in C++ like this
|
||||
|
||||
$ g++ -DINSTALL_DATADIR=\"/usr/share\" -ocpptest test.cpp -lwebsockets
|
||||
|
||||
INSTALL_DATADIR is only needed because the test server uses it as shipped, if
|
||||
you remove the references to it in your app you don't need to define it on
|
||||
the g++ line either.
|
||||
|
||||
|
||||
Availability of header information
|
||||
----------------------------------
|
||||
|
||||
From v1.2 of the library onwards, the HTTP header content is free()d as soon
|
||||
as the websocket connection is established. For websocket servers, you can
|
||||
copy interesting headers by handling LWS_CALLBACK_FILTER_PROTOCOL_CONNECTION
|
||||
callback, for clients there's a new callback just for this purpose
|
||||
LWS_CALLBACK_CLIENT_FILTER_PRE_ESTABLISH.
|
||||
|
||||
|
||||
TCP Keepalive
|
||||
-------------
|
||||
|
||||
It is possible for a connection which is not being used to send to die
|
||||
silently somewhere between the peer and the side not sending. In this case
|
||||
by default TCP will just not report anything and you will never get any more
|
||||
incoming data or sign the link is dead until you try to send.
|
||||
|
||||
To deal with getting a notification of that situation, you can choose to
|
||||
enable TCP keepalives on all libwebsockets sockets, when you create the
|
||||
context.
|
||||
|
||||
To enable keepalive, set the ka_time member of the context creation parameter
|
||||
struct to a nonzero value (in seconds) at context creation time. You should
|
||||
also fill ka_probes and ka_interval in that case.
|
||||
|
||||
With keepalive enabled, the TCP layer will send control packets that should
|
||||
stimulate a response from the peer without affecting link traffic. If the
|
||||
response is not coming, the socket will announce an error at poll() forcing
|
||||
a close.
|
||||
|
||||
Note that BSDs don't support keepalive time / probes / inteveral per-socket
|
||||
like Linux does. On those systems you can enable keepalive by a nonzero
|
||||
value in ka_time, but the systemwide kernel settings for the time / probes/
|
||||
interval are used, regardless of what nonzero value is in ka_time.
|
||||
|
||||
Optimizing SSL connections
|
||||
--------------------------
|
||||
|
||||
There's a member ssl_cipher_list in the lws_context_creation_info struct
|
||||
which allows the user code to restrict the possible cipher selection at
|
||||
context-creation time.
|
||||
|
||||
You might want to look into that to stop the ssl peers selecting a ciher which
|
||||
is too computationally expensive. To use it, point it to a string like
|
||||
|
||||
"RC4-MD5:RC4-SHA:AES128-SHA:AES256-SHA:HIGH:!DSS:!aNULL"
|
||||
|
||||
if left NULL, then the "DEFAULT" set of ciphers are all possible to select.
|
||||
|
||||
|
||||
Async nature of client connections
|
||||
----------------------------------
|
||||
|
||||
When you call libwebsocket_client_connect(..) and get a wsi back, it does not
|
||||
mean your connection is active. It just mean it started trying to connect.
|
||||
|
||||
Your client connection is actually active only when you receive
|
||||
LWS_CALLBACK_CLIENT_ESTABLISHED for it.
|
||||
|
||||
There's a 5 second timeout for the connection, and it may give up or die for
|
||||
other reasons, if any of that happens you'll get a
|
||||
LWS_CALLBACK_CLIENT_CONNECTION_ERROR callback on protocol 0 instead for the
|
||||
wsi.
|
||||
|
||||
After attempting the connection and getting back a non-NULL wsi you should
|
||||
loop calling libwebsocket_service() until one of the above callbacks occurs.
|
||||
|
||||
As usual, see test-client.c for example code.
|
||||
|
||||
272
dependencies/libwebsockets/README.test-apps
vendored
Normal file
272
dependencies/libwebsockets/README.test-apps
vendored
Normal file
@ -0,0 +1,272 @@
|
||||
Testing server with a browser
|
||||
-----------------------------
|
||||
|
||||
If you run libwebsockets-test-server and point your browser
|
||||
(eg, Chrome) to
|
||||
|
||||
http://127.0.0.1:7681
|
||||
|
||||
It will fetch a script in the form of test.html, and then run the
|
||||
script in there on the browser to open a websocket connection.
|
||||
Incrementing numbers should appear in the browser display.
|
||||
|
||||
By default the test server logs to both stderr and syslog, you can control
|
||||
what is logged using -d <log level>, see later.
|
||||
|
||||
|
||||
Running test server as a Daemon
|
||||
-------------------------------
|
||||
|
||||
You can use the -D option on the test server to have it fork into the
|
||||
background and return immediately. In this daemonized mode all stderr is
|
||||
disabled and logging goes only to syslog, eg, /var/log/messages or similar.
|
||||
|
||||
The server maintains a lockfile at /tmp/.lwsts-lock that contains the pid
|
||||
of the master process, and deletes this file when the master process
|
||||
terminates.
|
||||
|
||||
To stop the daemon, do
|
||||
|
||||
kill `cat /tmp/.lwsts-lock`
|
||||
|
||||
If it finds a stale lock (the pid mentioned in the file does not exist
|
||||
any more) it will delete the lock and create a new one during startup.
|
||||
|
||||
If the lock is valid, the daemon will exit with a note on stderr that
|
||||
it was already running.s
|
||||
|
||||
|
||||
Using SSL on the server side
|
||||
----------------------------
|
||||
|
||||
To test it using SSL/WSS, just run the test server with
|
||||
|
||||
$ libwebsockets-test-server --ssl
|
||||
|
||||
and use the URL
|
||||
|
||||
https://127.0.0.1:7681
|
||||
|
||||
The connection will be entirely encrypted using some generated
|
||||
certificates that your browser will not accept, since they are
|
||||
not signed by any real Certificate Authority. Just accept the
|
||||
certificates in the browser and the connection will proceed
|
||||
in first https and then websocket wss, acting exactly the
|
||||
same.
|
||||
|
||||
test-server.c is all that is needed to use libwebsockets for
|
||||
serving both the script html over http and websockets.
|
||||
|
||||
|
||||
Testing websocket client support
|
||||
--------------------------------
|
||||
|
||||
If you run the test server as described above, you can also
|
||||
connect to it using the test client as well as a browser.
|
||||
|
||||
$ libwebsockets-test-client localhost
|
||||
|
||||
will by default connect to the test server on localhost:7681
|
||||
and print the dumb increment number from the server at the
|
||||
same time as drawing random circles in the mirror protocol;
|
||||
if you connect to the test server using a browser at the
|
||||
same time you will be able to see the circles being drawn.
|
||||
|
||||
|
||||
Testing simple echo
|
||||
-------------------
|
||||
|
||||
You can test against echo.websockets.org as a sanity test like
|
||||
this (the client connects to port 80 by default):
|
||||
|
||||
$ libwebsockets-test-echo --client echo.websocket.org
|
||||
|
||||
This echo test is of limited use though because it doesn't
|
||||
negotiate any protocol. You can run the same test app as a
|
||||
local server, by default on localhost:7681
|
||||
|
||||
$ libwebsockets-test-echo
|
||||
|
||||
and do the echo test against the local echo server
|
||||
|
||||
$ libwebsockets-test-echo --client localhost --port 7681
|
||||
|
||||
If you add the --ssl switch to both the client and server, you can also test
|
||||
with an encrypted link.
|
||||
|
||||
|
||||
Testing SSL on the client side
|
||||
------------------------------
|
||||
|
||||
To test SSL/WSS client action, just run the client test with
|
||||
|
||||
$ libwebsockets-test-client localhost --ssl
|
||||
|
||||
By default the client test applet is set to accept selfsigned
|
||||
certificates used by the test server, this is indicated by the
|
||||
use_ssl var being set to 2. Set it to 1 to reject any server
|
||||
certificate that it doesn't have a trusted CA cert for.
|
||||
|
||||
|
||||
Using the websocket ping utility
|
||||
--------------------------------
|
||||
|
||||
libwebsockets-test-ping connects as a client to a remote
|
||||
websocket server using 04 protocol and pings it like the
|
||||
normal unix ping utility.
|
||||
|
||||
$ libwebsockets-test-ping localhost
|
||||
handshake OK for protocol lws-mirror-protocol
|
||||
Websocket PING localhost.localdomain (127.0.0.1) 64 bytes of data.
|
||||
64 bytes from localhost: req=1 time=0.1ms
|
||||
64 bytes from localhost: req=2 time=0.1ms
|
||||
64 bytes from localhost: req=3 time=0.1ms
|
||||
64 bytes from localhost: req=4 time=0.2ms
|
||||
64 bytes from localhost: req=5 time=0.1ms
|
||||
64 bytes from localhost: req=6 time=0.2ms
|
||||
64 bytes from localhost: req=7 time=0.2ms
|
||||
64 bytes from localhost: req=8 time=0.1ms
|
||||
^C
|
||||
--- localhost.localdomain websocket ping statistics ---
|
||||
8 packets transmitted, 8 received, 0% packet loss, time 7458ms
|
||||
rtt min/avg/max = 0.110/0.185/0.218 ms
|
||||
$
|
||||
|
||||
By default it sends 64 byte payload packets using the 04
|
||||
PING packet opcode type. You can change the payload size
|
||||
using the -s= flag, up to a maximum of 125 mandated by the
|
||||
04 standard.
|
||||
|
||||
Using the lws-mirror protocol that is provided by the test
|
||||
server, libwebsockets-test-ping can also use larger payload
|
||||
sizes up to 4096 is BINARY packets; lws-mirror will copy
|
||||
them back to the client and they appear as a PONG. Use the
|
||||
-m flag to select this operation.
|
||||
|
||||
The default interval between pings is 1s, you can use the -i=
|
||||
flag to set this, including fractions like -i=0.01 for 10ms
|
||||
interval.
|
||||
|
||||
Before you can even use the PING opcode that is part of the
|
||||
standard, you must complete a handshake with a specified
|
||||
protocol. By default lws-mirror-protocol is used which is
|
||||
supported by the test server. But if you are using it on
|
||||
another server, you can specify the protcol to handshake with
|
||||
by --protocol=protocolname
|
||||
|
||||
|
||||
Fraggle test app
|
||||
----------------
|
||||
|
||||
By default it runs in server mode
|
||||
|
||||
$ libwebsockets-test-fraggle
|
||||
libwebsockets test fraggle
|
||||
(C) Copyright 2010-2011 Andy Green <andy@warmcat.com> licensed under LGPL2.1
|
||||
Compiled with SSL support, not using it
|
||||
Listening on port 7681
|
||||
server sees client connect
|
||||
accepted v06 connection
|
||||
Spamming 360 random fragments
|
||||
Spamming session over, len = 371913. sum = 0x2D3C0AE
|
||||
Spamming 895 random fragments
|
||||
Spamming session over, len = 875970. sum = 0x6A74DA1
|
||||
...
|
||||
|
||||
You need to run a second session in client mode, you have to
|
||||
give the -c switch and the server address at least:
|
||||
|
||||
$ libwebsockets-test-fraggle -c localhost
|
||||
libwebsockets test fraggle
|
||||
(C) Copyright 2010-2011 Andy Green <andy@warmcat.com> licensed under LGPL2.1
|
||||
Client mode
|
||||
Connecting to localhost:7681
|
||||
denied deflate-stream extension
|
||||
handshake OK for protocol fraggle-protocol
|
||||
client connects to server
|
||||
EOM received 371913 correctly from 360 fragments
|
||||
EOM received 875970 correctly from 895 fragments
|
||||
EOM received 247140 correctly from 258 fragments
|
||||
EOM received 695451 correctly from 692 fragments
|
||||
...
|
||||
|
||||
The fraggle test sends a random number up to 1024 fragmented websocket frames
|
||||
each of a random size between 1 and 2001 bytes in a single message, then sends
|
||||
a checksum and starts sending a new randomly sized and fragmented message.
|
||||
|
||||
The fraggle test client receives the same message fragments and computes the
|
||||
same checksum using websocket framing to see when the message has ended. It
|
||||
then accepts the server checksum message and compares that to its checksum.
|
||||
|
||||
|
||||
proxy support
|
||||
-------------
|
||||
|
||||
The http_proxy environment variable is respected by the client
|
||||
connection code for both ws:// and wss://. It doesn't support
|
||||
authentication.
|
||||
|
||||
You use it like this
|
||||
|
||||
export http_proxy=myproxy.com:3128
|
||||
libwebsockets-test-client someserver.com
|
||||
|
||||
|
||||
debug logging
|
||||
-------------
|
||||
|
||||
By default logging of severity "notice", "warn" or "err" is enabled to stderr.
|
||||
|
||||
Again by default other logging is comiled in but disabled from printing.
|
||||
|
||||
If you want to eliminate the debug logging below notice in severity, use the
|
||||
--disable-debug configure option to have it removed from the code by the
|
||||
preprocesser.
|
||||
|
||||
If you want to see more detailed debug logs, you can control a bitfield to
|
||||
select which logs types may print using the lws_set_log_level() api, in the
|
||||
test apps you can use -d <number> to control this. The types of logging
|
||||
available are (OR together the numbers to select multiple)
|
||||
|
||||
1 ERR
|
||||
2 WARN
|
||||
4 NOTICE
|
||||
8 INFO
|
||||
16 DEBUG
|
||||
32 PARSER
|
||||
64 HEADER
|
||||
128 EXTENSION
|
||||
256 CLIENT
|
||||
512 LATENCY
|
||||
|
||||
|
||||
Websocket version supported
|
||||
---------------------------
|
||||
|
||||
The final IETF standard is supported for both client and server, protocol
|
||||
version 13.
|
||||
|
||||
|
||||
Latency Tracking
|
||||
----------------
|
||||
|
||||
Since libwebsockets runs using poll() and a single threaded approach, any
|
||||
unexpected latency coming from system calls would be bad news. There's now
|
||||
a latency tracking scheme that can be built in with --with-latency at
|
||||
configure-time, logging the time taken for system calls to complete and if
|
||||
the whole action did complete that time or was deferred.
|
||||
|
||||
You can see the detailed data by enabling logging level 512 (eg, -d 519 on
|
||||
the test server to see that and the usual logs), however even without that
|
||||
the "worst" latency is kept and reported to the logs with NOTICE severity
|
||||
when the context is destroyed.
|
||||
|
||||
Some care is needed interpreting them, if the action completed the first figure
|
||||
(in us) is the time taken for the whole action, which may have retried through
|
||||
the poll loop many times and will depend on network roundtrip times. High
|
||||
figures here don't indicate a problem. The figure in us reported after "lat"
|
||||
in the logging is the time taken by this particular attempt. High figures
|
||||
here may indicate a problem, or if you system is loaded with another app at
|
||||
that time, such as the browser, it may simply indicate the OS gave preferential
|
||||
treatment to the other app during that call.
|
||||
|
||||
621
dependencies/libwebsockets/changelog
vendored
Normal file
621
dependencies/libwebsockets/changelog
vendored
Normal file
@ -0,0 +1,621 @@
|
||||
Changelog
|
||||
---------
|
||||
|
||||
v1.3-chrome37-firefox30
|
||||
=======================
|
||||
|
||||
.gitignore | 1 -
|
||||
CMakeLists.txt | 447 +++--
|
||||
README.build | 35 +-
|
||||
README.coding | 14 +
|
||||
changelog | 66 +
|
||||
cmake/LibwebsocketsConfig.cmake.in | 17 +
|
||||
cmake/LibwebsocketsConfigVersion.cmake.in | 11 +
|
||||
config.h.cmake | 18 +
|
||||
cross-ming.cmake | 31 +
|
||||
cross-openwrt-makefile | 91 +
|
||||
lib/client-handshake.c | 205 ++-
|
||||
lib/client-parser.c | 58 +-
|
||||
lib/client.c | 158 +-
|
||||
lib/context.c | 341 ++++
|
||||
lib/extension-deflate-frame.c | 2 +-
|
||||
lib/extension.c | 178 ++
|
||||
lib/handshake.c | 287 +---
|
||||
lib/lextable.h | 338 ++++
|
||||
lib/libev.c | 175 ++
|
||||
lib/libwebsockets.c | 2089 +++--------------------
|
||||
lib/libwebsockets.h | 253 ++-
|
||||
lib/lws-plat-unix.c | 404 +++++
|
||||
lib/lws-plat-win.c | 358 ++++
|
||||
lib/minilex.c | 530 +++---
|
||||
lib/output.c | 445 ++---
|
||||
lib/parsers.c | 682 ++++----
|
||||
lib/pollfd.c | 239 +++
|
||||
lib/private-libwebsockets.h | 501 +++++-
|
||||
lib/server-handshake.c | 274 +--
|
||||
lib/server.c | 858 ++++++++--
|
||||
lib/service.c | 517 ++++++
|
||||
lib/sha-1.c | 38 +-
|
||||
lib/ssl-http2.c | 78 +
|
||||
lib/ssl.c | 571 +++++++
|
||||
test-server/attack.sh | 101 +-
|
||||
test-server/test-client.c | 9 +-
|
||||
test-server/test-echo.c | 17 +-
|
||||
test-server/test-fraggle.c | 7 -
|
||||
test-server/test-ping.c | 12 +-
|
||||
test-server/test-server.c | 330 ++--
|
||||
test-server/test.html | 4 +-
|
||||
win32port/client/client.vcxproj | 259 ---
|
||||
win32port/client/client.vcxproj.filters | 39 -
|
||||
.../libwebsocketswin32.vcxproj.filters | 93 -
|
||||
win32port/server/server.vcxproj | 276 ---
|
||||
win32port/server/server.vcxproj.filters | 51 -
|
||||
win32port/win32helpers/gettimeofday.h | 59 +-
|
||||
win32port/win32helpers/netdb.h | 1 -
|
||||
win32port/win32helpers/strings.h | 0
|
||||
win32port/win32helpers/sys/time.h | 1 -
|
||||
win32port/win32helpers/unistd.h | 0
|
||||
win32port/win32helpers/websock-w32.c | 104 --
|
||||
win32port/win32helpers/websock-w32.h | 62 -
|
||||
win32port/win32port.sln | 100 --
|
||||
win32port/zlib/gzio.c | 3 +-
|
||||
55 files changed, 6779 insertions(+), 5059 deletions(-)
|
||||
|
||||
|
||||
User api additions
|
||||
------------------
|
||||
|
||||
POST method is supported
|
||||
|
||||
The protocol 0 / HTTP callback can now get two new kinds of callback,
|
||||
LWS_CALLBACK_HTTP_BODY (in and len are a chunk of the body of the HTTP request)
|
||||
and LWS_CALLBACK_HTTP_BODY_COMPLETION (the expected amount of body has arrived
|
||||
and been passed to the user code already). These callbacks are used with the
|
||||
post method (see the test server for details).
|
||||
|
||||
The period between the HTTP header completion and the completion of the body
|
||||
processing is protected by a 5s timeout.
|
||||
|
||||
The chunks are stored in a malloc'd buffer of size protocols[0].rx_buffer_size.
|
||||
|
||||
|
||||
New server option you can enable from user code
|
||||
LWS_SERVER_OPTION_ALLOW_NON_SSL_ON_SSL_PORT allows non-SSL connections to
|
||||
also be accepted on an SSL listening port. It's disabled unless you enable
|
||||
it explicitly.
|
||||
|
||||
|
||||
Two new callbacks are added in protocols[0] that are optional for allowing
|
||||
limited thread access to libwebsockets, LWS_CALLBACK_LOCK_POLL and
|
||||
LWS_CALLBACK_UNLOCK_POLL.
|
||||
|
||||
If you use them, they protect internal and external poll list changes, but if
|
||||
you want to use external thread access to libwebsocket_callback_on_writable()
|
||||
you have to implement your locking here even if you don't use external
|
||||
poll support.
|
||||
|
||||
If you will use another thread for this, take a lot of care about managing
|
||||
your list of live wsi by doing it from ESTABLISHED and CLOSED callbacks
|
||||
(with your own locking).
|
||||
|
||||
If you configure cmake with -DLWS_WITH_LIBEV=1 then the code allowing the libev
|
||||
eventloop instead of the default poll() one will also be compiled in. But to
|
||||
use it, you must also set the LWS_SERVER_OPTION_LIBEV flag on the context
|
||||
creation info struct options member.
|
||||
|
||||
IPV6 is supported and enabled by default except for Windows, you can disable
|
||||
the support at build-time by giving -DLWS_IPV6=, and disable use of it even if
|
||||
compiled in by making sure the flag LWS_SERVER_OPTION_DISABLE_IPV6 is set on
|
||||
the context creation info struct options member.
|
||||
|
||||
You can give LWS_SERVER_OPTION_DISABLE_OS_CA_CERTS option flag to
|
||||
guarantee the OS CAs will not be used, even if that support was selected at
|
||||
build-time.
|
||||
|
||||
Optional "token limits" may be enforced by setting the member "token_limits"
|
||||
in struct lws_context_creation_info to point to a struct lws_token_limits.
|
||||
NULL means no token limits used for compatibility.
|
||||
|
||||
|
||||
User api changes
|
||||
----------------
|
||||
|
||||
Extra optional argument to libwebsockets_serve_http_file() allows injecion
|
||||
of HTTP headers into the canned response. Eg, cookies may be added like
|
||||
that without getting involved in having to send the header by hand.
|
||||
|
||||
A new info member http_proxy_address may be used at context creation time to
|
||||
set the http proxy. If non-NULL, it overrides http_proxy environment var.
|
||||
|
||||
Cmake supports LWS_SSL_CLIENT_USE_OS_CA_CERTS defaulting to on, which gets
|
||||
the client to use the OS CA Roots. If you're worried somebody with the
|
||||
ability to forge for force creation of a client cert from the root CA in
|
||||
your OS, you should disable this since your selfsigned $0 cert is a lot safer
|
||||
then...
|
||||
|
||||
|
||||
v1.23-chrome32-firefox24
|
||||
========================
|
||||
|
||||
Android.mk | 29 +
|
||||
CMakeLists.txt | 573 ++++++++----
|
||||
COPYING | 503 -----------
|
||||
INSTALL | 365 --------
|
||||
Makefile.am | 13 -
|
||||
README.build | 371 ++------
|
||||
README.coding | 63 ++
|
||||
autogen.sh | 1578 ---------------------------------
|
||||
changelog | 69 ++
|
||||
cmake/FindGit.cmake | 163 ++++
|
||||
cmake/FindOpenSSLbins.cmake | 15 +-
|
||||
cmake/UseRPMTools.cmake | 176 ++++
|
||||
config.h.cmake | 25 +-
|
||||
configure.ac | 226 -----
|
||||
cross-arm-linux-gnueabihf.cmake | 28 +
|
||||
lib/Makefile.am | 89 --
|
||||
lib/base64-decode.c | 98 +-
|
||||
lib/client-handshake.c | 123 ++-
|
||||
lib/client-parser.c | 19 +-
|
||||
lib/client.c | 145 ++-
|
||||
lib/daemonize.c | 4 +-
|
||||
lib/extension.c | 2 +-
|
||||
lib/getifaddrs.h | 4 +-
|
||||
lib/handshake.c | 76 +-
|
||||
lib/libwebsockets.c | 491 ++++++----
|
||||
lib/libwebsockets.h | 164 ++--
|
||||
lib/output.c | 214 ++++-
|
||||
lib/parsers.c | 102 +--
|
||||
lib/private-libwebsockets.h | 66 +-
|
||||
lib/server-handshake.c | 5 +-
|
||||
lib/server.c | 29 +-
|
||||
lib/sha-1.c | 2 +-
|
||||
libwebsockets-api-doc.html | 249 +++---
|
||||
libwebsockets.pc.in | 11 -
|
||||
libwebsockets.spec | 14 +-
|
||||
m4/ignore-me | 2 -
|
||||
scripts/FindLibWebSockets.cmake | 33 +
|
||||
scripts/kernel-doc | 1 +
|
||||
test-server/Makefile.am | 131 ---
|
||||
test-server/leaf.jpg | Bin 0 -> 2477518 bytes
|
||||
test-server/test-client.c | 78 +-
|
||||
test-server/test-echo.c | 33 +-
|
||||
test-server/test-fraggle.c | 26 +-
|
||||
test-server/test-ping.c | 15 +-
|
||||
test-server/test-server.c | 197 +++-
|
||||
test-server/test.html | 5 +-
|
||||
win32port/win32helpers/gettimeofday.c | 74 +-
|
||||
win32port/win32helpers/websock-w32.h | 6 +-
|
||||
48 files changed, 2493 insertions(+), 4212 deletions(-)
|
||||
|
||||
|
||||
User api additions
|
||||
------------------
|
||||
|
||||
- You can now call libwebsocket_callback_on_writable() on http connectons,
|
||||
and get a LWS_CALLBACK_HTTP_WRITEABLE callback, the same way you can
|
||||
regulate writes with a websocket protocol connection.
|
||||
|
||||
- A new member in the context creation parameter struct "ssl_cipher_list" is
|
||||
added, replacing CIPHERS_LIST_STRING. NULL means use the ssl library
|
||||
default list of ciphers.
|
||||
|
||||
- Not really an api addition, but libwebsocket_service_fd() will now zero
|
||||
the revents field of the pollfd it was called with if it handled the
|
||||
descriptor. So you can tell if it is a non-lws fd by checking revents
|
||||
after the service call... if it's still nonzero, the descriptor
|
||||
belongs to you and you need to take care of it.
|
||||
|
||||
- libwebsocket_rx_flow_allow_all_protocol(protocol) will unthrottle all
|
||||
connections with the established protocol. It's designed to be
|
||||
called from user server code when it sees it can accept more input
|
||||
and may have throttled connections using the server rx flow apis
|
||||
while it was unable to accept any other input The user server code
|
||||
then does not have to try to track while connections it choked, this
|
||||
will free up all of them in one call.
|
||||
|
||||
- there's a new, optional callback LWS_CALLBACK_CLOSED_HTTP which gets
|
||||
called when an HTTP protocol socket closes
|
||||
|
||||
- for LWS_CALLBACK_FILTER_PROTOCOL_CONNECTION callback, the user_space alloc
|
||||
has already been done before the callback happens. That means we can
|
||||
use the user parameter to the callback to contain the user pointer, and
|
||||
move the protocol name to the "in" parameter. The docs for this
|
||||
callback are also updated to reflect how to check headers in there.
|
||||
|
||||
- libwebsocket_client_connect() is now properly nonblocking and async. See
|
||||
README.coding and test-client.c for information on the callbacks you
|
||||
can rely on controlling the async connection period with.
|
||||
|
||||
- if your OS does not support the http_proxy environment variable convention
|
||||
(eg, reportedly OSX), you can use a new api libwebsocket_set_proxy()
|
||||
to set the proxy details inbetween context creation and the connection
|
||||
action. For OSes that support http_proxy, that's used automatically.
|
||||
|
||||
User api changes
|
||||
----------------
|
||||
|
||||
- the external poll callbacks now get the socket descriptor coming from the
|
||||
"in" parameter. The user parameter provides the user_space for the
|
||||
wsi as it normally does on the other callbacks.
|
||||
LWS_CALLBACK_FILTER_NETWORK_CONNECTION also has the socket descriptor
|
||||
delivered by @in now instead of @user.
|
||||
|
||||
- libwebsocket_write() now returns -1 for error, or the amount of data
|
||||
actually accepted for send. Under load, the OS may signal it is
|
||||
ready to send new data on the socket, but have only a restricted
|
||||
amount of memory to buffer the packet compared to usual.
|
||||
|
||||
|
||||
User api removal
|
||||
----------------
|
||||
|
||||
- libwebsocket_ensure_user_space() is removed from the public api, if you
|
||||
were using it to get user_space, you need to adapt your code to only
|
||||
use user_space inside the user callback.
|
||||
|
||||
- CIPHERS_LIST_STRING is removed
|
||||
|
||||
- autotools build has been removed. See README.build for info on how to
|
||||
use CMake for your platform
|
||||
|
||||
|
||||
v1.21-chrome26-firefox18
|
||||
========================
|
||||
|
||||
- Fixes buffer overflow bug in max frame size handling if you used the
|
||||
default protocol buffer size. If you declared rx_buffer_size in your
|
||||
protocol, which is recommended anyway, your code was unaffected.
|
||||
|
||||
v1.2-chrome26-firefox18
|
||||
=======================
|
||||
|
||||
Diffstat
|
||||
--------
|
||||
|
||||
.gitignore | 16 +++
|
||||
CMakeLists.txt | 544 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
LICENSE | 526 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
Makefile.am | 1 +
|
||||
README | 20 +++
|
||||
README.build | 258 ++++++++++++++++++++++++++++++++-----
|
||||
README.coding | 52 ++++++++
|
||||
changelog | 136 ++++++++++++++++++++
|
||||
cmake/FindOpenSSLbins.cmake | 33 +++++
|
||||
config.h.cmake | 173 +++++++++++++++++++++++++
|
||||
configure.ac | 22 +++-
|
||||
lib/Makefile.am | 20 ++-
|
||||
lib/base64-decode.c | 2 +-
|
||||
lib/client-handshake.c | 190 +++++++++++-----------------
|
||||
lib/client-parser.c | 88 +++++++------
|
||||
lib/client.c | 384 ++++++++++++++++++++++++++++++-------------------------
|
||||
lib/daemonize.c | 32 +++--
|
||||
lib/extension-deflate-frame.c | 58 +++++----
|
||||
lib/extension-deflate-stream.c | 19 ++-
|
||||
lib/extension-deflate-stream.h | 4 +-
|
||||
lib/extension.c | 11 +-
|
||||
lib/getifaddrs.c | 315 +++++++++++++++++++++++-----------------------
|
||||
lib/getifaddrs.h | 30 ++---
|
||||
lib/handshake.c | 124 +++++++++++-------
|
||||
lib/libwebsockets.c | 736 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--------------------------------------
|
||||
lib/libwebsockets.h | 237 ++++++++++++++++++++++------------
|
||||
lib/output.c | 192 +++++++++++-----------------
|
||||
lib/parsers.c | 966 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----------------------------------------------------------------
|
||||
lib/private-libwebsockets.h | 225 +++++++++++++++++++++------------
|
||||
lib/server-handshake.c | 82 ++++++------
|
||||
lib/server.c | 96 +++++++-------
|
||||
libwebsockets-api-doc.html | 189 ++++++++++++++++++----------
|
||||
libwebsockets.spec | 17 +--
|
||||
test-server/attack.sh | 148 ++++++++++++++++++++++
|
||||
test-server/test-client.c | 125 +++++++++---------
|
||||
test-server/test-echo.c | 31 +++--
|
||||
test-server/test-fraggle.c | 32 ++---
|
||||
test-server/test-ping.c | 52 ++++----
|
||||
test-server/test-server.c | 129 ++++++++++++-------
|
||||
win32port/libwebsocketswin32/libwebsocketswin32.vcxproj | 279 ----------------------------------------
|
||||
win32port/libwebsocketswin32/libwebsocketswin32.vcxproj.filters | 23 +++-
|
||||
41 files changed, 4398 insertions(+), 2219 deletions(-)
|
||||
|
||||
|
||||
User api additions
|
||||
------------------
|
||||
|
||||
- lws_get_library_version() returns a const char * with a string like
|
||||
"1.1 9e7f737", representing the library version from configure.ac
|
||||
and the git HEAD hash the library was built from
|
||||
|
||||
- TCP Keepalive can now optionally be applied to all lws sockets, on Linux
|
||||
also with controllable timeout, number of probes and probe interval.
|
||||
(On BSD type OS, you can only use system default settings for the
|
||||
timing and retries, although enabling it is supported by setting
|
||||
ka_time to nonzero, the exact value has no meaning.)
|
||||
This enables detection of idle connections which are logically okay,
|
||||
but are in fact dead, due to network connectivity issues at the server,
|
||||
client, or any intermediary. By default it's not enabled, but you
|
||||
can enable it by setting a non-zero timeout (in seconds) at the new
|
||||
ka_time member at context creation time.
|
||||
|
||||
- Two new optional user callbacks added, LWS_CALLBACK_PROTOCOL_DESTROY which
|
||||
is called one-time per protocol as the context is being destroyed, and
|
||||
LWS_CALLBACK_PROTOCOL_INIT which is called when the context is created
|
||||
and the protocols are added, again it's a one-time affair.
|
||||
This lets you manage per-protocol allocations properly including
|
||||
cleaning up after yourself when the server goes down.
|
||||
|
||||
User api changes
|
||||
----------------
|
||||
|
||||
- libwebsocket_create_context() has changed from taking a ton of parameters
|
||||
to just taking a pointer to a struct containing the parameters. The
|
||||
struct lws_context_creation_info is in libwebsockets.h, the members
|
||||
are in the same order as when they were parameters to the call
|
||||
previously. The test apps are all updated accordingly so you can
|
||||
see example code there.
|
||||
|
||||
- Header tokens are now deleted after the websocket connection is
|
||||
established. Not just the header data is saved, but the pointer and
|
||||
length array is also removed from (union) scope saving several hundred
|
||||
bytes per connection once it is established
|
||||
|
||||
- struct libwebsocket_protocols has a new member rx_buffer_size, this
|
||||
controls rx buffer size per connection of that protocol now. Sources
|
||||
for apps built against older versions of the library won't declare
|
||||
this in their protocols, defaulting it to 0. Zero buffer is legal,
|
||||
it causes a default buffer to be allocated (currently 4096)
|
||||
|
||||
If you want to receive only atomic frames in your user callback, you
|
||||
should set this to greater than your largest frame size. If a frame
|
||||
comes that exceeds that, no error occurs but the callback happens as
|
||||
soon as the buffer limit is reached, and again if it is reached again
|
||||
or the frame completes. You can detect that has happened by seeing
|
||||
there is still frame content pending using
|
||||
libwebsockets_remaining_packet_payload()
|
||||
|
||||
By correctly setting this, you can save a lot of memory when your
|
||||
protocol has small frames (see the test server and client sources).
|
||||
|
||||
- LWS_MAX_HEADER_LEN now defaults to 1024 and is the total amount of known
|
||||
header payload lws can cope with, that includes the GET URL, origin
|
||||
etc. Headers not understood by lws are ignored and their payload
|
||||
not included in this.
|
||||
|
||||
|
||||
User api removals
|
||||
-----------------
|
||||
|
||||
- The configuration-time option MAX_USER_RX_BUFFER has been replaced by a
|
||||
buffer size chosen per-protocol. For compatibility, there's a default
|
||||
of 4096 rx buffer, but user code should set the appropriate size for
|
||||
the protocol frames.
|
||||
|
||||
- LWS_INITIAL_HDR_ALLOC and LWS_ADDITIONAL_HDR_ALLOC are no longer needed
|
||||
and have been removed. There's a new header management scheme that
|
||||
handles them in a much more compact way.
|
||||
|
||||
- libwebsockets_hangup_on_client() is removed. If you want to close the
|
||||
connection you must do so from the user callback and by returning
|
||||
-1 from there.
|
||||
|
||||
- libwebsocket_close_and_free_session() is now private to the library code
|
||||
only and not exposed for user code. If you want to close the
|
||||
connection, you must do so from the user callback by returning -1
|
||||
from there.
|
||||
|
||||
|
||||
New features
|
||||
------------
|
||||
|
||||
- Cmake project file added, aimed initially at Windows support: this replaces
|
||||
the visual studio project files that were in the tree until now.
|
||||
|
||||
- CyaSSL now supported in place of OpenSSL (--use-cyassl on configure)
|
||||
|
||||
- PATH_MAX or MAX_PATH no longer needed
|
||||
|
||||
- cutomizable frame rx buffer size by protocol
|
||||
|
||||
- optional TCP keepalive so dead peers can be detected, can be enabled at
|
||||
context-creation time
|
||||
|
||||
- valgrind-clean: no SSL or CyaSSL: completely clean. With OpenSSL, 88 bytes
|
||||
lost at OpenSSL library init and symptomless reports of uninitialized
|
||||
memory usage... seems to be a known and ignored problem at OpenSSL
|
||||
|
||||
- By default debug is enabled and the library is built for -O0 -g to faclitate
|
||||
that. Use --disable-debug configure option to build instead with -O4
|
||||
and no -g (debug info), obviously providing best performance and
|
||||
reduced binary size.
|
||||
|
||||
- 1.0 introduced some code to try to not deflate small frames, however this
|
||||
seems to break when confronted with a mixture of frames above and
|
||||
below the threshold, so it's removed. Veto the compression extension
|
||||
in your user callback if you will typically have very small frames.
|
||||
|
||||
- There are many memory usage improvements, both a reduction in malloc/
|
||||
realloc and architectural changes. A websocket connection now
|
||||
consumes only 296 bytes with SSL or 272 bytes without on x86_64,
|
||||
during header processing an additional 1262 bytes is allocated in a
|
||||
single malloc, but is freed when the websocket connection starts.
|
||||
The RX frame buffer defined by the protocol in user
|
||||
code is also allocated per connection, this represents the largest
|
||||
frame you can receive atomically in that protocol.
|
||||
|
||||
- On ARM9 build, just http+ws server no extensions or ssl, <12Kbytes .text
|
||||
and 112 bytes per connection (+1328 only during header processing)
|
||||
|
||||
|
||||
v1.1-chrome26-firefox18
|
||||
=======================
|
||||
|
||||
Diffstat
|
||||
--------
|
||||
|
||||
Makefile.am | 4 +
|
||||
README-test-server | 291 ---
|
||||
README.build | 239 ++
|
||||
README.coding | 138 ++
|
||||
README.rst | 72 -
|
||||
README.test-apps | 272 +++
|
||||
configure.ac | 116 +-
|
||||
lib/Makefile.am | 55 +-
|
||||
lib/base64-decode.c | 5 +-
|
||||
lib/client-handshake.c | 121 +-
|
||||
lib/client-parser.c | 394 ++++
|
||||
lib/client.c | 807 +++++++
|
||||
lib/daemonize.c | 212 ++
|
||||
lib/extension-deflate-frame.c | 132 +-
|
||||
lib/extension-deflate-stream.c | 12 +-
|
||||
lib/extension-x-google-mux.c | 1223 ----------
|
||||
lib/extension-x-google-mux.h | 96 -
|
||||
lib/extension.c | 8 -
|
||||
lib/getifaddrs.c | 271 +++
|
||||
lib/getifaddrs.h | 76 +
|
||||
lib/handshake.c | 582 +----
|
||||
lib/libwebsockets.c | 2493 ++++++---------------
|
||||
lib/libwebsockets.h | 115 +-
|
||||
lib/md5.c | 217 --
|
||||
lib/minilex.c | 440 ++++
|
||||
lib/output.c | 628 ++++++
|
||||
lib/parsers.c | 2016 +++++------------
|
||||
lib/private-libwebsockets.h | 284 +--
|
||||
lib/server-handshake.c | 275 +++
|
||||
lib/server.c | 377 ++++
|
||||
libwebsockets-api-doc.html | 300 +--
|
||||
m4/ignore-me | 2 +
|
||||
test-server/Makefile.am | 111 +-
|
||||
test-server/libwebsockets.org-logo.png | Bin 0 -> 7029 bytes
|
||||
test-server/test-client.c | 45 +-
|
||||
test-server/test-echo.c | 330 +++
|
||||
test-server/test-fraggle.c | 20 +-
|
||||
test-server/test-ping.c | 22 +-
|
||||
test-server/test-server-extpoll.c | 554 -----
|
||||
test-server/test-server.c | 349 ++-
|
||||
test-server/test.html | 3 +-
|
||||
win32port/zlib/ZLib.vcxproj | 749 ++++---
|
||||
win32port/zlib/ZLib.vcxproj.filters | 188 +-
|
||||
win32port/zlib/adler32.c | 348 ++-
|
||||
win32port/zlib/compress.c | 160 +-
|
||||
win32port/zlib/crc32.c | 867 ++++----
|
||||
win32port/zlib/crc32.h | 882 ++++----
|
||||
win32port/zlib/deflate.c | 3799 +++++++++++++++-----------------
|
||||
win32port/zlib/deflate.h | 688 +++---
|
||||
win32port/zlib/gzclose.c | 50 +-
|
||||
win32port/zlib/gzguts.h | 325 ++-
|
||||
win32port/zlib/gzlib.c | 1157 +++++-----
|
||||
win32port/zlib/gzread.c | 1242 ++++++-----
|
||||
win32port/zlib/gzwrite.c | 1096 +++++----
|
||||
win32port/zlib/infback.c | 1272 ++++++-----
|
||||
win32port/zlib/inffast.c | 680 +++---
|
||||
win32port/zlib/inffast.h | 22 +-
|
||||
win32port/zlib/inffixed.h | 188 +-
|
||||
win32port/zlib/inflate.c | 2976 +++++++++++++------------
|
||||
win32port/zlib/inflate.h | 244 +-
|
||||
win32port/zlib/inftrees.c | 636 +++---
|
||||
win32port/zlib/inftrees.h | 124 +-
|
||||
win32port/zlib/trees.c | 2468 +++++++++++----------
|
||||
win32port/zlib/trees.h | 256 +--
|
||||
win32port/zlib/uncompr.c | 118 +-
|
||||
win32port/zlib/zconf.h | 934 ++++----
|
||||
win32port/zlib/zlib.h | 3357 ++++++++++++++--------------
|
||||
win32port/zlib/zutil.c | 642 +++---
|
||||
win32port/zlib/zutil.h | 526 ++---
|
||||
69 files changed, 19556 insertions(+), 20145 deletions(-)
|
||||
|
||||
user api changes
|
||||
----------------
|
||||
|
||||
- libwebsockets_serve_http_file() now takes a context as first argument
|
||||
|
||||
- libwebsockets_get_peer_addresses() now takes a context and wsi as first
|
||||
two arguments
|
||||
|
||||
|
||||
user api additions
|
||||
------------------
|
||||
|
||||
- lwsl_...() logging apis, default to stderr but retargetable by user code;
|
||||
may be used also by user code
|
||||
|
||||
- lws_set_log_level() set which logging apis are able to emit (defaults to
|
||||
notice, warn, err severities), optionally set the emit callback
|
||||
|
||||
- lwsl_emit_syslog() helper callback emits to syslog
|
||||
|
||||
- lws_daemonize() helper code that forks the app into a headless daemon
|
||||
properly, maintains a lock file with pid in suitable for sysvinit etc to
|
||||
control lifecycle
|
||||
|
||||
- LWS_CALLBACK_HTTP_FILE_COMPLETION callback added since http file
|
||||
transfer is now asynchronous (see test server code)
|
||||
|
||||
- lws_frame_is_binary() from a wsi pointer, let you know if the received
|
||||
data was sent in BINARY mode
|
||||
|
||||
|
||||
user api removals
|
||||
-----------------
|
||||
|
||||
- libwebsockets_fork_service_loop() - no longer supported (had intractable problems)
|
||||
arrange your code to act from the user callback instead from same
|
||||
process context as the service loop
|
||||
|
||||
- libwebsockets_broadcast() - use libwebsocket_callback_on_writable[_all_protocol]()
|
||||
instead from same process context as the service loop. See the test apps
|
||||
for examples.
|
||||
|
||||
- x-google-mux() removed until someone wants it
|
||||
|
||||
- pre -v13 (ancient) protocol support removed
|
||||
|
||||
|
||||
New features
|
||||
------------
|
||||
|
||||
- echo test server and client compatible with echo.websocket.org added
|
||||
|
||||
- many new configure options (see README.build) to reduce footprint of the
|
||||
library to what you actually need, eg, --without-client and
|
||||
--without-server
|
||||
|
||||
- http + websocket server can build to as little as 12K .text for ARM
|
||||
|
||||
- no more MAX_CLIENTS limitation; adapts to support the max number of fds
|
||||
allowed to the process by ulimit, defaults to 1024 on Fedora and
|
||||
Ubuntu. Use ulimit to control this without needing to configure
|
||||
the library. Code here is smaller and faster.
|
||||
|
||||
- adaptive ratio of listen socket to connection socket service allows
|
||||
good behaviour under Apache ab test load. Tested with thousands
|
||||
of simultaneous connections
|
||||
|
||||
- reduction in per-connection memory footprint by moving to a union to hold
|
||||
mutually-exclusive state for the connection
|
||||
|
||||
- robustness: Out of Memory taken care of for all allocation code now
|
||||
|
||||
- internal getifaddrs option if your toolchain lacks it (some uclibc)
|
||||
|
||||
- configurable memory limit for deflate operations
|
||||
|
||||
- improvements in SSL code nonblocking operation, possible hang solved,
|
||||
some SSL operations broken down into pollable states so there is
|
||||
no library blocking, timeout coverage for SSL_connect
|
||||
|
||||
- extpoll test server merged into single test server source
|
||||
|
||||
- robustness: library should deal with all recoverable socket conditions
|
||||
|
||||
- rx flowcontrol for backpressure notification fixed and implmeneted
|
||||
correctly in the test server
|
||||
|
||||
- optimal lexical parser added for header processing; all headers in a
|
||||
single 276-byte state table
|
||||
|
||||
- latency tracking api added (configure --with-latency)
|
||||
|
||||
- Improved in-tree documentation, REAME.build, README.coding,
|
||||
README.test-apps, changelog
|
||||
|
||||
- Many small fixes
|
||||
|
||||
|
||||
v1.0-chrome25-firefox17 (6cd1ea9b005933f)
|
||||
163
dependencies/libwebsockets/cmake/FindGit.cmake
vendored
Normal file
163
dependencies/libwebsockets/cmake/FindGit.cmake
vendored
Normal file
@ -0,0 +1,163 @@
|
||||
################################################################################
|
||||
#
|
||||
# Program: 3D Slicer
|
||||
#
|
||||
# Copyright (c) Kitware Inc.
|
||||
#
|
||||
# See COPYRIGHT.txt
|
||||
# or http://www.slicer.org/copyright/copyright.txt for details.
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
# This file was originally developed by Jean-Christophe Fillion-Robin, Kitware Inc.
|
||||
# and was partially funded by NIH grant 3P41RR013218-12S1
|
||||
#
|
||||
# AG 2013-02-18: I got it from here
|
||||
# https://github.com/Slicer/Slicer/blob/master/CMake/FindGit.cmake
|
||||
# license is BSD
|
||||
#
|
||||
################################################################################
|
||||
|
||||
#
|
||||
# The module defines the following variables:
|
||||
# GIT_EXECUTABLE - path to git command line client
|
||||
# GIT_FOUND - true if the command line client was found
|
||||
#
|
||||
# If the command line client executable is found the macro
|
||||
# GIT_WC_INFO(<dir> <var-prefix>)
|
||||
# is defined to extract information of a git working copy at
|
||||
# a given location.
|
||||
#
|
||||
# The macro defines the following variables:
|
||||
# <var-prefix>_WC_REVISION_HASH - Current SHA1 hash
|
||||
# <var-prefix>_WC_REVISION - Current SHA1 hash
|
||||
# <var-prefix>_WC_REVISION_NAME - Name associated with <var-prefix>_WC_REVISION_HASH
|
||||
# <var-prefix>_WC_URL - output of command `git config --get remote.origin.url'
|
||||
# <var-prefix>_WC_ROOT - Same value as working copy URL
|
||||
# <var-prefix>_WC_GITSVN - Set to false
|
||||
#
|
||||
# ... and also the following ones if it's a git-svn repository:
|
||||
# <var-prefix>_WC_GITSVN - Set to True if it is a
|
||||
# <var-prefix>_WC_INFO - output of command `git svn info'
|
||||
# <var-prefix>_WC_URL - url of the associated SVN repository
|
||||
# <var-prefix>_WC_ROOT - root url of the associated SVN repository
|
||||
# <var-prefix>_WC_REVISION - current SVN revision number
|
||||
# <var-prefix>_WC_LAST_CHANGED_AUTHOR - author of last commit
|
||||
# <var-prefix>_WC_LAST_CHANGED_DATE - date of last commit
|
||||
# <var-prefix>_WC_LAST_CHANGED_REV - revision of last commit
|
||||
# <var-prefix>_WC_LAST_CHANGED_LOG - last log of base revision
|
||||
#
|
||||
# Example usage:
|
||||
# find_package(Git)
|
||||
# if(GIT_FOUND)
|
||||
# GIT_WC_INFO(${PROJECT_SOURCE_DIR} Project)
|
||||
# message("Current revision is ${Project_WC_REVISION_HASH}")
|
||||
# message("git found: ${GIT_EXECUTABLE}")
|
||||
# endif()
|
||||
#
|
||||
|
||||
# Look for 'git' or 'eg' (easy git)
|
||||
#
|
||||
set(git_names git eg)
|
||||
|
||||
# Prefer .cmd variants on Windows unless running in a Makefile
|
||||
# in the MSYS shell.
|
||||
#
|
||||
if(WIN32)
|
||||
if(NOT CMAKE_GENERATOR MATCHES "MSYS")
|
||||
# Note: Due to a bug in 'git.cmd' preventing it from returning the exit code of 'git',
|
||||
# we excluded it from the list of executables to search.
|
||||
# See http://code.google.com/p/msysgit/issues/detail?id=428
|
||||
# TODO Check if 'git' exists, get the associated version, if the corresponding version
|
||||
# is known to have a working version of 'git.cmd', use it.
|
||||
set(git_names git eg.cmd eg)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
find_program(GIT_EXECUTABLE ${git_names}
|
||||
PATHS
|
||||
"C:/Program Files/Git/bin"
|
||||
"C:/Program Files (x86)/Git/bin"
|
||||
DOC "git command line client")
|
||||
mark_as_advanced(GIT_EXECUTABLE)
|
||||
|
||||
if(GIT_EXECUTABLE)
|
||||
macro(GIT_WC_INFO dir prefix)
|
||||
execute_process(COMMAND ${GIT_EXECUTABLE} rev-parse --verify -q --short=7 HEAD
|
||||
WORKING_DIRECTORY ${dir}
|
||||
ERROR_VARIABLE GIT_error
|
||||
OUTPUT_VARIABLE ${prefix}_WC_REVISION_HASH
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||
set(${prefix}_WC_REVISION ${${prefix}_WC_REVISION_HASH})
|
||||
if(NOT ${GIT_error} EQUAL 0)
|
||||
message(SEND_ERROR "Command \"${GIT_EXECUTBALE} rev-parse --verify -q --short=7 HEAD\" in directory ${dir} failed with output:\n${GIT_error}")
|
||||
else(NOT ${GIT_error} EQUAL 0)
|
||||
execute_process(COMMAND ${GIT_EXECUTABLE} name-rev ${${prefix}_WC_REVISION_HASH}
|
||||
WORKING_DIRECTORY ${dir}
|
||||
OUTPUT_VARIABLE ${prefix}_WC_REVISION_NAME
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||
endif(NOT ${GIT_error} EQUAL 0)
|
||||
|
||||
execute_process(COMMAND ${GIT_EXECUTABLE} config --get remote.origin.url
|
||||
WORKING_DIRECTORY ${dir}
|
||||
OUTPUT_VARIABLE ${prefix}_WC_URL
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||
|
||||
set(${prefix}_WC_GITSVN False)
|
||||
|
||||
# Check if this git is likely to be a git-svn repository
|
||||
execute_process(COMMAND ${GIT_EXECUTABLE} config --get-regexp "^svn-remote"
|
||||
WORKING_DIRECTORY ${dir}
|
||||
OUTPUT_VARIABLE git_config_output
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
)
|
||||
|
||||
if(NOT "${git_config_output}" STREQUAL "")
|
||||
# In case git-svn is used, attempt to extract svn info
|
||||
execute_process(COMMAND ${GIT_EXECUTABLE} svn info
|
||||
WORKING_DIRECTORY ${dir}
|
||||
TIMEOUT 3
|
||||
ERROR_VARIABLE git_svn_info_error
|
||||
OUTPUT_VARIABLE ${prefix}_WC_INFO
|
||||
RESULT_VARIABLE git_svn_info_result
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||
|
||||
if(${git_svn_info_result} EQUAL 0)
|
||||
set(${prefix}_WC_GITSVN True)
|
||||
string(REGEX REPLACE "^(.*\n)?URL: ([^\n]+).*"
|
||||
"\\2" ${prefix}_WC_URL "${${prefix}_WC_INFO}")
|
||||
string(REGEX REPLACE "^(.*\n)?Revision: ([^\n]+).*"
|
||||
"\\2" ${prefix}_WC_REVISION "${${prefix}_WC_INFO}")
|
||||
string(REGEX REPLACE "^(.*\n)?Repository Root: ([^\n]+).*"
|
||||
"\\2" ${prefix}_WC_ROOT "${${prefix}_WC_INFO}")
|
||||
string(REGEX REPLACE "^(.*\n)?Last Changed Author: ([^\n]+).*"
|
||||
"\\2" ${prefix}_WC_LAST_CHANGED_AUTHOR "${${prefix}_WC_INFO}")
|
||||
string(REGEX REPLACE "^(.*\n)?Last Changed Rev: ([^\n]+).*"
|
||||
"\\2" ${prefix}_WC_LAST_CHANGED_REV "${${prefix}_WC_INFO}")
|
||||
string(REGEX REPLACE "^(.*\n)?Last Changed Date: ([^\n]+).*"
|
||||
"\\2" ${prefix}_WC_LAST_CHANGED_DATE "${${prefix}_WC_INFO}")
|
||||
endif(${git_svn_info_result} EQUAL 0)
|
||||
endif(NOT "${git_config_output}" STREQUAL "")
|
||||
|
||||
# If there is no 'remote.origin', default to "NA" value and print a warning message.
|
||||
if(NOT ${prefix}_WC_URL)
|
||||
message(WARNING "No remote origin set for git repository: ${dir}" )
|
||||
set( ${prefix}_WC_URL "NA" )
|
||||
else()
|
||||
set(${prefix}_WC_ROOT ${${prefix}_WC_URL})
|
||||
endif()
|
||||
|
||||
endmacro(GIT_WC_INFO)
|
||||
endif(GIT_EXECUTABLE)
|
||||
|
||||
# Handle the QUIETLY and REQUIRED arguments and set GIT_FOUND to TRUE if
|
||||
# all listed variables are TRUE
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(Git DEFAULT_MSG GIT_EXECUTABLE)
|
||||
|
||||
|
||||
42
dependencies/libwebsockets/cmake/FindOpenSSLbins.cmake
vendored
Normal file
42
dependencies/libwebsockets/cmake/FindOpenSSLbins.cmake
vendored
Normal file
@ -0,0 +1,42 @@
|
||||
|
||||
if(OPENSSL_FOUND)
|
||||
|
||||
find_program(OPENSSL_EXECUTABLE openssl openssl.exe bin/openssl.exe
|
||||
HINTS ${_OPENSSL_ROOT_HINTS}
|
||||
PATH
|
||||
/usr/bin/
|
||||
bin/
|
||||
DOC "Openssl executable")
|
||||
|
||||
mark_as_advanced(OPENSSL_EXECUTABLE)
|
||||
|
||||
# On Windows, we need to copy the OpenSSL dlls
|
||||
# to the output directory.
|
||||
if(WIN32)
|
||||
set(OPENSSL_BIN_FOUND 0)
|
||||
|
||||
find_file(LIBEAY_BIN
|
||||
NAMES
|
||||
libeay32.dll
|
||||
HINTS
|
||||
${_OPENSSL_ROOT_HINTS}
|
||||
PATH_SUFFIXES
|
||||
bin)
|
||||
|
||||
find_file(SSLEAY_BIN
|
||||
NAMES
|
||||
ssleay32.dll
|
||||
HINTS
|
||||
${_OPENSSL_ROOT_HINTS}
|
||||
PATH_SUFFIXES
|
||||
bin)
|
||||
|
||||
if(LIBEAY_BIN)
|
||||
if(SSLEAY_BIN)
|
||||
set(OPENSSL_BIN_FOUND 1)
|
||||
endif(SSLEAY_BIN)
|
||||
endif(LIBEAY_BIN)
|
||||
endif(WIN32)
|
||||
|
||||
endif(OPENSSL_FOUND)
|
||||
|
||||
17
dependencies/libwebsockets/cmake/LibwebsocketsConfig.cmake.in
vendored
Normal file
17
dependencies/libwebsockets/cmake/LibwebsocketsConfig.cmake.in
vendored
Normal file
@ -0,0 +1,17 @@
|
||||
# - Config file for the Libevent package
|
||||
# It defines the following variables
|
||||
# LIBWEBSOCKETS_INCLUDE_DIRS - include directories for FooBar
|
||||
# LIBWEBSOCKETS_LIBRARIES - libraries to link against
|
||||
|
||||
# Get the path of the current file.
|
||||
get_filename_component(LWS_CMAKE_DIR "${CMAKE_CURRENT_LIST_FILE}" PATH)
|
||||
|
||||
# Set the include directories.
|
||||
set(LIBWEBSOCKETS_INCLUDE_DIRS "@LWS__INCLUDE_DIRS@")
|
||||
|
||||
# Include the project Targets file, this contains definitions for IMPORTED targets.
|
||||
include(${LWS_CMAKE_DIR}/LibwebsocketsTargets.cmake)
|
||||
|
||||
# IMPORTED targets from LibwebsocketsTargets.cmake
|
||||
set(LIBWEBSOCKETS_LIBRARIES websockets websockets_shared)
|
||||
|
||||
11
dependencies/libwebsockets/cmake/LibwebsocketsConfigVersion.cmake.in
vendored
Normal file
11
dependencies/libwebsockets/cmake/LibwebsocketsConfigVersion.cmake.in
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
set(PACKAGE_VERSION "@CPACK_PACKAGE_VERSION@")
|
||||
|
||||
# Check whether the requested PACKAGE_FIND_VERSION is compatible
|
||||
if("${PACKAGE_VERSION}" VERSION_LESS "${PACKAGE_FIND_VERSION}")
|
||||
set(PACKAGE_VERSION_COMPATIBLE FALSE)
|
||||
else()
|
||||
set(PACKAGE_VERSION_COMPATIBLE TRUE)
|
||||
if ("${PACKAGE_VERSION}" VERSION_EQUAL "${PACKAGE_FIND_VERSION}")
|
||||
set(PACKAGE_VERSION_EXACT TRUE)
|
||||
endif()
|
||||
endif()
|
||||
176
dependencies/libwebsockets/cmake/UseRPMTools.cmake
vendored
Normal file
176
dependencies/libwebsockets/cmake/UseRPMTools.cmake
vendored
Normal file
@ -0,0 +1,176 @@
|
||||
#
|
||||
# - Find tools needed for building RPM Packages
|
||||
# on Linux systems and defines macro that helps to
|
||||
# build source or binary RPM, the MACRO assumes
|
||||
# CMake 2.4.x which includes CPack support.
|
||||
# CPack is used to build tar.gz source tarball
|
||||
# which may be used by a custom user-made spec file.
|
||||
#
|
||||
# - Define RPMTools_ADD_RPM_TARGETS which defines
|
||||
# two (top-level) CUSTOM targets for building
|
||||
# source and binary RPMs
|
||||
#
|
||||
# Those CMake macros are provided by the TSP Developer Team
|
||||
# https://savannah.nongnu.org/projects/tsp
|
||||
#
|
||||
|
||||
IF (WIN32)
|
||||
MESSAGE(STATUS "RPM tools not available on Win32 systems")
|
||||
ENDIF(WIN32)
|
||||
|
||||
IF (UNIX)
|
||||
# Look for RPM builder executable
|
||||
FIND_PROGRAM(RPMTools_RPMBUILD_EXECUTABLE
|
||||
NAMES rpmbuild
|
||||
PATHS "/usr/bin;/usr/lib/rpm"
|
||||
PATH_SUFFIXES bin
|
||||
DOC "The RPM builder tool")
|
||||
|
||||
IF (RPMTools_RPMBUILD_EXECUTABLE)
|
||||
MESSAGE(STATUS "Looking for RPMTools... - found rpmuild is ${RPMTools_RPMBUILD_EXECUTABLE}")
|
||||
SET(RPMTools_RPMBUILD_FOUND "YES")
|
||||
GET_FILENAME_COMPONENT(RPMTools_BINARY_DIRS ${RPMTools_RPMBUILD_EXECUTABLE} PATH)
|
||||
ELSE (RPMTools_RPMBUILD_EXECUTABLE)
|
||||
SET(RPMTools_RPMBUILD_FOUND "NO")
|
||||
MESSAGE(STATUS "Looking for RPMTools... - rpmbuild NOT FOUND")
|
||||
ENDIF (RPMTools_RPMBUILD_EXECUTABLE)
|
||||
|
||||
# Detect if CPack was included or not
|
||||
IF (NOT DEFINED "CPACK_PACKAGE_NAME")
|
||||
MESSAGE(FATAL_ERROR "CPack was not included, you should include CPack before Using RPMTools")
|
||||
ENDIF (NOT DEFINED "CPACK_PACKAGE_NAME")
|
||||
|
||||
IF (RPMTools_RPMBUILD_FOUND)
|
||||
SET(RPMTools_FOUND TRUE)
|
||||
#
|
||||
# - first arg (ARGV0) is RPM name
|
||||
# - second arg (ARGV1) is the RPM spec file path [optional]
|
||||
# - third arg (ARGV2) is the RPM ROOT DIRECTORY used to build RPMs [optional]
|
||||
#
|
||||
MACRO(RPMTools_ADD_RPM_TARGETS RPMNAME)
|
||||
|
||||
#
|
||||
# If no spec file is provided create a minimal one
|
||||
#
|
||||
IF ("${ARGV1}" STREQUAL "")
|
||||
SET(SPECFILE_PATH "${CMAKE_BINARY_DIR}/${RPMNAME}.spec")
|
||||
ELSE ("${ARGV1}" STREQUAL "")
|
||||
SET(SPECFILE_PATH "${ARGV1}")
|
||||
ENDIF("${ARGV1}" STREQUAL "")
|
||||
|
||||
# Verify whether if RPM_ROOTDIR was provided or not
|
||||
IF("${ARGV2}" STREQUAL "")
|
||||
SET(RPM_ROOTDIR ${CMAKE_BINARY_DIR}/RPM)
|
||||
ELSE ("${ARGV2}" STREQUAL "")
|
||||
SET(RPM_ROOTDIR "${ARGV2}")
|
||||
ENDIF("${ARGV2}" STREQUAL "")
|
||||
MESSAGE(STATUS "RPMTools:: Using RPM_ROOTDIR=${RPM_ROOTDIR}")
|
||||
|
||||
# Prepare RPM build tree
|
||||
FILE(MAKE_DIRECTORY ${RPM_ROOTDIR})
|
||||
FILE(MAKE_DIRECTORY ${RPM_ROOTDIR}/tmp)
|
||||
FILE(MAKE_DIRECTORY ${RPM_ROOTDIR}/BUILD)
|
||||
FILE(MAKE_DIRECTORY ${RPM_ROOTDIR}/RPMS)
|
||||
FILE(MAKE_DIRECTORY ${RPM_ROOTDIR}/SOURCES)
|
||||
FILE(MAKE_DIRECTORY ${RPM_ROOTDIR}/SPECS)
|
||||
FILE(MAKE_DIRECTORY ${RPM_ROOTDIR}/SRPMS)
|
||||
|
||||
#
|
||||
# We check whether if the provided spec file is
|
||||
# to be configure or not.
|
||||
#
|
||||
IF ("${ARGV1}" STREQUAL "")
|
||||
SET(SPECFILE_PATH "${RPM_ROOTDIR}/SPECS/${RPMNAME}.spec")
|
||||
SET(SPECFILE_NAME "${RPMNAME}.spec")
|
||||
MESSAGE(STATUS "No Spec file given generate a minimal one --> ${RPM_ROOTDIR}/SPECS/${RPMNAME}.spec")
|
||||
FILE(WRITE ${RPM_ROOTDIR}/SPECS/${RPMNAME}.spec
|
||||
"# -*- rpm-spec -*-
|
||||
Summary: ${RPMNAME}
|
||||
Name: ${RPMNAME}
|
||||
Version: ${CPACK_PACKAGE_VERSION}
|
||||
Release: 1
|
||||
License: Unknown
|
||||
Group: Unknown
|
||||
Source: ${CPACK_SOURCE_PACKAGE_FILE_NAME}.tar.gz
|
||||
BuildRoot: %{_tmppath}/%{name}-%{CPACK_PACKAGE_VERSION}-1-root
|
||||
BuildRequires: cmake
|
||||
|
||||
%define prefix /opt/${RPMNAME}-%{version}
|
||||
%define rpmprefix $RPM_BUILD_ROOT%{prefix}
|
||||
%define srcdirname %{name}-%{version}
|
||||
|
||||
%description
|
||||
${RPMNAME} : No description for now
|
||||
|
||||
%prep
|
||||
%setup -q -n %{srcdirname}
|
||||
|
||||
%build
|
||||
cd ..
|
||||
rm -rf build_tree
|
||||
mkdir build_tree
|
||||
cd build_tree
|
||||
cmake -DCMAKE_INSTALL_PREFIX=%{rpmprefix} ../%{srcdirname}
|
||||
make
|
||||
|
||||
%install
|
||||
cd ../build_tree
|
||||
make install
|
||||
|
||||
%clean
|
||||
rm -rf %{srcdirname}
|
||||
rm -rf build_tree
|
||||
|
||||
%files
|
||||
%defattr(-,root,root,-)
|
||||
%dir %{prefix}
|
||||
%{prefix}/*
|
||||
|
||||
%changelog
|
||||
* Wed Feb 28 2007 Erk <eric.noulard@gmail.com>
|
||||
Generated by CMake UseRPMTools macros"
|
||||
)
|
||||
|
||||
ELSE ("${ARGV1}" STREQUAL "")
|
||||
SET(SPECFILE_PATH "${ARGV1}")
|
||||
|
||||
GET_FILENAME_COMPONENT(SPECFILE_EXT ${SPECFILE_PATH} EXT)
|
||||
IF ("${SPECFILE_EXT}" STREQUAL ".spec")
|
||||
# This is a 'ready-to-use' spec file which does not need to be CONFIGURED
|
||||
GET_FILENAME_COMPONENT(SPECFILE_NAME ${SPECFILE_PATH} NAME)
|
||||
MESSAGE(STATUS "Simple copy spec file <${SPECFILE_PATH}> --> <${RPM_ROOTDIR}/SPECS/${SPECFILE_NAME}>")
|
||||
CONFIGURE_FILE(
|
||||
${SPECFILE_PATH}
|
||||
${RPM_ROOTDIR}/SPECS/${SPECFILE_NAME}
|
||||
COPYONLY)
|
||||
ELSE ("${SPECFILE_EXT}" STREQUAL ".spec")
|
||||
# This is a to-be-configured spec file
|
||||
GET_FILENAME_COMPONENT(SPECFILE_NAME ${SPECFILE_PATH} NAME_WE)
|
||||
SET(SPECFILE_NAME "${SPECFILE_NAME}.spec")
|
||||
MESSAGE(STATUS "Configuring spec file <${SPECFILE_PATH}> --> <${RPM_ROOTDIR}/SPECS/${SPECFILE_NAME}>")
|
||||
CONFIGURE_FILE(
|
||||
${SPECFILE_PATH}
|
||||
${RPM_ROOTDIR}/SPECS/${SPECFILE_NAME}
|
||||
@ONLY)
|
||||
ENDIF ("${SPECFILE_EXT}" STREQUAL ".spec")
|
||||
ENDIF("${ARGV1}" STREQUAL "")
|
||||
|
||||
ADD_CUSTOM_TARGET(${RPMNAME}_srpm
|
||||
COMMAND cpack -G TGZ --config CPackSourceConfig.cmake
|
||||
COMMAND ${CMAKE_COMMAND} -E copy ${CPACK_SOURCE_PACKAGE_FILE_NAME}.tar.gz ${RPM_ROOTDIR}/SOURCES
|
||||
COMMAND ${RPMTools_RPMBUILD_EXECUTABLE} -bs --define=\"_topdir ${RPM_ROOTDIR}\" --buildroot=${RPM_ROOTDIR}/tmp ${RPM_ROOTDIR}/SPECS/${SPECFILE_NAME}
|
||||
)
|
||||
|
||||
ADD_CUSTOM_TARGET(${RPMNAME}_rpm
|
||||
COMMAND cpack -G TGZ --config CPackSourceConfig.cmake
|
||||
COMMAND ${CMAKE_COMMAND} -E copy ${CPACK_SOURCE_PACKAGE_FILE_NAME}.tar.gz ${RPM_ROOTDIR}/SOURCES
|
||||
COMMAND ${RPMTools_RPMBUILD_EXECUTABLE} -bb --define=\"_topdir ${RPM_ROOTDIR}\" --buildroot=${RPM_ROOTDIR}/tmp ${RPM_ROOTDIR}/SPECS/${SPECFILE_NAME}
|
||||
)
|
||||
ENDMACRO(RPMTools_ADD_RPM_TARGETS)
|
||||
|
||||
ELSE (RPMTools_RPMBUILD_FOUND)
|
||||
SET(RPMTools FALSE)
|
||||
ENDIF (RPMTools_RPMBUILD_FOUND)
|
||||
|
||||
ENDIF (UNIX)
|
||||
|
||||
174
dependencies/libwebsockets/config.h.cmake
vendored
Normal file
174
dependencies/libwebsockets/config.h.cmake
vendored
Normal file
@ -0,0 +1,174 @@
|
||||
/* config.h.in. Generated from configure.ac by autoheader. */
|
||||
|
||||
#ifndef WIN32
|
||||
#cmakedefine _DEBUG
|
||||
#endif
|
||||
|
||||
/* Define to 1 to use CyaSSL as a replacement for OpenSSL.
|
||||
* LWS_OPENSSL_SUPPORT needs to be set also for this to work. */
|
||||
#cmakedefine USE_CYASSL
|
||||
|
||||
/* The Libwebsocket version */
|
||||
#cmakedefine LWS_LIBRARY_VERSION "${LWS_LIBRARY_VERSION}"
|
||||
|
||||
/* The current git commit hash that we're building from */
|
||||
#cmakedefine LWS_BUILD_HASH "${LWS_BUILD_HASH}"
|
||||
|
||||
/* Build with OpenSSL support */
|
||||
#cmakedefine LWS_OPENSSL_SUPPORT
|
||||
|
||||
/* The client should load and trust CA root certs it finds in the OS */
|
||||
#cmakedefine LWS_SSL_CLIENT_USE_OS_CA_CERTS
|
||||
|
||||
/* Sets the path where the client certs should be installed. */
|
||||
#cmakedefine LWS_OPENSSL_CLIENT_CERTS "${LWS_OPENSSL_CLIENT_CERTS}"
|
||||
|
||||
/* Turn off websocket extensions */
|
||||
#cmakedefine LWS_NO_EXTENSIONS
|
||||
|
||||
/* Enable libev io loop */
|
||||
#cmakedefine LWS_USE_LIBEV
|
||||
|
||||
/* Build with support for ipv6 */
|
||||
#cmakedefine LWS_USE_IPV6
|
||||
|
||||
/* Build with support for HTTP2 */
|
||||
#cmakedefine LWS_USE_HTTP2
|
||||
|
||||
/* Turn on latency measuring code */
|
||||
#cmakedefine LWS_LATENCY
|
||||
|
||||
/* Don't build the daemonizeation api */
|
||||
#cmakedefine LWS_NO_DAEMONIZE
|
||||
|
||||
/* Build without server support */
|
||||
#cmakedefine LWS_NO_SERVER
|
||||
|
||||
/* Build without client support */
|
||||
#cmakedefine LWS_NO_CLIENT
|
||||
|
||||
/* If we should compile with MinGW support */
|
||||
#cmakedefine LWS_MINGW_SUPPORT
|
||||
|
||||
/* Use the BSD getifaddrs that comes with libwebsocket, for uclibc support */
|
||||
#cmakedefine LWS_BUILTIN_GETIFADDRS
|
||||
|
||||
/* Define to 1 if you have the `bzero' function. */
|
||||
#cmakedefine HAVE_BZERO
|
||||
|
||||
/* Define to 1 if you have the <dlfcn.h> header file. */
|
||||
#cmakedefine HAVE_DLFCN_H
|
||||
|
||||
/* Define to 1 if you have the <fcntl.h> header file. */
|
||||
#cmakedefine HAVE_FCNTL_H
|
||||
|
||||
/* Define to 1 if you have the `fork' function. */
|
||||
#cmakedefine HAVE_FORK
|
||||
|
||||
/* Define to 1 if you have the `getenv’ function. */
|
||||
#cmakedefine HAVE_GETENV
|
||||
|
||||
/* Define to 1 if you have the <in6addr.h> header file. */
|
||||
#cmakedefine HAVE_IN6ADDR_H
|
||||
|
||||
/* Define to 1 if you have the <inttypes.h> header file. */
|
||||
#cmakedefine HAVE_INTTYPES_H
|
||||
|
||||
/* Define to 1 if you have the `ssl' library (-lssl). */
|
||||
//#cmakedefine HAVE_LIBSSL
|
||||
|
||||
/* Define to 1 if your system has a GNU libc compatible `malloc' function, and
|
||||
to 0 otherwise. */
|
||||
#cmakedefine HAVE_MALLOC
|
||||
|
||||
/* Define to 1 if you have the <memory.h> header file. */
|
||||
#cmakedefine HAVE_MEMORY_H
|
||||
|
||||
/* Define to 1 if you have the `memset' function. */
|
||||
#cmakedefine HAVE_MEMSET
|
||||
|
||||
/* Define to 1 if you have the <netinet/in.h> header file. */
|
||||
#cmakedefine HAVE_NETINET_IN_H
|
||||
|
||||
/* Define to 1 if your system has a GNU libc compatible `realloc' function,
|
||||
and to 0 otherwise. */
|
||||
#cmakedefine HAVE_REALLOC
|
||||
|
||||
/* Define to 1 if you have the `socket' function. */
|
||||
#cmakedefine HAVE_SOCKET
|
||||
|
||||
/* Define to 1 if you have the <stdint.h> header file. */
|
||||
#cmakedefine HAVE_STDINT_H
|
||||
|
||||
/* Define to 1 if you have the <stdlib.h> header file. */
|
||||
#cmakedefine HAVE_STDLIB_H
|
||||
|
||||
/* Define to 1 if you have the `strerror' function. */
|
||||
#cmakedefine HAVE_STRERROR
|
||||
|
||||
/* Define to 1 if you have the <strings.h> header file. */
|
||||
#cmakedefine HAVE_STRINGS_H
|
||||
|
||||
/* Define to 1 if you have the <string.h> header file. */
|
||||
#cmakedefine HAVE_STRING_H
|
||||
|
||||
/* Define to 1 if you have the <sys/prctl.h> header file. */
|
||||
#cmakedefine HAVE_SYS_PRCTL_H
|
||||
|
||||
/* Define to 1 if you have the <sys/socket.h> header file. */
|
||||
#cmakedefine HAVE_SYS_SOCKET_H
|
||||
|
||||
/* Define to 1 if you have the <sys/stat.h> header file. */
|
||||
#cmakedefine HAVE_SYS_STAT_H
|
||||
|
||||
/* Define to 1 if you have the <sys/types.h> header file. */
|
||||
#cmakedefine HAVE_SYS_TYPES_H
|
||||
|
||||
/* Define to 1 if you have the <unistd.h> header file. */
|
||||
#cmakedefine HAVE_UNISTD_H
|
||||
|
||||
/* Define to 1 if you have the `vfork' function. */
|
||||
#cmakedefine HAVE_VFORK
|
||||
|
||||
/* Define to 1 if you have the <vfork.h> header file. */
|
||||
#cmakedefine HAVE_VFORK_H
|
||||
|
||||
/* Define to 1 if `fork' works. */
|
||||
#cmakedefine HAVE_WORKING_FORK
|
||||
|
||||
/* Define to 1 if `vfork' works. */
|
||||
#cmakedefine HAVE_WORKING_VFORK
|
||||
|
||||
/* Define to 1 if you have the <zlib.h> header file. */
|
||||
#cmakedefine HAVE_ZLIB_H
|
||||
|
||||
/* Define to the sub-directory in which libtool stores uninstalled libraries.
|
||||
*/
|
||||
#undef LT_OBJDIR // We're not using libtool
|
||||
|
||||
/* Define to 1 if you have the ANSI C header files. */
|
||||
#cmakedefine STDC_HEADERS
|
||||
|
||||
/* Version number of package */
|
||||
#cmakedefine VERSION
|
||||
|
||||
/* Define to rpl_malloc if the replacement function should be used. */
|
||||
#cmakedefine malloc
|
||||
|
||||
/* Define to `int' if <sys/types.h> does not define. */
|
||||
#cmakedefine pid_t
|
||||
|
||||
/* Define to rpl_realloc if the replacement function should be used. */
|
||||
#cmakedefine realloc
|
||||
|
||||
/* Define to `unsigned int' if <sys/types.h> does not define. */
|
||||
#cmakedefine size_t
|
||||
|
||||
/* Define to 1 if we have getifaddrs */
|
||||
#cmakedefine HAVE_GETIFADDRS
|
||||
|
||||
/* Define as `fork' if `vfork' does not work. */
|
||||
//#cmakedefine vfork
|
||||
|
||||
/* Define if the inline keyword doesn't exist. */
|
||||
#cmakedefine inline
|
||||
28
dependencies/libwebsockets/cross-arm-linux-gnueabihf.cmake
vendored
Normal file
28
dependencies/libwebsockets/cross-arm-linux-gnueabihf.cmake
vendored
Normal file
@ -0,0 +1,28 @@
|
||||
#
|
||||
# CMake Toolchain file for crosscompiling on ARM.
|
||||
#
|
||||
# This can be used when running cmake in the following way:
|
||||
# cd build/
|
||||
# cmake .. -DCMAKE_TOOLCHAIN_FILE=../cross-arm-linux-gnueabihf.cmake
|
||||
#
|
||||
|
||||
set(CROSS_PATH /opt/gcc-linaro-arm-linux-gnueabihf-4.7-2013.02-01-20130221_linux)
|
||||
|
||||
# Target operating system name.
|
||||
set(CMAKE_SYSTEM_NAME Linux)
|
||||
|
||||
# Name of C compiler.
|
||||
set(CMAKE_C_COMPILER "${CROSS_PATH}/bin/arm-linux-gnueabihf-gcc")
|
||||
set(CMAKE_CXX_COMPILER "${CROSS_PATH}/bin/arm-linux-gnueabihf-g++")
|
||||
|
||||
# Where to look for the target environment. (More paths can be added here)
|
||||
set(CMAKE_FIND_ROOT_PATH "${CROSS_PATH}")
|
||||
|
||||
# Adjust the default behavior of the FIND_XXX() commands:
|
||||
# search programs in the host environment only.
|
||||
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
|
||||
|
||||
# Search headers and libraries in the target environment only.
|
||||
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
|
||||
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
|
||||
|
||||
31
dependencies/libwebsockets/cross-ming.cmake
vendored
Normal file
31
dependencies/libwebsockets/cross-ming.cmake
vendored
Normal file
@ -0,0 +1,31 @@
|
||||
#
|
||||
# CMake Toolchain file for crosscompiling on MingW.
|
||||
#
|
||||
# This can be used when running cmake in the following way:
|
||||
# cd build/
|
||||
# cmake .. -DCMAKE_TOOLCHAIN_FILE=../cross-ming.cmake
|
||||
#
|
||||
|
||||
set(CROSS_PATH /usr/bin)
|
||||
|
||||
# Target operating system name.
|
||||
set(CMAKE_SYSTEM_NAME Windows)
|
||||
set(BUILD_SHARED_LIBS OFF)
|
||||
|
||||
# Name of C compiler.
|
||||
set(CMAKE_C_COMPILER "${CROSS_PATH}/x86_64-w64-mingw32-gcc")
|
||||
#set(CMAKE_CXX_COMPILER "${CROSS_PATH}/x86_64-w64-mingw32-g++")
|
||||
set(CMAKE_RC_COMPILER "${CROSS_PATH}/x86_64-w64-mingw32-windres")
|
||||
set(CMAKE_C_FLAGS "-Wno-error")
|
||||
|
||||
# Where to look for the target environment. (More paths can be added here)
|
||||
set(CMAKE_FIND_ROOT_PATH "${CROSS_PATH}")
|
||||
|
||||
# Adjust the default behavior of the FIND_XXX() commands:
|
||||
# search programs in the host environment only.
|
||||
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
|
||||
|
||||
# Search headers and libraries in the target environment only.
|
||||
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
|
||||
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
|
||||
|
||||
91
dependencies/libwebsockets/cross-openwrt-makefile
vendored
Normal file
91
dependencies/libwebsockets/cross-openwrt-makefile
vendored
Normal file
@ -0,0 +1,91 @@
|
||||
#
|
||||
# libwebsockets makefile for openwrt
|
||||
#
|
||||
|
||||
include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=libwebsockets
|
||||
PKG_VERSION:=2014-03-01
|
||||
PKG_RELEASE=$(PKG_SOURCE_VERSION)
|
||||
|
||||
PKG_SOURCE_PROTO:=git
|
||||
PKG_SOURCE_URL:=https://github.com/warmcat/libwebsockets.git
|
||||
PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION)
|
||||
PKG_SOURCE_VERSION:=388dc7d201d8d123841869fb49ec4d94d6dd7f54
|
||||
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION)-$(PKG_SOURCE_VERSION).tar.gz
|
||||
CMAKE_INSTALL:=1
|
||||
|
||||
include $(INCLUDE_DIR)/package.mk
|
||||
include $(INCLUDE_DIR)/cmake.mk
|
||||
|
||||
CMAKE_OPTIONS += -DLWS_OPENSSL_CLIENT_CERTS=/etc/ssl/certs
|
||||
CMAKE_OPTIONS += -DLWS_OPENSSL_SUPPORT=ON
|
||||
CMAKE_OPTIONS += -DLWS_WITH_SSL=ON
|
||||
CMAKE_OPTIONS += -DLWS_WITHOUT_TESTAPPS=$(if $(CONFIG_PACKAGE_libwebsockets-examples),"OFF","ON")
|
||||
|
||||
# for cyassl, define these in addition to LWS_OPENSSL_SUPPORT and
|
||||
# edit package/libs/cyassl/Makefile to include --enable-opensslextra
|
||||
# CMAKE_OPTIONS += -DLWS_USE_CYASSL=ON
|
||||
# CMAKE_OPTIONS += -DLWS_CYASSL_LIB=$(STAGING_DIR)/usr/lib/libcyassl.so
|
||||
# CMAKE_OPTIONS += -DLWS_CYASSL_INCLUDE_DIRS=$(STAGING_DIR)/usr/include
|
||||
|
||||
# other options worth noting
|
||||
# CMAKE_OPTIONS += -DLWS_WITHOUT_EXTENSIONS=ON
|
||||
# CMAKE_OPTIONS += -DLWS_WITHOUT_DAEMONIZE=ON
|
||||
# CMAKE_OPTIONS += -DLWS_WITHOUT_SERVER=ON
|
||||
# CMAKE_OPTIONS += -DLWS_WITHOUT_DEBUG=ON
|
||||
|
||||
|
||||
define Package/libwebsockets/Default
|
||||
SECTION:=libs
|
||||
CATEGORY:=Libraries
|
||||
TITLE:=libwebsockets
|
||||
DEPENDS:=+zlib +libopenssl
|
||||
endef
|
||||
|
||||
define Package/libwebsockets
|
||||
$(call Package/libwebsockets/Default)
|
||||
TITLE+= (libraries)
|
||||
endef
|
||||
|
||||
define Package/libwebsockets/description
|
||||
libwebsockets
|
||||
This package contains libwebsocket libraries
|
||||
endef
|
||||
|
||||
define Package/libwebsockets-examples
|
||||
$(call Package/libwebsockets/Default)
|
||||
DEPENDS:=libwebsockets
|
||||
TITLE+= (examples)
|
||||
endef
|
||||
|
||||
define Package/libwebsockets-examples/description
|
||||
libwebsockets examples
|
||||
This package contains libwebsockets examples
|
||||
endef
|
||||
|
||||
define Package/libwebsockets/install
|
||||
$(INSTALL_DIR) $(1)/usr/lib
|
||||
$(CP) $(PKG_INSTALL_DIR)/usr/lib/libwebsockets.so* $(1)/usr/lib/
|
||||
endef
|
||||
|
||||
define Package/libwebsockets-examples/install
|
||||
$(INSTALL_DIR) $(1)/usr/bin
|
||||
$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/bin/libwebsockets-test-client $(1)/usr/bin/
|
||||
$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/bin/libwebsockets-test-echo $(1)/usr/bin/
|
||||
$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/bin/libwebsockets-test-fraggle $(1)/usr/bin/
|
||||
$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/bin/libwebsockets-test-ping $(1)/usr/bin/
|
||||
$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/bin/libwebsockets-test-server $(1)/usr/bin/
|
||||
$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/bin/libwebsockets-test-server-extpoll $(1)/usr/bin/
|
||||
|
||||
$(INSTALL_DIR) $(1)/usr/share/libwebsockets-test-server
|
||||
$(INSTALL_DATA) $(PKG_INSTALL_DIR)/usr/share/libwebsockets-test-server/favicon.ico $(1)/usr/share/libwebsockets-test-server/
|
||||
$(INSTALL_DATA) $(PKG_INSTALL_DIR)/usr/share/libwebsockets-test-server/leaf.jpg $(1)/usr/share/libwebsockets-test-server/
|
||||
$(INSTALL_DATA) $(PKG_INSTALL_DIR)/usr/share/libwebsockets-test-server/libwebsockets.org-logo.png $(1)/usr/share/libwebsockets-test-server/
|
||||
$(INSTALL_DATA) $(PKG_INSTALL_DIR)/usr/share/libwebsockets-test-server/libwebsockets-test-server.key.pem $(1)/usr/share/libwebsockets-test-server/
|
||||
$(INSTALL_DATA) $(PKG_INSTALL_DIR)/usr/share/libwebsockets-test-server/libwebsockets-test-server.pem $(1)/usr/share/libwebsockets-test-server/
|
||||
$(INSTALL_DATA) $(PKG_INSTALL_DIR)/usr/share/libwebsockets-test-server/test.html $(1)/usr/share/libwebsockets-test-server/
|
||||
endef
|
||||
|
||||
$(eval $(call BuildPackage,libwebsockets))
|
||||
$(eval $(call BuildPackage,libwebsockets-examples))
|
||||
8
dependencies/libwebsockets/lib/.gitignore
vendored
Normal file
8
dependencies/libwebsockets/lib/.gitignore
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
#Ignore build files
|
||||
Makefile
|
||||
*.o
|
||||
*.lo
|
||||
*.la
|
||||
.libs
|
||||
.deps
|
||||
|
||||
93
dependencies/libwebsockets/lib/base64-decode.c
vendored
Normal file
93
dependencies/libwebsockets/lib/base64-decode.c
vendored
Normal file
@ -0,0 +1,93 @@
|
||||
/*
|
||||
* This code originally came from here
|
||||
*
|
||||
* http://base64.sourceforge.net/b64.c
|
||||
*
|
||||
* with the following license:
|
||||
*
|
||||
* LICENCE: Copyright (c) 2001 Bob Trower, Trantor Standard Systems Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person
|
||||
* obtaining a copy of this software and associated
|
||||
* documentation files (the "Software"), to deal in the
|
||||
* Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute,
|
||||
* sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall
|
||||
* be included in all copies or substantial portions of the
|
||||
* Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
|
||||
* KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
|
||||
* WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
|
||||
* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS
|
||||
* OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
||||
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* VERSION HISTORY:
|
||||
* Bob Trower 08/04/01 -- Create Version 0.00.00B
|
||||
*
|
||||
* I cleaned it up quite a bit to match the (linux kernel) style of the rest
|
||||
* of libwebsockets; this version is under LGPL2 like the rest of libwebsockets
|
||||
* since he explictly allows sublicensing, but I give the URL above so you can
|
||||
* get the original with Bob's super-liberal terms directly if you prefer.
|
||||
*/
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "private-libwebsockets.h"
|
||||
|
||||
static const char encode[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
"abcdefghijklmnopqrstuvwxyz0123456789+/";
|
||||
static const char decode[] = "|$$$}rstuvwxyz{$$$$$$$>?@ABCDEFGHIJKLMNOPQRSTUVW"
|
||||
"$$$$$$XYZ[\\]^_`abcdefghijklmnopq";
|
||||
|
||||
LWS_VISIBLE int
|
||||
lws_b64_encode_string(const char *in, int in_len, char *out, int out_size)
|
||||
{
|
||||
unsigned char triple[3];
|
||||
int i;
|
||||
int len;
|
||||
int line = 0;
|
||||
int done = 0;
|
||||
|
||||
while (in_len) {
|
||||
len = 0;
|
||||
for (i = 0; i < 3; i++) {
|
||||
if (in_len) {
|
||||
triple[i] = *in++;
|
||||
len++;
|
||||
in_len--;
|
||||
} else
|
||||
triple[i] = 0;
|
||||
}
|
||||
if (!len)
|
||||
continue;
|
||||
|
||||
if (done + 4 >= out_size)
|
||||
return -1;
|
||||
|
||||
*out++ = encode[triple[0] >> 2];
|
||||
*out++ = encode[((triple[0] & 0x03) << 4) |
|
||||
((triple[1] & 0xf0) >> 4)];
|
||||
*out++ = (len > 1 ? encode[((triple[1] & 0x0f) << 2) |
|
||||
((triple[2] & 0xc0) >> 6)] : '=');
|
||||
*out++ = (len > 2 ? encode[triple[2] & 0x3f] : '=');
|
||||
|
||||
done += 4;
|
||||
line += 4;
|
||||
}
|
||||
|
||||
if (done + 1 >= out_size)
|
||||
return -1;
|
||||
|
||||
*out++ = '\0';
|
||||
|
||||
return done;
|
||||
}
|
||||
443
dependencies/libwebsockets/lib/client-handshake.c
vendored
Normal file
443
dependencies/libwebsockets/lib/client-handshake.c
vendored
Normal file
@ -0,0 +1,443 @@
|
||||
#include "private-libwebsockets.h"
|
||||
|
||||
struct libwebsocket *libwebsocket_client_connect_2(
|
||||
struct libwebsocket_context *context,
|
||||
struct libwebsocket *wsi
|
||||
) {
|
||||
struct libwebsocket_pollfd pfd;
|
||||
#ifdef LWS_USE_IPV6
|
||||
struct sockaddr_in6 server_addr6;
|
||||
struct sockaddr_in6 client_addr6;
|
||||
struct addrinfo hints, *result;
|
||||
#endif
|
||||
struct sockaddr_in server_addr4;
|
||||
struct sockaddr_in client_addr4;
|
||||
struct hostent *server_hostent;
|
||||
|
||||
struct sockaddr *v;
|
||||
int n;
|
||||
int plen = 0;
|
||||
const char *ads;
|
||||
|
||||
lwsl_client("libwebsocket_client_connect_2\n");
|
||||
|
||||
/*
|
||||
* proxy?
|
||||
*/
|
||||
|
||||
if (context->http_proxy_port) {
|
||||
plen = sprintf((char *)context->service_buffer,
|
||||
"CONNECT %s:%u HTTP/1.0\x0d\x0a"
|
||||
"User-agent: libwebsockets\x0d\x0a"
|
||||
/*Proxy-authorization: basic aGVsbG86d29ybGQ= */
|
||||
"\x0d\x0a",
|
||||
lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_PEER_ADDRESS),
|
||||
wsi->u.hdr.ah->c_port);
|
||||
ads = context->http_proxy_address;
|
||||
|
||||
#ifdef LWS_USE_IPV6
|
||||
if (LWS_IPV6_ENABLED(context))
|
||||
server_addr6.sin6_port = htons(context->http_proxy_port);
|
||||
else
|
||||
#endif
|
||||
server_addr4.sin_port = htons(context->http_proxy_port);
|
||||
|
||||
} else {
|
||||
ads = lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_PEER_ADDRESS);
|
||||
#ifdef LWS_USE_IPV6
|
||||
if (LWS_IPV6_ENABLED(context))
|
||||
server_addr6.sin6_port = htons(wsi->u.hdr.ah->c_port);
|
||||
else
|
||||
#endif
|
||||
server_addr4.sin_port = htons(wsi->u.hdr.ah->c_port);
|
||||
}
|
||||
|
||||
/*
|
||||
* prepare the actual connection (to the proxy, if any)
|
||||
*/
|
||||
lwsl_client("libwebsocket_client_connect_2: address %s\n", ads);
|
||||
|
||||
#ifdef LWS_USE_IPV6
|
||||
if (LWS_IPV6_ENABLED(context)) {
|
||||
memset(&hints, 0, sizeof(struct addrinfo));
|
||||
n = getaddrinfo(ads, NULL, &hints, &result);
|
||||
if (n) {
|
||||
#ifdef _WIN32
|
||||
lwsl_err("getaddrinfo: %ls\n", gai_strerrorW(n));
|
||||
#else
|
||||
lwsl_err("getaddrinfo: %s\n", gai_strerror(n));
|
||||
#endif
|
||||
goto oom4;
|
||||
}
|
||||
|
||||
server_addr6.sin6_family = AF_INET6;
|
||||
switch (result->ai_family) {
|
||||
case AF_INET:
|
||||
/* map IPv4 to IPv6 */
|
||||
bzero((char *)&server_addr6.sin6_addr,
|
||||
sizeof(struct in6_addr));
|
||||
server_addr6.sin6_addr.s6_addr[10] = 0xff;
|
||||
server_addr6.sin6_addr.s6_addr[11] = 0xff;
|
||||
memcpy(&server_addr6.sin6_addr.s6_addr[12],
|
||||
&((struct sockaddr_in *)result->ai_addr)->sin_addr,
|
||||
sizeof(struct in_addr));
|
||||
break;
|
||||
case AF_INET6:
|
||||
memcpy(&server_addr6.sin6_addr,
|
||||
&((struct sockaddr_in6 *)result->ai_addr)->sin6_addr,
|
||||
sizeof(struct in6_addr));
|
||||
break;
|
||||
default:
|
||||
lwsl_err("Unknown address family\n");
|
||||
freeaddrinfo(result);
|
||||
goto oom4;
|
||||
}
|
||||
|
||||
freeaddrinfo(result);
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
server_hostent = gethostbyname(ads);
|
||||
if (!server_hostent) {
|
||||
lwsl_err("Unable to get host name from %s\n", ads);
|
||||
goto oom4;
|
||||
}
|
||||
|
||||
server_addr4.sin_family = AF_INET;
|
||||
server_addr4.sin_addr =
|
||||
*((struct in_addr *)server_hostent->h_addr);
|
||||
bzero(&server_addr4.sin_zero, 8);
|
||||
}
|
||||
|
||||
if (wsi->sock < 0) {
|
||||
|
||||
#ifdef LWS_USE_IPV6
|
||||
if (LWS_IPV6_ENABLED(context))
|
||||
wsi->sock = socket(AF_INET6, SOCK_STREAM, 0);
|
||||
else
|
||||
#endif
|
||||
wsi->sock = socket(AF_INET, SOCK_STREAM, 0);
|
||||
|
||||
if (wsi->sock < 0) {
|
||||
lwsl_warn("Unable to open socket\n");
|
||||
goto oom4;
|
||||
}
|
||||
|
||||
if (lws_plat_set_socket_options(context, wsi->sock)) {
|
||||
lwsl_err("Failed to set wsi socket options\n");
|
||||
compatible_close(wsi->sock);
|
||||
goto oom4;
|
||||
}
|
||||
|
||||
wsi->mode = LWS_CONNMODE_WS_CLIENT_WAITING_CONNECT;
|
||||
|
||||
insert_wsi_socket_into_fds(context, wsi);
|
||||
|
||||
libwebsocket_set_timeout(wsi,
|
||||
PENDING_TIMEOUT_AWAITING_CONNECT_RESPONSE,
|
||||
AWAITING_TIMEOUT);
|
||||
#ifdef LWS_USE_IPV6
|
||||
if (LWS_IPV6_ENABLED(context)) {
|
||||
v = (struct sockaddr *)&client_addr6;
|
||||
n = sizeof(client_addr6);
|
||||
bzero((char *)v, n);
|
||||
client_addr6.sin6_family = AF_INET6;
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
v = (struct sockaddr *)&client_addr4;
|
||||
n = sizeof(client_addr4);
|
||||
bzero((char *)v, n);
|
||||
client_addr4.sin_family = AF_INET;
|
||||
}
|
||||
|
||||
if (context->iface) {
|
||||
if (interface_to_sa(context, context->iface,
|
||||
(struct sockaddr_in *)v, n) < 0) {
|
||||
lwsl_err("Unable to find interface %s\n",
|
||||
context->iface);
|
||||
compatible_close(wsi->sock);
|
||||
goto failed;
|
||||
}
|
||||
|
||||
if (bind(wsi->sock, v, n) < 0) {
|
||||
lwsl_err("Error binding to interface %s",
|
||||
context->iface);
|
||||
compatible_close(wsi->sock);
|
||||
goto failed;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef LWS_USE_IPV6
|
||||
if (LWS_IPV6_ENABLED(context)) {
|
||||
v = (struct sockaddr *)&server_addr6;
|
||||
n = sizeof(struct sockaddr_in6);
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
v = (struct sockaddr *)&server_addr4;
|
||||
n = sizeof(struct sockaddr);
|
||||
}
|
||||
|
||||
if (connect(wsi->sock, v, n) == -1 || LWS_ERRNO == LWS_EISCONN) {
|
||||
|
||||
if (LWS_ERRNO == LWS_EALREADY || LWS_ERRNO == LWS_EINPROGRESS
|
||||
|| LWS_ERRNO == LWS_EWOULDBLOCK) {
|
||||
lwsl_client("nonblocking connect retry\n");
|
||||
|
||||
/*
|
||||
* must do specifically a POLLOUT poll to hear
|
||||
* about the connect completion
|
||||
*/
|
||||
if (lws_change_pollfd(wsi, 0, LWS_POLLOUT))
|
||||
goto oom4;
|
||||
|
||||
return wsi;
|
||||
}
|
||||
|
||||
if (LWS_ERRNO != LWS_EISCONN) {
|
||||
lwsl_debug("Connect failed errno=%d\n", LWS_ERRNO);
|
||||
goto failed;
|
||||
}
|
||||
}
|
||||
|
||||
lwsl_client("connected\n");
|
||||
|
||||
/* we are connected to server, or proxy */
|
||||
|
||||
if (context->http_proxy_port) {
|
||||
|
||||
/* OK from now on we talk via the proxy, so connect to that */
|
||||
|
||||
/*
|
||||
* (will overwrite existing pointer,
|
||||
* leaving old string/frag there but unreferenced)
|
||||
*/
|
||||
if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_PEER_ADDRESS,
|
||||
context->http_proxy_address))
|
||||
goto failed;
|
||||
wsi->u.hdr.ah->c_port = context->http_proxy_port;
|
||||
|
||||
n = send(wsi->sock, context->service_buffer, plen, MSG_NOSIGNAL);
|
||||
if (n < 0) {
|
||||
lwsl_debug("ERROR writing to proxy socket\n");
|
||||
goto failed;
|
||||
}
|
||||
|
||||
libwebsocket_set_timeout(wsi,
|
||||
PENDING_TIMEOUT_AWAITING_PROXY_RESPONSE,
|
||||
AWAITING_TIMEOUT);
|
||||
|
||||
wsi->mode = LWS_CONNMODE_WS_CLIENT_WAITING_PROXY_REPLY;
|
||||
|
||||
return wsi;
|
||||
}
|
||||
|
||||
/*
|
||||
* provoke service to issue the handshake directly
|
||||
* we need to do it this way because in the proxy case, this is the
|
||||
* next state and executed only if and when we get a good proxy
|
||||
* response inside the state machine... but notice in SSL case this
|
||||
* may not have sent anything yet with 0 return, and won't until some
|
||||
* many retries from main loop. To stop that becoming endless,
|
||||
* cover with a timeout.
|
||||
*/
|
||||
|
||||
libwebsocket_set_timeout(wsi,
|
||||
PENDING_TIMEOUT_SENT_CLIENT_HANDSHAKE, AWAITING_TIMEOUT);
|
||||
|
||||
wsi->mode = LWS_CONNMODE_WS_CLIENT_ISSUE_HANDSHAKE;
|
||||
pfd.fd = wsi->sock;
|
||||
pfd.revents = LWS_POLLIN;
|
||||
|
||||
n = libwebsocket_service_fd(context, &pfd);
|
||||
|
||||
if (n < 0)
|
||||
goto failed;
|
||||
|
||||
if (n) /* returns 1 on failure after closing wsi */
|
||||
return NULL;
|
||||
|
||||
return wsi;
|
||||
|
||||
oom4:
|
||||
free(wsi->u.hdr.ah);
|
||||
free(wsi);
|
||||
return NULL;
|
||||
|
||||
failed:
|
||||
libwebsocket_close_and_free_session(context, wsi,
|
||||
LWS_CLOSE_STATUS_NOSTATUS);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* libwebsocket_client_connect() - Connect to another websocket server
|
||||
* @context: Websocket context
|
||||
* @address: Remote server address, eg, "myserver.com"
|
||||
* @port: Port to connect to on the remote server, eg, 80
|
||||
* @ssl_connection: 0 = ws://, 1 = wss:// encrypted, 2 = wss:// allow self
|
||||
* signed certs
|
||||
* @path: Websocket path on server
|
||||
* @host: Hostname on server
|
||||
* @origin: Socket origin name
|
||||
* @protocol: Comma-separated list of protocols being asked for from
|
||||
* the server, or just one. The server will pick the one it
|
||||
* likes best.
|
||||
* @ietf_version_or_minus_one: -1 to ask to connect using the default, latest
|
||||
* protocol supported, or the specific protocol ordinal
|
||||
*
|
||||
* This function creates a connection to a remote server
|
||||
*/
|
||||
|
||||
LWS_VISIBLE struct libwebsocket *
|
||||
libwebsocket_client_connect(struct libwebsocket_context *context,
|
||||
const char *address,
|
||||
int port,
|
||||
int ssl_connection,
|
||||
const char *path,
|
||||
const char *host,
|
||||
const char *origin,
|
||||
const char *protocol,
|
||||
int ietf_version_or_minus_one)
|
||||
{
|
||||
struct libwebsocket *wsi;
|
||||
|
||||
wsi = (struct libwebsocket *) malloc(sizeof(struct libwebsocket));
|
||||
if (wsi == NULL)
|
||||
goto bail;
|
||||
|
||||
memset(wsi, 0, sizeof(*wsi));
|
||||
wsi->sock = -1;
|
||||
|
||||
/* -1 means just use latest supported */
|
||||
|
||||
if (ietf_version_or_minus_one == -1)
|
||||
ietf_version_or_minus_one = SPEC_LATEST_SUPPORTED;
|
||||
|
||||
wsi->ietf_spec_revision = ietf_version_or_minus_one;
|
||||
wsi->user_space = NULL;
|
||||
wsi->state = WSI_STATE_CLIENT_UNCONNECTED;
|
||||
wsi->protocol = NULL;
|
||||
wsi->pending_timeout = NO_PENDING_TIMEOUT;
|
||||
|
||||
#ifdef LWS_OPENSSL_SUPPORT
|
||||
wsi->use_ssl = ssl_connection;
|
||||
#else
|
||||
if (ssl_connection) {
|
||||
lwsl_err("libwebsockets not configured for ssl\n");
|
||||
goto bail;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (lws_allocate_header_table(wsi))
|
||||
goto bail;
|
||||
|
||||
/*
|
||||
* we're not necessarily in a position to action these right away,
|
||||
* stash them... we only need during connect phase so u.hdr is fine
|
||||
*/
|
||||
wsi->u.hdr.ah->c_port = port;
|
||||
if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_PEER_ADDRESS, address))
|
||||
goto bail1;
|
||||
|
||||
/* these only need u.hdr lifetime as well */
|
||||
|
||||
if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_URI, path))
|
||||
goto bail1;
|
||||
|
||||
if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_HOST, host))
|
||||
goto bail1;
|
||||
|
||||
if (origin)
|
||||
if (lws_hdr_simple_create(wsi,
|
||||
_WSI_TOKEN_CLIENT_ORIGIN, origin))
|
||||
goto bail1;
|
||||
/*
|
||||
* this is a list of protocols we tell the server we're okay with
|
||||
* stash it for later when we compare server response with it
|
||||
*/
|
||||
if (protocol)
|
||||
if (lws_hdr_simple_create(wsi,
|
||||
_WSI_TOKEN_CLIENT_SENT_PROTOCOLS, protocol))
|
||||
goto bail1;
|
||||
|
||||
wsi->protocol = &context->protocols[0];
|
||||
|
||||
/*
|
||||
* Check with each extension if it is able to route and proxy this
|
||||
* connection for us. For example, an extension like x-google-mux
|
||||
* can handle this and then we don't need an actual socket for this
|
||||
* connection.
|
||||
*/
|
||||
|
||||
if (lws_ext_callback_for_each_extension_type(context, wsi,
|
||||
LWS_EXT_CALLBACK_CAN_PROXY_CLIENT_CONNECTION,
|
||||
(void *)address, port) > 0) {
|
||||
lwsl_client("libwebsocket_client_connect: ext handling conn\n");
|
||||
|
||||
libwebsocket_set_timeout(wsi,
|
||||
PENDING_TIMEOUT_AWAITING_EXTENSION_CONNECT_RESPONSE,
|
||||
AWAITING_TIMEOUT);
|
||||
|
||||
wsi->mode = LWS_CONNMODE_WS_CLIENT_WAITING_EXTENSION_CONNECT;
|
||||
return wsi;
|
||||
}
|
||||
lwsl_client("libwebsocket_client_connect: direct conn\n");
|
||||
|
||||
return libwebsocket_client_connect_2(context, wsi);
|
||||
|
||||
bail1:
|
||||
free(wsi->u.hdr.ah);
|
||||
bail:
|
||||
free(wsi);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* libwebsocket_client_connect_extended() - Connect to another websocket server
|
||||
* @context: Websocket context
|
||||
* @address: Remote server address, eg, "myserver.com"
|
||||
* @port: Port to connect to on the remote server, eg, 80
|
||||
* @ssl_connection: 0 = ws://, 1 = wss:// encrypted, 2 = wss:// allow self
|
||||
* signed certs
|
||||
* @path: Websocket path on server
|
||||
* @host: Hostname on server
|
||||
* @origin: Socket origin name
|
||||
* @protocol: Comma-separated list of protocols being asked for from
|
||||
* the server, or just one. The server will pick the one it
|
||||
* likes best.
|
||||
* @ietf_version_or_minus_one: -1 to ask to connect using the default, latest
|
||||
* protocol supported, or the specific protocol ordinal
|
||||
* @userdata: Pre-allocated user data
|
||||
*
|
||||
* This function creates a connection to a remote server
|
||||
*/
|
||||
|
||||
LWS_VISIBLE struct libwebsocket *
|
||||
libwebsocket_client_connect_extended(struct libwebsocket_context *context,
|
||||
const char *address,
|
||||
int port,
|
||||
int ssl_connection,
|
||||
const char *path,
|
||||
const char *host,
|
||||
const char *origin,
|
||||
const char *protocol,
|
||||
int ietf_version_or_minus_one,
|
||||
void *userdata)
|
||||
{
|
||||
struct libwebsocket *ws =
|
||||
libwebsocket_client_connect(context, address, port,
|
||||
ssl_connection, path, host, origin, protocol,
|
||||
ietf_version_or_minus_one);
|
||||
|
||||
if (ws && !ws->user_space && userdata) {
|
||||
ws->user_space_externally_allocated = 1;
|
||||
ws->user_space = userdata ;
|
||||
}
|
||||
|
||||
return ws ;
|
||||
}
|
||||
402
dependencies/libwebsockets/lib/client-parser.c
vendored
Normal file
402
dependencies/libwebsockets/lib/client-parser.c
vendored
Normal file
@ -0,0 +1,402 @@
|
||||
/*
|
||||
* libwebsockets - small server side websockets and web server implementation
|
||||
*
|
||||
* Copyright (C) 2010-2014 Andy Green <andy@warmcat.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation:
|
||||
* version 2.1 of the License.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
* MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "private-libwebsockets.h"
|
||||
|
||||
int libwebsocket_client_rx_sm(struct libwebsocket *wsi, unsigned char c)
|
||||
{
|
||||
int callback_action = LWS_CALLBACK_CLIENT_RECEIVE;
|
||||
int handled;
|
||||
struct lws_tokens eff_buf;
|
||||
int m;
|
||||
|
||||
switch (wsi->lws_rx_parse_state) {
|
||||
case LWS_RXPS_NEW:
|
||||
|
||||
switch (wsi->ietf_spec_revision) {
|
||||
|
||||
case 13:
|
||||
wsi->u.ws.opcode = c & 0xf;
|
||||
wsi->u.ws.rsv = (c & 0x70);
|
||||
wsi->u.ws.final = !!((c >> 7) & 1);
|
||||
switch (wsi->u.ws.opcode) {
|
||||
case LWS_WS_OPCODE_07__TEXT_FRAME:
|
||||
case LWS_WS_OPCODE_07__BINARY_FRAME:
|
||||
wsi->u.ws.frame_is_binary = wsi->u.ws.opcode ==
|
||||
LWS_WS_OPCODE_07__BINARY_FRAME;
|
||||
break;
|
||||
}
|
||||
wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN;
|
||||
break;
|
||||
|
||||
default:
|
||||
lwsl_err("unknown spec version %02d\n",
|
||||
wsi->ietf_spec_revision);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
case LWS_RXPS_04_FRAME_HDR_LEN:
|
||||
|
||||
wsi->u.ws.this_frame_masked = !!(c & 0x80);
|
||||
|
||||
switch (c & 0x7f) {
|
||||
case 126:
|
||||
/* control frames are not allowed to have big lengths */
|
||||
if (wsi->u.ws.opcode & 8)
|
||||
goto illegal_ctl_length;
|
||||
wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN16_2;
|
||||
break;
|
||||
case 127:
|
||||
/* control frames are not allowed to have big lengths */
|
||||
if (wsi->u.ws.opcode & 8)
|
||||
goto illegal_ctl_length;
|
||||
wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_8;
|
||||
break;
|
||||
default:
|
||||
wsi->u.ws.rx_packet_length = c;
|
||||
if (wsi->u.ws.this_frame_masked)
|
||||
wsi->lws_rx_parse_state =
|
||||
LWS_RXPS_07_COLLECT_FRAME_KEY_1;
|
||||
else {
|
||||
if (c)
|
||||
wsi->lws_rx_parse_state =
|
||||
LWS_RXPS_PAYLOAD_UNTIL_LENGTH_EXHAUSTED;
|
||||
else {
|
||||
wsi->lws_rx_parse_state = LWS_RXPS_NEW;
|
||||
goto spill;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case LWS_RXPS_04_FRAME_HDR_LEN16_2:
|
||||
wsi->u.ws.rx_packet_length = c << 8;
|
||||
wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN16_1;
|
||||
break;
|
||||
|
||||
case LWS_RXPS_04_FRAME_HDR_LEN16_1:
|
||||
wsi->u.ws.rx_packet_length |= c;
|
||||
if (wsi->u.ws.this_frame_masked)
|
||||
wsi->lws_rx_parse_state =
|
||||
LWS_RXPS_07_COLLECT_FRAME_KEY_1;
|
||||
else {
|
||||
if (wsi->u.ws.rx_packet_length)
|
||||
wsi->lws_rx_parse_state =
|
||||
LWS_RXPS_PAYLOAD_UNTIL_LENGTH_EXHAUSTED;
|
||||
else {
|
||||
wsi->lws_rx_parse_state = LWS_RXPS_NEW;
|
||||
goto spill;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case LWS_RXPS_04_FRAME_HDR_LEN64_8:
|
||||
if (c & 0x80) {
|
||||
lwsl_warn("b63 of length must be zero\n");
|
||||
/* kill the connection */
|
||||
return -1;
|
||||
}
|
||||
#if defined __LP64__
|
||||
wsi->u.ws.rx_packet_length = ((size_t)c) << 56;
|
||||
#else
|
||||
wsi->u.ws.rx_packet_length = 0;
|
||||
#endif
|
||||
wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_7;
|
||||
break;
|
||||
|
||||
case LWS_RXPS_04_FRAME_HDR_LEN64_7:
|
||||
#if defined __LP64__
|
||||
wsi->u.ws.rx_packet_length |= ((size_t)c) << 48;
|
||||
#endif
|
||||
wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_6;
|
||||
break;
|
||||
|
||||
case LWS_RXPS_04_FRAME_HDR_LEN64_6:
|
||||
#if defined __LP64__
|
||||
wsi->u.ws.rx_packet_length |= ((size_t)c) << 40;
|
||||
#endif
|
||||
wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_5;
|
||||
break;
|
||||
|
||||
case LWS_RXPS_04_FRAME_HDR_LEN64_5:
|
||||
#if defined __LP64__
|
||||
wsi->u.ws.rx_packet_length |= ((size_t)c) << 32;
|
||||
#endif
|
||||
wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_4;
|
||||
break;
|
||||
|
||||
case LWS_RXPS_04_FRAME_HDR_LEN64_4:
|
||||
wsi->u.ws.rx_packet_length |= ((size_t)c) << 24;
|
||||
wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_3;
|
||||
break;
|
||||
|
||||
case LWS_RXPS_04_FRAME_HDR_LEN64_3:
|
||||
wsi->u.ws.rx_packet_length |= ((size_t)c) << 16;
|
||||
wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_2;
|
||||
break;
|
||||
|
||||
case LWS_RXPS_04_FRAME_HDR_LEN64_2:
|
||||
wsi->u.ws.rx_packet_length |= ((size_t)c) << 8;
|
||||
wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_1;
|
||||
break;
|
||||
|
||||
case LWS_RXPS_04_FRAME_HDR_LEN64_1:
|
||||
wsi->u.ws.rx_packet_length |= (size_t)c;
|
||||
if (wsi->u.ws.this_frame_masked)
|
||||
wsi->lws_rx_parse_state =
|
||||
LWS_RXPS_07_COLLECT_FRAME_KEY_1;
|
||||
else {
|
||||
if (wsi->u.ws.rx_packet_length)
|
||||
wsi->lws_rx_parse_state =
|
||||
LWS_RXPS_PAYLOAD_UNTIL_LENGTH_EXHAUSTED;
|
||||
else {
|
||||
wsi->lws_rx_parse_state = LWS_RXPS_NEW;
|
||||
goto spill;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case LWS_RXPS_07_COLLECT_FRAME_KEY_1:
|
||||
wsi->u.ws.frame_masking_nonce_04[0] = c;
|
||||
if (c)
|
||||
wsi->u.ws.all_zero_nonce = 0;
|
||||
wsi->lws_rx_parse_state = LWS_RXPS_07_COLLECT_FRAME_KEY_2;
|
||||
break;
|
||||
|
||||
case LWS_RXPS_07_COLLECT_FRAME_KEY_2:
|
||||
wsi->u.ws.frame_masking_nonce_04[1] = c;
|
||||
if (c)
|
||||
wsi->u.ws.all_zero_nonce = 0;
|
||||
wsi->lws_rx_parse_state = LWS_RXPS_07_COLLECT_FRAME_KEY_3;
|
||||
break;
|
||||
|
||||
case LWS_RXPS_07_COLLECT_FRAME_KEY_3:
|
||||
wsi->u.ws.frame_masking_nonce_04[2] = c;
|
||||
if (c)
|
||||
wsi->u.ws.all_zero_nonce = 0;
|
||||
wsi->lws_rx_parse_state = LWS_RXPS_07_COLLECT_FRAME_KEY_4;
|
||||
break;
|
||||
|
||||
case LWS_RXPS_07_COLLECT_FRAME_KEY_4:
|
||||
wsi->u.ws.frame_masking_nonce_04[3] = c;
|
||||
if (c)
|
||||
wsi->u.ws.all_zero_nonce = 0;
|
||||
|
||||
if (wsi->u.ws.rx_packet_length)
|
||||
wsi->lws_rx_parse_state =
|
||||
LWS_RXPS_PAYLOAD_UNTIL_LENGTH_EXHAUSTED;
|
||||
else {
|
||||
wsi->lws_rx_parse_state = LWS_RXPS_NEW;
|
||||
goto spill;
|
||||
}
|
||||
break;
|
||||
|
||||
case LWS_RXPS_PAYLOAD_UNTIL_LENGTH_EXHAUSTED:
|
||||
|
||||
if (!wsi->u.ws.rx_user_buffer)
|
||||
lwsl_err("NULL client rx_user_buffer\n");
|
||||
|
||||
if ((!wsi->u.ws.this_frame_masked) || wsi->u.ws.all_zero_nonce)
|
||||
wsi->u.ws.rx_user_buffer[LWS_SEND_BUFFER_PRE_PADDING +
|
||||
(wsi->u.ws.rx_user_buffer_head++)] = c;
|
||||
else
|
||||
wsi->u.ws.rx_user_buffer[LWS_SEND_BUFFER_PRE_PADDING +
|
||||
(wsi->u.ws.rx_user_buffer_head++)] =
|
||||
c ^ wsi->u.ws.frame_masking_nonce_04[
|
||||
(wsi->u.ws.frame_mask_index++) & 3];
|
||||
|
||||
if (--wsi->u.ws.rx_packet_length == 0) {
|
||||
/* spill because we have the whole frame */
|
||||
wsi->lws_rx_parse_state = LWS_RXPS_NEW;
|
||||
goto spill;
|
||||
}
|
||||
|
||||
/*
|
||||
* if there's no protocol max frame size given, we are
|
||||
* supposed to default to LWS_MAX_SOCKET_IO_BUF
|
||||
*/
|
||||
|
||||
if (!wsi->protocol->rx_buffer_size &&
|
||||
wsi->u.ws.rx_user_buffer_head !=
|
||||
LWS_MAX_SOCKET_IO_BUF)
|
||||
break;
|
||||
else
|
||||
if (wsi->protocol->rx_buffer_size &&
|
||||
wsi->u.ws.rx_user_buffer_head !=
|
||||
wsi->protocol->rx_buffer_size)
|
||||
break;
|
||||
|
||||
/* spill because we filled our rx buffer */
|
||||
spill:
|
||||
|
||||
handled = 0;
|
||||
|
||||
/*
|
||||
* is this frame a control packet we should take care of at this
|
||||
* layer? If so service it and hide it from the user callback
|
||||
*/
|
||||
|
||||
switch (wsi->u.ws.opcode) {
|
||||
case LWS_WS_OPCODE_07__CLOSE:
|
||||
/* is this an acknowledgement of our close? */
|
||||
if (wsi->state == WSI_STATE_AWAITING_CLOSE_ACK) {
|
||||
/*
|
||||
* fine he has told us he is closing too, let's
|
||||
* finish our close
|
||||
*/
|
||||
lwsl_parser("seen server's close ack\n");
|
||||
return -1;
|
||||
}
|
||||
lwsl_parser("client sees server close len = %d\n",
|
||||
wsi->u.ws.rx_user_buffer_head);
|
||||
/*
|
||||
* parrot the close packet payload back
|
||||
* we do not care about how it went, we are closing
|
||||
* immediately afterwards
|
||||
*/
|
||||
libwebsocket_write(wsi, (unsigned char *)
|
||||
&wsi->u.ws.rx_user_buffer[
|
||||
LWS_SEND_BUFFER_PRE_PADDING],
|
||||
wsi->u.ws.rx_user_buffer_head, LWS_WRITE_CLOSE);
|
||||
wsi->state = WSI_STATE_RETURNED_CLOSE_ALREADY;
|
||||
/* close the connection */
|
||||
return -1;
|
||||
|
||||
case LWS_WS_OPCODE_07__PING:
|
||||
lwsl_info("client received ping, doing pong\n");
|
||||
/*
|
||||
* parrot the ping packet payload back as a pong
|
||||
* !!! this may block or have partial write or fail
|
||||
* !!! very unlikely if the ping size is small
|
||||
*/
|
||||
libwebsocket_write(wsi, (unsigned char *)
|
||||
&wsi->u.ws.rx_user_buffer[
|
||||
LWS_SEND_BUFFER_PRE_PADDING],
|
||||
wsi->u.ws.rx_user_buffer_head,
|
||||
LWS_WRITE_PONG);
|
||||
handled = 1;
|
||||
break;
|
||||
|
||||
case LWS_WS_OPCODE_07__PONG:
|
||||
lwsl_info("client receied pong\n");
|
||||
lwsl_hexdump(&wsi->u.ws.rx_user_buffer[
|
||||
LWS_SEND_BUFFER_PRE_PADDING],
|
||||
wsi->u.ws.rx_user_buffer_head);
|
||||
|
||||
/* issue it */
|
||||
callback_action = LWS_CALLBACK_CLIENT_RECEIVE_PONG;
|
||||
break;
|
||||
|
||||
case LWS_WS_OPCODE_07__CONTINUATION:
|
||||
case LWS_WS_OPCODE_07__TEXT_FRAME:
|
||||
case LWS_WS_OPCODE_07__BINARY_FRAME:
|
||||
break;
|
||||
|
||||
default:
|
||||
|
||||
lwsl_parser("Reserved opc 0x%2X\n", wsi->u.ws.opcode);
|
||||
|
||||
/*
|
||||
* It's something special we can't understand here.
|
||||
* Pass the payload up to the extension's parsing
|
||||
* state machine.
|
||||
*/
|
||||
|
||||
eff_buf.token = &wsi->u.ws.rx_user_buffer[
|
||||
LWS_SEND_BUFFER_PRE_PADDING];
|
||||
eff_buf.token_len = wsi->u.ws.rx_user_buffer_head;
|
||||
|
||||
if (lws_ext_callback_for_each_active(wsi,
|
||||
LWS_EXT_CALLBACK_EXTENDED_PAYLOAD_RX,
|
||||
&eff_buf, 0) <= 0) { /* not handle or fail */
|
||||
|
||||
lwsl_ext("Unhandled ext opc 0x%x\n",
|
||||
wsi->u.ws.opcode);
|
||||
wsi->u.ws.rx_user_buffer_head = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
handled = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* No it's real payload, pass it up to the user callback.
|
||||
* It's nicely buffered with the pre-padding taken care of
|
||||
* so it can be sent straight out again using libwebsocket_write
|
||||
*/
|
||||
if (handled)
|
||||
goto already_done;
|
||||
|
||||
eff_buf.token = &wsi->u.ws.rx_user_buffer[
|
||||
LWS_SEND_BUFFER_PRE_PADDING];
|
||||
eff_buf.token_len = wsi->u.ws.rx_user_buffer_head;
|
||||
|
||||
if (lws_ext_callback_for_each_active(wsi,
|
||||
LWS_EXT_CALLBACK_PAYLOAD_RX,
|
||||
&eff_buf, 0) < 0) /* fail */
|
||||
return -1;
|
||||
|
||||
if (eff_buf.token_len <= 0 &&
|
||||
callback_action != LWS_CALLBACK_CLIENT_RECEIVE_PONG)
|
||||
goto already_done;
|
||||
|
||||
eff_buf.token[eff_buf.token_len] = '\0';
|
||||
|
||||
if (!wsi->protocol->callback)
|
||||
goto already_done;
|
||||
|
||||
if (callback_action == LWS_CALLBACK_CLIENT_RECEIVE_PONG)
|
||||
lwsl_info("Client doing pong callback\n");
|
||||
|
||||
m = wsi->protocol->callback(
|
||||
wsi->protocol->owning_server,
|
||||
wsi,
|
||||
(enum libwebsocket_callback_reasons)callback_action,
|
||||
wsi->user_space,
|
||||
eff_buf.token,
|
||||
eff_buf.token_len);
|
||||
|
||||
/* if user code wants to close, let caller know */
|
||||
if (m)
|
||||
return 1;
|
||||
|
||||
already_done:
|
||||
wsi->u.ws.rx_user_buffer_head = 0;
|
||||
break;
|
||||
default:
|
||||
lwsl_err("client rx illegal state\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
illegal_ctl_length:
|
||||
|
||||
lwsl_warn("Control frame asking for extended length is illegal\n");
|
||||
/* kill the connection */
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
958
dependencies/libwebsockets/lib/client.c
vendored
Normal file
958
dependencies/libwebsockets/lib/client.c
vendored
Normal file
@ -0,0 +1,958 @@
|
||||
/*
|
||||
* libwebsockets - small server side websockets and web server implementation
|
||||
*
|
||||
* Copyright (C) 2010-2014 Andy Green <andy@warmcat.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation:
|
||||
* version 2.1 of the License.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
* MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "private-libwebsockets.h"
|
||||
|
||||
int lws_handshake_client(struct libwebsocket *wsi, unsigned char **buf, size_t len)
|
||||
{
|
||||
int n;
|
||||
|
||||
switch (wsi->mode) {
|
||||
case LWS_CONNMODE_WS_CLIENT_WAITING_PROXY_REPLY:
|
||||
case LWS_CONNMODE_WS_CLIENT_ISSUE_HANDSHAKE:
|
||||
case LWS_CONNMODE_WS_CLIENT_WAITING_SERVER_REPLY:
|
||||
case LWS_CONNMODE_WS_CLIENT_WAITING_EXTENSION_CONNECT:
|
||||
case LWS_CONNMODE_WS_CLIENT:
|
||||
for (n = 0; n < len; n++)
|
||||
if (libwebsocket_client_rx_sm(wsi, *(*buf)++)) {
|
||||
lwsl_debug("client_rx_sm failed\n");
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int lws_client_socket_service(struct libwebsocket_context *context,
|
||||
struct libwebsocket *wsi, struct libwebsocket_pollfd *pollfd)
|
||||
{
|
||||
int n;
|
||||
char *p = (char *)&context->service_buffer[0];
|
||||
int len;
|
||||
unsigned char c;
|
||||
|
||||
switch (wsi->mode) {
|
||||
|
||||
case LWS_CONNMODE_WS_CLIENT_WAITING_CONNECT:
|
||||
|
||||
/*
|
||||
* we are under PENDING_TIMEOUT_SENT_CLIENT_HANDSHAKE
|
||||
* timeout protection set in client-handshake.c
|
||||
*/
|
||||
|
||||
if (libwebsocket_client_connect_2(context, wsi) == NULL) {
|
||||
/* closed */
|
||||
lwsl_client("closed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* either still pending connection, or changed mode */
|
||||
return 0;
|
||||
|
||||
case LWS_CONNMODE_WS_CLIENT_WAITING_PROXY_REPLY:
|
||||
|
||||
/* handle proxy hung up on us */
|
||||
|
||||
if (pollfd->revents & LWS_POLLHUP) {
|
||||
|
||||
lwsl_warn("Proxy connection %p (fd=%d) dead\n",
|
||||
(void *)wsi, pollfd->fd);
|
||||
|
||||
libwebsocket_close_and_free_session(context, wsi,
|
||||
LWS_CLOSE_STATUS_NOSTATUS);
|
||||
return 0;
|
||||
}
|
||||
|
||||
n = recv(wsi->sock, context->service_buffer,
|
||||
sizeof(context->service_buffer), 0);
|
||||
if (n < 0) {
|
||||
|
||||
if (LWS_ERRNO == LWS_EAGAIN) {
|
||||
lwsl_debug(
|
||||
"Proxy read returned EAGAIN... retrying\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
libwebsocket_close_and_free_session(context, wsi,
|
||||
LWS_CLOSE_STATUS_NOSTATUS);
|
||||
lwsl_err("ERROR reading from proxy socket\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
context->service_buffer[13] = '\0';
|
||||
if (strcmp((char *)context->service_buffer, "HTTP/1.0 200 ")) {
|
||||
libwebsocket_close_and_free_session(context, wsi,
|
||||
LWS_CLOSE_STATUS_NOSTATUS);
|
||||
lwsl_err("ERROR proxy: %s\n", context->service_buffer);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* clear his proxy connection timeout */
|
||||
|
||||
libwebsocket_set_timeout(wsi, NO_PENDING_TIMEOUT, 0);
|
||||
|
||||
/* fallthru */
|
||||
|
||||
case LWS_CONNMODE_WS_CLIENT_ISSUE_HANDSHAKE:
|
||||
|
||||
/*
|
||||
* we are under PENDING_TIMEOUT_SENT_CLIENT_HANDSHAKE
|
||||
* timeout protection set in client-handshake.c
|
||||
*/
|
||||
|
||||
/*
|
||||
* take care of our libwebsocket_callback_on_writable
|
||||
* happening at a time when there's no real connection yet
|
||||
*/
|
||||
if (lws_change_pollfd(wsi, LWS_POLLOUT, 0))
|
||||
return -1;
|
||||
|
||||
#ifdef LWS_OPENSSL_SUPPORT
|
||||
/* we can retry this... just cook the SSL BIO the first time */
|
||||
|
||||
if (wsi->use_ssl && !wsi->ssl) {
|
||||
#if defined(CYASSL_SNI_HOST_NAME) || defined(SSL_CTRL_SET_TLSEXT_HOSTNAME)
|
||||
const char *hostname = lws_hdr_simple_ptr(wsi,
|
||||
_WSI_TOKEN_CLIENT_PEER_ADDRESS);
|
||||
#endif
|
||||
|
||||
wsi->ssl = SSL_new(context->ssl_client_ctx);
|
||||
#ifndef USE_CYASSL
|
||||
SSL_set_mode(wsi->ssl,
|
||||
SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
|
||||
#endif
|
||||
/*
|
||||
* use server name indication (SNI), if supported,
|
||||
* when establishing connection
|
||||
*/
|
||||
#ifdef USE_CYASSL
|
||||
#ifdef CYASSL_SNI_HOST_NAME
|
||||
CyaSSL_UseSNI(wsi->ssl, CYASSL_SNI_HOST_NAME,
|
||||
hostname, strlen(hostname));
|
||||
#endif
|
||||
#else
|
||||
#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
|
||||
SSL_set_tlsext_host_name(wsi->ssl, hostname);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef USE_CYASSL
|
||||
/*
|
||||
* CyaSSL does certificate verification differently
|
||||
* from OpenSSL.
|
||||
* If we should ignore the certificate, we need to set
|
||||
* this before SSL_new and SSL_connect is called.
|
||||
* Otherwise the connect will simply fail with error
|
||||
* code -155
|
||||
*/
|
||||
if (wsi->use_ssl == 2)
|
||||
CyaSSL_set_verify(wsi->ssl,
|
||||
SSL_VERIFY_NONE, NULL);
|
||||
#endif /* USE_CYASSL */
|
||||
|
||||
wsi->client_bio =
|
||||
BIO_new_socket(wsi->sock, BIO_NOCLOSE);
|
||||
SSL_set_bio(wsi->ssl, wsi->client_bio, wsi->client_bio);
|
||||
|
||||
#ifdef USE_CYASSL
|
||||
CyaSSL_set_using_nonblock(wsi->ssl, 1);
|
||||
#else
|
||||
BIO_set_nbio(wsi->client_bio, 1); /* nonblocking */
|
||||
#endif
|
||||
|
||||
SSL_set_ex_data(wsi->ssl,
|
||||
openssl_websocket_private_data_index,
|
||||
context);
|
||||
}
|
||||
|
||||
if (wsi->use_ssl) {
|
||||
lws_latency_pre(context, wsi);
|
||||
n = SSL_connect(wsi->ssl);
|
||||
lws_latency(context, wsi,
|
||||
"SSL_connect LWS_CONNMODE_WS_CLIENT_ISSUE_HANDSHAKE",
|
||||
n, n > 0);
|
||||
|
||||
if (n < 0) {
|
||||
n = SSL_get_error(wsi->ssl, n);
|
||||
|
||||
if (n == SSL_ERROR_WANT_READ ||
|
||||
n == SSL_ERROR_WANT_WRITE) {
|
||||
/*
|
||||
* wants us to retry connect due to
|
||||
* state of the underlying ssl layer...
|
||||
* but since it may be stalled on
|
||||
* blocked write, no incoming data may
|
||||
* arrive to trigger the retry.
|
||||
* Force (possibly many times if the SSL
|
||||
* state persists in returning the
|
||||
* condition code, but other sockets
|
||||
* are getting serviced inbetweentimes)
|
||||
* us to get called back when writable.
|
||||
*/
|
||||
|
||||
lwsl_info(
|
||||
"SSL_connect WANT_... retrying\n");
|
||||
libwebsocket_callback_on_writable(
|
||||
context, wsi);
|
||||
|
||||
wsi->mode = LWS_CONNMODE_WS_CLIENT_WAITING_SSL;
|
||||
|
||||
return 0; /* no error */
|
||||
}
|
||||
n = -1;
|
||||
}
|
||||
|
||||
if (n <= 0) {
|
||||
/*
|
||||
* retry if new data comes until we
|
||||
* run into the connection timeout or win
|
||||
*/
|
||||
|
||||
n = ERR_get_error();
|
||||
if (n != SSL_ERROR_NONE) {
|
||||
lwsl_err("SSL connect error %lu: %s\n",
|
||||
n,
|
||||
ERR_error_string(n,
|
||||
(char *)context->service_buffer));
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
} else
|
||||
wsi->ssl = NULL;
|
||||
|
||||
/* fallthru */
|
||||
|
||||
case LWS_CONNMODE_WS_CLIENT_WAITING_SSL:
|
||||
|
||||
if (wsi->use_ssl) {
|
||||
|
||||
if (wsi->mode == LWS_CONNMODE_WS_CLIENT_WAITING_SSL) {
|
||||
lws_latency_pre(context, wsi);
|
||||
n = SSL_connect(wsi->ssl);
|
||||
lws_latency(context, wsi,
|
||||
"SSL_connect LWS_CONNMODE_WS_CLIENT_WAITING_SSL",
|
||||
n, n > 0);
|
||||
|
||||
if (n < 0) {
|
||||
n = SSL_get_error(wsi->ssl, n);
|
||||
|
||||
if (n == SSL_ERROR_WANT_READ ||
|
||||
n == SSL_ERROR_WANT_WRITE) {
|
||||
/*
|
||||
* wants us to retry connect due to
|
||||
* state of the underlying ssl layer...
|
||||
* but since it may be stalled on
|
||||
* blocked write, no incoming data may
|
||||
* arrive to trigger the retry.
|
||||
* Force (possibly many times if the SSL
|
||||
* state persists in returning the
|
||||
* condition code, but other sockets
|
||||
* are getting serviced inbetweentimes)
|
||||
* us to get called back when writable.
|
||||
*/
|
||||
|
||||
lwsl_info(
|
||||
"SSL_connect WANT_... retrying\n");
|
||||
libwebsocket_callback_on_writable(
|
||||
context, wsi);
|
||||
|
||||
wsi->mode = LWS_CONNMODE_WS_CLIENT_WAITING_SSL;
|
||||
|
||||
return 0; /* no error */
|
||||
}
|
||||
n = -1;
|
||||
}
|
||||
|
||||
if (n <= 0) {
|
||||
/*
|
||||
* retry if new data comes until we
|
||||
* run into the connection timeout or win
|
||||
*/
|
||||
n = ERR_get_error();
|
||||
if (n != SSL_ERROR_NONE) {
|
||||
lwsl_err("SSL connect error %lu: %s\n",
|
||||
n,
|
||||
ERR_error_string(n,
|
||||
(char *)context->service_buffer));
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef USE_CYASSL
|
||||
/*
|
||||
* See comment above about CyaSSL certificate
|
||||
* verification
|
||||
*/
|
||||
lws_latency_pre(context, wsi);
|
||||
n = SSL_get_verify_result(wsi->ssl);
|
||||
lws_latency(context, wsi,
|
||||
"SSL_get_verify_result LWS_CONNMODE..HANDSHAKE",
|
||||
n, n > 0);
|
||||
if ((n != X509_V_OK) && (
|
||||
n != X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT ||
|
||||
wsi->use_ssl != 2)) {
|
||||
|
||||
lwsl_err(
|
||||
"server's cert didn't look good %d\n", n);
|
||||
libwebsocket_close_and_free_session(context,
|
||||
wsi, LWS_CLOSE_STATUS_NOSTATUS);
|
||||
return 0;
|
||||
}
|
||||
#endif /* USE_CYASSL */
|
||||
} else
|
||||
wsi->ssl = NULL;
|
||||
#endif
|
||||
|
||||
wsi->mode = LWS_CONNMODE_WS_CLIENT_ISSUE_HANDSHAKE2;
|
||||
libwebsocket_set_timeout(wsi,
|
||||
PENDING_TIMEOUT_AWAITING_CLIENT_HS_SEND,
|
||||
AWAITING_TIMEOUT);
|
||||
|
||||
/* fallthru */
|
||||
|
||||
case LWS_CONNMODE_WS_CLIENT_ISSUE_HANDSHAKE2:
|
||||
p = libwebsockets_generate_client_handshake(context, wsi, p);
|
||||
if (p == NULL) {
|
||||
lwsl_err("Failed to generate handshake for client\n");
|
||||
libwebsocket_close_and_free_session(context, wsi,
|
||||
LWS_CLOSE_STATUS_NOSTATUS);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* send our request to the server */
|
||||
|
||||
lws_latency_pre(context, wsi);
|
||||
|
||||
n = lws_ssl_capable_write(wsi, context->service_buffer, p - (char *)context->service_buffer);
|
||||
lws_latency(context, wsi, "send lws_issue_raw", n, n == p - (char *)context->service_buffer);
|
||||
switch (n) {
|
||||
case LWS_SSL_CAPABLE_ERROR:
|
||||
lwsl_debug("ERROR writing to client socket\n");
|
||||
libwebsocket_close_and_free_session(context, wsi,
|
||||
LWS_CLOSE_STATUS_NOSTATUS);
|
||||
return 0;
|
||||
case LWS_SSL_CAPABLE_MORE_SERVICE:
|
||||
libwebsocket_callback_on_writable(context, wsi);
|
||||
break;
|
||||
}
|
||||
|
||||
wsi->u.hdr.parser_state = WSI_TOKEN_NAME_PART;
|
||||
wsi->u.hdr.lextable_pos = 0;
|
||||
wsi->mode = LWS_CONNMODE_WS_CLIENT_WAITING_SERVER_REPLY;
|
||||
libwebsocket_set_timeout(wsi,
|
||||
PENDING_TIMEOUT_AWAITING_SERVER_RESPONSE,
|
||||
AWAITING_TIMEOUT);
|
||||
break;
|
||||
|
||||
case LWS_CONNMODE_WS_CLIENT_WAITING_SERVER_REPLY:
|
||||
|
||||
/* handle server hung up on us */
|
||||
|
||||
if (pollfd->revents & LWS_POLLHUP) {
|
||||
|
||||
lwsl_debug("Server connection %p (fd=%d) dead\n",
|
||||
(void *)wsi, pollfd->fd);
|
||||
|
||||
goto bail3;
|
||||
}
|
||||
|
||||
if (!(pollfd->revents & LWS_POLLIN))
|
||||
break;
|
||||
|
||||
/* interpret the server response */
|
||||
|
||||
/*
|
||||
* HTTP/1.1 101 Switching Protocols
|
||||
* Upgrade: websocket
|
||||
* Connection: Upgrade
|
||||
* Sec-WebSocket-Accept: me89jWimTRKTWwrS3aRrL53YZSo=
|
||||
* Sec-WebSocket-Nonce: AQIDBAUGBwgJCgsMDQ4PEC==
|
||||
* Sec-WebSocket-Protocol: chat
|
||||
*/
|
||||
|
||||
/*
|
||||
* we have to take some care here to only take from the
|
||||
* socket bytewise. The browser may (and has been seen to
|
||||
* in the case that onopen() performs websocket traffic)
|
||||
* coalesce both handshake response and websocket traffic
|
||||
* in one packet, since at that point the connection is
|
||||
* definitively ready from browser pov.
|
||||
*/
|
||||
len = 1;
|
||||
while (wsi->u.hdr.parser_state != WSI_PARSING_COMPLETE &&
|
||||
len > 0) {
|
||||
n = lws_ssl_capable_read(wsi, &c, 1);
|
||||
lws_latency(context, wsi, "send lws_issue_raw", n, n == 1);
|
||||
switch (n) {
|
||||
case LWS_SSL_CAPABLE_ERROR:
|
||||
goto bail3;
|
||||
case LWS_SSL_CAPABLE_MORE_SERVICE:
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (libwebsocket_parse(context, wsi, c)) {
|
||||
lwsl_warn("problems parsing header\n");
|
||||
goto bail3;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* hs may also be coming in multiple packets, there is a 5-sec
|
||||
* libwebsocket timeout still active here too, so if parsing did
|
||||
* not complete just wait for next packet coming in this state
|
||||
*/
|
||||
|
||||
if (wsi->u.hdr.parser_state != WSI_PARSING_COMPLETE)
|
||||
break;
|
||||
|
||||
/*
|
||||
* otherwise deal with the handshake. If there's any
|
||||
* packet traffic already arrived we'll trigger poll() again
|
||||
* right away and deal with it that way
|
||||
*/
|
||||
|
||||
return lws_client_interpret_server_handshake(context, wsi);
|
||||
|
||||
bail3:
|
||||
lwsl_info(
|
||||
"closing connection at LWS_CONNMODE...SERVER_REPLY\n");
|
||||
libwebsocket_close_and_free_session(context, wsi,
|
||||
LWS_CLOSE_STATUS_NOSTATUS);
|
||||
return -1;
|
||||
|
||||
case LWS_CONNMODE_WS_CLIENT_WAITING_EXTENSION_CONNECT:
|
||||
lwsl_ext("LWS_CONNMODE_WS_CLIENT_WAITING_EXTENSION_CONNECT\n");
|
||||
break;
|
||||
|
||||
case LWS_CONNMODE_WS_CLIENT_PENDING_CANDIDATE_CHILD:
|
||||
lwsl_ext("LWS_CONNMODE_WS_CLIENT_PENDING_CANDIDATE_CHILD\n");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* In-place str to lower case
|
||||
*/
|
||||
|
||||
static void
|
||||
strtolower(char *s)
|
||||
{
|
||||
while (*s) {
|
||||
*s = tolower((int)*s);
|
||||
s++;
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
lws_client_interpret_server_handshake(struct libwebsocket_context *context,
|
||||
struct libwebsocket *wsi)
|
||||
{
|
||||
const char *pc;
|
||||
int okay = 0;
|
||||
char *p;
|
||||
int len;
|
||||
#ifndef LWS_NO_EXTENSIONS
|
||||
char ext_name[128];
|
||||
struct libwebsocket_extension *ext;
|
||||
void *v;
|
||||
int more = 1;
|
||||
const char *c;
|
||||
#endif
|
||||
int n;
|
||||
int close_reason = LWS_CLOSE_STATUS_PROTOCOL_ERR;
|
||||
|
||||
/*
|
||||
* well, what the server sent looked reasonable for syntax.
|
||||
* Now let's confirm it sent all the necessary headers
|
||||
*/
|
||||
|
||||
if (lws_hdr_total_length(wsi, WSI_TOKEN_ACCEPT) == 0) {
|
||||
lwsl_info("no ACCEPT\n");
|
||||
goto bail3;
|
||||
}
|
||||
|
||||
p = lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP);
|
||||
if (!p) {
|
||||
lwsl_info("no URI\n");
|
||||
goto bail3;
|
||||
}
|
||||
if (p && strncmp(p, "101", 3)) {
|
||||
lwsl_warn(
|
||||
"lws_client_handshake: got bad HTTP response '%s'\n", p);
|
||||
goto bail3;
|
||||
}
|
||||
|
||||
p = lws_hdr_simple_ptr(wsi, WSI_TOKEN_UPGRADE);
|
||||
if (!p) {
|
||||
lwsl_info("no UPGRADE\n");
|
||||
goto bail3;
|
||||
}
|
||||
strtolower(p);
|
||||
if (strcmp(p, "websocket")) {
|
||||
lwsl_warn(
|
||||
"lws_client_handshake: got bad Upgrade header '%s'\n", p);
|
||||
goto bail3;
|
||||
}
|
||||
|
||||
p = lws_hdr_simple_ptr(wsi, WSI_TOKEN_CONNECTION);
|
||||
if (!p) {
|
||||
lwsl_info("no Connection hdr\n");
|
||||
goto bail3;
|
||||
}
|
||||
strtolower(p);
|
||||
if (strcmp(p, "upgrade")) {
|
||||
lwsl_warn("lws_client_int_s_hs: bad header %s\n", p);
|
||||
goto bail3;
|
||||
}
|
||||
|
||||
pc = lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_SENT_PROTOCOLS);
|
||||
if (pc == NULL)
|
||||
lwsl_parser("lws_client_int_s_hs: no protocol list\n");
|
||||
else
|
||||
lwsl_parser("lws_client_int_s_hs: protocol list '%s'\n", pc);
|
||||
|
||||
/*
|
||||
* confirm the protocol the server wants to talk was in the list
|
||||
* of protocols we offered
|
||||
*/
|
||||
|
||||
len = lws_hdr_total_length(wsi, WSI_TOKEN_PROTOCOL);
|
||||
if (!len) {
|
||||
|
||||
lwsl_info("lws_client_int_s_hs: WSI_TOKEN_PROTOCOL is null\n");
|
||||
/*
|
||||
* no protocol name to work from,
|
||||
* default to first protocol
|
||||
*/
|
||||
wsi->protocol = &context->protocols[0];
|
||||
goto check_extensions;
|
||||
}
|
||||
|
||||
p = lws_hdr_simple_ptr(wsi, WSI_TOKEN_PROTOCOL);
|
||||
len = strlen(p);
|
||||
|
||||
while (*pc && !okay) {
|
||||
if (!strncmp(pc, p, len) &&
|
||||
(pc[len] == ',' || pc[len] == '\0')) {
|
||||
okay = 1;
|
||||
continue;
|
||||
}
|
||||
while (*pc && *pc != ',')
|
||||
pc++;
|
||||
while (*pc && *pc != ' ')
|
||||
pc++;
|
||||
}
|
||||
|
||||
if (!okay) {
|
||||
lwsl_err("lws_client_int_s_hs: got bad protocol %s\n", p);
|
||||
goto bail2;
|
||||
}
|
||||
|
||||
/*
|
||||
* identify the selected protocol struct and set it
|
||||
*/
|
||||
n = 0;
|
||||
wsi->protocol = NULL;
|
||||
while (context->protocols[n].callback && !wsi->protocol) {
|
||||
if (strcmp(p, context->protocols[n].name) == 0) {
|
||||
wsi->protocol = &context->protocols[n];
|
||||
break;
|
||||
}
|
||||
n++;
|
||||
}
|
||||
|
||||
if (wsi->protocol == NULL) {
|
||||
lwsl_err("lws_client_int_s_hs: fail protocol %s\n", p);
|
||||
goto bail2;
|
||||
}
|
||||
|
||||
|
||||
check_extensions:
|
||||
#ifndef LWS_NO_EXTENSIONS
|
||||
/* instantiate the accepted extensions */
|
||||
|
||||
if (!lws_hdr_total_length(wsi, WSI_TOKEN_EXTENSIONS)) {
|
||||
lwsl_ext("no client extenstions allowed by server\n");
|
||||
goto check_accept;
|
||||
}
|
||||
|
||||
/*
|
||||
* break down the list of server accepted extensions
|
||||
* and go through matching them or identifying bogons
|
||||
*/
|
||||
|
||||
if (lws_hdr_copy(wsi, (char *)context->service_buffer,
|
||||
sizeof(context->service_buffer), WSI_TOKEN_EXTENSIONS) < 0) {
|
||||
lwsl_warn("ext list from server failed to copy\n");
|
||||
goto bail2;
|
||||
}
|
||||
|
||||
c = (char *)context->service_buffer;
|
||||
n = 0;
|
||||
while (more) {
|
||||
|
||||
if (*c && (*c != ',' && *c != ' ' && *c != '\t')) {
|
||||
ext_name[n] = *c++;
|
||||
if (n < sizeof(ext_name) - 1)
|
||||
n++;
|
||||
continue;
|
||||
}
|
||||
ext_name[n] = '\0';
|
||||
if (!*c)
|
||||
more = 0;
|
||||
else {
|
||||
c++;
|
||||
if (!n)
|
||||
continue;
|
||||
}
|
||||
|
||||
/* check we actually support it */
|
||||
|
||||
lwsl_ext("checking client ext %s\n", ext_name);
|
||||
|
||||
n = 0;
|
||||
ext = wsi->protocol->owning_server->extensions;
|
||||
while (ext && ext->callback) {
|
||||
|
||||
if (strcmp(ext_name, ext->name)) {
|
||||
ext++;
|
||||
continue;
|
||||
}
|
||||
|
||||
n = 1;
|
||||
|
||||
lwsl_ext("instantiating client ext %s\n", ext_name);
|
||||
|
||||
/* instantiate the extension on this conn */
|
||||
|
||||
wsi->active_extensions_user[
|
||||
wsi->count_active_extensions] =
|
||||
malloc(ext->per_session_data_size);
|
||||
if (wsi->active_extensions_user[
|
||||
wsi->count_active_extensions] == NULL) {
|
||||
lwsl_err("Out of mem\n");
|
||||
goto bail2;
|
||||
}
|
||||
memset(wsi->active_extensions_user[
|
||||
wsi->count_active_extensions], 0,
|
||||
ext->per_session_data_size);
|
||||
wsi->active_extensions[
|
||||
wsi->count_active_extensions] = ext;
|
||||
|
||||
/* allow him to construct his context */
|
||||
|
||||
ext->callback(wsi->protocol->owning_server,
|
||||
ext, wsi,
|
||||
LWS_EXT_CALLBACK_CLIENT_CONSTRUCT,
|
||||
wsi->active_extensions_user[
|
||||
wsi->count_active_extensions],
|
||||
NULL, 0);
|
||||
|
||||
wsi->count_active_extensions++;
|
||||
|
||||
ext++;
|
||||
}
|
||||
|
||||
if (n == 0) {
|
||||
lwsl_warn("Unknown ext '%s'!\n", ext_name);
|
||||
goto bail2;
|
||||
}
|
||||
|
||||
n = 0;
|
||||
}
|
||||
|
||||
check_accept:
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Confirm his accept token is the one we precomputed
|
||||
*/
|
||||
|
||||
p = lws_hdr_simple_ptr(wsi, WSI_TOKEN_ACCEPT);
|
||||
if (strcmp(p, wsi->u.hdr.ah->initial_handshake_hash_base64)) {
|
||||
lwsl_warn("lws_client_int_s_hs: accept %s wrong vs %s\n", p,
|
||||
wsi->u.hdr.ah->initial_handshake_hash_base64);
|
||||
goto bail2;
|
||||
}
|
||||
|
||||
/* allocate the per-connection user memory (if any) */
|
||||
if (libwebsocket_ensure_user_space(wsi)) {
|
||||
lwsl_err("Problem allocating wsi user mem\n");
|
||||
goto bail2;
|
||||
}
|
||||
|
||||
/*
|
||||
* we seem to be good to go, give client last chance to check
|
||||
* headers and OK it
|
||||
*/
|
||||
|
||||
wsi->protocol->callback(context, wsi,
|
||||
LWS_CALLBACK_CLIENT_FILTER_PRE_ESTABLISH,
|
||||
wsi->user_space, NULL, 0);
|
||||
|
||||
/* clear his proxy connection timeout */
|
||||
|
||||
libwebsocket_set_timeout(wsi, NO_PENDING_TIMEOUT, 0);
|
||||
|
||||
/* free up his parsing allocations */
|
||||
if (wsi->u.hdr.ah)
|
||||
free(wsi->u.hdr.ah);
|
||||
|
||||
/* mark him as being alive */
|
||||
|
||||
wsi->state = WSI_STATE_ESTABLISHED;
|
||||
wsi->mode = LWS_CONNMODE_WS_CLIENT;
|
||||
|
||||
/* union transition */
|
||||
|
||||
memset(&wsi->u, 0, sizeof(wsi->u));
|
||||
|
||||
wsi->u.ws.rxflow_change_to = LWS_RXFLOW_ALLOW;
|
||||
|
||||
/*
|
||||
* create the frame buffer for this connection according to the
|
||||
* size mentioned in the protocol definition. If 0 there, then
|
||||
* use a big default for compatibility
|
||||
*/
|
||||
|
||||
n = wsi->protocol->rx_buffer_size;
|
||||
if (!n)
|
||||
n = LWS_MAX_SOCKET_IO_BUF;
|
||||
n += LWS_SEND_BUFFER_PRE_PADDING + LWS_SEND_BUFFER_POST_PADDING;
|
||||
wsi->u.ws.rx_user_buffer = malloc(n);
|
||||
if (!wsi->u.ws.rx_user_buffer) {
|
||||
lwsl_err("Out of Mem allocating rx buffer %d\n", n);
|
||||
goto bail2;
|
||||
}
|
||||
lwsl_info("Allocating client RX buffer %d\n", n);
|
||||
|
||||
if (setsockopt(wsi->sock, SOL_SOCKET, SO_SNDBUF, (const char *)&n, sizeof n)) {
|
||||
lwsl_warn("Failed to set SNDBUF to %d", n);
|
||||
goto bail3;
|
||||
}
|
||||
|
||||
lwsl_debug("handshake OK for protocol %s\n", wsi->protocol->name);
|
||||
|
||||
/* call him back to inform him he is up */
|
||||
|
||||
wsi->protocol->callback(context, wsi,
|
||||
LWS_CALLBACK_CLIENT_ESTABLISHED,
|
||||
wsi->user_space, NULL, 0);
|
||||
#ifndef LWS_NO_EXTENSIONS
|
||||
/*
|
||||
* inform all extensions, not just active ones since they
|
||||
* already know
|
||||
*/
|
||||
|
||||
ext = context->extensions;
|
||||
|
||||
while (ext && ext->callback) {
|
||||
v = NULL;
|
||||
for (n = 0; n < wsi->count_active_extensions; n++)
|
||||
if (wsi->active_extensions[n] == ext)
|
||||
v = wsi->active_extensions_user[n];
|
||||
|
||||
ext->callback(context, ext, wsi,
|
||||
LWS_EXT_CALLBACK_ANY_WSI_ESTABLISHED, v, NULL, 0);
|
||||
ext++;
|
||||
}
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
|
||||
bail3:
|
||||
free(wsi->u.ws.rx_user_buffer);
|
||||
wsi->u.ws.rx_user_buffer = NULL;
|
||||
close_reason = LWS_CLOSE_STATUS_NOSTATUS;
|
||||
|
||||
bail2:
|
||||
if (wsi->protocol)
|
||||
wsi->protocol->callback(context, wsi,
|
||||
LWS_CALLBACK_CLIENT_CONNECTION_ERROR,
|
||||
wsi->user_space, NULL, 0);
|
||||
|
||||
lwsl_info("closing connection due to bail2 connection error\n");
|
||||
|
||||
/* free up his parsing allocations */
|
||||
|
||||
if (wsi->u.hdr.ah)
|
||||
free(wsi->u.hdr.ah);
|
||||
|
||||
libwebsocket_close_and_free_session(context, wsi, close_reason);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
char *
|
||||
libwebsockets_generate_client_handshake(struct libwebsocket_context *context,
|
||||
struct libwebsocket *wsi, char *pkt)
|
||||
{
|
||||
char buf[128];
|
||||
char hash[20];
|
||||
char key_b64[40];
|
||||
char *p = pkt;
|
||||
int n;
|
||||
#ifndef LWS_NO_EXTENSIONS
|
||||
struct libwebsocket_extension *ext;
|
||||
int ext_count = 0;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* create the random key
|
||||
*/
|
||||
|
||||
n = libwebsockets_get_random(context, hash, 16);
|
||||
if (n != 16) {
|
||||
lwsl_err("Unable to read from random dev %s\n",
|
||||
SYSTEM_RANDOM_FILEPATH);
|
||||
libwebsocket_close_and_free_session(context, wsi,
|
||||
LWS_CLOSE_STATUS_NOSTATUS);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
lws_b64_encode_string(hash, 16, key_b64, sizeof(key_b64));
|
||||
|
||||
/*
|
||||
* 00 example client handshake
|
||||
*
|
||||
* GET /socket.io/websocket HTTP/1.1
|
||||
* Upgrade: WebSocket
|
||||
* Connection: Upgrade
|
||||
* Host: 127.0.0.1:9999
|
||||
* Origin: http://127.0.0.1
|
||||
* Sec-WebSocket-Key1: 1 0 2#0W 9 89 7 92 ^
|
||||
* Sec-WebSocket-Key2: 7 7Y 4328 B2v[8(z1
|
||||
* Cookie: socketio=websocket
|
||||
*
|
||||
* (Á®Ä0¶†≥
|
||||
*
|
||||
* 04 example client handshake
|
||||
*
|
||||
* GET /chat HTTP/1.1
|
||||
* Host: server.example.com
|
||||
* Upgrade: websocket
|
||||
* Connection: Upgrade
|
||||
* Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
|
||||
* Sec-WebSocket-Origin: http://example.com
|
||||
* Sec-WebSocket-Protocol: chat, superchat
|
||||
* Sec-WebSocket-Version: 4
|
||||
*/
|
||||
|
||||
p += sprintf(p, "GET %s HTTP/1.1\x0d\x0a",
|
||||
lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_URI));
|
||||
|
||||
p += sprintf(p,
|
||||
"Pragma: no-cache\x0d\x0a""Cache-Control: no-cache\x0d\x0a");
|
||||
|
||||
p += sprintf(p, "Host: %s\x0d\x0a",
|
||||
lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_HOST));
|
||||
p += sprintf(p,
|
||||
"Upgrade: websocket\x0d\x0a""Connection: Upgrade\x0d\x0a""Sec-WebSocket-Key: ");
|
||||
strcpy(p, key_b64);
|
||||
p += strlen(key_b64);
|
||||
p += sprintf(p, "\x0d\x0a");
|
||||
if (lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_ORIGIN))
|
||||
p += sprintf(p, "Origin: http://%s\x0d\x0a",
|
||||
lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_ORIGIN));
|
||||
|
||||
if (lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_SENT_PROTOCOLS))
|
||||
p += sprintf(p, "Sec-WebSocket-Protocol: %s\x0d\x0a",
|
||||
lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_SENT_PROTOCOLS));
|
||||
|
||||
/* tell the server what extensions we could support */
|
||||
|
||||
p += sprintf(p, "Sec-WebSocket-Extensions: ");
|
||||
#ifndef LWS_NO_EXTENSIONS
|
||||
ext = context->extensions;
|
||||
while (ext && ext->callback) {
|
||||
|
||||
n = lws_ext_callback_for_each_extension_type(context, wsi,
|
||||
LWS_EXT_CALLBACK_CHECK_OK_TO_PROPOSE_EXTENSION,
|
||||
(char *)ext->name, 0);
|
||||
if (n) { /* an extension vetos us */
|
||||
lwsl_ext("ext %s vetoed\n", (char *)ext->name);
|
||||
ext++;
|
||||
continue;
|
||||
}
|
||||
|
||||
n = context->protocols[0].callback(context, wsi,
|
||||
LWS_CALLBACK_CLIENT_CONFIRM_EXTENSION_SUPPORTED,
|
||||
wsi->user_space, (char *)ext->name, 0);
|
||||
|
||||
/*
|
||||
* zero return from callback means
|
||||
* go ahead and allow the extension,
|
||||
* it's what we get if the callback is
|
||||
* unhandled
|
||||
*/
|
||||
|
||||
if (n) {
|
||||
ext++;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* apply it */
|
||||
|
||||
if (ext_count)
|
||||
*p++ = ',';
|
||||
p += sprintf(p, "%s", ext->name);
|
||||
ext_count++;
|
||||
|
||||
ext++;
|
||||
}
|
||||
#endif
|
||||
p += sprintf(p, "\x0d\x0a");
|
||||
|
||||
if (wsi->ietf_spec_revision)
|
||||
p += sprintf(p, "Sec-WebSocket-Version: %d\x0d\x0a",
|
||||
wsi->ietf_spec_revision);
|
||||
|
||||
/* give userland a chance to append, eg, cookies */
|
||||
|
||||
context->protocols[0].callback(context, wsi,
|
||||
LWS_CALLBACK_CLIENT_APPEND_HANDSHAKE_HEADER,
|
||||
NULL, &p, (pkt + sizeof(context->service_buffer)) - p - 12);
|
||||
|
||||
p += sprintf(p, "\x0d\x0a");
|
||||
|
||||
/* prepare the expected server accept response */
|
||||
|
||||
key_b64[39] = '\0'; /* enforce composed length below buf sizeof */
|
||||
n = sprintf(buf, "%s258EAFA5-E914-47DA-95CA-C5AB0DC85B11", key_b64);
|
||||
|
||||
SHA1((unsigned char *)buf, n, (unsigned char *)hash);
|
||||
|
||||
lws_b64_encode_string(hash, 20,
|
||||
wsi->u.hdr.ah->initial_handshake_hash_base64,
|
||||
sizeof(wsi->u.hdr.ah->initial_handshake_hash_base64));
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
341
dependencies/libwebsockets/lib/context.c
vendored
Normal file
341
dependencies/libwebsockets/lib/context.c
vendored
Normal file
@ -0,0 +1,341 @@
|
||||
/*
|
||||
* libwebsockets - small server side websockets and web server implementation
|
||||
*
|
||||
* Copyright (C) 2010-2014 Andy Green <andy@warmcat.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation:
|
||||
* version 2.1 of the License.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
* MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "private-libwebsockets.h"
|
||||
|
||||
#ifndef LWS_BUILD_HASH
|
||||
#define LWS_BUILD_HASH "unknown-build-hash"
|
||||
#endif
|
||||
|
||||
static const char *library_version = LWS_LIBRARY_VERSION " " LWS_BUILD_HASH;
|
||||
|
||||
/**
|
||||
* lws_get_library_version: get version and git hash library built from
|
||||
*
|
||||
* returns a const char * to a string like "1.1 178d78c"
|
||||
* representing the library version followed by the git head hash it
|
||||
* was built from
|
||||
*/
|
||||
|
||||
LWS_VISIBLE const char *
|
||||
lws_get_library_version(void)
|
||||
{
|
||||
return library_version;
|
||||
}
|
||||
|
||||
/**
|
||||
* libwebsocket_create_context() - Create the websocket handler
|
||||
* @info: pointer to struct with parameters
|
||||
*
|
||||
* This function creates the listening socket (if serving) and takes care
|
||||
* of all initialization in one step.
|
||||
*
|
||||
* After initialization, it returns a struct libwebsocket_context * that
|
||||
* represents this server. After calling, user code needs to take care
|
||||
* of calling libwebsocket_service() with the context pointer to get the
|
||||
* server's sockets serviced. This must be done in the same process
|
||||
* context as the initialization call.
|
||||
*
|
||||
* The protocol callback functions are called for a handful of events
|
||||
* including http requests coming in, websocket connections becoming
|
||||
* established, and data arriving; it's also called periodically to allow
|
||||
* async transmission.
|
||||
*
|
||||
* HTTP requests are sent always to the FIRST protocol in @protocol, since
|
||||
* at that time websocket protocol has not been negotiated. Other
|
||||
* protocols after the first one never see any HTTP callack activity.
|
||||
*
|
||||
* The server created is a simple http server by default; part of the
|
||||
* websocket standard is upgrading this http connection to a websocket one.
|
||||
*
|
||||
* This allows the same server to provide files like scripts and favicon /
|
||||
* images or whatever over http and dynamic data over websockets all in
|
||||
* one place; they're all handled in the user callback.
|
||||
*/
|
||||
|
||||
LWS_VISIBLE struct libwebsocket_context *
|
||||
libwebsocket_create_context(struct lws_context_creation_info *info)
|
||||
{
|
||||
struct libwebsocket_context *context = NULL;
|
||||
char *p;
|
||||
|
||||
int pid_daemon = get_daemonize_pid();
|
||||
|
||||
lwsl_notice("Initial logging level %d\n", log_level);
|
||||
lwsl_notice("Library version: %s\n", library_version);
|
||||
#ifdef LWS_USE_IPV6
|
||||
if (!(info->options & LWS_SERVER_OPTION_DISABLE_IPV6))
|
||||
lwsl_notice("IPV6 compiled in and enabled\n");
|
||||
else
|
||||
lwsl_notice("IPV6 compiled in but disabled\n");
|
||||
#else
|
||||
lwsl_notice("IPV6 not compiled in\n");
|
||||
#endif
|
||||
lws_feature_status_libev(info);
|
||||
lwsl_info(" LWS_MAX_HEADER_LEN: %u\n", LWS_MAX_HEADER_LEN);
|
||||
lwsl_info(" LWS_MAX_PROTOCOLS: %u\n", LWS_MAX_PROTOCOLS);
|
||||
|
||||
lwsl_info(" SPEC_LATEST_SUPPORTED: %u\n", SPEC_LATEST_SUPPORTED);
|
||||
lwsl_info(" AWAITING_TIMEOUT: %u\n", AWAITING_TIMEOUT);
|
||||
lwsl_info(" SYSTEM_RANDOM_FILEPATH: '%s'\n", SYSTEM_RANDOM_FILEPATH);
|
||||
lwsl_info(" LWS_MAX_ZLIB_CONN_BUFFER: %u\n", LWS_MAX_ZLIB_CONN_BUFFER);
|
||||
|
||||
if (lws_plat_context_early_init())
|
||||
return NULL;
|
||||
|
||||
context = (struct libwebsocket_context *)
|
||||
malloc(sizeof(struct libwebsocket_context));
|
||||
if (!context) {
|
||||
lwsl_err("No memory for websocket context\n");
|
||||
return NULL;
|
||||
}
|
||||
memset(context, 0, sizeof(*context));
|
||||
|
||||
if (pid_daemon) {
|
||||
context->started_with_parent = pid_daemon;
|
||||
lwsl_notice(" Started with daemon pid %d\n", pid_daemon);
|
||||
}
|
||||
|
||||
context->listen_service_extraseen = 0;
|
||||
context->protocols = info->protocols;
|
||||
context->token_limits = info->token_limits;
|
||||
context->listen_port = info->port;
|
||||
context->http_proxy_port = 0;
|
||||
context->http_proxy_address[0] = '\0';
|
||||
context->options = info->options;
|
||||
context->iface = info->iface;
|
||||
/* to reduce this allocation, */
|
||||
context->max_fds = getdtablesize();
|
||||
lwsl_notice(" static allocation: %u + (%u x %u fds) = %u bytes\n",
|
||||
sizeof(struct libwebsocket_context),
|
||||
sizeof(struct libwebsocket_pollfd) +
|
||||
sizeof(struct libwebsocket *),
|
||||
context->max_fds,
|
||||
sizeof(struct libwebsocket_context) +
|
||||
((sizeof(struct libwebsocket_pollfd) +
|
||||
sizeof(struct libwebsocket *)) *
|
||||
context->max_fds));
|
||||
|
||||
context->fds = (struct libwebsocket_pollfd *)
|
||||
malloc(sizeof(struct libwebsocket_pollfd) *
|
||||
context->max_fds);
|
||||
if (context->fds == NULL) {
|
||||
lwsl_err("Unable to allocate fds array for %d connections\n",
|
||||
context->max_fds);
|
||||
free(context);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
context->lws_lookup = (struct libwebsocket **)
|
||||
malloc(sizeof(struct libwebsocket *) * context->max_fds);
|
||||
if (context->lws_lookup == NULL) {
|
||||
lwsl_err(
|
||||
"Unable to allocate lws_lookup array for %d connections\n",
|
||||
context->max_fds);
|
||||
free(context->fds);
|
||||
free(context);
|
||||
return NULL;
|
||||
}
|
||||
memset(context->lws_lookup, 0, sizeof(struct libwebsocket *) *
|
||||
context->max_fds);
|
||||
|
||||
if (lws_plat_init_fd_tables(context)) {
|
||||
free(context->lws_lookup);
|
||||
free(context->fds);
|
||||
free(context);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
lws_context_init_extensions(info, context);
|
||||
|
||||
context->user_space = info->user;
|
||||
|
||||
strcpy(context->canonical_hostname, "unknown");
|
||||
|
||||
lws_server_get_canonical_hostname(context, info);
|
||||
|
||||
/* split the proxy ads:port if given */
|
||||
|
||||
if (info->http_proxy_address) {
|
||||
strncpy(context->http_proxy_address, info->http_proxy_address,
|
||||
sizeof(context->http_proxy_address) - 1);
|
||||
context->http_proxy_address[
|
||||
sizeof(context->http_proxy_address) - 1] = '\0';
|
||||
context->http_proxy_port = info->http_proxy_port;
|
||||
} else {
|
||||
#ifdef HAVE_GETENV
|
||||
p = getenv("http_proxy");
|
||||
if (p) {
|
||||
strncpy(context->http_proxy_address, p,
|
||||
sizeof(context->http_proxy_address) - 1);
|
||||
context->http_proxy_address[
|
||||
sizeof(context->http_proxy_address) - 1] = '\0';
|
||||
|
||||
p = strchr(context->http_proxy_address, ':');
|
||||
if (p == NULL) {
|
||||
lwsl_err("http_proxy needs to be ads:port\n");
|
||||
goto bail;
|
||||
}
|
||||
*p = '\0';
|
||||
context->http_proxy_port = atoi(p + 1);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
if (context->http_proxy_address[0])
|
||||
lwsl_notice(" Proxy %s:%u\n",
|
||||
context->http_proxy_address,
|
||||
context->http_proxy_port);
|
||||
|
||||
lwsl_notice(
|
||||
" per-conn mem: %u + %u headers + protocol rx buf\n",
|
||||
sizeof(struct libwebsocket),
|
||||
sizeof(struct allocated_headers));
|
||||
|
||||
if (lws_context_init_server_ssl(info, context))
|
||||
goto bail;
|
||||
|
||||
if (lws_context_init_client_ssl(info, context))
|
||||
goto bail;
|
||||
|
||||
if (lws_context_init_server(info, context))
|
||||
goto bail;
|
||||
|
||||
/*
|
||||
* drop any root privs for this process
|
||||
* to listen on port < 1023 we would have needed root, but now we are
|
||||
* listening, we don't want the power for anything else
|
||||
*/
|
||||
lws_plat_drop_app_privileges(info);
|
||||
|
||||
/* initialize supported protocols */
|
||||
|
||||
for (context->count_protocols = 0;
|
||||
info->protocols[context->count_protocols].callback;
|
||||
context->count_protocols++) {
|
||||
|
||||
lwsl_parser(" Protocol: %s\n",
|
||||
info->protocols[context->count_protocols].name);
|
||||
|
||||
info->protocols[context->count_protocols].owning_server =
|
||||
context;
|
||||
info->protocols[context->count_protocols].protocol_index =
|
||||
context->count_protocols;
|
||||
|
||||
/*
|
||||
* inform all the protocols that they are doing their one-time
|
||||
* initialization if they want to
|
||||
*/
|
||||
info->protocols[context->count_protocols].callback(context,
|
||||
NULL, LWS_CALLBACK_PROTOCOL_INIT, NULL, NULL, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* give all extensions a chance to create any per-context
|
||||
* allocations they need
|
||||
*/
|
||||
|
||||
if (info->port != CONTEXT_PORT_NO_LISTEN) {
|
||||
if (lws_ext_callback_for_each_extension_type(context, NULL,
|
||||
LWS_EXT_CALLBACK_SERVER_CONTEXT_CONSTRUCT,
|
||||
NULL, 0) < 0)
|
||||
goto bail;
|
||||
} else
|
||||
if (lws_ext_callback_for_each_extension_type(context, NULL,
|
||||
LWS_EXT_CALLBACK_CLIENT_CONTEXT_CONSTRUCT,
|
||||
NULL, 0) < 0)
|
||||
goto bail;
|
||||
|
||||
return context;
|
||||
|
||||
bail:
|
||||
libwebsocket_context_destroy(context);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* libwebsocket_context_destroy() - Destroy the websocket context
|
||||
* @context: Websocket context
|
||||
*
|
||||
* This function closes any active connections and then frees the
|
||||
* context. After calling this, any further use of the context is
|
||||
* undefined.
|
||||
*/
|
||||
LWS_VISIBLE void
|
||||
libwebsocket_context_destroy(struct libwebsocket_context *context)
|
||||
{
|
||||
int n;
|
||||
struct libwebsocket_protocols *protocol = context->protocols;
|
||||
|
||||
lwsl_notice("%s\n", __func__);
|
||||
|
||||
#ifdef LWS_LATENCY
|
||||
if (context->worst_latency_info[0])
|
||||
lwsl_notice("Worst latency: %s\n", context->worst_latency_info);
|
||||
#endif
|
||||
|
||||
for (n = 0; n < context->fds_count; n++) {
|
||||
struct libwebsocket *wsi =
|
||||
context->lws_lookup[context->fds[n].fd];
|
||||
if (!wsi)
|
||||
continue;
|
||||
libwebsocket_close_and_free_session(context,
|
||||
wsi, LWS_CLOSE_STATUS_NOSTATUS /* no protocol close */);
|
||||
n--;
|
||||
}
|
||||
|
||||
/*
|
||||
* give all extensions a chance to clean up any per-context
|
||||
* allocations they might have made
|
||||
*/
|
||||
if (context->listen_port) {
|
||||
if (lws_ext_callback_for_each_extension_type(context, NULL,
|
||||
LWS_EXT_CALLBACK_SERVER_CONTEXT_DESTRUCT, NULL, 0) < 0)
|
||||
return;
|
||||
} else
|
||||
if (lws_ext_callback_for_each_extension_type(context, NULL,
|
||||
LWS_EXT_CALLBACK_CLIENT_CONTEXT_DESTRUCT, NULL, 0) < 0)
|
||||
return;
|
||||
|
||||
/*
|
||||
* inform all the protocols that they are done and will have no more
|
||||
* callbacks
|
||||
*/
|
||||
|
||||
while (protocol->callback) {
|
||||
protocol->callback(context, NULL, LWS_CALLBACK_PROTOCOL_DESTROY,
|
||||
NULL, NULL, 0);
|
||||
protocol++;
|
||||
}
|
||||
|
||||
lws_plat_context_early_destroy(context);
|
||||
|
||||
lws_ssl_context_destroy(context);
|
||||
|
||||
if (context->fds)
|
||||
free(context->fds);
|
||||
if (context->lws_lookup)
|
||||
free(context->lws_lookup);
|
||||
|
||||
lws_plat_context_late_destroy(context);
|
||||
|
||||
free(context);
|
||||
}
|
||||
222
dependencies/libwebsockets/lib/daemonize.c
vendored
Normal file
222
dependencies/libwebsockets/lib/daemonize.c
vendored
Normal file
@ -0,0 +1,222 @@
|
||||
/*
|
||||
* This code is mainly taken from Doug Potter's page
|
||||
*
|
||||
* http://www-theorie.physik.unizh.ch/~dpotter/howto/daemonize
|
||||
*
|
||||
* I contacted him 2007-04-16 about the license for the original code,
|
||||
* he replied it is Public Domain. Use the URL above to get the original
|
||||
* Public Domain version if you want it.
|
||||
*
|
||||
* This version is LGPL2 and is (c)2006 - 2013 Andy Green <andy@warmcat.com>
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <signal.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <limits.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "private-libwebsockets.h"
|
||||
|
||||
int pid_daemon;
|
||||
static char *lock_path;
|
||||
|
||||
int get_daemonize_pid()
|
||||
{
|
||||
return pid_daemon;
|
||||
}
|
||||
|
||||
static void
|
||||
child_handler(int signum)
|
||||
{
|
||||
int fd;
|
||||
int len;
|
||||
int sent;
|
||||
char sz[20];
|
||||
|
||||
switch (signum) {
|
||||
|
||||
case SIGALRM: /* timedout daemonizing */
|
||||
exit(1);
|
||||
break;
|
||||
|
||||
case SIGUSR1: /* positive confirmation we daemonized well */
|
||||
/* Create the lock file as the current user */
|
||||
|
||||
fd = open(lock_path, O_TRUNC | O_RDWR | O_CREAT, 0640);
|
||||
if (fd < 0) {
|
||||
fprintf(stderr,
|
||||
"unable to create lock file %s, code=%d (%s)\n",
|
||||
lock_path, errno, strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
len = sprintf(sz, "%u", pid_daemon);
|
||||
sent = write(fd, sz, len);
|
||||
if (sent != len)
|
||||
fprintf(stderr,
|
||||
"unable write pid to lock file %s, code=%d (%s)\n",
|
||||
lock_path, errno, strerror(errno));
|
||||
|
||||
close(fd);
|
||||
exit(!!(sent == len));
|
||||
|
||||
case SIGCHLD: /* daemonization failed */
|
||||
exit(1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void lws_daemon_closing(int sigact)
|
||||
{
|
||||
if (getpid() == pid_daemon)
|
||||
if (lock_path) {
|
||||
unlink(lock_path);
|
||||
free(lock_path);
|
||||
lock_path = NULL;
|
||||
}
|
||||
|
||||
kill(getpid(), SIGKILL);
|
||||
}
|
||||
|
||||
/*
|
||||
* You just need to call this from your main(), when it
|
||||
* returns you are all set "in the background" decoupled
|
||||
* from the console you were started from.
|
||||
*
|
||||
* The process context you called from has been terminated then.
|
||||
*/
|
||||
|
||||
LWS_VISIBLE int
|
||||
lws_daemonize(const char *_lock_path)
|
||||
{
|
||||
pid_t sid, parent;
|
||||
int fd;
|
||||
char buf[10];
|
||||
int n, ret;
|
||||
struct sigaction act;
|
||||
|
||||
/* already a daemon */
|
||||
if (getppid() == 1)
|
||||
return 1;
|
||||
|
||||
fd = open(_lock_path, O_RDONLY);
|
||||
if (fd > 0) {
|
||||
n = read(fd, buf, sizeof(buf));
|
||||
close(fd);
|
||||
if (n) {
|
||||
n = atoi(buf);
|
||||
ret = kill(n, 0);
|
||||
if (ret >= 0) {
|
||||
fprintf(stderr,
|
||||
"Daemon already running from pid %d\n", n);
|
||||
exit(1);
|
||||
}
|
||||
fprintf(stderr,
|
||||
"Removing stale lock file %s from dead pid %d\n",
|
||||
_lock_path, n);
|
||||
unlink(lock_path);
|
||||
}
|
||||
}
|
||||
|
||||
n = strlen(_lock_path) + 1;
|
||||
lock_path = malloc(n);
|
||||
if (!lock_path) {
|
||||
fprintf(stderr, "Out of mem in lws_daemonize\n");
|
||||
return 1;
|
||||
}
|
||||
strcpy(lock_path, _lock_path);
|
||||
|
||||
/* Trap signals that we expect to recieve */
|
||||
signal(SIGCHLD, child_handler); /* died */
|
||||
signal(SIGUSR1, child_handler); /* was happy */
|
||||
signal(SIGALRM, child_handler); /* timeout daemonizing */
|
||||
|
||||
/* Fork off the parent process */
|
||||
pid_daemon = fork();
|
||||
if (pid_daemon < 0) {
|
||||
fprintf(stderr, "unable to fork daemon, code=%d (%s)",
|
||||
errno, strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* If we got a good PID, then we can exit the parent process. */
|
||||
if (pid_daemon > 0) {
|
||||
|
||||
/*
|
||||
* Wait for confirmation signal from the child via
|
||||
* SIGCHILD / USR1, or for two seconds to elapse
|
||||
* (SIGALRM). pause() should not return.
|
||||
*/
|
||||
alarm(2);
|
||||
|
||||
pause();
|
||||
/* should not be reachable */
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* At this point we are executing as the child process */
|
||||
parent = getppid();
|
||||
pid_daemon = getpid();
|
||||
|
||||
/* Cancel certain signals */
|
||||
signal(SIGCHLD, SIG_DFL); /* A child process dies */
|
||||
signal(SIGTSTP, SIG_IGN); /* Various TTY signals */
|
||||
signal(SIGTTOU, SIG_IGN);
|
||||
signal(SIGTTIN, SIG_IGN);
|
||||
signal(SIGHUP, SIG_IGN); /* Ignore hangup signal */
|
||||
|
||||
/* Change the file mode mask */
|
||||
umask(0);
|
||||
|
||||
/* Create a new SID for the child process */
|
||||
sid = setsid();
|
||||
if (sid < 0) {
|
||||
fprintf(stderr,
|
||||
"unable to create a new session, code %d (%s)",
|
||||
errno, strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Change the current working directory. This prevents the current
|
||||
* directory from being locked; hence not being able to remove it.
|
||||
*/
|
||||
if (chdir("/") < 0) {
|
||||
fprintf(stderr,
|
||||
"unable to change directory to %s, code %d (%s)",
|
||||
"/", errno, strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* Redirect standard files to /dev/null */
|
||||
if (!freopen("/dev/null", "r", stdin))
|
||||
fprintf(stderr, "unable to freopen() stdin, code %d (%s)",
|
||||
errno, strerror(errno));
|
||||
|
||||
if (!freopen("/dev/null", "w", stdout))
|
||||
fprintf(stderr, "unable to freopen() stdout, code %d (%s)",
|
||||
errno, strerror(errno));
|
||||
|
||||
if (!freopen("/dev/null", "w", stderr))
|
||||
fprintf(stderr, "unable to freopen() stderr, code %d (%s)",
|
||||
errno, strerror(errno));
|
||||
|
||||
/* Tell the parent process that we are A-okay */
|
||||
kill(parent, SIGUSR1);
|
||||
|
||||
act.sa_handler = lws_daemon_closing;
|
||||
sigemptyset(&act.sa_mask);
|
||||
act.sa_flags = 0;
|
||||
|
||||
sigaction(SIGTERM, &act, NULL);
|
||||
|
||||
/* return to continue what is now "the daemon" */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
294
dependencies/libwebsockets/lib/extension-deflate-frame.c
vendored
Normal file
294
dependencies/libwebsockets/lib/extension-deflate-frame.c
vendored
Normal file
@ -0,0 +1,294 @@
|
||||
#include "private-libwebsockets.h"
|
||||
#include "extension-deflate-frame.h"
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
#define LWS_ZLIB_WINDOW_BITS 15
|
||||
#define LWS_ZLIB_MEMLEVEL 8
|
||||
|
||||
int lws_extension_callback_deflate_frame(
|
||||
struct libwebsocket_context *context,
|
||||
struct libwebsocket_extension *ext,
|
||||
struct libwebsocket *wsi,
|
||||
enum libwebsocket_extension_callback_reasons reason,
|
||||
void *user, void *in, size_t len)
|
||||
{
|
||||
struct lws_ext_deflate_frame_conn *conn =
|
||||
(struct lws_ext_deflate_frame_conn *)user;
|
||||
struct lws_tokens *eff_buf = (struct lws_tokens *)in;
|
||||
size_t current_payload, remaining_payload, total_payload;
|
||||
int n;
|
||||
size_t len_so_far;
|
||||
|
||||
switch (reason) {
|
||||
|
||||
/*
|
||||
* for deflate-frame, both client and server sides act the same
|
||||
*/
|
||||
|
||||
case LWS_EXT_CALLBACK_CLIENT_CONSTRUCT:
|
||||
case LWS_EXT_CALLBACK_CONSTRUCT:
|
||||
conn->zs_in.zalloc = conn->zs_out.zalloc = Z_NULL;
|
||||
conn->zs_in.zfree = conn->zs_out.zfree = Z_NULL;
|
||||
conn->zs_in.opaque = conn->zs_out.opaque = Z_NULL;
|
||||
n = inflateInit2(&conn->zs_in, -LWS_ZLIB_WINDOW_BITS);
|
||||
if (n != Z_OK) {
|
||||
lwsl_ext("deflateInit returned %d\n", n);
|
||||
return 1;
|
||||
}
|
||||
n = deflateInit2(&conn->zs_out,
|
||||
(context->listen_port ?
|
||||
DEFLATE_FRAME_COMPRESSION_LEVEL_SERVER :
|
||||
DEFLATE_FRAME_COMPRESSION_LEVEL_CLIENT),
|
||||
Z_DEFLATED,
|
||||
-LWS_ZLIB_WINDOW_BITS, LWS_ZLIB_MEMLEVEL,
|
||||
Z_DEFAULT_STRATEGY);
|
||||
if (n != Z_OK) {
|
||||
lwsl_ext("deflateInit2 returned %d\n", n);
|
||||
return 1;
|
||||
}
|
||||
conn->buf_pre_used = 0;
|
||||
conn->buf_pre_length = 0;
|
||||
conn->buf_in_length = sizeof(conn->buf_in);
|
||||
conn->buf_out_length = sizeof(conn->buf_out);
|
||||
conn->compressed_out = 0;
|
||||
conn->buf_pre = NULL;
|
||||
conn->buf_in = (unsigned char *)
|
||||
malloc(LWS_SEND_BUFFER_PRE_PADDING +
|
||||
conn->buf_in_length +
|
||||
LWS_SEND_BUFFER_POST_PADDING);
|
||||
if (!conn->buf_in)
|
||||
goto bail;
|
||||
conn->buf_out = (unsigned char *)
|
||||
malloc(LWS_SEND_BUFFER_PRE_PADDING +
|
||||
conn->buf_out_length +
|
||||
LWS_SEND_BUFFER_POST_PADDING);
|
||||
if (!conn->buf_out)
|
||||
goto bail;
|
||||
lwsl_ext("zlibs constructed\n");
|
||||
break;
|
||||
bail:
|
||||
lwsl_err("Out of mem\n");
|
||||
(void)inflateEnd(&conn->zs_in);
|
||||
(void)deflateEnd(&conn->zs_out);
|
||||
return -1;
|
||||
|
||||
case LWS_EXT_CALLBACK_DESTROY:
|
||||
if (conn->buf_pre)
|
||||
free(conn->buf_pre);
|
||||
free(conn->buf_in);
|
||||
free(conn->buf_out);
|
||||
conn->buf_pre_used = 0;
|
||||
conn->buf_pre_length = 0;
|
||||
conn->buf_in_length = 0;
|
||||
conn->buf_out_length = 0;
|
||||
conn->compressed_out = 0;
|
||||
(void)inflateEnd(&conn->zs_in);
|
||||
(void)deflateEnd(&conn->zs_out);
|
||||
lwsl_ext("zlibs destructed\n");
|
||||
break;
|
||||
|
||||
case LWS_EXT_CALLBACK_PAYLOAD_RX:
|
||||
if (!(wsi->u.ws.rsv & 0x40))
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* inflate the incoming payload
|
||||
*/
|
||||
current_payload = eff_buf->token_len;
|
||||
|
||||
remaining_payload = wsi->u.ws.rx_packet_length;
|
||||
if (remaining_payload) {
|
||||
total_payload = conn->buf_pre_used +
|
||||
current_payload +
|
||||
remaining_payload;
|
||||
|
||||
if (conn->buf_pre_length < total_payload) {
|
||||
conn->buf_pre_length = total_payload;
|
||||
if (conn->buf_pre)
|
||||
free(conn->buf_pre);
|
||||
conn->buf_pre =
|
||||
(unsigned char *)malloc(total_payload + 4);
|
||||
if (!conn->buf_pre) {
|
||||
lwsl_err("Out of memory\n");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
memcpy(conn->buf_pre + conn->buf_pre_used,
|
||||
eff_buf->token, current_payload);
|
||||
conn->buf_pre_used += current_payload;
|
||||
|
||||
eff_buf->token = NULL;
|
||||
eff_buf->token_len = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
if (conn->buf_pre_used) {
|
||||
total_payload = conn->buf_pre_used +
|
||||
current_payload;
|
||||
|
||||
memcpy(conn->buf_pre + conn->buf_pre_used,
|
||||
eff_buf->token, current_payload);
|
||||
conn->buf_pre_used = 0;
|
||||
|
||||
conn->zs_in.next_in = conn->buf_pre;
|
||||
} else {
|
||||
total_payload = current_payload;
|
||||
|
||||
conn->zs_in.next_in = (unsigned char *)eff_buf->token;
|
||||
}
|
||||
|
||||
conn->zs_in.next_in[total_payload + 0] = 0;
|
||||
conn->zs_in.next_in[total_payload + 1] = 0;
|
||||
conn->zs_in.next_in[total_payload + 2] = 0xff;
|
||||
conn->zs_in.next_in[total_payload + 3] = 0xff;
|
||||
|
||||
conn->zs_in.avail_in = total_payload + 4;
|
||||
|
||||
conn->zs_in.next_out =
|
||||
conn->buf_in + LWS_SEND_BUFFER_PRE_PADDING;
|
||||
conn->zs_in.avail_out = conn->buf_in_length;
|
||||
|
||||
while (1) {
|
||||
n = inflate(&conn->zs_in, Z_SYNC_FLUSH);
|
||||
switch (n) {
|
||||
case Z_NEED_DICT:
|
||||
case Z_STREAM_ERROR:
|
||||
case Z_DATA_ERROR:
|
||||
case Z_MEM_ERROR:
|
||||
/*
|
||||
* screwed.. close the connection...
|
||||
* we will get a destroy callback to take care
|
||||
* of closing nicely
|
||||
*/
|
||||
lwsl_info("zlib error inflate %d: %s\n",
|
||||
n, conn->zs_in.msg);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (conn->zs_in.avail_out)
|
||||
break;
|
||||
|
||||
len_so_far = conn->zs_in.next_out -
|
||||
(conn->buf_in + LWS_SEND_BUFFER_PRE_PADDING);
|
||||
|
||||
conn->buf_in_length *= 2;
|
||||
if (conn->buf_in_length > LWS_MAX_ZLIB_CONN_BUFFER) {
|
||||
lwsl_ext("zlib in buffer hit limit %u\n",
|
||||
LWS_MAX_ZLIB_CONN_BUFFER);
|
||||
return -1;
|
||||
}
|
||||
conn->buf_in = (unsigned char *)realloc(conn->buf_in,
|
||||
LWS_SEND_BUFFER_PRE_PADDING +
|
||||
conn->buf_in_length +
|
||||
LWS_SEND_BUFFER_POST_PADDING);
|
||||
if (!conn->buf_in) {
|
||||
lwsl_err("Out of memory\n");
|
||||
return -1;
|
||||
}
|
||||
lwsl_debug(
|
||||
"deflate-frame ext RX did realloc to %ld\n",
|
||||
conn->buf_in_length);
|
||||
conn->zs_in.next_out = conn->buf_in +
|
||||
LWS_SEND_BUFFER_PRE_PADDING + len_so_far;
|
||||
conn->zs_in.avail_out =
|
||||
conn->buf_in_length - len_so_far;
|
||||
}
|
||||
|
||||
/* rewrite the buffer pointers and length */
|
||||
eff_buf->token =
|
||||
(char *)(conn->buf_in + LWS_SEND_BUFFER_PRE_PADDING);
|
||||
eff_buf->token_len = (int)(conn->zs_in.next_out -
|
||||
(conn->buf_in + LWS_SEND_BUFFER_PRE_PADDING));
|
||||
|
||||
return 0;
|
||||
|
||||
case LWS_EXT_CALLBACK_PAYLOAD_TX:
|
||||
/*
|
||||
* deflate the outgoing payload
|
||||
*/
|
||||
current_payload = eff_buf->token_len;
|
||||
|
||||
conn->zs_out.next_in = (unsigned char *)eff_buf->token;
|
||||
conn->zs_out.avail_in = current_payload;
|
||||
|
||||
conn->zs_out.next_out =
|
||||
conn->buf_out + LWS_SEND_BUFFER_PRE_PADDING;
|
||||
conn->zs_out.avail_out = conn->buf_out_length;
|
||||
|
||||
while (1) {
|
||||
n = deflate(&conn->zs_out, Z_SYNC_FLUSH);
|
||||
if (n == Z_STREAM_ERROR) {
|
||||
/*
|
||||
* screwed.. close the connection... we will
|
||||
* get a destroy callback to take care of
|
||||
* closing nicely
|
||||
*/
|
||||
lwsl_ext("zlib error deflate\n");
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (conn->zs_out.avail_out)
|
||||
break;
|
||||
|
||||
len_so_far = (conn->zs_out.next_out -
|
||||
(conn->buf_out +
|
||||
LWS_SEND_BUFFER_PRE_PADDING));
|
||||
conn->buf_out_length *= 2;
|
||||
if (conn->buf_out_length > LWS_MAX_ZLIB_CONN_BUFFER) {
|
||||
lwsl_ext("zlib out hit limit %u\n",
|
||||
LWS_MAX_ZLIB_CONN_BUFFER);
|
||||
return -1;
|
||||
}
|
||||
conn->buf_out = (unsigned char *)realloc(
|
||||
conn->buf_out,
|
||||
LWS_SEND_BUFFER_PRE_PADDING +
|
||||
conn->buf_out_length +
|
||||
LWS_SEND_BUFFER_POST_PADDING);
|
||||
if (!conn->buf_out) {
|
||||
lwsl_err("Out of memory\n");
|
||||
return -1;
|
||||
}
|
||||
lwsl_debug(
|
||||
"deflate-frame ext TX did realloc to %ld\n",
|
||||
conn->buf_in_length);
|
||||
|
||||
conn->zs_out.next_out = (conn->buf_out +
|
||||
LWS_SEND_BUFFER_PRE_PADDING + len_so_far);
|
||||
conn->zs_out.avail_out =
|
||||
(conn->buf_out_length - len_so_far);
|
||||
}
|
||||
|
||||
conn->compressed_out = 1;
|
||||
|
||||
/* rewrite the buffer pointers and length */
|
||||
eff_buf->token = (char *)(conn->buf_out +
|
||||
LWS_SEND_BUFFER_PRE_PADDING);
|
||||
eff_buf->token_len = (int)(conn->zs_out.next_out -
|
||||
(conn->buf_out + LWS_SEND_BUFFER_PRE_PADDING)) - 4;
|
||||
|
||||
return 0;
|
||||
|
||||
case LWS_EXT_CALLBACK_PACKET_TX_PRESEND:
|
||||
if (conn->compressed_out) {
|
||||
conn->compressed_out = 0;
|
||||
*((unsigned char *)eff_buf->token) |= 0x40;
|
||||
}
|
||||
break;
|
||||
|
||||
case LWS_EXT_CALLBACK_CHECK_OK_TO_PROPOSE_EXTENSION:
|
||||
/* Avoid x-webkit-deflate-frame extension on client */
|
||||
if (!strcmp((char *)in, "x-webkit-deflate-frame"))
|
||||
return 1;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
25
dependencies/libwebsockets/lib/extension-deflate-frame.h
vendored
Normal file
25
dependencies/libwebsockets/lib/extension-deflate-frame.h
vendored
Normal file
@ -0,0 +1,25 @@
|
||||
|
||||
#include <zlib.h>
|
||||
|
||||
#define DEFLATE_FRAME_COMPRESSION_LEVEL_SERVER 1
|
||||
#define DEFLATE_FRAME_COMPRESSION_LEVEL_CLIENT Z_DEFAULT_COMPRESSION
|
||||
|
||||
struct lws_ext_deflate_frame_conn {
|
||||
z_stream zs_in;
|
||||
z_stream zs_out;
|
||||
size_t buf_pre_used;
|
||||
size_t buf_pre_length;
|
||||
size_t buf_in_length;
|
||||
size_t buf_out_length;
|
||||
int compressed_out;
|
||||
unsigned char *buf_pre;
|
||||
unsigned char *buf_in;
|
||||
unsigned char *buf_out;
|
||||
};
|
||||
|
||||
extern int lws_extension_callback_deflate_frame(
|
||||
struct libwebsocket_context *context,
|
||||
struct libwebsocket_extension *ext,
|
||||
struct libwebsocket *wsi,
|
||||
enum libwebsocket_extension_callback_reasons reason,
|
||||
void *user, void *in, size_t len);
|
||||
166
dependencies/libwebsockets/lib/extension-deflate-stream.c
vendored
Normal file
166
dependencies/libwebsockets/lib/extension-deflate-stream.c
vendored
Normal file
@ -0,0 +1,166 @@
|
||||
#include "private-libwebsockets.h"
|
||||
#include "extension-deflate-stream.h"
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
#define LWS_ZLIB_WINDOW_BITS 15
|
||||
#define LWS_ZLIB_MEMLEVEL 8
|
||||
|
||||
int lws_extension_callback_deflate_stream(
|
||||
struct libwebsocket_context *context,
|
||||
struct libwebsocket_extension *ext,
|
||||
struct libwebsocket *wsi,
|
||||
enum libwebsocket_extension_callback_reasons reason,
|
||||
void *user, void *in, size_t len)
|
||||
{
|
||||
struct lws_ext_deflate_stream_conn *conn =
|
||||
(struct lws_ext_deflate_stream_conn *)user;
|
||||
int n;
|
||||
struct lws_tokens *eff_buf = (struct lws_tokens *)in;
|
||||
|
||||
switch (reason) {
|
||||
|
||||
/*
|
||||
* for deflate-stream, both client and server sides act the same
|
||||
*/
|
||||
|
||||
case LWS_EXT_CALLBACK_CLIENT_CONSTRUCT:
|
||||
case LWS_EXT_CALLBACK_CONSTRUCT:
|
||||
conn->zs_in.zalloc = conn->zs_out.zalloc = Z_NULL;
|
||||
conn->zs_in.zfree = conn->zs_out.zfree = Z_NULL;
|
||||
conn->zs_in.opaque = conn->zs_out.opaque = Z_NULL;
|
||||
n = inflateInit2(&conn->zs_in, -LWS_ZLIB_WINDOW_BITS);
|
||||
if (n != Z_OK) {
|
||||
lwsl_err("deflateInit returned %d\n", n);
|
||||
return 1;
|
||||
}
|
||||
n = deflateInit2(&conn->zs_out,
|
||||
DEFLATE_STREAM_COMPRESSION_LEVEL, Z_DEFLATED,
|
||||
-LWS_ZLIB_WINDOW_BITS, LWS_ZLIB_MEMLEVEL,
|
||||
Z_DEFAULT_STRATEGY);
|
||||
if (n != Z_OK) {
|
||||
lwsl_err("deflateInit returned %d\n", n);
|
||||
return 1;
|
||||
}
|
||||
lwsl_ext("zlibs constructed\n");
|
||||
conn->remaining_in = 0;
|
||||
break;
|
||||
|
||||
case LWS_EXT_CALLBACK_DESTROY:
|
||||
(void)inflateEnd(&conn->zs_in);
|
||||
(void)deflateEnd(&conn->zs_out);
|
||||
lwsl_ext("zlibs destructed\n");
|
||||
break;
|
||||
|
||||
case LWS_EXT_CALLBACK_PACKET_RX_PREPARSE:
|
||||
|
||||
/*
|
||||
* inflate the incoming compressed data
|
||||
* Notice, length may be 0 and pointer NULL
|
||||
* in the case we are flushing with nothing new coming in
|
||||
*/
|
||||
if (conn->remaining_in) {
|
||||
conn->zs_in.next_in = conn->buf_in;
|
||||
conn->zs_in.avail_in = conn->remaining_in;
|
||||
conn->remaining_in = 0;
|
||||
} else {
|
||||
conn->zs_in.next_in = (unsigned char *)eff_buf->token;
|
||||
conn->zs_in.avail_in = eff_buf->token_len;
|
||||
}
|
||||
|
||||
conn->zs_in.next_out = conn->buf_out;
|
||||
conn->zs_in.avail_out = sizeof(conn->buf_out);
|
||||
|
||||
n = inflate(&conn->zs_in, Z_SYNC_FLUSH);
|
||||
switch (n) {
|
||||
case Z_NEED_DICT:
|
||||
case Z_DATA_ERROR:
|
||||
case Z_MEM_ERROR:
|
||||
/*
|
||||
* screwed.. close the connection... we will get a
|
||||
* destroy callback to take care of closing nicely
|
||||
*/
|
||||
lwsl_err("zlib error inflate %d\n", n);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* rewrite the buffer pointers and length */
|
||||
|
||||
eff_buf->token = (char *)conn->buf_out;
|
||||
eff_buf->token_len =
|
||||
sizeof(conn->buf_out) - conn->zs_in.avail_out;
|
||||
|
||||
/* copy avail data if not consumed */
|
||||
if (conn->zs_in.avail_in > 0) {
|
||||
conn->remaining_in = conn->zs_in.avail_in;
|
||||
memcpy(conn->buf_in, conn->zs_in.next_in,
|
||||
conn->zs_in.avail_in);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* if we filled the output buffer, signal that we likely have
|
||||
* more and need to be called again
|
||||
*/
|
||||
|
||||
if (eff_buf->token_len == sizeof(conn->buf_out))
|
||||
return 1;
|
||||
|
||||
/* we don't need calling again until new input data comes */
|
||||
|
||||
return 0;
|
||||
|
||||
case LWS_EXT_CALLBACK_FLUSH_PENDING_TX:
|
||||
case LWS_EXT_CALLBACK_PACKET_TX_PRESEND:
|
||||
|
||||
/*
|
||||
* deflate the outgoing compressed data
|
||||
*/
|
||||
|
||||
conn->zs_out.next_in = (unsigned char *)eff_buf->token;
|
||||
conn->zs_out.avail_in = eff_buf->token_len;
|
||||
|
||||
conn->zs_out.next_out = conn->buf_out;
|
||||
conn->zs_out.avail_out = sizeof(conn->buf_out);
|
||||
|
||||
n = Z_PARTIAL_FLUSH;
|
||||
if (reason == LWS_EXT_CALLBACK_FLUSH_PENDING_TX)
|
||||
n = Z_FULL_FLUSH;
|
||||
|
||||
n = deflate(&conn->zs_out, n);
|
||||
if (n == Z_STREAM_ERROR) {
|
||||
/*
|
||||
* screwed.. close the connection... we will get a
|
||||
* destroy callback to take care of closing nicely
|
||||
*/
|
||||
lwsl_ext("zlib error deflate\n");
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* rewrite the buffer pointers and length */
|
||||
|
||||
eff_buf->token = (char *)conn->buf_out;
|
||||
eff_buf->token_len =
|
||||
sizeof(conn->buf_out) - conn->zs_out.avail_out;
|
||||
|
||||
/*
|
||||
* if we filled the output buffer, signal that we likely have
|
||||
* more and need to be called again... even in deflate case
|
||||
* we might sometimes need to spill more than came in
|
||||
*/
|
||||
|
||||
if (eff_buf->token_len == sizeof(conn->buf_out))
|
||||
return 1;
|
||||
|
||||
/* we don't need calling again until new input data comes */
|
||||
|
||||
return 0;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
20
dependencies/libwebsockets/lib/extension-deflate-stream.h
vendored
Normal file
20
dependencies/libwebsockets/lib/extension-deflate-stream.h
vendored
Normal file
@ -0,0 +1,20 @@
|
||||
|
||||
#include <zlib.h>
|
||||
|
||||
#define DEFLATE_STREAM_CHUNK 128
|
||||
#define DEFLATE_STREAM_COMPRESSION_LEVEL 1
|
||||
|
||||
struct lws_ext_deflate_stream_conn {
|
||||
z_stream zs_in;
|
||||
z_stream zs_out;
|
||||
int remaining_in;
|
||||
unsigned char buf_in[LWS_MAX_SOCKET_IO_BUF];
|
||||
unsigned char buf_out[LWS_MAX_SOCKET_IO_BUF];
|
||||
};
|
||||
|
||||
extern int lws_extension_callback_deflate_stream(
|
||||
struct libwebsocket_context *context,
|
||||
struct libwebsocket_extension *ext,
|
||||
struct libwebsocket *wsi,
|
||||
enum libwebsocket_extension_callback_reasons reason,
|
||||
void *user, void *in, size_t len);
|
||||
211
dependencies/libwebsockets/lib/extension.c
vendored
Normal file
211
dependencies/libwebsockets/lib/extension.c
vendored
Normal file
@ -0,0 +1,211 @@
|
||||
#include "private-libwebsockets.h"
|
||||
|
||||
#include "extension-deflate-frame.h"
|
||||
#include "extension-deflate-stream.h"
|
||||
|
||||
struct libwebsocket_extension libwebsocket_internal_extensions[] = {
|
||||
#ifdef LWS_EXT_DEFLATE_STREAM
|
||||
{
|
||||
"deflate-stream",
|
||||
lws_extension_callback_deflate_stream,
|
||||
sizeof(struct lws_ext_deflate_stream_conn)
|
||||
},
|
||||
#else
|
||||
{
|
||||
"x-webkit-deflate-frame",
|
||||
lws_extension_callback_deflate_frame,
|
||||
sizeof(struct lws_ext_deflate_frame_conn)
|
||||
},
|
||||
{
|
||||
"deflate-frame",
|
||||
lws_extension_callback_deflate_frame,
|
||||
sizeof(struct lws_ext_deflate_frame_conn)
|
||||
},
|
||||
#endif
|
||||
{ /* terminator */
|
||||
NULL, NULL, 0
|
||||
}
|
||||
};
|
||||
|
||||
LWS_VISIBLE void
|
||||
lws_context_init_extensions(struct lws_context_creation_info *info,
|
||||
struct libwebsocket_context *context)
|
||||
{
|
||||
context->extensions = info->extensions;
|
||||
lwsl_info(" LWS_MAX_EXTENSIONS_ACTIVE: %u\n", LWS_MAX_EXTENSIONS_ACTIVE);
|
||||
}
|
||||
|
||||
LWS_VISIBLE struct libwebsocket_extension *libwebsocket_get_internal_extensions()
|
||||
{
|
||||
return libwebsocket_internal_extensions;
|
||||
}
|
||||
|
||||
|
||||
/* 0 = nobody had nonzero return, 1 = somebody had positive return, -1 = fail */
|
||||
|
||||
int lws_ext_callback_for_each_active(struct libwebsocket *wsi, int reason,
|
||||
void *arg, int len)
|
||||
{
|
||||
int n, m, handled = 0;
|
||||
|
||||
for (n = 0; n < wsi->count_active_extensions; n++) {
|
||||
m = wsi->active_extensions[n]->callback(
|
||||
wsi->protocol->owning_server,
|
||||
wsi->active_extensions[n], wsi,
|
||||
reason,
|
||||
wsi->active_extensions_user[n],
|
||||
arg, len);
|
||||
if (m < 0) {
|
||||
lwsl_ext(
|
||||
"Extension '%s' failed to handle callback %d!\n",
|
||||
wsi->active_extensions[n]->name, reason);
|
||||
return -1;
|
||||
}
|
||||
if (m > handled)
|
||||
handled = m;
|
||||
}
|
||||
|
||||
return handled;
|
||||
}
|
||||
|
||||
int lws_ext_callback_for_each_extension_type(
|
||||
struct libwebsocket_context *context, struct libwebsocket *wsi,
|
||||
int reason, void *arg, int len)
|
||||
{
|
||||
int n = 0, m, handled = 0;
|
||||
struct libwebsocket_extension *ext = context->extensions;
|
||||
|
||||
while (ext && ext->callback && !handled) {
|
||||
m = ext->callback(context, ext, wsi, reason,
|
||||
(void *)(long)n, arg, len);
|
||||
if (m < 0) {
|
||||
lwsl_ext(
|
||||
"Extension '%s' failed to handle callback %d!\n",
|
||||
wsi->active_extensions[n]->name, reason);
|
||||
return -1;
|
||||
}
|
||||
if (m)
|
||||
handled = 1;
|
||||
|
||||
ext++;
|
||||
n++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
lws_issue_raw_ext_access(struct libwebsocket *wsi,
|
||||
unsigned char *buf, size_t len)
|
||||
{
|
||||
int ret;
|
||||
struct lws_tokens eff_buf;
|
||||
int m;
|
||||
int n = 0;
|
||||
|
||||
eff_buf.token = (char *)buf;
|
||||
eff_buf.token_len = len;
|
||||
|
||||
/*
|
||||
* while we have original buf to spill ourselves, or extensions report
|
||||
* more in their pipeline
|
||||
*/
|
||||
|
||||
ret = 1;
|
||||
while (ret == 1) {
|
||||
|
||||
/* default to nobody has more to spill */
|
||||
|
||||
ret = 0;
|
||||
|
||||
/* show every extension the new incoming data */
|
||||
m = lws_ext_callback_for_each_active(wsi,
|
||||
LWS_EXT_CALLBACK_PACKET_TX_PRESEND, &eff_buf, 0);
|
||||
if (m < 0)
|
||||
return -1;
|
||||
if (m) /* handled */
|
||||
ret = 1;
|
||||
|
||||
if ((char *)buf != eff_buf.token)
|
||||
/*
|
||||
* extension recreated it:
|
||||
* need to buffer this if not all sent
|
||||
*/
|
||||
wsi->u.ws.clean_buffer = 0;
|
||||
|
||||
/* assuming they left us something to send, send it */
|
||||
|
||||
if (eff_buf.token_len) {
|
||||
n = lws_issue_raw(wsi, (unsigned char *)eff_buf.token,
|
||||
eff_buf.token_len);
|
||||
if (n < 0) {
|
||||
lwsl_info("closing from ext access\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* always either sent it all or privately buffered */
|
||||
if (wsi->u.ws.clean_buffer) {
|
||||
eff_buf.token_len = n;
|
||||
len = n;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
lwsl_parser("written %d bytes to client\n", n);
|
||||
|
||||
/* no extension has more to spill? Then we can go */
|
||||
|
||||
if (!ret)
|
||||
break;
|
||||
|
||||
/* we used up what we had */
|
||||
|
||||
eff_buf.token = NULL;
|
||||
eff_buf.token_len = 0;
|
||||
|
||||
/*
|
||||
* Did that leave the pipe choked?
|
||||
* Or we had to hold on to some of it?
|
||||
*/
|
||||
|
||||
if (!lws_send_pipe_choked(wsi) && !wsi->truncated_send_len)
|
||||
/* no we could add more, lets's do that */
|
||||
continue;
|
||||
|
||||
lwsl_debug("choked\n");
|
||||
|
||||
/*
|
||||
* Yes, he's choked. Don't spill the rest now get a callback
|
||||
* when he is ready to send and take care of it there
|
||||
*/
|
||||
libwebsocket_callback_on_writable(
|
||||
wsi->protocol->owning_server, wsi);
|
||||
wsi->extension_data_pending = 1;
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
int
|
||||
lws_any_extension_handled(struct libwebsocket_context *context,
|
||||
struct libwebsocket *wsi,
|
||||
enum libwebsocket_extension_callback_reasons r,
|
||||
void *v, size_t len)
|
||||
{
|
||||
int n;
|
||||
int handled = 0;
|
||||
|
||||
/* maybe an extension will take care of it for us */
|
||||
|
||||
for (n = 0; n < wsi->count_active_extensions && !handled; n++) {
|
||||
if (!wsi->active_extensions[n]->callback)
|
||||
continue;
|
||||
|
||||
handled |= wsi->active_extensions[n]->callback(context,
|
||||
wsi->active_extensions[n], wsi,
|
||||
r, wsi->active_extensions_user[n], v, len);
|
||||
}
|
||||
|
||||
return handled;
|
||||
}
|
||||
276
dependencies/libwebsockets/lib/getifaddrs.c
vendored
Normal file
276
dependencies/libwebsockets/lib/getifaddrs.c
vendored
Normal file
@ -0,0 +1,276 @@
|
||||
/*
|
||||
* downloaded from
|
||||
* http://ftp.uninett.no/pub/OpenBSD/src/kerberosV/src/lib/roken/getifaddrs.c
|
||||
*/
|
||||
#if !HAVE_GETIFADDRS
|
||||
/*
|
||||
* Copyright (c) 2000 - 2001 Kungliga Tekniska H<EFBFBD>gskolan
|
||||
* (Royal Institute of Technology, Stockholm, Sweden).
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* 3. Neither the name of the Institute nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <net/if.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#ifdef HAVE_SYS_SOCKIO_H
|
||||
#include <sys/sockio.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_NETINET_IN6_VAR_H
|
||||
#include <netinet/in6_var.h>
|
||||
#endif
|
||||
|
||||
#ifndef max
|
||||
#define max(a, b) ((a) > (b) ? (a) : (b))
|
||||
#endif
|
||||
|
||||
#include "getifaddrs.h"
|
||||
|
||||
static int
|
||||
getifaddrs2(struct ifaddrs **ifap,
|
||||
int af, int siocgifconf, int siocgifflags,
|
||||
size_t ifreq_sz)
|
||||
{
|
||||
int ret;
|
||||
int fd;
|
||||
size_t buf_size;
|
||||
char *buf;
|
||||
struct ifconf ifconf;
|
||||
char *p;
|
||||
size_t sz;
|
||||
struct sockaddr sa_zero;
|
||||
struct ifreq *ifr;
|
||||
|
||||
struct ifaddrs *start, **end = &start;
|
||||
|
||||
buf = NULL;
|
||||
|
||||
memset(&sa_zero, 0, sizeof(sa_zero));
|
||||
fd = socket(af, SOCK_DGRAM, 0);
|
||||
if (fd < 0)
|
||||
return -1;
|
||||
|
||||
buf_size = 8192;
|
||||
for (;;) {
|
||||
buf = calloc(1, buf_size);
|
||||
if (buf == NULL) {
|
||||
ret = ENOMEM;
|
||||
goto error_out;
|
||||
}
|
||||
ifconf.ifc_len = buf_size;
|
||||
ifconf.ifc_buf = buf;
|
||||
|
||||
/*
|
||||
* Solaris returns EINVAL when the buffer is too small.
|
||||
*/
|
||||
if (ioctl(fd, siocgifconf, &ifconf) < 0 && errno != EINVAL) {
|
||||
ret = errno;
|
||||
goto error_out;
|
||||
}
|
||||
/*
|
||||
* Can the difference between a full and a overfull buf
|
||||
* be determined?
|
||||
*/
|
||||
|
||||
if (ifconf.ifc_len < (int)buf_size)
|
||||
break;
|
||||
free(buf);
|
||||
buf_size *= 2;
|
||||
}
|
||||
|
||||
for (p = ifconf.ifc_buf; p < ifconf.ifc_buf + ifconf.ifc_len; p += sz) {
|
||||
struct ifreq ifreq;
|
||||
struct sockaddr *sa;
|
||||
size_t salen;
|
||||
|
||||
ifr = (struct ifreq *)p;
|
||||
sa = &ifr->ifr_addr;
|
||||
|
||||
sz = ifreq_sz;
|
||||
salen = sizeof(struct sockaddr);
|
||||
#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
|
||||
salen = sa->sa_len;
|
||||
sz = max(sz, sizeof(ifr->ifr_name) + sa->sa_len);
|
||||
#endif
|
||||
#ifdef SA_LEN
|
||||
salen = SA_LEN(sa);
|
||||
sz = max(sz, sizeof(ifr->ifr_name) + SA_LEN(sa));
|
||||
#endif
|
||||
memset(&ifreq, 0, sizeof(ifreq));
|
||||
memcpy(ifreq.ifr_name, ifr->ifr_name, sizeof(ifr->ifr_name));
|
||||
|
||||
if (ioctl(fd, siocgifflags, &ifreq) < 0) {
|
||||
ret = errno;
|
||||
goto error_out;
|
||||
}
|
||||
|
||||
*end = malloc(sizeof(**end));
|
||||
|
||||
(*end)->ifa_next = NULL;
|
||||
(*end)->ifa_name = strdup(ifr->ifr_name);
|
||||
(*end)->ifa_flags = ifreq.ifr_flags;
|
||||
(*end)->ifa_addr = malloc(salen);
|
||||
memcpy((*end)->ifa_addr, sa, salen);
|
||||
(*end)->ifa_netmask = NULL;
|
||||
|
||||
#if 0
|
||||
/* fix these when we actually need them */
|
||||
if (ifreq.ifr_flags & IFF_BROADCAST) {
|
||||
(*end)->ifa_broadaddr =
|
||||
malloc(sizeof(ifr->ifr_broadaddr));
|
||||
memcpy((*end)->ifa_broadaddr, &ifr->ifr_broadaddr,
|
||||
sizeof(ifr->ifr_broadaddr));
|
||||
} else if (ifreq.ifr_flags & IFF_POINTOPOINT) {
|
||||
(*end)->ifa_dstaddr = malloc(sizeof(ifr->ifr_dstaddr));
|
||||
memcpy((*end)->ifa_dstaddr, &ifr->ifr_dstaddr,
|
||||
sizeof(ifr->ifr_dstaddr));
|
||||
} else
|
||||
(*end)->ifa_dstaddr = NULL;
|
||||
#else
|
||||
(*end)->ifa_dstaddr = NULL;
|
||||
#endif
|
||||
(*end)->ifa_data = NULL;
|
||||
|
||||
end = &(*end)->ifa_next;
|
||||
|
||||
}
|
||||
*ifap = start;
|
||||
close(fd);
|
||||
free(buf);
|
||||
return 0;
|
||||
|
||||
error_out:
|
||||
close(fd);
|
||||
free(buf);
|
||||
errno = ret;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int
|
||||
getifaddrs(struct ifaddrs **ifap)
|
||||
{
|
||||
int ret = -1;
|
||||
errno = ENXIO;
|
||||
#if defined(AF_INET6) && defined(SIOCGIF6CONF) && defined(SIOCGIF6FLAGS)
|
||||
if (ret)
|
||||
ret = getifaddrs2(ifap, AF_INET6, SIOCGIF6CONF, SIOCGIF6FLAGS,
|
||||
sizeof(struct in6_ifreq));
|
||||
#endif
|
||||
#if defined(HAVE_IPV6) && defined(SIOCGIFCONF)
|
||||
if (ret)
|
||||
ret = getifaddrs2(ifap, AF_INET6, SIOCGIFCONF, SIOCGIFFLAGS,
|
||||
sizeof(struct ifreq));
|
||||
#endif
|
||||
#if defined(AF_INET) && defined(SIOCGIFCONF) && defined(SIOCGIFFLAGS)
|
||||
if (ret)
|
||||
ret = getifaddrs2(ifap, AF_INET, SIOCGIFCONF, SIOCGIFFLAGS,
|
||||
sizeof(struct ifreq));
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
|
||||
void
|
||||
freeifaddrs(struct ifaddrs *ifp)
|
||||
{
|
||||
struct ifaddrs *p, *q;
|
||||
|
||||
for (p = ifp; p; ) {
|
||||
free(p->ifa_name);
|
||||
if (p->ifa_addr)
|
||||
free(p->ifa_addr);
|
||||
if (p->ifa_dstaddr)
|
||||
free(p->ifa_dstaddr);
|
||||
if (p->ifa_netmask)
|
||||
free(p->ifa_netmask);
|
||||
if (p->ifa_data)
|
||||
free(p->ifa_data);
|
||||
q = p;
|
||||
p = p->ifa_next;
|
||||
free(q);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef TEST
|
||||
|
||||
void
|
||||
print_addr(const char *s, struct sockaddr *sa)
|
||||
{
|
||||
int i;
|
||||
printf(" %s=%d/", s, sa->sa_family);
|
||||
#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
|
||||
for (i = 0;
|
||||
i < sa->sa_len - ((long)sa->sa_data - (long)&sa->sa_family); i++)
|
||||
printf("%02x", ((unsigned char *)sa->sa_data)[i]);
|
||||
#else
|
||||
for (i = 0; i < sizeof(sa->sa_data); i++)
|
||||
printf("%02x", ((unsigned char *)sa->sa_data)[i]);
|
||||
#endif
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
void
|
||||
print_ifaddrs(struct ifaddrs *x)
|
||||
{
|
||||
struct ifaddrs *p;
|
||||
|
||||
for (p = x; p; p = p->ifa_next) {
|
||||
printf("%s\n", p->ifa_name);
|
||||
printf(" flags=%x\n", p->ifa_flags);
|
||||
if (p->ifa_addr)
|
||||
print_addr("addr", p->ifa_addr);
|
||||
if (p->ifa_dstaddr)
|
||||
print_addr("dstaddr", p->ifa_dstaddr);
|
||||
if (p->ifa_netmask)
|
||||
print_addr("netmask", p->ifa_netmask);
|
||||
printf(" %p\n", p->ifa_data);
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
main()
|
||||
{
|
||||
struct ifaddrs *a = NULL, *b;
|
||||
getifaddrs2(&a, AF_INET, SIOCGIFCONF,
|
||||
SIOCGIFFLAGS, sizeof(struct ifreq));
|
||||
print_ifaddrs(a);
|
||||
printf("---\n");
|
||||
getifaddrs(&b);
|
||||
print_ifaddrs(b);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
76
dependencies/libwebsockets/lib/getifaddrs.h
vendored
Normal file
76
dependencies/libwebsockets/lib/getifaddrs.h
vendored
Normal file
@ -0,0 +1,76 @@
|
||||
#if HAVE_GETIFADDRS
|
||||
#include <sys/types.h>
|
||||
#include <ifaddrs.h>
|
||||
#else
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
/*
|
||||
* Copyright (c) 2000 Kungliga Tekniska H<EFBFBD>gskolan
|
||||
* (Royal Institute of Technology, Stockholm, Sweden).
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* 3. Neither the name of the Institute nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/* $KTH: ifaddrs.hin,v 1.3 2000/12/11 00:01:13 assar Exp $ */
|
||||
|
||||
#ifndef ifaddrs_h_7467027A95AD4B5C8DDD40FE7D973791
|
||||
#define ifaddrs_h_7467027A95AD4B5C8DDD40FE7D973791
|
||||
|
||||
/*
|
||||
* the interface is defined in terms of the fields below, and this is
|
||||
* sometimes #define'd, so there seems to be no simple way of solving
|
||||
* this and this seemed the best. */
|
||||
|
||||
#undef ifa_dstaddr
|
||||
|
||||
struct ifaddrs {
|
||||
struct ifaddrs *ifa_next;
|
||||
char *ifa_name;
|
||||
unsigned int ifa_flags;
|
||||
struct sockaddr *ifa_addr;
|
||||
struct sockaddr *ifa_netmask;
|
||||
struct sockaddr *ifa_dstaddr;
|
||||
void *ifa_data;
|
||||
};
|
||||
|
||||
#ifndef ifa_broadaddr
|
||||
#define ifa_broadaddr ifa_dstaddr
|
||||
#endif
|
||||
|
||||
int getifaddrs(struct ifaddrs **);
|
||||
|
||||
void freeifaddrs(struct ifaddrs *);
|
||||
|
||||
#endif /* __ifaddrs_h__ */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
171
dependencies/libwebsockets/lib/handshake.c
vendored
Normal file
171
dependencies/libwebsockets/lib/handshake.c
vendored
Normal file
@ -0,0 +1,171 @@
|
||||
/*
|
||||
* libwebsockets - small server side websockets and web server implementation
|
||||
*
|
||||
* Copyright (C) 2010-2013 Andy Green <andy@warmcat.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation:
|
||||
* version 2.1 of the License.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
* MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "private-libwebsockets.h"
|
||||
|
||||
/*
|
||||
* -04 of the protocol (actually the 80th version) has a radically different
|
||||
* handshake. The 04 spec gives the following idea
|
||||
*
|
||||
* The handshake from the client looks as follows:
|
||||
*
|
||||
* GET /chat HTTP/1.1
|
||||
* Host: server.example.com
|
||||
* Upgrade: websocket
|
||||
* Connection: Upgrade
|
||||
* Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
|
||||
* Sec-WebSocket-Origin: http://example.com
|
||||
* Sec-WebSocket-Protocol: chat, superchat
|
||||
* Sec-WebSocket-Version: 4
|
||||
*
|
||||
* The handshake from the server looks as follows:
|
||||
*
|
||||
* HTTP/1.1 101 Switching Protocols
|
||||
* Upgrade: websocket
|
||||
* Connection: Upgrade
|
||||
* Sec-WebSocket-Accept: me89jWimTRKTWwrS3aRrL53YZSo=
|
||||
* Sec-WebSocket-Nonce: AQIDBAUGBwgJCgsMDQ4PEC==
|
||||
* Sec-WebSocket-Protocol: chat
|
||||
*/
|
||||
|
||||
/*
|
||||
* We have to take care about parsing because the headers may be split
|
||||
* into multiple fragments. They may contain unknown headers with arbitrary
|
||||
* argument lengths. So, we parse using a single-character at a time state
|
||||
* machine that is completely independent of packet size.
|
||||
*/
|
||||
|
||||
LWS_VISIBLE int
|
||||
libwebsocket_read(struct libwebsocket_context *context,
|
||||
struct libwebsocket *wsi, unsigned char *buf, size_t len)
|
||||
{
|
||||
size_t n;
|
||||
|
||||
switch (wsi->state) {
|
||||
|
||||
case WSI_STATE_HTTP_BODY:
|
||||
http_postbody:
|
||||
while (len--) {
|
||||
|
||||
if (wsi->u.http.content_length_seen >= wsi->u.http.content_length)
|
||||
break;
|
||||
|
||||
wsi->u.http.post_buffer[wsi->u.http.body_index++] = *buf++;
|
||||
wsi->u.http.content_length_seen++;
|
||||
n = wsi->protocol->rx_buffer_size;
|
||||
if (!n)
|
||||
n = LWS_MAX_SOCKET_IO_BUF;
|
||||
|
||||
if (wsi->u.http.body_index != n &&
|
||||
wsi->u.http.content_length_seen != wsi->u.http.content_length)
|
||||
continue;
|
||||
|
||||
if (wsi->protocol->callback) {
|
||||
n = wsi->protocol->callback(
|
||||
wsi->protocol->owning_server, wsi,
|
||||
LWS_CALLBACK_HTTP_BODY,
|
||||
wsi->user_space, wsi->u.http.post_buffer,
|
||||
wsi->u.http.body_index);
|
||||
wsi->u.http.body_index = 0;
|
||||
if (n)
|
||||
goto bail;
|
||||
}
|
||||
|
||||
if (wsi->u.http.content_length_seen == wsi->u.http.content_length) {
|
||||
/* he sent the content in time */
|
||||
libwebsocket_set_timeout(wsi, NO_PENDING_TIMEOUT, 0);
|
||||
n = wsi->protocol->callback(
|
||||
wsi->protocol->owning_server, wsi,
|
||||
LWS_CALLBACK_HTTP_BODY_COMPLETION,
|
||||
wsi->user_space, NULL, 0);
|
||||
wsi->u.http.body_index = 0;
|
||||
if (n)
|
||||
goto bail;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* we need to spill here so everything is seen in the case
|
||||
* there is no content-length
|
||||
*/
|
||||
if (wsi->u.http.body_index && wsi->protocol->callback) {
|
||||
n = wsi->protocol->callback(
|
||||
wsi->protocol->owning_server, wsi,
|
||||
LWS_CALLBACK_HTTP_BODY,
|
||||
wsi->user_space, wsi->u.http.post_buffer,
|
||||
wsi->u.http.body_index);
|
||||
wsi->u.http.body_index = 0;
|
||||
if (n)
|
||||
goto bail;
|
||||
}
|
||||
break;
|
||||
|
||||
case WSI_STATE_HTTP_ISSUING_FILE:
|
||||
case WSI_STATE_HTTP:
|
||||
wsi->state = WSI_STATE_HTTP_HEADERS;
|
||||
wsi->u.hdr.parser_state = WSI_TOKEN_NAME_PART;
|
||||
wsi->u.hdr.lextable_pos = 0;
|
||||
/* fallthru */
|
||||
case WSI_STATE_HTTP_HEADERS:
|
||||
|
||||
lwsl_parser("issuing %d bytes to parser\n", (int)len);
|
||||
|
||||
if (lws_handshake_client(wsi, &buf, len))
|
||||
goto bail;
|
||||
|
||||
switch (lws_handshake_server(context, wsi, &buf, len)) {
|
||||
case 1:
|
||||
goto bail;
|
||||
case 2:
|
||||
goto http_postbody;
|
||||
}
|
||||
break;
|
||||
|
||||
case WSI_STATE_AWAITING_CLOSE_ACK:
|
||||
case WSI_STATE_ESTABLISHED:
|
||||
if (lws_handshake_client(wsi, &buf, len))
|
||||
goto bail;
|
||||
switch (wsi->mode) {
|
||||
case LWS_CONNMODE_WS_SERVING:
|
||||
|
||||
if (libwebsocket_interpret_incoming_packet(wsi, buf, len) < 0) {
|
||||
lwsl_info("interpret_incoming_packet has bailed\n");
|
||||
goto bail;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
lwsl_err("libwebsocket_read: Unhandled state\n");
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
bail:
|
||||
lwsl_debug("closing connection at libwebsocket_read bail:\n");
|
||||
|
||||
libwebsocket_close_and_free_session(context, wsi,
|
||||
LWS_CLOSE_STATUS_NOSTATUS);
|
||||
|
||||
return -1;
|
||||
}
|
||||
338
dependencies/libwebsockets/lib/lextable.h
vendored
Normal file
338
dependencies/libwebsockets/lib/lextable.h
vendored
Normal file
@ -0,0 +1,338 @@
|
||||
/* pos 0000: 0 */ 0x67 /* 'g' */, 0x25, 0x00 /* (to 0x0025 state 1) */,
|
||||
0x70 /* 'p' */, 0x27, 0x00 /* (to 0x002A state 5) */,
|
||||
0x6F /* 'o' */, 0x30, 0x00 /* (to 0x0036 state 10) */,
|
||||
0x68 /* 'h' */, 0x3C, 0x00 /* (to 0x0045 state 18) */,
|
||||
0x63 /* 'c' */, 0x45, 0x00 /* (to 0x0051 state 23) */,
|
||||
0x73 /* 's' */, 0x60, 0x00 /* (to 0x006F state 34) */,
|
||||
0x75 /* 'u' */, 0x9F, 0x00 /* (to 0x00B1 state 64) */,
|
||||
0x0D /* '.' */, 0xB3, 0x00 /* (to 0x00C8 state 84) */,
|
||||
0x61 /* 'a' */, 0xEA, 0x00 /* (to 0x0102 state 134) */,
|
||||
0x69 /* 'i' */, 0x1D, 0x01 /* (to 0x0138 state 168) */,
|
||||
0x64 /* 'd' */, 0x9C, 0x01 /* (to 0x01BA state 270) */,
|
||||
0x72 /* 'r' */, 0x9F, 0x01 /* (to 0x01C0 state 275) */,
|
||||
0x08, /* fail */
|
||||
/* pos 0025: 1 */ 0xE5 /* 'e' -> */,
|
||||
/* pos 0026: 2 */ 0xF4 /* 't' -> */,
|
||||
/* pos 0027: 3 */ 0xA0 /* ' ' -> */,
|
||||
/* pos 0028: 4 */ 0x00, 0x00 /* - terminal marker 0 - */,
|
||||
/* pos 002a: 5 */ 0x6F /* 'o' */, 0x07, 0x00 /* (to 0x0031 state 6) */,
|
||||
0x72 /* 'r' */, 0x4B, 0x01 /* (to 0x0178 state 216) */,
|
||||
0x08, /* fail */
|
||||
/* pos 0031: 6 */ 0xF3 /* 's' -> */,
|
||||
/* pos 0032: 7 */ 0xF4 /* 't' -> */,
|
||||
/* pos 0033: 8 */ 0xA0 /* ' ' -> */,
|
||||
/* pos 0034: 9 */ 0x00, 0x01 /* - terminal marker 1 - */,
|
||||
/* pos 0036: 10 */ 0x70 /* 'p' */, 0x07, 0x00 /* (to 0x003D state 11) */,
|
||||
0x72 /* 'r' */, 0x81, 0x00 /* (to 0x00BA state 72) */,
|
||||
0x08, /* fail */
|
||||
/* pos 003d: 11 */ 0xF4 /* 't' -> */,
|
||||
/* pos 003e: 12 */ 0xE9 /* 'i' -> */,
|
||||
/* pos 003f: 13 */ 0xEF /* 'o' -> */,
|
||||
/* pos 0040: 14 */ 0xEE /* 'n' -> */,
|
||||
/* pos 0041: 15 */ 0xF3 /* 's' -> */,
|
||||
/* pos 0042: 16 */ 0xA0 /* ' ' -> */,
|
||||
/* pos 0043: 17 */ 0x00, 0x02 /* - terminal marker 2 - */,
|
||||
/* pos 0045: 18 */ 0x6F /* 'o' */, 0x07, 0x00 /* (to 0x004C state 19) */,
|
||||
0x74 /* 't' */, 0xB1, 0x00 /* (to 0x00F9 state 126) */,
|
||||
0x08, /* fail */
|
||||
/* pos 004c: 19 */ 0xF3 /* 's' -> */,
|
||||
/* pos 004d: 20 */ 0xF4 /* 't' -> */,
|
||||
/* pos 004e: 21 */ 0xBA /* ':' -> */,
|
||||
/* pos 004f: 22 */ 0x00, 0x03 /* - terminal marker 3 - */,
|
||||
/* pos 0051: 23 */ 0x6F /* 'o' */, 0x07, 0x00 /* (to 0x0058 state 24) */,
|
||||
0x61 /* 'a' */, 0x2B, 0x01 /* (to 0x017F state 222) */,
|
||||
0x08, /* fail */
|
||||
/* pos 0058: 24 */ 0x6E /* 'n' */, 0x07, 0x00 /* (to 0x005F state 25) */,
|
||||
0x6F /* 'o' */, 0x40, 0x01 /* (to 0x019B state 248) */,
|
||||
0x08, /* fail */
|
||||
/* pos 005f: 25 */ 0x6E /* 'n' */, 0x07, 0x00 /* (to 0x0066 state 26) */,
|
||||
0x74 /* 't' */, 0x3F, 0x01 /* (to 0x01A1 state 253) */,
|
||||
0x08, /* fail */
|
||||
/* pos 0066: 26 */ 0xE5 /* 'e' -> */,
|
||||
/* pos 0067: 27 */ 0xE3 /* 'c' -> */,
|
||||
/* pos 0068: 28 */ 0xF4 /* 't' -> */,
|
||||
/* pos 0069: 29 */ 0xE9 /* 'i' -> */,
|
||||
/* pos 006a: 30 */ 0xEF /* 'o' -> */,
|
||||
/* pos 006b: 31 */ 0xEE /* 'n' -> */,
|
||||
/* pos 006c: 32 */ 0xBA /* ':' -> */,
|
||||
/* pos 006d: 33 */ 0x00, 0x04 /* - terminal marker 4 - */,
|
||||
/* pos 006f: 34 */ 0xE5 /* 'e' -> */,
|
||||
/* pos 0070: 35 */ 0xE3 /* 'c' -> */,
|
||||
/* pos 0071: 36 */ 0xAD /* '-' -> */,
|
||||
/* pos 0072: 37 */ 0xF7 /* 'w' -> */,
|
||||
/* pos 0073: 38 */ 0xE5 /* 'e' -> */,
|
||||
/* pos 0074: 39 */ 0xE2 /* 'b' -> */,
|
||||
/* pos 0075: 40 */ 0xF3 /* 's' -> */,
|
||||
/* pos 0076: 41 */ 0xEF /* 'o' -> */,
|
||||
/* pos 0077: 42 */ 0xE3 /* 'c' -> */,
|
||||
/* pos 0078: 43 */ 0xEB /* 'k' -> */,
|
||||
/* pos 0079: 44 */ 0xE5 /* 'e' -> */,
|
||||
/* pos 007a: 45 */ 0xF4 /* 't' -> */,
|
||||
/* pos 007b: 46 */ 0xAD /* '-' -> */,
|
||||
/* pos 007c: 47 */ 0x6B /* 'k' */, 0x19, 0x00 /* (to 0x0095 state 48) */,
|
||||
0x70 /* 'p' */, 0x28, 0x00 /* (to 0x00A7 state 55) */,
|
||||
0x64 /* 'd' */, 0x3F, 0x00 /* (to 0x00C1 state 78) */,
|
||||
0x76 /* 'v' */, 0x48, 0x00 /* (to 0x00CD state 87) */,
|
||||
0x6F /* 'o' */, 0x4E, 0x00 /* (to 0x00D6 state 95) */,
|
||||
0x65 /* 'e' */, 0x53, 0x00 /* (to 0x00DE state 102) */,
|
||||
0x61 /* 'a' */, 0x5C, 0x00 /* (to 0x00EA state 113) */,
|
||||
0x6E /* 'n' */, 0x61, 0x00 /* (to 0x00F2 state 120) */,
|
||||
0x08, /* fail */
|
||||
/* pos 0095: 48 */ 0xE5 /* 'e' -> */,
|
||||
/* pos 0096: 49 */ 0xF9 /* 'y' -> */,
|
||||
/* pos 0097: 50 */ 0x31 /* '1' */, 0x0A, 0x00 /* (to 0x00A1 state 51) */,
|
||||
0x32 /* '2' */, 0x0A, 0x00 /* (to 0x00A4 state 53) */,
|
||||
0x3A /* ':' */, 0x2E, 0x00 /* (to 0x00CB state 86) */,
|
||||
0x08, /* fail */
|
||||
/* pos 00a1: 51 */ 0xBA /* ':' -> */,
|
||||
/* pos 00a2: 52 */ 0x00, 0x05 /* - terminal marker 5 - */,
|
||||
/* pos 00a4: 53 */ 0xBA /* ':' -> */,
|
||||
/* pos 00a5: 54 */ 0x00, 0x06 /* - terminal marker 6 - */,
|
||||
/* pos 00a7: 55 */ 0xF2 /* 'r' -> */,
|
||||
/* pos 00a8: 56 */ 0xEF /* 'o' -> */,
|
||||
/* pos 00a9: 57 */ 0xF4 /* 't' -> */,
|
||||
/* pos 00aa: 58 */ 0xEF /* 'o' -> */,
|
||||
/* pos 00ab: 59 */ 0xE3 /* 'c' -> */,
|
||||
/* pos 00ac: 60 */ 0xEF /* 'o' -> */,
|
||||
/* pos 00ad: 61 */ 0xEC /* 'l' -> */,
|
||||
/* pos 00ae: 62 */ 0xBA /* ':' -> */,
|
||||
/* pos 00af: 63 */ 0x00, 0x07 /* - terminal marker 7 - */,
|
||||
/* pos 00b1: 64 */ 0xF0 /* 'p' -> */,
|
||||
/* pos 00b2: 65 */ 0xE7 /* 'g' -> */,
|
||||
/* pos 00b3: 66 */ 0xF2 /* 'r' -> */,
|
||||
/* pos 00b4: 67 */ 0xE1 /* 'a' -> */,
|
||||
/* pos 00b5: 68 */ 0xE4 /* 'd' -> */,
|
||||
/* pos 00b6: 69 */ 0xE5 /* 'e' -> */,
|
||||
/* pos 00b7: 70 */ 0xBA /* ':' -> */,
|
||||
/* pos 00b8: 71 */ 0x00, 0x08 /* - terminal marker 8 - */,
|
||||
/* pos 00ba: 72 */ 0xE9 /* 'i' -> */,
|
||||
/* pos 00bb: 73 */ 0xE7 /* 'g' -> */,
|
||||
/* pos 00bc: 74 */ 0xE9 /* 'i' -> */,
|
||||
/* pos 00bd: 75 */ 0xEE /* 'n' -> */,
|
||||
/* pos 00be: 76 */ 0xBA /* ':' -> */,
|
||||
/* pos 00bf: 77 */ 0x00, 0x09 /* - terminal marker 9 - */,
|
||||
/* pos 00c1: 78 */ 0xF2 /* 'r' -> */,
|
||||
/* pos 00c2: 79 */ 0xE1 /* 'a' -> */,
|
||||
/* pos 00c3: 80 */ 0xE6 /* 'f' -> */,
|
||||
/* pos 00c4: 81 */ 0xF4 /* 't' -> */,
|
||||
/* pos 00c5: 82 */ 0xBA /* ':' -> */,
|
||||
/* pos 00c6: 83 */ 0x00, 0x0A /* - terminal marker 10 - */,
|
||||
/* pos 00c8: 84 */ 0x8A /* '.' -> */,
|
||||
/* pos 00c9: 85 */ 0x00, 0x0B /* - terminal marker 11 - */,
|
||||
/* pos 00cb: 86 */ 0x00, 0x0C /* - terminal marker 12 - */,
|
||||
/* pos 00cd: 87 */ 0xE5 /* 'e' -> */,
|
||||
/* pos 00ce: 88 */ 0xF2 /* 'r' -> */,
|
||||
/* pos 00cf: 89 */ 0xF3 /* 's' -> */,
|
||||
/* pos 00d0: 90 */ 0xE9 /* 'i' -> */,
|
||||
/* pos 00d1: 91 */ 0xEF /* 'o' -> */,
|
||||
/* pos 00d2: 92 */ 0xEE /* 'n' -> */,
|
||||
/* pos 00d3: 93 */ 0xBA /* ':' -> */,
|
||||
/* pos 00d4: 94 */ 0x00, 0x0D /* - terminal marker 13 - */,
|
||||
/* pos 00d6: 95 */ 0xF2 /* 'r' -> */,
|
||||
/* pos 00d7: 96 */ 0xE9 /* 'i' -> */,
|
||||
/* pos 00d8: 97 */ 0xE7 /* 'g' -> */,
|
||||
/* pos 00d9: 98 */ 0xE9 /* 'i' -> */,
|
||||
/* pos 00da: 99 */ 0xEE /* 'n' -> */,
|
||||
/* pos 00db: 100 */ 0xBA /* ':' -> */,
|
||||
/* pos 00dc: 101 */ 0x00, 0x0E /* - terminal marker 14 - */,
|
||||
/* pos 00de: 102 */ 0xF8 /* 'x' -> */,
|
||||
/* pos 00df: 103 */ 0xF4 /* 't' -> */,
|
||||
/* pos 00e0: 104 */ 0xE5 /* 'e' -> */,
|
||||
/* pos 00e1: 105 */ 0xEE /* 'n' -> */,
|
||||
/* pos 00e2: 106 */ 0xF3 /* 's' -> */,
|
||||
/* pos 00e3: 107 */ 0xE9 /* 'i' -> */,
|
||||
/* pos 00e4: 108 */ 0xEF /* 'o' -> */,
|
||||
/* pos 00e5: 109 */ 0xEE /* 'n' -> */,
|
||||
/* pos 00e6: 110 */ 0xF3 /* 's' -> */,
|
||||
/* pos 00e7: 111 */ 0xBA /* ':' -> */,
|
||||
/* pos 00e8: 112 */ 0x00, 0x0F /* - terminal marker 15 - */,
|
||||
/* pos 00ea: 113 */ 0xE3 /* 'c' -> */,
|
||||
/* pos 00eb: 114 */ 0xE3 /* 'c' -> */,
|
||||
/* pos 00ec: 115 */ 0xE5 /* 'e' -> */,
|
||||
/* pos 00ed: 116 */ 0xF0 /* 'p' -> */,
|
||||
/* pos 00ee: 117 */ 0xF4 /* 't' -> */,
|
||||
/* pos 00ef: 118 */ 0xBA /* ':' -> */,
|
||||
/* pos 00f0: 119 */ 0x00, 0x10 /* - terminal marker 16 - */,
|
||||
/* pos 00f2: 120 */ 0xEF /* 'o' -> */,
|
||||
/* pos 00f3: 121 */ 0xEE /* 'n' -> */,
|
||||
/* pos 00f4: 122 */ 0xE3 /* 'c' -> */,
|
||||
/* pos 00f5: 123 */ 0xE5 /* 'e' -> */,
|
||||
/* pos 00f6: 124 */ 0xBA /* ':' -> */,
|
||||
/* pos 00f7: 125 */ 0x00, 0x11 /* - terminal marker 17 - */,
|
||||
/* pos 00f9: 126 */ 0xF4 /* 't' -> */,
|
||||
/* pos 00fa: 127 */ 0xF0 /* 'p' -> */,
|
||||
/* pos 00fb: 128 */ 0xAF /* '/' -> */,
|
||||
/* pos 00fc: 129 */ 0xB1 /* '1' -> */,
|
||||
/* pos 00fd: 130 */ 0xAE /* '.' -> */,
|
||||
/* pos 00fe: 131 */ 0xB1 /* '1' -> */,
|
||||
/* pos 00ff: 132 */ 0xA0 /* ' ' -> */,
|
||||
/* pos 0100: 133 */ 0x00, 0x12 /* - terminal marker 18 - */,
|
||||
/* pos 0102: 134 */ 0x63 /* 'c' */, 0x07, 0x00 /* (to 0x0109 state 135) */,
|
||||
0x75 /* 'u' */, 0x88, 0x00 /* (to 0x018D state 235) */,
|
||||
0x08, /* fail */
|
||||
/* pos 0109: 135 */ 0xE3 /* 'c' -> */,
|
||||
/* pos 010a: 136 */ 0xE5 /* 'e' -> */,
|
||||
/* pos 010b: 137 */ 0x70 /* 'p' */, 0x07, 0x00 /* (to 0x0112 state 138) */,
|
||||
0x73 /* 's' */, 0x0E, 0x00 /* (to 0x011C state 141) */,
|
||||
0x08, /* fail */
|
||||
/* pos 0112: 138 */ 0xF4 /* 't' -> */,
|
||||
/* pos 0113: 139 */ 0x3A /* ':' */, 0x07, 0x00 /* (to 0x011A state 140) */,
|
||||
0x2D /* '-' */, 0x47, 0x00 /* (to 0x015D state 197) */,
|
||||
0x08, /* fail */
|
||||
/* pos 011a: 140 */ 0x00, 0x13 /* - terminal marker 19 - */,
|
||||
/* pos 011c: 141 */ 0xF3 /* 's' -> */,
|
||||
/* pos 011d: 142 */ 0xAD /* '-' -> */,
|
||||
/* pos 011e: 143 */ 0xE3 /* 'c' -> */,
|
||||
/* pos 011f: 144 */ 0xEF /* 'o' -> */,
|
||||
/* pos 0120: 145 */ 0xEE /* 'n' -> */,
|
||||
/* pos 0121: 146 */ 0xF4 /* 't' -> */,
|
||||
/* pos 0122: 147 */ 0xF2 /* 'r' -> */,
|
||||
/* pos 0123: 148 */ 0xEF /* 'o' -> */,
|
||||
/* pos 0124: 149 */ 0xEC /* 'l' -> */,
|
||||
/* pos 0125: 150 */ 0xAD /* '-' -> */,
|
||||
/* pos 0126: 151 */ 0xF2 /* 'r' -> */,
|
||||
/* pos 0127: 152 */ 0xE5 /* 'e' -> */,
|
||||
/* pos 0128: 153 */ 0xF1 /* 'q' -> */,
|
||||
/* pos 0129: 154 */ 0xF5 /* 'u' -> */,
|
||||
/* pos 012a: 155 */ 0xE5 /* 'e' -> */,
|
||||
/* pos 012b: 156 */ 0xF3 /* 's' -> */,
|
||||
/* pos 012c: 157 */ 0xF4 /* 't' -> */,
|
||||
/* pos 012d: 158 */ 0xAD /* '-' -> */,
|
||||
/* pos 012e: 159 */ 0xE8 /* 'h' -> */,
|
||||
/* pos 012f: 160 */ 0xE5 /* 'e' -> */,
|
||||
/* pos 0130: 161 */ 0xE1 /* 'a' -> */,
|
||||
/* pos 0131: 162 */ 0xE4 /* 'd' -> */,
|
||||
/* pos 0132: 163 */ 0xE5 /* 'e' -> */,
|
||||
/* pos 0133: 164 */ 0xF2 /* 'r' -> */,
|
||||
/* pos 0134: 165 */ 0xF3 /* 's' -> */,
|
||||
/* pos 0135: 166 */ 0xBA /* ':' -> */,
|
||||
/* pos 0136: 167 */ 0x00, 0x14 /* - terminal marker 20 - */,
|
||||
/* pos 0138: 168 */ 0xE6 /* 'f' -> */,
|
||||
/* pos 0139: 169 */ 0xAD /* '-' -> */,
|
||||
/* pos 013a: 170 */ 0x6D /* 'm' */, 0x07, 0x00 /* (to 0x0141 state 171) */,
|
||||
0x6E /* 'n' */, 0x14, 0x00 /* (to 0x0151 state 186) */,
|
||||
0x08, /* fail */
|
||||
/* pos 0141: 171 */ 0xEF /* 'o' -> */,
|
||||
/* pos 0142: 172 */ 0xE4 /* 'd' -> */,
|
||||
/* pos 0143: 173 */ 0xE9 /* 'i' -> */,
|
||||
/* pos 0144: 174 */ 0xE6 /* 'f' -> */,
|
||||
/* pos 0145: 175 */ 0xE9 /* 'i' -> */,
|
||||
/* pos 0146: 176 */ 0xE5 /* 'e' -> */,
|
||||
/* pos 0147: 177 */ 0xE4 /* 'd' -> */,
|
||||
/* pos 0148: 178 */ 0xAD /* '-' -> */,
|
||||
/* pos 0149: 179 */ 0xF3 /* 's' -> */,
|
||||
/* pos 014a: 180 */ 0xE9 /* 'i' -> */,
|
||||
/* pos 014b: 181 */ 0xEE /* 'n' -> */,
|
||||
/* pos 014c: 182 */ 0xE3 /* 'c' -> */,
|
||||
/* pos 014d: 183 */ 0xE5 /* 'e' -> */,
|
||||
/* pos 014e: 184 */ 0xBA /* ':' -> */,
|
||||
/* pos 014f: 185 */ 0x00, 0x15 /* - terminal marker 21 - */,
|
||||
/* pos 0151: 186 */ 0xEF /* 'o' -> */,
|
||||
/* pos 0152: 187 */ 0xEE /* 'n' -> */,
|
||||
/* pos 0153: 188 */ 0xE5 /* 'e' -> */,
|
||||
/* pos 0154: 189 */ 0xAD /* '-' -> */,
|
||||
/* pos 0155: 190 */ 0xED /* 'm' -> */,
|
||||
/* pos 0156: 191 */ 0xE1 /* 'a' -> */,
|
||||
/* pos 0157: 192 */ 0xF4 /* 't' -> */,
|
||||
/* pos 0158: 193 */ 0xE3 /* 'c' -> */,
|
||||
/* pos 0159: 194 */ 0xE8 /* 'h' -> */,
|
||||
/* pos 015a: 195 */ 0xBA /* ':' -> */,
|
||||
/* pos 015b: 196 */ 0x00, 0x16 /* - terminal marker 22 - */,
|
||||
/* pos 015d: 197 */ 0x65 /* 'e' */, 0x07, 0x00 /* (to 0x0164 state 198) */,
|
||||
0x6C /* 'l' */, 0x0E, 0x00 /* (to 0x016E state 207) */,
|
||||
0x08, /* fail */
|
||||
/* pos 0164: 198 */ 0xEE /* 'n' -> */,
|
||||
/* pos 0165: 199 */ 0xE3 /* 'c' -> */,
|
||||
/* pos 0166: 200 */ 0xEF /* 'o' -> */,
|
||||
/* pos 0167: 201 */ 0xE4 /* 'd' -> */,
|
||||
/* pos 0168: 202 */ 0xE9 /* 'i' -> */,
|
||||
/* pos 0169: 203 */ 0xEE /* 'n' -> */,
|
||||
/* pos 016a: 204 */ 0xE7 /* 'g' -> */,
|
||||
/* pos 016b: 205 */ 0xBA /* ':' -> */,
|
||||
/* pos 016c: 206 */ 0x00, 0x17 /* - terminal marker 23 - */,
|
||||
/* pos 016e: 207 */ 0xE1 /* 'a' -> */,
|
||||
/* pos 016f: 208 */ 0xEE /* 'n' -> */,
|
||||
/* pos 0170: 209 */ 0xE7 /* 'g' -> */,
|
||||
/* pos 0171: 210 */ 0xF5 /* 'u' -> */,
|
||||
/* pos 0172: 211 */ 0xE1 /* 'a' -> */,
|
||||
/* pos 0173: 212 */ 0xE7 /* 'g' -> */,
|
||||
/* pos 0174: 213 */ 0xE5 /* 'e' -> */,
|
||||
/* pos 0175: 214 */ 0xBA /* ':' -> */,
|
||||
/* pos 0176: 215 */ 0x00, 0x18 /* - terminal marker 24 - */,
|
||||
/* pos 0178: 216 */ 0xE1 /* 'a' -> */,
|
||||
/* pos 0179: 217 */ 0xE7 /* 'g' -> */,
|
||||
/* pos 017a: 218 */ 0xED /* 'm' -> */,
|
||||
/* pos 017b: 219 */ 0xE1 /* 'a' -> */,
|
||||
/* pos 017c: 220 */ 0xBA /* ':' -> */,
|
||||
/* pos 017d: 221 */ 0x00, 0x19 /* - terminal marker 25 - */,
|
||||
/* pos 017f: 222 */ 0xE3 /* 'c' -> */,
|
||||
/* pos 0180: 223 */ 0xE8 /* 'h' -> */,
|
||||
/* pos 0181: 224 */ 0xE5 /* 'e' -> */,
|
||||
/* pos 0182: 225 */ 0xAD /* '-' -> */,
|
||||
/* pos 0183: 226 */ 0xE3 /* 'c' -> */,
|
||||
/* pos 0184: 227 */ 0xEF /* 'o' -> */,
|
||||
/* pos 0185: 228 */ 0xEE /* 'n' -> */,
|
||||
/* pos 0186: 229 */ 0xF4 /* 't' -> */,
|
||||
/* pos 0187: 230 */ 0xF2 /* 'r' -> */,
|
||||
/* pos 0188: 231 */ 0xEF /* 'o' -> */,
|
||||
/* pos 0189: 232 */ 0xEC /* 'l' -> */,
|
||||
/* pos 018a: 233 */ 0xBA /* ':' -> */,
|
||||
/* pos 018b: 234 */ 0x00, 0x1A /* - terminal marker 26 - */,
|
||||
/* pos 018d: 235 */ 0xF4 /* 't' -> */,
|
||||
/* pos 018e: 236 */ 0xE8 /* 'h' -> */,
|
||||
/* pos 018f: 237 */ 0xEF /* 'o' -> */,
|
||||
/* pos 0190: 238 */ 0xF2 /* 'r' -> */,
|
||||
/* pos 0191: 239 */ 0xE9 /* 'i' -> */,
|
||||
/* pos 0192: 240 */ 0xFA /* 'z' -> */,
|
||||
/* pos 0193: 241 */ 0xE1 /* 'a' -> */,
|
||||
/* pos 0194: 242 */ 0xF4 /* 't' -> */,
|
||||
/* pos 0195: 243 */ 0xE9 /* 'i' -> */,
|
||||
/* pos 0196: 244 */ 0xEF /* 'o' -> */,
|
||||
/* pos 0197: 245 */ 0xEE /* 'n' -> */,
|
||||
/* pos 0198: 246 */ 0xBA /* ':' -> */,
|
||||
/* pos 0199: 247 */ 0x00, 0x1B /* - terminal marker 27 - */,
|
||||
/* pos 019b: 248 */ 0xEB /* 'k' -> */,
|
||||
/* pos 019c: 249 */ 0xE9 /* 'i' -> */,
|
||||
/* pos 019d: 250 */ 0xE5 /* 'e' -> */,
|
||||
/* pos 019e: 251 */ 0xBA /* ':' -> */,
|
||||
/* pos 019f: 252 */ 0x00, 0x1C /* - terminal marker 28 - */,
|
||||
/* pos 01a1: 253 */ 0xE5 /* 'e' -> */,
|
||||
/* pos 01a2: 254 */ 0xEE /* 'n' -> */,
|
||||
/* pos 01a3: 255 */ 0xF4 /* 't' -> */,
|
||||
/* pos 01a4: 256 */ 0xAD /* '-' -> */,
|
||||
/* pos 01a5: 257 */ 0x6C /* 'l' */, 0x07, 0x00 /* (to 0x01AC state 258) */,
|
||||
0x74 /* 't' */, 0x0C, 0x00 /* (to 0x01B4 state 265) */,
|
||||
0x08, /* fail */
|
||||
/* pos 01ac: 258 */ 0xE5 /* 'e' -> */,
|
||||
/* pos 01ad: 259 */ 0xEE /* 'n' -> */,
|
||||
/* pos 01ae: 260 */ 0xE7 /* 'g' -> */,
|
||||
/* pos 01af: 261 */ 0xF4 /* 't' -> */,
|
||||
/* pos 01b0: 262 */ 0xE8 /* 'h' -> */,
|
||||
/* pos 01b1: 263 */ 0xBA /* ':' -> */,
|
||||
/* pos 01b2: 264 */ 0x00, 0x1D /* - terminal marker 29 - */,
|
||||
/* pos 01b4: 265 */ 0xF9 /* 'y' -> */,
|
||||
/* pos 01b5: 266 */ 0xF0 /* 'p' -> */,
|
||||
/* pos 01b6: 267 */ 0xE5 /* 'e' -> */,
|
||||
/* pos 01b7: 268 */ 0xBA /* ':' -> */,
|
||||
/* pos 01b8: 269 */ 0x00, 0x1E /* - terminal marker 30 - */,
|
||||
/* pos 01ba: 270 */ 0xE1 /* 'a' -> */,
|
||||
/* pos 01bb: 271 */ 0xF4 /* 't' -> */,
|
||||
/* pos 01bc: 272 */ 0xE5 /* 'e' -> */,
|
||||
/* pos 01bd: 273 */ 0xBA /* ':' -> */,
|
||||
/* pos 01be: 274 */ 0x00, 0x1F /* - terminal marker 31 - */,
|
||||
/* pos 01c0: 275 */ 0x61 /* 'a' */, 0x07, 0x00 /* (to 0x01C7 state 276) */,
|
||||
0x65 /* 'e' */, 0x0A, 0x00 /* (to 0x01CD state 281) */,
|
||||
0x08, /* fail */
|
||||
/* pos 01c7: 276 */ 0xEE /* 'n' -> */,
|
||||
/* pos 01c8: 277 */ 0xE7 /* 'g' -> */,
|
||||
/* pos 01c9: 278 */ 0xE5 /* 'e' -> */,
|
||||
/* pos 01ca: 279 */ 0xBA /* ':' -> */,
|
||||
/* pos 01cb: 280 */ 0x00, 0x20 /* - terminal marker 32 - */,
|
||||
/* pos 01cd: 281 */ 0xE6 /* 'f' -> */,
|
||||
/* pos 01ce: 282 */ 0xE5 /* 'e' -> */,
|
||||
/* pos 01cf: 283 */ 0xF2 /* 'r' -> */,
|
||||
/* pos 01d0: 284 */ 0xE5 /* 'e' -> */,
|
||||
/* pos 01d1: 285 */ 0xF2 /* 'r' -> */,
|
||||
/* pos 01d2: 286 */ 0xBA /* ':' -> */,
|
||||
/* pos 01d3: 287 */ 0x00, 0x21 /* - terminal marker 33 - */,
|
||||
/* total size 469 bytes */
|
||||
175
dependencies/libwebsockets/lib/libev.c
vendored
Normal file
175
dependencies/libwebsockets/lib/libev.c
vendored
Normal file
@ -0,0 +1,175 @@
|
||||
/*
|
||||
* libwebsockets - small server side websockets and web server implementation
|
||||
*
|
||||
* Copyright (C) 2010-2014 Andy Green <andy@warmcat.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation:
|
||||
* version 2.1 of the License.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
* MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "private-libwebsockets.h"
|
||||
|
||||
void lws_feature_status_libev(struct lws_context_creation_info *info)
|
||||
{
|
||||
if (info->options & LWS_SERVER_OPTION_LIBEV)
|
||||
lwsl_notice("libev support compiled in and enabled\n");
|
||||
else
|
||||
lwsl_notice("libev support compiled in but disabled\n");
|
||||
}
|
||||
|
||||
static void
|
||||
libwebsocket_accept_cb(struct ev_loop *loop, struct ev_io *watcher, int revents)
|
||||
{
|
||||
struct libwebsocket_pollfd eventfd;
|
||||
struct lws_io_watcher *lws_io = (struct lws_io_watcher *)watcher;
|
||||
struct libwebsocket_context *context = lws_io->context;
|
||||
|
||||
if (revents & EV_ERROR)
|
||||
return;
|
||||
|
||||
eventfd.fd = watcher->fd;
|
||||
eventfd.revents = EV_NONE;
|
||||
if (revents & EV_READ)
|
||||
eventfd.revents |= LWS_POLLIN;
|
||||
|
||||
if (revents & EV_WRITE)
|
||||
eventfd.revents |= LWS_POLLOUT;
|
||||
|
||||
libwebsocket_service_fd(context, &eventfd);
|
||||
}
|
||||
|
||||
LWS_VISIBLE void
|
||||
libwebsocket_sigint_cb(struct ev_loop *loop,
|
||||
struct ev_signal *watcher, int revents)
|
||||
{
|
||||
ev_break(loop, EVBREAK_ALL);
|
||||
}
|
||||
|
||||
LWS_VISIBLE int
|
||||
libwebsocket_initloop(
|
||||
struct libwebsocket_context *context,
|
||||
struct ev_loop *loop)
|
||||
{
|
||||
int status = 0;
|
||||
int backend;
|
||||
const char * backend_name;
|
||||
struct ev_io *w_accept = (ev_io *)&context->w_accept;
|
||||
struct ev_signal *w_sigint = (ev_signal *)&context->w_sigint;
|
||||
|
||||
if (!loop)
|
||||
loop = ev_default_loop(0);
|
||||
|
||||
context->io_loop = loop;
|
||||
|
||||
/*
|
||||
* Initialize the accept w_accept with the listening socket
|
||||
* and register a callback for read operations:
|
||||
*/
|
||||
ev_io_init(w_accept, libwebsocket_accept_cb,
|
||||
context->listen_service_fd, EV_READ);
|
||||
ev_io_start(context->io_loop,w_accept);
|
||||
ev_signal_init(w_sigint, libwebsocket_sigint_cb, SIGINT);
|
||||
ev_signal_start(context->io_loop,w_sigint);
|
||||
backend = ev_backend(loop);
|
||||
|
||||
switch (backend) {
|
||||
case EVBACKEND_SELECT:
|
||||
backend_name = "select";
|
||||
break;
|
||||
case EVBACKEND_POLL:
|
||||
backend_name = "poll";
|
||||
break;
|
||||
case EVBACKEND_EPOLL:
|
||||
backend_name = "epoll";
|
||||
break;
|
||||
case EVBACKEND_KQUEUE:
|
||||
backend_name = "kqueue";
|
||||
break;
|
||||
case EVBACKEND_DEVPOLL:
|
||||
backend_name = "/dev/poll";
|
||||
break;
|
||||
case EVBACKEND_PORT:
|
||||
backend_name = "Solaris 10 \"port\"";
|
||||
break;
|
||||
default:
|
||||
backend_name = "Unknown libev backend";
|
||||
break;
|
||||
};
|
||||
|
||||
lwsl_notice(" libev backend: %s\n", backend_name);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
LWS_VISIBLE void
|
||||
lws_libev_accept(struct libwebsocket_context *context,
|
||||
struct libwebsocket *new_wsi, int accept_fd)
|
||||
{
|
||||
struct ev_io *r = &new_wsi->w_read.watcher;
|
||||
struct ev_io *w = &new_wsi->w_write.watcher;
|
||||
|
||||
if (!LWS_LIBEV_ENABLED(context))
|
||||
return;
|
||||
|
||||
new_wsi->w_read.context = context;
|
||||
new_wsi->w_write.context = context;
|
||||
ev_io_init(r, libwebsocket_accept_cb, accept_fd, EV_READ);
|
||||
ev_io_init(w, libwebsocket_accept_cb, accept_fd, EV_WRITE);
|
||||
}
|
||||
|
||||
LWS_VISIBLE void
|
||||
lws_libev_io(struct libwebsocket_context *context,
|
||||
struct libwebsocket *wsi, int flags)
|
||||
{
|
||||
if (!LWS_LIBEV_ENABLED(context))
|
||||
return;
|
||||
|
||||
if (!context->io_loop)
|
||||
return;
|
||||
|
||||
assert((flags & (LWS_EV_START | LWS_EV_STOP)) &&
|
||||
(flags & (LWS_EV_READ | LWS_EV_WRITE)));
|
||||
|
||||
if (flags & LWS_EV_START) {
|
||||
if (flags & LWS_EV_WRITE)
|
||||
ev_io_start(context->io_loop, &wsi->w_write.watcher);
|
||||
if (flags & LWS_EV_READ)
|
||||
ev_io_start(context->io_loop, &wsi->w_read.watcher);
|
||||
} else {
|
||||
if (flags & LWS_EV_WRITE)
|
||||
ev_io_stop(context->io_loop, &wsi->w_write.watcher);
|
||||
if (flags & LWS_EV_READ)
|
||||
ev_io_stop(context->io_loop, &wsi->w_read.watcher);
|
||||
}
|
||||
}
|
||||
|
||||
LWS_VISIBLE int
|
||||
lws_libev_init_fd_table(struct libwebsocket_context *context)
|
||||
{
|
||||
if (!LWS_LIBEV_ENABLED(context))
|
||||
return 0;
|
||||
|
||||
context->w_accept.context = context;
|
||||
context->w_sigint.context = context;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
LWS_VISIBLE void
|
||||
lws_libev_run(struct libwebsocket_context *context)
|
||||
{
|
||||
if (context->io_loop && LWS_LIBEV_ENABLED(context))
|
||||
ev_run(context->io_loop, 0);
|
||||
}
|
||||
761
dependencies/libwebsockets/lib/libwebsockets.c
vendored
Normal file
761
dependencies/libwebsockets/lib/libwebsockets.c
vendored
Normal file
@ -0,0 +1,761 @@
|
||||
/*
|
||||
* libwebsockets - small server side websockets and web server implementation
|
||||
*
|
||||
* Copyright (C) 2010-2014 Andy Green <andy@warmcat.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation:
|
||||
* version 2.1 of the License.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
* MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "private-libwebsockets.h"
|
||||
|
||||
int log_level = LLL_ERR | LLL_WARN | LLL_NOTICE;
|
||||
static void (*lwsl_emit)(int level, const char *line) = lwsl_emit_stderr;
|
||||
|
||||
static const char * const log_level_names[] = {
|
||||
"ERR",
|
||||
"WARN",
|
||||
"NOTICE",
|
||||
"INFO",
|
||||
"DEBUG",
|
||||
"PARSER",
|
||||
"HEADER",
|
||||
"EXTENSION",
|
||||
"CLIENT",
|
||||
"LATENCY",
|
||||
};
|
||||
|
||||
|
||||
void
|
||||
libwebsocket_close_and_free_session(struct libwebsocket_context *context,
|
||||
struct libwebsocket *wsi, enum lws_close_status reason)
|
||||
{
|
||||
int n, m, ret;
|
||||
int old_state;
|
||||
unsigned char buf[LWS_SEND_BUFFER_PRE_PADDING + 2 +
|
||||
LWS_SEND_BUFFER_POST_PADDING];
|
||||
struct lws_tokens eff_buf;
|
||||
|
||||
if (!wsi)
|
||||
return;
|
||||
|
||||
old_state = wsi->state;
|
||||
|
||||
switch (old_state) {
|
||||
case WSI_STATE_DEAD_SOCKET:
|
||||
return;
|
||||
|
||||
/* we tried the polite way... */
|
||||
case WSI_STATE_AWAITING_CLOSE_ACK:
|
||||
goto just_kill_connection;
|
||||
|
||||
case WSI_STATE_FLUSHING_STORED_SEND_BEFORE_CLOSE:
|
||||
if (wsi->truncated_send_len) {
|
||||
libwebsocket_callback_on_writable(context, wsi);
|
||||
return;
|
||||
}
|
||||
lwsl_info("wsi %p completed WSI_STATE_FLUSHING_STORED_SEND_BEFORE_CLOSE\n", wsi);
|
||||
goto just_kill_connection;
|
||||
default:
|
||||
if (wsi->truncated_send_len) {
|
||||
lwsl_info("wsi %p entering WSI_STATE_FLUSHING_STORED_SEND_BEFORE_CLOSE\n", wsi);
|
||||
wsi->state = WSI_STATE_FLUSHING_STORED_SEND_BEFORE_CLOSE;
|
||||
return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
wsi->u.ws.close_reason = reason;
|
||||
|
||||
if (wsi->mode == LWS_CONNMODE_WS_CLIENT_WAITING_CONNECT ||
|
||||
wsi->mode == LWS_CONNMODE_WS_CLIENT_ISSUE_HANDSHAKE) {
|
||||
|
||||
context->protocols[0].callback(context, wsi,
|
||||
LWS_CALLBACK_CLIENT_CONNECTION_ERROR, NULL, NULL, 0);
|
||||
|
||||
free(wsi->u.hdr.ah);
|
||||
goto just_kill_connection;
|
||||
}
|
||||
|
||||
if (wsi->mode == LWS_CONNMODE_HTTP_SERVING_ACCEPTED) {
|
||||
if (wsi->u.http.post_buffer) {
|
||||
free(wsi->u.http.post_buffer);
|
||||
wsi->u.http.post_buffer = NULL;
|
||||
}
|
||||
if (wsi->u.http.fd != LWS_INVALID_FILE) {
|
||||
lwsl_debug("closing http file\n");
|
||||
compatible_file_close(wsi->u.http.fd);
|
||||
wsi->u.http.fd = LWS_INVALID_FILE;
|
||||
context->protocols[0].callback(context, wsi,
|
||||
LWS_CALLBACK_CLOSED_HTTP, wsi->user_space, NULL, 0);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* are his extensions okay with him closing? Eg he might be a mux
|
||||
* parent and just his ch1 aspect is closing?
|
||||
*/
|
||||
|
||||
if (lws_ext_callback_for_each_active(wsi,
|
||||
LWS_EXT_CALLBACK_CHECK_OK_TO_REALLY_CLOSE, NULL, 0) > 0) {
|
||||
lwsl_ext("extension vetoed close\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* flush any tx pending from extensions, since we may send close packet
|
||||
* if there are problems with send, just nuke the connection
|
||||
*/
|
||||
|
||||
do {
|
||||
ret = 0;
|
||||
eff_buf.token = NULL;
|
||||
eff_buf.token_len = 0;
|
||||
|
||||
/* show every extension the new incoming data */
|
||||
|
||||
m = lws_ext_callback_for_each_active(wsi,
|
||||
LWS_EXT_CALLBACK_FLUSH_PENDING_TX, &eff_buf, 0);
|
||||
if (m < 0) {
|
||||
lwsl_ext("Extension reports fatal error\n");
|
||||
goto just_kill_connection;
|
||||
}
|
||||
if (m)
|
||||
/*
|
||||
* at least one extension told us he has more
|
||||
* to spill, so we will go around again after
|
||||
*/
|
||||
ret = 1;
|
||||
|
||||
/* assuming they left us something to send, send it */
|
||||
|
||||
if (eff_buf.token_len)
|
||||
if (lws_issue_raw(wsi, (unsigned char *)eff_buf.token,
|
||||
eff_buf.token_len) != eff_buf.token_len) {
|
||||
lwsl_debug("close: ext spill failed\n");
|
||||
goto just_kill_connection;
|
||||
}
|
||||
} while (ret);
|
||||
|
||||
/*
|
||||
* signal we are closing, libsocket_write will
|
||||
* add any necessary version-specific stuff. If the write fails,
|
||||
* no worries we are closing anyway. If we didn't initiate this
|
||||
* close, then our state has been changed to
|
||||
* WSI_STATE_RETURNED_CLOSE_ALREADY and we will skip this.
|
||||
*
|
||||
* Likewise if it's a second call to close this connection after we
|
||||
* sent the close indication to the peer already, we are in state
|
||||
* WSI_STATE_AWAITING_CLOSE_ACK and will skip doing this a second time.
|
||||
*/
|
||||
|
||||
if (old_state == WSI_STATE_ESTABLISHED &&
|
||||
reason != LWS_CLOSE_STATUS_NOSTATUS) {
|
||||
|
||||
lwsl_debug("sending close indication...\n");
|
||||
|
||||
/* make valgrind happy */
|
||||
memset(buf, 0, sizeof(buf));
|
||||
n = libwebsocket_write(wsi,
|
||||
&buf[LWS_SEND_BUFFER_PRE_PADDING + 2],
|
||||
0, LWS_WRITE_CLOSE);
|
||||
if (n >= 0) {
|
||||
/*
|
||||
* we have sent a nice protocol level indication we
|
||||
* now wish to close, we should not send anything more
|
||||
*/
|
||||
|
||||
wsi->state = WSI_STATE_AWAITING_CLOSE_ACK;
|
||||
|
||||
/*
|
||||
* ...and we should wait for a reply for a bit
|
||||
* out of politeness
|
||||
*/
|
||||
|
||||
libwebsocket_set_timeout(wsi,
|
||||
PENDING_TIMEOUT_CLOSE_ACK, 1);
|
||||
|
||||
lwsl_debug("sent close indication, awaiting ack\n");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
lwsl_info("close: sending close packet failed, hanging up\n");
|
||||
|
||||
/* else, the send failed and we should just hang up */
|
||||
}
|
||||
|
||||
just_kill_connection:
|
||||
|
||||
lwsl_debug("close: just_kill_connection\n");
|
||||
|
||||
/*
|
||||
* we won't be servicing or receiving anything further from this guy
|
||||
* delete socket from the internal poll list if still present
|
||||
*/
|
||||
|
||||
remove_wsi_socket_from_fds(context, wsi);
|
||||
|
||||
wsi->state = WSI_STATE_DEAD_SOCKET;
|
||||
|
||||
if ((old_state == WSI_STATE_ESTABLISHED ||
|
||||
wsi->mode == LWS_CONNMODE_WS_SERVING ||
|
||||
wsi->mode == LWS_CONNMODE_WS_CLIENT)) {
|
||||
|
||||
if (wsi->u.ws.rx_user_buffer) {
|
||||
free(wsi->u.ws.rx_user_buffer);
|
||||
wsi->u.ws.rx_user_buffer = NULL;
|
||||
}
|
||||
if (wsi->u.ws.rxflow_buffer) {
|
||||
free(wsi->u.ws.rxflow_buffer);
|
||||
wsi->u.ws.rxflow_buffer = NULL;
|
||||
}
|
||||
if (wsi->truncated_send_malloc) {
|
||||
/* not going to be completed... nuke it */
|
||||
free(wsi->truncated_send_malloc);
|
||||
wsi->truncated_send_malloc = NULL;
|
||||
wsi->truncated_send_len = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* tell the user it's all over for this guy */
|
||||
|
||||
if (wsi->protocol && wsi->protocol->callback &&
|
||||
((old_state == WSI_STATE_ESTABLISHED) ||
|
||||
(old_state == WSI_STATE_RETURNED_CLOSE_ALREADY) ||
|
||||
(old_state == WSI_STATE_AWAITING_CLOSE_ACK))) {
|
||||
lwsl_debug("calling back CLOSED\n");
|
||||
wsi->protocol->callback(context, wsi, LWS_CALLBACK_CLOSED,
|
||||
wsi->user_space, NULL, 0);
|
||||
} else if (wsi->mode == LWS_CONNMODE_HTTP_SERVING_ACCEPTED) {
|
||||
lwsl_debug("calling back CLOSED_HTTP\n");
|
||||
context->protocols[0].callback(context, wsi,
|
||||
LWS_CALLBACK_CLOSED_HTTP, wsi->user_space, NULL, 0 );
|
||||
} else
|
||||
lwsl_debug("not calling back closed\n");
|
||||
|
||||
/* deallocate any active extension contexts */
|
||||
|
||||
if (lws_ext_callback_for_each_active(wsi, LWS_EXT_CALLBACK_DESTROY, NULL, 0) < 0)
|
||||
lwsl_warn("extension destruction failed\n");
|
||||
#ifndef LWS_NO_EXTENSIONS
|
||||
for (n = 0; n < wsi->count_active_extensions; n++)
|
||||
free(wsi->active_extensions_user[n]);
|
||||
#endif
|
||||
/*
|
||||
* inform all extensions in case they tracked this guy out of band
|
||||
* even though not active on him specifically
|
||||
*/
|
||||
if (lws_ext_callback_for_each_extension_type(context, wsi,
|
||||
LWS_EXT_CALLBACK_DESTROY_ANY_WSI_CLOSING, NULL, 0) < 0)
|
||||
lwsl_warn("ext destroy wsi failed\n");
|
||||
|
||||
/* lwsl_info("closing fd=%d\n", wsi->sock); */
|
||||
|
||||
if (!lws_ssl_close(wsi) && wsi->sock >= 0) {
|
||||
n = shutdown(wsi->sock, SHUT_RDWR);
|
||||
if (n)
|
||||
lwsl_debug("closing: shutdown ret %d\n", LWS_ERRNO);
|
||||
|
||||
n = compatible_close(wsi->sock);
|
||||
if (n)
|
||||
lwsl_debug("closing: close ret %d\n", LWS_ERRNO);
|
||||
}
|
||||
|
||||
/* outermost destroy notification for wsi (user_space still intact) */
|
||||
context->protocols[0].callback(context, wsi,
|
||||
LWS_CALLBACK_WSI_DESTROY, wsi->user_space, NULL, 0);
|
||||
|
||||
if (wsi->protocol && wsi->protocol->per_session_data_size &&
|
||||
wsi->user_space && !wsi->user_space_externally_allocated)
|
||||
free(wsi->user_space);
|
||||
|
||||
free(wsi);
|
||||
}
|
||||
|
||||
/**
|
||||
* libwebsockets_get_peer_addresses() - Get client address information
|
||||
* @context: Libwebsockets context
|
||||
* @wsi: Local struct libwebsocket associated with
|
||||
* @fd: Connection socket descriptor
|
||||
* @name: Buffer to take client address name
|
||||
* @name_len: Length of client address name buffer
|
||||
* @rip: Buffer to take client address IP qotted quad
|
||||
* @rip_len: Length of client address IP buffer
|
||||
*
|
||||
* This function fills in @name and @rip with the name and IP of
|
||||
* the client connected with socket descriptor @fd. Names may be
|
||||
* truncated if there is not enough room. If either cannot be
|
||||
* determined, they will be returned as valid zero-length strings.
|
||||
*/
|
||||
|
||||
LWS_VISIBLE void
|
||||
libwebsockets_get_peer_addresses(struct libwebsocket_context *context,
|
||||
struct libwebsocket *wsi, int fd, char *name, int name_len,
|
||||
char *rip, int rip_len)
|
||||
{
|
||||
socklen_t len;
|
||||
#ifdef LWS_USE_IPV6
|
||||
struct sockaddr_in6 sin6;
|
||||
#endif
|
||||
struct sockaddr_in sin4;
|
||||
struct hostent *host;
|
||||
struct hostent *host1;
|
||||
char ip[128];
|
||||
unsigned char *p;
|
||||
int n;
|
||||
#ifdef AF_LOCAL
|
||||
struct sockaddr_un *un;
|
||||
#endif
|
||||
int ret = -1;
|
||||
|
||||
rip[0] = '\0';
|
||||
name[0] = '\0';
|
||||
|
||||
lws_latency_pre(context, wsi);
|
||||
|
||||
#ifdef LWS_USE_IPV6
|
||||
if (LWS_IPV6_ENABLED(context)) {
|
||||
|
||||
len = sizeof(sin6);
|
||||
if (getpeername(fd, (struct sockaddr *) &sin6, &len) < 0) {
|
||||
lwsl_warn("getpeername: %s\n", strerror(LWS_ERRNO));
|
||||
goto bail;
|
||||
}
|
||||
|
||||
if (!lws_plat_inet_ntop(AF_INET6, &sin6.sin6_addr, rip, rip_len)) {
|
||||
lwsl_err("inet_ntop", strerror(LWS_ERRNO));
|
||||
goto bail;
|
||||
}
|
||||
|
||||
// Strip off the IPv4 to IPv6 header if one exists
|
||||
if (strncmp(rip, "::ffff:", 7) == 0)
|
||||
memmove(rip, rip + 7, strlen(rip) - 6);
|
||||
|
||||
getnameinfo((struct sockaddr *)&sin6,
|
||||
sizeof(struct sockaddr_in6), name,
|
||||
name_len, NULL, 0, 0);
|
||||
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
len = sizeof(sin4);
|
||||
if (getpeername(fd, (struct sockaddr *) &sin4, &len) < 0) {
|
||||
lwsl_warn("getpeername: %s\n", strerror(LWS_ERRNO));
|
||||
goto bail;
|
||||
}
|
||||
host = gethostbyaddr((char *) &sin4.sin_addr,
|
||||
sizeof(sin4.sin_addr), AF_INET);
|
||||
if (host == NULL) {
|
||||
lwsl_warn("gethostbyaddr: %s\n", strerror(LWS_ERRNO));
|
||||
goto bail;
|
||||
}
|
||||
|
||||
strncpy(name, host->h_name, name_len);
|
||||
name[name_len - 1] = '\0';
|
||||
|
||||
host1 = gethostbyname(host->h_name);
|
||||
if (host1 == NULL)
|
||||
goto bail;
|
||||
p = (unsigned char *)host1;
|
||||
n = 0;
|
||||
while (p != NULL) {
|
||||
p = (unsigned char *)host1->h_addr_list[n++];
|
||||
if (p == NULL)
|
||||
continue;
|
||||
if ((host1->h_addrtype != AF_INET)
|
||||
#ifdef AF_LOCAL
|
||||
&& (host1->h_addrtype != AF_LOCAL)
|
||||
#endif
|
||||
)
|
||||
continue;
|
||||
|
||||
if (host1->h_addrtype == AF_INET)
|
||||
sprintf(ip, "%u.%u.%u.%u",
|
||||
p[0], p[1], p[2], p[3]);
|
||||
#ifdef AF_LOCAL
|
||||
else {
|
||||
un = (struct sockaddr_un *)p;
|
||||
strncpy(ip, un->sun_path, sizeof(ip) - 1);
|
||||
ip[sizeof(ip) - 1] = '\0';
|
||||
}
|
||||
#endif
|
||||
p = NULL;
|
||||
strncpy(rip, ip, rip_len);
|
||||
rip[rip_len - 1] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
bail:
|
||||
lws_latency(context, wsi, "libwebsockets_get_peer_addresses", ret, 1);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* libwebsocket_context_user() - get the user data associated with the context
|
||||
* @context: Websocket context
|
||||
*
|
||||
* This returns the optional user allocation that can be attached to
|
||||
* the context the sockets live in at context_create time. It's a way
|
||||
* to let all sockets serviced in the same context share data without
|
||||
* using globals statics in the user code.
|
||||
*/
|
||||
LWS_EXTERN void *
|
||||
libwebsocket_context_user(struct libwebsocket_context *context)
|
||||
{
|
||||
return context->user_space;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* libwebsocket_callback_all_protocol() - Callback all connections using
|
||||
* the given protocol with the given reason
|
||||
*
|
||||
* @protocol: Protocol whose connections will get callbacks
|
||||
* @reason: Callback reason index
|
||||
*/
|
||||
|
||||
LWS_VISIBLE int
|
||||
libwebsocket_callback_all_protocol(
|
||||
const struct libwebsocket_protocols *protocol, int reason)
|
||||
{
|
||||
struct libwebsocket_context *context = protocol->owning_server;
|
||||
int n;
|
||||
struct libwebsocket *wsi;
|
||||
|
||||
for (n = 0; n < context->fds_count; n++) {
|
||||
wsi = context->lws_lookup[context->fds[n].fd];
|
||||
if (!wsi)
|
||||
continue;
|
||||
if (wsi->protocol == protocol)
|
||||
protocol->callback(context, wsi,
|
||||
reason, wsi->user_space, NULL, 0);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* libwebsocket_set_timeout() - marks the wsi as subject to a timeout
|
||||
*
|
||||
* You will not need this unless you are doing something special
|
||||
*
|
||||
* @wsi: Websocket connection instance
|
||||
* @reason: timeout reason
|
||||
* @secs: how many seconds
|
||||
*/
|
||||
|
||||
LWS_VISIBLE void
|
||||
libwebsocket_set_timeout(struct libwebsocket *wsi,
|
||||
enum pending_timeout reason, int secs)
|
||||
{
|
||||
time_t now;
|
||||
|
||||
time(&now);
|
||||
|
||||
wsi->pending_timeout_limit = now + secs;
|
||||
wsi->pending_timeout = reason;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* libwebsocket_get_socket_fd() - returns the socket file descriptor
|
||||
*
|
||||
* You will not need this unless you are doing something special
|
||||
*
|
||||
* @wsi: Websocket connection instance
|
||||
*/
|
||||
|
||||
LWS_VISIBLE int
|
||||
libwebsocket_get_socket_fd(struct libwebsocket *wsi)
|
||||
{
|
||||
return wsi->sock;
|
||||
}
|
||||
|
||||
#ifdef LWS_LATENCY
|
||||
void
|
||||
lws_latency(struct libwebsocket_context *context, struct libwebsocket *wsi,
|
||||
const char *action, int ret, int completed)
|
||||
{
|
||||
unsigned long long u;
|
||||
char buf[256];
|
||||
|
||||
u = time_in_microseconds();
|
||||
|
||||
if (!action) {
|
||||
wsi->latency_start = u;
|
||||
if (!wsi->action_start)
|
||||
wsi->action_start = u;
|
||||
return;
|
||||
}
|
||||
if (completed) {
|
||||
if (wsi->action_start == wsi->latency_start)
|
||||
sprintf(buf,
|
||||
"Completion first try lat %lluus: %p: ret %d: %s\n",
|
||||
u - wsi->latency_start,
|
||||
(void *)wsi, ret, action);
|
||||
else
|
||||
sprintf(buf,
|
||||
"Completion %lluus: lat %lluus: %p: ret %d: %s\n",
|
||||
u - wsi->action_start,
|
||||
u - wsi->latency_start,
|
||||
(void *)wsi, ret, action);
|
||||
wsi->action_start = 0;
|
||||
} else
|
||||
sprintf(buf, "lat %lluus: %p: ret %d: %s\n",
|
||||
u - wsi->latency_start, (void *)wsi, ret, action);
|
||||
|
||||
if (u - wsi->latency_start > context->worst_latency) {
|
||||
context->worst_latency = u - wsi->latency_start;
|
||||
strcpy(context->worst_latency_info, buf);
|
||||
}
|
||||
lwsl_latency("%s", buf);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* libwebsocket_rx_flow_control() - Enable and disable socket servicing for
|
||||
* receieved packets.
|
||||
*
|
||||
* If the output side of a server process becomes choked, this allows flow
|
||||
* control for the input side.
|
||||
*
|
||||
* @wsi: Websocket connection instance to get callback for
|
||||
* @enable: 0 = disable read servicing for this connection, 1 = enable
|
||||
*/
|
||||
|
||||
LWS_VISIBLE int
|
||||
libwebsocket_rx_flow_control(struct libwebsocket *wsi, int enable)
|
||||
{
|
||||
if (enable == (wsi->u.ws.rxflow_change_to & LWS_RXFLOW_ALLOW))
|
||||
return 0;
|
||||
|
||||
lwsl_info("libwebsocket_rx_flow_control(0x%p, %d)\n", wsi, enable);
|
||||
wsi->u.ws.rxflow_change_to = LWS_RXFLOW_PENDING_CHANGE | !!enable;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* libwebsocket_rx_flow_allow_all_protocol() - Allow all connections with this protocol to receive
|
||||
*
|
||||
* When the user server code realizes it can accept more input, it can
|
||||
* call this to have the RX flow restriction removed from all connections using
|
||||
* the given protocol.
|
||||
*
|
||||
* @protocol: all connections using this protocol will be allowed to receive
|
||||
*/
|
||||
|
||||
LWS_VISIBLE void
|
||||
libwebsocket_rx_flow_allow_all_protocol(
|
||||
const struct libwebsocket_protocols *protocol)
|
||||
{
|
||||
struct libwebsocket_context *context = protocol->owning_server;
|
||||
int n;
|
||||
struct libwebsocket *wsi;
|
||||
|
||||
for (n = 0; n < context->fds_count; n++) {
|
||||
wsi = context->lws_lookup[context->fds[n].fd];
|
||||
if (!wsi)
|
||||
continue;
|
||||
if (wsi->protocol == protocol)
|
||||
libwebsocket_rx_flow_control(wsi, LWS_RXFLOW_ALLOW);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* libwebsocket_canonical_hostname() - returns this host's hostname
|
||||
*
|
||||
* This is typically used by client code to fill in the host parameter
|
||||
* when making a client connection. You can only call it after the context
|
||||
* has been created.
|
||||
*
|
||||
* @context: Websocket context
|
||||
*/
|
||||
LWS_VISIBLE extern const char *
|
||||
libwebsocket_canonical_hostname(struct libwebsocket_context *context)
|
||||
{
|
||||
return (const char *)context->canonical_hostname;
|
||||
}
|
||||
|
||||
int user_callback_handle_rxflow(callback_function callback_function,
|
||||
struct libwebsocket_context *context,
|
||||
struct libwebsocket *wsi,
|
||||
enum libwebsocket_callback_reasons reason, void *user,
|
||||
void *in, size_t len)
|
||||
{
|
||||
int n;
|
||||
|
||||
n = callback_function(context, wsi, reason, user, in, len);
|
||||
if (!n)
|
||||
n = _libwebsocket_rx_flow_control(wsi);
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* libwebsocket_set_proxy() - Setups proxy to libwebsocket_context.
|
||||
* @context: pointer to struct libwebsocket_context you want set proxy to
|
||||
* @proxy: pointer to c string containing proxy in format address:port
|
||||
*
|
||||
* Returns 0 if proxy string was parsed and proxy was setup.
|
||||
* Returns -1 if @proxy is NULL or has incorrect format.
|
||||
*
|
||||
* This is only required if your OS does not provide the http_proxy
|
||||
* enviroment variable (eg, OSX)
|
||||
*
|
||||
* IMPORTANT! You should call this function right after creation of the
|
||||
* libwebsocket_context and before call to connect. If you call this
|
||||
* function after connect behavior is undefined.
|
||||
* This function will override proxy settings made on libwebsocket_context
|
||||
* creation with genenv() call.
|
||||
*/
|
||||
|
||||
LWS_VISIBLE int
|
||||
libwebsocket_set_proxy(struct libwebsocket_context *context, const char *proxy)
|
||||
{
|
||||
char *p;
|
||||
|
||||
if (!proxy)
|
||||
return -1;
|
||||
|
||||
strncpy(context->http_proxy_address, proxy,
|
||||
sizeof(context->http_proxy_address) - 1);
|
||||
context->http_proxy_address[
|
||||
sizeof(context->http_proxy_address) - 1] = '\0';
|
||||
|
||||
p = strchr(context->http_proxy_address, ':');
|
||||
if (!p) {
|
||||
lwsl_err("http_proxy needs to be ads:port\n");
|
||||
|
||||
return -1;
|
||||
}
|
||||
*p = '\0';
|
||||
context->http_proxy_port = atoi(p + 1);
|
||||
|
||||
lwsl_notice(" Proxy %s:%u\n", context->http_proxy_address,
|
||||
context->http_proxy_port);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* libwebsockets_get_protocol() - Returns a protocol pointer from a websocket
|
||||
* connection.
|
||||
* @wsi: pointer to struct websocket you want to know the protocol of
|
||||
*
|
||||
*
|
||||
* Some apis can act on all live connections of a given protocol,
|
||||
* this is how you can get a pointer to the active protocol if needed.
|
||||
*/
|
||||
|
||||
LWS_VISIBLE const struct libwebsocket_protocols *
|
||||
libwebsockets_get_protocol(struct libwebsocket *wsi)
|
||||
{
|
||||
return wsi->protocol;
|
||||
}
|
||||
|
||||
LWS_VISIBLE int
|
||||
libwebsocket_is_final_fragment(struct libwebsocket *wsi)
|
||||
{
|
||||
return wsi->u.ws.final;
|
||||
}
|
||||
|
||||
LWS_VISIBLE unsigned char
|
||||
libwebsocket_get_reserved_bits(struct libwebsocket *wsi)
|
||||
{
|
||||
return wsi->u.ws.rsv;
|
||||
}
|
||||
|
||||
int
|
||||
libwebsocket_ensure_user_space(struct libwebsocket *wsi)
|
||||
{
|
||||
if (!wsi->protocol)
|
||||
return 1;
|
||||
|
||||
/* allocate the per-connection user memory (if any) */
|
||||
|
||||
if (wsi->protocol->per_session_data_size && !wsi->user_space) {
|
||||
wsi->user_space = malloc(
|
||||
wsi->protocol->per_session_data_size);
|
||||
if (wsi->user_space == NULL) {
|
||||
lwsl_err("Out of memory for conn user space\n");
|
||||
return 1;
|
||||
}
|
||||
memset(wsi->user_space, 0,
|
||||
wsi->protocol->per_session_data_size);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
LWS_VISIBLE void lwsl_emit_stderr(int level, const char *line)
|
||||
{
|
||||
char buf[300];
|
||||
unsigned long long now;
|
||||
int n;
|
||||
|
||||
buf[0] = '\0';
|
||||
for (n = 0; n < LLL_COUNT; n++)
|
||||
if (level == (1 << n)) {
|
||||
now = time_in_microseconds() / 100;
|
||||
sprintf(buf, "[%lu:%04d] %s: ", (unsigned long) now / 10000,
|
||||
(int)(now % 10000), log_level_names[n]);
|
||||
break;
|
||||
}
|
||||
|
||||
fprintf(stderr, "%s%s", buf, line);
|
||||
}
|
||||
|
||||
|
||||
LWS_VISIBLE void _lws_log(int filter, const char *format, ...)
|
||||
{
|
||||
char buf[256];
|
||||
va_list ap;
|
||||
|
||||
if (!(log_level & filter))
|
||||
return;
|
||||
|
||||
va_start(ap, format);
|
||||
vsnprintf(buf, sizeof(buf), format, ap);
|
||||
buf[sizeof(buf) - 1] = '\0';
|
||||
va_end(ap);
|
||||
|
||||
lwsl_emit(filter, buf);
|
||||
}
|
||||
|
||||
/**
|
||||
* lws_set_log_level() - Set the logging bitfield
|
||||
* @level: OR together the LLL_ debug contexts you want output from
|
||||
* @log_emit_function: NULL to leave it as it is, or a user-supplied
|
||||
* function to perform log string emission instead of
|
||||
* the default stderr one.
|
||||
*
|
||||
* log level defaults to "err", "warn" and "notice" contexts enabled and
|
||||
* emission on stderr.
|
||||
*/
|
||||
|
||||
LWS_VISIBLE void lws_set_log_level(int level, void (*log_emit_function)(int level,
|
||||
const char *line))
|
||||
{
|
||||
log_level = level;
|
||||
if (log_emit_function)
|
||||
lwsl_emit = log_emit_function;
|
||||
}
|
||||
1207
dependencies/libwebsockets/lib/libwebsockets.h
vendored
Normal file
1207
dependencies/libwebsockets/lib/libwebsockets.h
vendored
Normal file
File diff suppressed because it is too large
Load Diff
404
dependencies/libwebsockets/lib/lws-plat-unix.c
vendored
Normal file
404
dependencies/libwebsockets/lib/lws-plat-unix.c
vendored
Normal file
@ -0,0 +1,404 @@
|
||||
#include "private-libwebsockets.h"
|
||||
|
||||
/*
|
||||
* included from libwebsockets.c for unix builds
|
||||
*/
|
||||
|
||||
unsigned long long time_in_microseconds(void)
|
||||
{
|
||||
struct timeval tv;
|
||||
gettimeofday(&tv, NULL);
|
||||
return (tv.tv_sec * 1000000) + tv.tv_usec;
|
||||
}
|
||||
|
||||
LWS_VISIBLE int libwebsockets_get_random(struct libwebsocket_context *context,
|
||||
void *buf, int len)
|
||||
{
|
||||
return read(context->fd_random, (char *)buf, len);
|
||||
}
|
||||
|
||||
LWS_VISIBLE int lws_send_pipe_choked(struct libwebsocket *wsi)
|
||||
{
|
||||
struct libwebsocket_pollfd fds;
|
||||
|
||||
/* treat the fact we got a truncated send pending as if we're choked */
|
||||
if (wsi->truncated_send_len)
|
||||
return 1;
|
||||
|
||||
fds.fd = wsi->sock;
|
||||
fds.events = POLLOUT;
|
||||
fds.revents = 0;
|
||||
|
||||
if (poll(&fds, 1, 0) != 1)
|
||||
return 1;
|
||||
|
||||
if ((fds.revents & POLLOUT) == 0)
|
||||
return 1;
|
||||
|
||||
/* okay to send another packet without blocking */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
LWS_VISIBLE int
|
||||
lws_poll_listen_fd(struct libwebsocket_pollfd *fd)
|
||||
{
|
||||
return poll(fd, 1, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* This is just used to interrupt poll waiting
|
||||
* we don't have to do anything with it.
|
||||
*/
|
||||
static void lws_sigusr2(int sig)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* libwebsocket_cancel_service() - Cancel servicing of pending websocket activity
|
||||
* @context: Websocket context
|
||||
*
|
||||
* This function let a call to libwebsocket_service() waiting for a timeout
|
||||
* immediately return.
|
||||
*/
|
||||
LWS_VISIBLE void
|
||||
libwebsocket_cancel_service(struct libwebsocket_context *context)
|
||||
{
|
||||
char buf = 0;
|
||||
|
||||
if (write(context->dummy_pipe_fds[1], &buf, sizeof(buf)) != 1)
|
||||
lwsl_err("Cannot write to dummy pipe");
|
||||
}
|
||||
|
||||
LWS_VISIBLE void lwsl_emit_syslog(int level, const char *line)
|
||||
{
|
||||
int syslog_level = LOG_DEBUG;
|
||||
|
||||
switch (level) {
|
||||
case LLL_ERR:
|
||||
syslog_level = LOG_ERR;
|
||||
break;
|
||||
case LLL_WARN:
|
||||
syslog_level = LOG_WARNING;
|
||||
break;
|
||||
case LLL_NOTICE:
|
||||
syslog_level = LOG_NOTICE;
|
||||
break;
|
||||
case LLL_INFO:
|
||||
syslog_level = LOG_INFO;
|
||||
break;
|
||||
}
|
||||
syslog(syslog_level, "%s", line);
|
||||
}
|
||||
|
||||
LWS_VISIBLE int
|
||||
lws_plat_service(struct libwebsocket_context *context, int timeout_ms)
|
||||
{
|
||||
int n;
|
||||
int m;
|
||||
char buf;
|
||||
|
||||
/* stay dead once we are dead */
|
||||
|
||||
if (!context)
|
||||
return 1;
|
||||
|
||||
lws_libev_run(context);
|
||||
|
||||
context->service_tid = context->protocols[0].callback(context, NULL,
|
||||
LWS_CALLBACK_GET_THREAD_ID, NULL, NULL, 0);
|
||||
|
||||
n = poll(context->fds, context->fds_count, timeout_ms);
|
||||
context->service_tid = 0;
|
||||
|
||||
if (n == 0) /* poll timeout */ {
|
||||
libwebsocket_service_fd(context, NULL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (n < 0) {
|
||||
if (LWS_ERRNO != LWS_EINTR)
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* any socket with events to service? */
|
||||
|
||||
for (n = 0; n < context->fds_count; n++) {
|
||||
if (!context->fds[n].revents)
|
||||
continue;
|
||||
|
||||
if (context->fds[n].fd == context->dummy_pipe_fds[0]) {
|
||||
if (read(context->fds[n].fd, &buf, 1) != 1)
|
||||
lwsl_err("Cannot read from dummy pipe.");
|
||||
continue;
|
||||
}
|
||||
|
||||
m = libwebsocket_service_fd(context, &context->fds[n]);
|
||||
if (m < 0)
|
||||
return -1;
|
||||
/* if something closed, retry this slot */
|
||||
if (m)
|
||||
n--;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
LWS_VISIBLE int
|
||||
lws_plat_set_socket_options(struct libwebsocket_context *context, int fd)
|
||||
{
|
||||
int optval = 1;
|
||||
socklen_t optlen = sizeof(optval);
|
||||
|
||||
#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__) || \
|
||||
defined(__OpenBSD__)
|
||||
struct protoent *tcp_proto;
|
||||
#endif
|
||||
|
||||
if (context->ka_time) {
|
||||
/* enable keepalive on this socket */
|
||||
optval = 1;
|
||||
if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE,
|
||||
(const void *)&optval, optlen) < 0)
|
||||
return 1;
|
||||
|
||||
#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__) || \
|
||||
defined(__CYGWIN__) || defined(__OpenBSD__)
|
||||
|
||||
/*
|
||||
* didn't find a way to set these per-socket, need to
|
||||
* tune kernel systemwide values
|
||||
*/
|
||||
#else
|
||||
/* set the keepalive conditions we want on it too */
|
||||
optval = context->ka_time;
|
||||
if (setsockopt(fd, IPPROTO_IP, TCP_KEEPIDLE,
|
||||
(const void *)&optval, optlen) < 0)
|
||||
return 1;
|
||||
|
||||
optval = context->ka_interval;
|
||||
if (setsockopt(fd, IPPROTO_IP, TCP_KEEPINTVL,
|
||||
(const void *)&optval, optlen) < 0)
|
||||
return 1;
|
||||
|
||||
optval = context->ka_probes;
|
||||
if (setsockopt(fd, IPPROTO_IP, TCP_KEEPCNT,
|
||||
(const void *)&optval, optlen) < 0)
|
||||
return 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Disable Nagle */
|
||||
optval = 1;
|
||||
#if !defined(__APPLE__) && !defined(__FreeBSD__) && !defined(__NetBSD__) && \
|
||||
!defined(__OpenBSD__)
|
||||
setsockopt(fd, SOL_TCP, TCP_NODELAY, (const void *)&optval, optlen);
|
||||
#else
|
||||
tcp_proto = getprotobyname("TCP");
|
||||
setsockopt(fd, tcp_proto->p_proto, TCP_NODELAY, &optval, optlen);
|
||||
#endif
|
||||
|
||||
/* We are nonblocking... */
|
||||
fcntl(fd, F_SETFL, O_NONBLOCK);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
LWS_VISIBLE void
|
||||
lws_plat_drop_app_privileges(struct lws_context_creation_info *info)
|
||||
{
|
||||
if (info->gid != -1)
|
||||
if (setgid(info->gid))
|
||||
lwsl_warn("setgid: %s\n", strerror(LWS_ERRNO));
|
||||
if (info->uid != -1)
|
||||
if (setuid(info->uid))
|
||||
lwsl_warn("setuid: %s\n", strerror(LWS_ERRNO));
|
||||
}
|
||||
|
||||
LWS_VISIBLE int
|
||||
lws_plat_init_fd_tables(struct libwebsocket_context *context)
|
||||
{
|
||||
if (lws_libev_init_fd_table(context))
|
||||
/* libev handled it instead */
|
||||
return 0;
|
||||
|
||||
if (pipe(context->dummy_pipe_fds)) {
|
||||
lwsl_err("Unable to create pipe\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* use the read end of pipe as first item */
|
||||
context->fds[0].fd = context->dummy_pipe_fds[0];
|
||||
context->fds[0].events = LWS_POLLIN;
|
||||
context->fds[0].revents = 0;
|
||||
context->fds_count = 1;
|
||||
|
||||
context->fd_random = open(SYSTEM_RANDOM_FILEPATH, O_RDONLY);
|
||||
if (context->fd_random < 0) {
|
||||
lwsl_err("Unable to open random device %s %d\n",
|
||||
SYSTEM_RANDOM_FILEPATH, context->fd_random);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void sigpipe_handler(int x)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
LWS_VISIBLE int
|
||||
lws_plat_context_early_init(void)
|
||||
{
|
||||
sigset_t mask;
|
||||
|
||||
signal(SIGUSR2, lws_sigusr2);
|
||||
sigemptyset(&mask);
|
||||
sigaddset(&mask, SIGUSR2);
|
||||
|
||||
sigprocmask(SIG_BLOCK, &mask, NULL);
|
||||
|
||||
signal(SIGPIPE, sigpipe_handler);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
LWS_VISIBLE void
|
||||
lws_plat_context_early_destroy(struct libwebsocket_context *context)
|
||||
{
|
||||
}
|
||||
|
||||
LWS_VISIBLE void
|
||||
lws_plat_context_late_destroy(struct libwebsocket_context *context)
|
||||
{
|
||||
close(context->dummy_pipe_fds[0]);
|
||||
close(context->dummy_pipe_fds[1]);
|
||||
close(context->fd_random);
|
||||
}
|
||||
|
||||
/* cast a struct sockaddr_in6 * into addr for ipv6 */
|
||||
|
||||
LWS_VISIBLE int
|
||||
interface_to_sa(struct libwebsocket_context *context,
|
||||
const char *ifname, struct sockaddr_in *addr, size_t addrlen)
|
||||
{
|
||||
int rc = -1;
|
||||
|
||||
struct ifaddrs *ifr;
|
||||
struct ifaddrs *ifc;
|
||||
#ifdef LWS_USE_IPV6
|
||||
struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)addr;
|
||||
#endif
|
||||
|
||||
getifaddrs(&ifr);
|
||||
for (ifc = ifr; ifc != NULL && rc; ifc = ifc->ifa_next) {
|
||||
if (!ifc->ifa_addr)
|
||||
continue;
|
||||
|
||||
lwsl_info(" interface %s vs %s\n", ifc->ifa_name, ifname);
|
||||
|
||||
if (strcmp(ifc->ifa_name, ifname))
|
||||
continue;
|
||||
|
||||
switch (ifc->ifa_addr->sa_family) {
|
||||
case AF_INET:
|
||||
#ifdef LWS_USE_IPV6
|
||||
if (LWS_IPV6_ENABLED(context)) {
|
||||
/* map IPv4 to IPv6 */
|
||||
bzero((char *)&addr6->sin6_addr,
|
||||
sizeof(struct in6_addr));
|
||||
addr6->sin6_addr.s6_addr[10] = 0xff;
|
||||
addr6->sin6_addr.s6_addr[11] = 0xff;
|
||||
memcpy(&addr6->sin6_addr.s6_addr[12],
|
||||
&((struct sockaddr_in *)ifc->ifa_addr)->sin_addr,
|
||||
sizeof(struct in_addr));
|
||||
} else
|
||||
#endif
|
||||
memcpy(addr,
|
||||
(struct sockaddr_in *)ifc->ifa_addr,
|
||||
sizeof(struct sockaddr_in));
|
||||
break;
|
||||
#ifdef LWS_USE_IPV6
|
||||
case AF_INET6:
|
||||
if (rc >= 0)
|
||||
break;
|
||||
memcpy(&addr6->sin6_addr,
|
||||
&((struct sockaddr_in6 *)ifc->ifa_addr)->sin6_addr,
|
||||
sizeof(struct in6_addr));
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
rc = 0;
|
||||
}
|
||||
|
||||
freeifaddrs(ifr);
|
||||
|
||||
if (rc == -1) {
|
||||
/* check if bind to IP adddress */
|
||||
#ifdef LWS_USE_IPV6
|
||||
if (inet_pton(AF_INET6, ifname, &addr6->sin6_addr) == 1)
|
||||
rc = 0;
|
||||
else
|
||||
#endif
|
||||
if (inet_pton(AF_INET, ifname, &addr->sin_addr) == 1)
|
||||
rc = 0;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
LWS_VISIBLE void
|
||||
lws_plat_insert_socket_into_fds(struct libwebsocket_context *context,
|
||||
struct libwebsocket *wsi)
|
||||
{
|
||||
lws_libev_io(context, wsi, LWS_EV_START | LWS_EV_READ);
|
||||
context->fds[context->fds_count++].revents = 0;
|
||||
}
|
||||
|
||||
LWS_VISIBLE void
|
||||
lws_plat_delete_socket_from_fds(struct libwebsocket_context *context,
|
||||
struct libwebsocket *wsi, int m)
|
||||
{
|
||||
}
|
||||
|
||||
LWS_VISIBLE void
|
||||
lws_plat_service_periodic(struct libwebsocket_context *context)
|
||||
{
|
||||
/* if our parent went down, don't linger around */
|
||||
if (context->started_with_parent &&
|
||||
kill(context->started_with_parent, 0) < 0)
|
||||
kill(getpid(), SIGTERM);
|
||||
}
|
||||
|
||||
LWS_VISIBLE int
|
||||
lws_plat_change_pollfd(struct libwebsocket_context *context,
|
||||
struct libwebsocket *wsi, struct libwebsocket_pollfd *pfd)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
LWS_VISIBLE int
|
||||
lws_plat_open_file(const char* filename, unsigned long* filelen)
|
||||
{
|
||||
struct stat stat_buf;
|
||||
int ret = open(filename, O_RDONLY);
|
||||
|
||||
if (ret < 0)
|
||||
return LWS_INVALID_FILE;
|
||||
|
||||
fstat(ret, &stat_buf);
|
||||
*filelen = stat_buf.st_size;
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef LWS_USE_IPV6
|
||||
LWS_VISIBLE const char *
|
||||
lws_plat_inet_ntop(int af, const void *src, char *dst, int cnt)
|
||||
{
|
||||
return inet_ntop(af, src, dst, cnt);
|
||||
}
|
||||
#endif
|
||||
358
dependencies/libwebsockets/lib/lws-plat-win.c
vendored
Normal file
358
dependencies/libwebsockets/lib/lws-plat-win.c
vendored
Normal file
@ -0,0 +1,358 @@
|
||||
#include "private-libwebsockets.h"
|
||||
|
||||
unsigned long long
|
||||
time_in_microseconds()
|
||||
{
|
||||
#define DELTA_EPOCH_IN_MICROSECS 11644473600000000ULL
|
||||
FILETIME filetime;
|
||||
ULARGE_INTEGER datetime;
|
||||
|
||||
#ifdef _WIN32_WCE
|
||||
GetCurrentFT(&filetime);
|
||||
#else
|
||||
GetSystemTimeAsFileTime(&filetime);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* As per Windows documentation for FILETIME, copy the resulting FILETIME structure to a
|
||||
* ULARGE_INTEGER structure using memcpy (using memcpy instead of direct assignment can
|
||||
* prevent alignment faults on 64-bit Windows).
|
||||
*/
|
||||
memcpy(&datetime, &filetime, sizeof(datetime));
|
||||
|
||||
/* Windows file times are in 100s of nanoseconds. */
|
||||
return (datetime.QuadPart - DELTA_EPOCH_IN_MICROSECS) / 10;
|
||||
}
|
||||
|
||||
#ifdef _WIN32_WCE
|
||||
time_t time(time_t *t)
|
||||
{
|
||||
time_t ret = time_in_microseconds() / 1000000;
|
||||
*t = ret;
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
LWS_VISIBLE int libwebsockets_get_random(struct libwebsocket_context *context,
|
||||
void *buf, int len)
|
||||
{
|
||||
int n;
|
||||
char *p = (char *)buf;
|
||||
|
||||
for (n = 0; n < len; n++)
|
||||
p[n] = (unsigned char)rand();
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
LWS_VISIBLE int lws_send_pipe_choked(struct libwebsocket *wsi)
|
||||
{
|
||||
return wsi->sock_send_blocking;
|
||||
}
|
||||
|
||||
LWS_VISIBLE int lws_poll_listen_fd(struct libwebsocket_pollfd *fd)
|
||||
{
|
||||
fd_set readfds;
|
||||
struct timeval tv = { 0, 0 };
|
||||
|
||||
assert(fd->events == LWS_POLLIN);
|
||||
|
||||
FD_ZERO(&readfds);
|
||||
FD_SET(fd->fd, &readfds);
|
||||
|
||||
return select(fd->fd + 1, &readfds, NULL, NULL, &tv);
|
||||
}
|
||||
|
||||
/**
|
||||
* libwebsocket_cancel_service() - Cancel servicing of pending websocket activity
|
||||
* @context: Websocket context
|
||||
*
|
||||
* This function let a call to libwebsocket_service() waiting for a timeout
|
||||
* immediately return.
|
||||
*/
|
||||
LWS_VISIBLE void
|
||||
libwebsocket_cancel_service(struct libwebsocket_context *context)
|
||||
{
|
||||
WSASetEvent(context->events[0]);
|
||||
}
|
||||
|
||||
LWS_VISIBLE void lwsl_emit_syslog(int level, const char *line)
|
||||
{
|
||||
lwsl_emit_stderr(level, line);
|
||||
}
|
||||
|
||||
LWS_VISIBLE int
|
||||
lws_plat_service(struct libwebsocket_context *context, int timeout_ms)
|
||||
{
|
||||
int n;
|
||||
int i;
|
||||
DWORD ev;
|
||||
WSANETWORKEVENTS networkevents;
|
||||
struct libwebsocket_pollfd *pfd;
|
||||
|
||||
/* stay dead once we are dead */
|
||||
|
||||
if (context == NULL)
|
||||
return 1;
|
||||
|
||||
context->service_tid = context->protocols[0].callback(context, NULL,
|
||||
LWS_CALLBACK_GET_THREAD_ID, NULL, NULL, 0);
|
||||
|
||||
for (i = 0; i < context->fds_count; ++i) {
|
||||
pfd = &context->fds[i];
|
||||
if (pfd->fd == context->listen_service_fd)
|
||||
continue;
|
||||
|
||||
if (pfd->events & LWS_POLLOUT) {
|
||||
if (context->lws_lookup[pfd->fd]->sock_send_blocking)
|
||||
continue;
|
||||
pfd->revents = LWS_POLLOUT;
|
||||
n = libwebsocket_service_fd(context, pfd);
|
||||
if (n < 0)
|
||||
return n;
|
||||
}
|
||||
}
|
||||
|
||||
ev = WSAWaitForMultipleEvents(context->fds_count + 1,
|
||||
context->events, FALSE, timeout_ms, FALSE);
|
||||
context->service_tid = 0;
|
||||
|
||||
if (ev == WSA_WAIT_TIMEOUT) {
|
||||
libwebsocket_service_fd(context, NULL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (ev == WSA_WAIT_EVENT_0) {
|
||||
WSAResetEvent(context->events[0]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (ev < WSA_WAIT_EVENT_0 || ev > WSA_WAIT_EVENT_0 + context->fds_count)
|
||||
return -1;
|
||||
|
||||
pfd = &context->fds[ev - WSA_WAIT_EVENT_0 - 1];
|
||||
|
||||
if (WSAEnumNetworkEvents(pfd->fd,
|
||||
context->events[ev - WSA_WAIT_EVENT_0],
|
||||
&networkevents) == SOCKET_ERROR) {
|
||||
lwsl_err("WSAEnumNetworkEvents() failed with error %d\n",
|
||||
LWS_ERRNO);
|
||||
return -1;
|
||||
}
|
||||
|
||||
pfd->revents = networkevents.lNetworkEvents;
|
||||
|
||||
if (pfd->revents & LWS_POLLOUT)
|
||||
context->lws_lookup[pfd->fd]->sock_send_blocking = FALSE;
|
||||
|
||||
return libwebsocket_service_fd(context, pfd);
|
||||
}
|
||||
|
||||
LWS_VISIBLE int
|
||||
lws_plat_set_socket_options(struct libwebsocket_context *context, int fd)
|
||||
{
|
||||
int optval = 1;
|
||||
int optlen = sizeof(optval);
|
||||
u_long optl = 1;
|
||||
DWORD dwBytesRet;
|
||||
struct tcp_keepalive alive;
|
||||
struct protoent *tcp_proto;
|
||||
|
||||
if (context->ka_time) {
|
||||
/* enable keepalive on this socket */
|
||||
optval = 1;
|
||||
if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE,
|
||||
(const char *)&optval, optlen) < 0)
|
||||
return 1;
|
||||
|
||||
alive.onoff = TRUE;
|
||||
alive.keepalivetime = context->ka_time;
|
||||
alive.keepaliveinterval = context->ka_interval;
|
||||
|
||||
if (WSAIoctl(fd, SIO_KEEPALIVE_VALS, &alive, sizeof(alive),
|
||||
NULL, 0, &dwBytesRet, NULL, NULL))
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Disable Nagle */
|
||||
optval = 1;
|
||||
tcp_proto = getprotobyname("TCP");
|
||||
setsockopt(fd, tcp_proto->p_proto, TCP_NODELAY, (const char *)&optval, optlen);
|
||||
|
||||
/* We are nonblocking... */
|
||||
ioctlsocket(fd, FIONBIO, &optl);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
LWS_VISIBLE void
|
||||
lws_plat_drop_app_privileges(struct lws_context_creation_info *info)
|
||||
{
|
||||
}
|
||||
|
||||
LWS_VISIBLE int
|
||||
lws_plat_init_fd_tables(struct libwebsocket_context *context)
|
||||
{
|
||||
context->events = (WSAEVENT *)malloc(sizeof(WSAEVENT) *
|
||||
(context->max_fds + 1));
|
||||
if (context->events == NULL) {
|
||||
lwsl_err("Unable to allocate events array for %d connections\n",
|
||||
context->max_fds);
|
||||
return 1;
|
||||
}
|
||||
|
||||
context->fds_count = 0;
|
||||
context->events[0] = WSACreateEvent();
|
||||
|
||||
context->fd_random = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
LWS_VISIBLE int
|
||||
lws_plat_context_early_init(void)
|
||||
{
|
||||
WORD wVersionRequested;
|
||||
WSADATA wsaData;
|
||||
int err;
|
||||
|
||||
/* Use the MAKEWORD(lowbyte, highbyte) macro from Windef.h */
|
||||
wVersionRequested = MAKEWORD(2, 2);
|
||||
|
||||
err = WSAStartup(wVersionRequested, &wsaData);
|
||||
if (!err)
|
||||
return 0;
|
||||
/*
|
||||
* Tell the user that we could not find a usable
|
||||
* Winsock DLL
|
||||
*/
|
||||
lwsl_err("WSAStartup failed with error: %d\n", err);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
LWS_VISIBLE void
|
||||
lws_plat_context_early_destroy(struct libwebsocket_context *context)
|
||||
{
|
||||
if (context->events) {
|
||||
WSACloseEvent(context->events[0]);
|
||||
free(context->events);
|
||||
}
|
||||
}
|
||||
|
||||
LWS_VISIBLE void
|
||||
lws_plat_context_late_destroy(struct libwebsocket_context *context)
|
||||
{
|
||||
WSACleanup();
|
||||
}
|
||||
|
||||
LWS_VISIBLE int
|
||||
interface_to_sa(struct libwebsocket_context *context,
|
||||
const char *ifname, struct sockaddr_in *addr, size_t addrlen)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
LWS_VISIBLE void
|
||||
lws_plat_insert_socket_into_fds(struct libwebsocket_context *context,
|
||||
struct libwebsocket *wsi)
|
||||
{
|
||||
context->fds[context->fds_count++].revents = 0;
|
||||
context->events[context->fds_count] = WSACreateEvent();
|
||||
WSAEventSelect(wsi->sock, context->events[context->fds_count], LWS_POLLIN);
|
||||
}
|
||||
|
||||
LWS_VISIBLE void
|
||||
lws_plat_delete_socket_from_fds(struct libwebsocket_context *context,
|
||||
struct libwebsocket *wsi, int m)
|
||||
{
|
||||
WSACloseEvent(context->events[m + 1]);
|
||||
context->events[m + 1] = context->events[context->fds_count + 1];
|
||||
}
|
||||
|
||||
LWS_VISIBLE void
|
||||
lws_plat_service_periodic(struct libwebsocket_context *context)
|
||||
{
|
||||
}
|
||||
|
||||
LWS_VISIBLE int
|
||||
lws_plat_change_pollfd(struct libwebsocket_context *context,
|
||||
struct libwebsocket *wsi, struct libwebsocket_pollfd *pfd)
|
||||
{
|
||||
long networkevents = LWS_POLLOUT | LWS_POLLHUP;
|
||||
|
||||
if ((pfd->events & LWS_POLLIN))
|
||||
networkevents |= LWS_POLLIN;
|
||||
|
||||
if (WSAEventSelect(wsi->sock,
|
||||
context->events[wsi->position_in_fds_table + 1],
|
||||
networkevents) != SOCKET_ERROR)
|
||||
return 0;
|
||||
|
||||
lwsl_err("WSAEventSelect() failed with error %d\n", LWS_ERRNO);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
LWS_VISIBLE HANDLE
|
||||
lws_plat_open_file(const char* filename, unsigned long* filelen)
|
||||
{
|
||||
HANDLE ret;
|
||||
WCHAR buffer[MAX_PATH];
|
||||
|
||||
MultiByteToWideChar(CP_UTF8, 0, filename, -1, buffer,
|
||||
sizeof(buffer) / sizeof(buffer[0]));
|
||||
ret = CreateFileW(buffer, GENERIC_READ, FILE_SHARE_READ,
|
||||
NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
|
||||
if (ret != LWS_INVALID_FILE)
|
||||
*filelen = GetFileSize(ret, NULL);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
LWS_VISIBLE const char *
|
||||
lws_plat_inet_ntop(int af, const void *src, char *dst, int cnt)
|
||||
{
|
||||
WCHAR *buffer;
|
||||
DWORD bufferlen = cnt;
|
||||
BOOL ok = FALSE;
|
||||
|
||||
buffer = malloc(bufferlen);
|
||||
if (!buffer) {
|
||||
lwsl_err("Out of memory\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (af == AF_INET) {
|
||||
struct sockaddr_in srcaddr;
|
||||
bzero(&srcaddr, sizeof(srcaddr));
|
||||
srcaddr.sin_family = AF_INET;
|
||||
memcpy(&(srcaddr.sin_addr), src, sizeof(srcaddr.sin_addr));
|
||||
|
||||
if (!WSAAddressToStringW((struct sockaddr*)&srcaddr, sizeof(srcaddr), 0, buffer, &bufferlen))
|
||||
ok = TRUE;
|
||||
#ifdef LWS_USE_IPV6
|
||||
} else if (af == AF_INET6) {
|
||||
struct sockaddr_in6 srcaddr;
|
||||
bzero(&srcaddr, sizeof(srcaddr));
|
||||
srcaddr.sin6_family = AF_INET6;
|
||||
memcpy(&(srcaddr.sin6_addr), src, sizeof(srcaddr.sin6_addr));
|
||||
|
||||
if (!WSAAddressToStringW((struct sockaddr*)&srcaddr, sizeof(srcaddr), 0, buffer, &bufferlen))
|
||||
ok = TRUE;
|
||||
#endif
|
||||
} else
|
||||
lwsl_err("Unsupported type\n");
|
||||
|
||||
if (!ok) {
|
||||
int rv = WSAGetLastError();
|
||||
lwsl_err("WSAAddressToString() : %d\n", rv);
|
||||
} else {
|
||||
if (WideCharToMultiByte(CP_ACP, 0, buffer, bufferlen, dst, cnt, 0, NULL) <= 0)
|
||||
ok = FALSE;
|
||||
}
|
||||
|
||||
free(buffer);
|
||||
return ok ? dst : NULL;
|
||||
}
|
||||
316
dependencies/libwebsockets/lib/minilex.c
vendored
Normal file
316
dependencies/libwebsockets/lib/minilex.c
vendored
Normal file
@ -0,0 +1,316 @@
|
||||
/*
|
||||
* minilex.c
|
||||
*
|
||||
* High efficiency lexical state parser
|
||||
*
|
||||
* Copyright (C)2011-2014 Andy Green <andy@warmcat.com>
|
||||
*
|
||||
* Licensed under LGPL2
|
||||
*
|
||||
* Usage: gcc minilex.c -o minilex && ./minilex > lextable.h
|
||||
*
|
||||
* Run it twice to test parsing on the generated table on stderr
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
/* set of parsable strings -- ALL LOWER CASE */
|
||||
|
||||
const char *set[] = {
|
||||
"get ",
|
||||
"post ",
|
||||
"options ",
|
||||
"host:",
|
||||
"connection:",
|
||||
"sec-websocket-key1:",
|
||||
"sec-websocket-key2:",
|
||||
"sec-websocket-protocol:",
|
||||
"upgrade:",
|
||||
"origin:",
|
||||
"sec-websocket-draft:",
|
||||
"\x0d\x0a",
|
||||
|
||||
"sec-websocket-key:",
|
||||
"sec-websocket-version:",
|
||||
"sec-websocket-origin:",
|
||||
|
||||
"sec-websocket-extensions:",
|
||||
|
||||
"sec-websocket-accept:",
|
||||
"sec-websocket-nonce:",
|
||||
"http/1.1 ",
|
||||
|
||||
"accept:",
|
||||
"access-control-request-headers:",
|
||||
"if-modified-since:",
|
||||
"if-none-match:",
|
||||
"accept-encoding:",
|
||||
"accept-language:",
|
||||
"pragma:",
|
||||
"cache-control:",
|
||||
"authorization:",
|
||||
"cookie:",
|
||||
"content-length:",
|
||||
"content-type:",
|
||||
"date:",
|
||||
"range:",
|
||||
"referer:",
|
||||
"", /* not matchable */
|
||||
|
||||
};
|
||||
|
||||
/*
|
||||
* b7 = 0 = 1-byte seq
|
||||
* 0x08 = fail
|
||||
* 2-byte seq
|
||||
* 0x00 - 0x07, then terminal as given in 2nd byte
|
||||
3-byte seq
|
||||
* no match: go fwd 3 byte, match: jump fwd by amt in +1/+2 bytes
|
||||
* = 1 = 1-byte seq
|
||||
* no match: die, match go fwd 1 byte
|
||||
*/
|
||||
|
||||
unsigned char lextable[] = {
|
||||
#include "lextable.h"
|
||||
};
|
||||
|
||||
#define PARALLEL 30
|
||||
|
||||
struct state {
|
||||
char c[PARALLEL];
|
||||
int state[PARALLEL];
|
||||
int count;
|
||||
int bytepos;
|
||||
|
||||
int real_pos;
|
||||
};
|
||||
|
||||
struct state state[1000];
|
||||
int next = 1;
|
||||
|
||||
#define FAIL_CHAR 0x08
|
||||
|
||||
int lextable_decode(int pos, char c)
|
||||
{
|
||||
|
||||
while (1) {
|
||||
if (lextable[pos] & (1 << 7)) { /* 1-byte, fail on mismatch */
|
||||
if ((lextable[pos] & 0x7f) != c)
|
||||
return -1;
|
||||
/* fall thru */
|
||||
pos++;
|
||||
if (lextable[pos] == FAIL_CHAR)
|
||||
return -1;
|
||||
return pos;
|
||||
} else { /* b7 = 0, end or 3-byte */
|
||||
if (lextable[pos] < FAIL_CHAR) /* terminal marker */
|
||||
return pos;
|
||||
|
||||
if (lextable[pos] == c) /* goto */
|
||||
return pos + (lextable[pos + 1]) +
|
||||
(lextable[pos + 2] << 8);
|
||||
/* fall thru goto */
|
||||
pos += 3;
|
||||
/* continue */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
int n = 0;
|
||||
int m = 0;
|
||||
int prev;
|
||||
char c;
|
||||
int walk;
|
||||
int saw;
|
||||
int y;
|
||||
int j;
|
||||
int pos = 0;
|
||||
|
||||
while (n < sizeof(set) / sizeof(set[0])) {
|
||||
|
||||
m = 0;
|
||||
walk = 0;
|
||||
prev = 0;
|
||||
|
||||
if (set[n][0] == '\0') {
|
||||
n++;
|
||||
continue;
|
||||
}
|
||||
|
||||
while (set[n][m]) {
|
||||
|
||||
saw = 0;
|
||||
for (y = 0; y < state[walk].count; y++)
|
||||
if (state[walk].c[y] == set[n][m]) {
|
||||
/* exists -- go forward */
|
||||
walk = state[walk].state[y];
|
||||
saw = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
if (saw)
|
||||
goto again;
|
||||
|
||||
/* something we didn't see before */
|
||||
|
||||
state[walk].c[state[walk].count] = set[n][m];
|
||||
|
||||
state[walk].state[state[walk].count] = next;
|
||||
state[walk].count++;
|
||||
walk = next++;
|
||||
again:
|
||||
m++;
|
||||
}
|
||||
|
||||
state[walk].c[0] = n++;
|
||||
state[walk].state[0] = 0; /* terminal marker */
|
||||
state[walk].count = 1;
|
||||
}
|
||||
|
||||
walk = 0;
|
||||
for (n = 0; n < next; n++) {
|
||||
state[n].bytepos = walk;
|
||||
walk += (2 * state[n].count);
|
||||
}
|
||||
|
||||
/* compute everyone's position first */
|
||||
|
||||
pos = 0;
|
||||
walk = 0;
|
||||
for (n = 0; n < next; n++) {
|
||||
|
||||
state[n].real_pos = pos;
|
||||
|
||||
for (m = 0; m < state[n].count; m++) {
|
||||
|
||||
if (state[n].state[m] == 0)
|
||||
pos += 2; /* terminal marker */
|
||||
else { /* c is a character */
|
||||
if ((state[state[n].state[m]].bytepos -
|
||||
walk) == 2)
|
||||
pos++;
|
||||
else {
|
||||
pos += 3;
|
||||
if (m == state[n].count - 1)
|
||||
pos++; /* fail */
|
||||
}
|
||||
}
|
||||
walk += 2;
|
||||
}
|
||||
}
|
||||
|
||||
walk = 0;
|
||||
pos = 0;
|
||||
for (n = 0; n < next; n++) {
|
||||
for (m = 0; m < state[n].count; m++) {
|
||||
|
||||
if (!m)
|
||||
fprintf(stdout, "/* pos %04x: %3d */ ",
|
||||
state[n].real_pos, n);
|
||||
else
|
||||
fprintf(stdout, " ");
|
||||
|
||||
y = state[n].c[m];
|
||||
saw = state[n].state[m];
|
||||
|
||||
if (saw == 0) { // c is a terminal then
|
||||
|
||||
if (y > 0x7ff) {
|
||||
fprintf(stderr, "terminal too big\n");
|
||||
return 2;
|
||||
}
|
||||
|
||||
fprintf(stdout, " 0x%02X, 0x%02X "
|
||||
" "
|
||||
"/* - terminal marker %2d - */,\n",
|
||||
y >> 8, y & 0xff, y & 0x7f);
|
||||
pos += 2;
|
||||
walk += 2;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* c is a character */
|
||||
|
||||
prev = y &0x7f;
|
||||
if (prev < 32 || prev > 126)
|
||||
prev = '.';
|
||||
|
||||
|
||||
if ((state[saw].bytepos - walk) == 2) {
|
||||
fprintf(stdout, " 0x%02X /* '%c' -> */,\n",
|
||||
y | 0x80, prev);
|
||||
pos++;
|
||||
walk += 2;
|
||||
continue;
|
||||
}
|
||||
|
||||
j = state[saw].real_pos - pos;
|
||||
|
||||
if (j > 0xffff) {
|
||||
fprintf(stderr,
|
||||
"Jump > 64K bytes ahead (%d to %d)\n",
|
||||
state[n].real_pos, state[saw].real_pos);
|
||||
return 1;
|
||||
}
|
||||
fprintf(stdout, " 0x%02X /* '%c' */, 0x%02X, 0x%02X "
|
||||
"/* (to 0x%04X state %3d) */,\n",
|
||||
y, prev,
|
||||
j & 0xff, j >> 8,
|
||||
state[saw].real_pos, saw);
|
||||
pos += 3;
|
||||
|
||||
if (m == state[n].count - 1) {
|
||||
fprintf(stdout,
|
||||
" 0x%02X, /* fail */\n",
|
||||
FAIL_CHAR);
|
||||
pos++; /* fail */
|
||||
}
|
||||
|
||||
walk += 2;
|
||||
}
|
||||
}
|
||||
|
||||
fprintf(stdout, "/* total size %d bytes */\n", pos);
|
||||
|
||||
/*
|
||||
* Try to parse every legal input string
|
||||
*/
|
||||
|
||||
for (n = 0; n < sizeof(set) / sizeof(set[0]); n++) {
|
||||
walk = 0;
|
||||
m = 0;
|
||||
y = -1;
|
||||
|
||||
if (set[n][0] == '\0')
|
||||
continue;
|
||||
|
||||
fprintf(stderr, " trying '%s'\n", set[n]);
|
||||
|
||||
while (set[n][m]) {
|
||||
walk = lextable_decode(walk, set[n][m]);
|
||||
if (walk < 0) {
|
||||
fprintf(stderr, "failed\n");
|
||||
return 3;
|
||||
}
|
||||
|
||||
if (lextable[walk] < FAIL_CHAR) {
|
||||
y = (lextable[walk] << 8) + lextable[walk + 1];
|
||||
break;
|
||||
}
|
||||
m++;
|
||||
}
|
||||
|
||||
if (y != n) {
|
||||
fprintf(stderr, "decode failed %d\n", y);
|
||||
return 4;
|
||||
}
|
||||
}
|
||||
|
||||
fprintf(stderr, "All decode OK\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
571
dependencies/libwebsockets/lib/output.c
vendored
Normal file
571
dependencies/libwebsockets/lib/output.c
vendored
Normal file
@ -0,0 +1,571 @@
|
||||
/*
|
||||
* libwebsockets - small server side websockets and web server implementation
|
||||
*
|
||||
* Copyright (C) 2010-2014 Andy Green <andy@warmcat.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation:
|
||||
* version 2.1 of the License.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
* MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "private-libwebsockets.h"
|
||||
|
||||
static int
|
||||
libwebsocket_0405_frame_mask_generate(struct libwebsocket *wsi)
|
||||
{
|
||||
int n;
|
||||
|
||||
/* fetch the per-frame nonce */
|
||||
|
||||
n = libwebsockets_get_random(wsi->protocol->owning_server,
|
||||
wsi->u.ws.frame_masking_nonce_04, 4);
|
||||
if (n != 4) {
|
||||
lwsl_parser("Unable to read from random device %s %d\n",
|
||||
SYSTEM_RANDOM_FILEPATH, n);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* start masking from first byte of masking key buffer */
|
||||
wsi->u.ws.frame_mask_index = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef _DEBUG
|
||||
|
||||
LWS_VISIBLE void lwsl_hexdump(void *vbuf, size_t len)
|
||||
{
|
||||
int n;
|
||||
int m;
|
||||
int start;
|
||||
unsigned char *buf = (unsigned char *)vbuf;
|
||||
char line[80];
|
||||
char *p;
|
||||
|
||||
lwsl_parser("\n");
|
||||
|
||||
for (n = 0; n < len;) {
|
||||
start = n;
|
||||
p = line;
|
||||
|
||||
p += sprintf(p, "%04X: ", start);
|
||||
|
||||
for (m = 0; m < 16 && n < len; m++)
|
||||
p += sprintf(p, "%02X ", buf[n++]);
|
||||
while (m++ < 16)
|
||||
p += sprintf(p, " ");
|
||||
|
||||
p += sprintf(p, " ");
|
||||
|
||||
for (m = 0; m < 16 && (start + m) < len; m++) {
|
||||
if (buf[start + m] >= ' ' && buf[start + m] < 127)
|
||||
*p++ = buf[start + m];
|
||||
else
|
||||
*p++ = '.';
|
||||
}
|
||||
while (m++ < 16)
|
||||
*p++ = ' ';
|
||||
|
||||
*p++ = '\n';
|
||||
*p = '\0';
|
||||
lwsl_debug("%s", line);
|
||||
}
|
||||
lwsl_debug("\n");
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
* notice this returns number of bytes consumed, or -1
|
||||
*/
|
||||
|
||||
int lws_issue_raw(struct libwebsocket *wsi, unsigned char *buf, size_t len)
|
||||
{
|
||||
struct libwebsocket_context *context = wsi->protocol->owning_server;
|
||||
int n;
|
||||
size_t real_len = len;
|
||||
int m;
|
||||
|
||||
if (!len)
|
||||
return 0;
|
||||
/* just ignore sends after we cleared the truncation buffer */
|
||||
if (wsi->state == WSI_STATE_FLUSHING_STORED_SEND_BEFORE_CLOSE &&
|
||||
!wsi->truncated_send_len)
|
||||
return len;
|
||||
|
||||
if (wsi->truncated_send_len && (buf < wsi->truncated_send_malloc ||
|
||||
buf > (wsi->truncated_send_malloc +
|
||||
wsi->truncated_send_len +
|
||||
wsi->truncated_send_offset))) {
|
||||
lwsl_err("****** %x Sending new, pending truncated ...\n", wsi);
|
||||
assert(0);
|
||||
}
|
||||
|
||||
m = lws_ext_callback_for_each_active(wsi,
|
||||
LWS_EXT_CALLBACK_PACKET_TX_DO_SEND, &buf, len);
|
||||
if (m < 0)
|
||||
return -1;
|
||||
if (m) /* handled */ {
|
||||
n = m;
|
||||
goto handle_truncated_send;
|
||||
}
|
||||
if (wsi->sock < 0)
|
||||
lwsl_warn("** error invalid sock but expected to send\n");
|
||||
|
||||
/*
|
||||
* nope, send it on the socket directly
|
||||
*/
|
||||
lws_latency_pre(context, wsi);
|
||||
n = lws_ssl_capable_write(wsi, buf, len);
|
||||
lws_latency(context, wsi, "send lws_issue_raw", n, n == len);
|
||||
|
||||
switch (n) {
|
||||
case LWS_SSL_CAPABLE_ERROR:
|
||||
return -1;
|
||||
case LWS_SSL_CAPABLE_MORE_SERVICE:
|
||||
/* nothing got sent, not fatal, retry the whole thing later */
|
||||
n = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
handle_truncated_send:
|
||||
/*
|
||||
* we were already handling a truncated send?
|
||||
*/
|
||||
if (wsi->truncated_send_len) {
|
||||
lwsl_info("***** %x partial send moved on by %d (vs %d)\n",
|
||||
wsi, n, real_len);
|
||||
wsi->truncated_send_offset += n;
|
||||
wsi->truncated_send_len -= n;
|
||||
|
||||
if (!wsi->truncated_send_len) {
|
||||
lwsl_info("***** %x partial send completed\n", wsi);
|
||||
/* done with it, but don't free it */
|
||||
n = real_len;
|
||||
if (wsi->state == WSI_STATE_FLUSHING_STORED_SEND_BEFORE_CLOSE) {
|
||||
lwsl_info("***** %x signalling to close now\n", wsi);
|
||||
return -1; /* retry closing now */
|
||||
}
|
||||
}
|
||||
/* always callback on writeable */
|
||||
libwebsocket_callback_on_writable(
|
||||
wsi->protocol->owning_server, wsi);
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
if (n == real_len)
|
||||
/* what we just sent went out cleanly */
|
||||
return n;
|
||||
|
||||
if (n && wsi->u.ws.clean_buffer)
|
||||
/*
|
||||
* This buffer unaffected by extension rewriting.
|
||||
* It means the user code is expected to deal with
|
||||
* partial sends. (lws knows the header was already
|
||||
* sent, so on next send will just resume sending
|
||||
* payload)
|
||||
*/
|
||||
return n;
|
||||
|
||||
/*
|
||||
* Newly truncated send. Buffer the remainder (it will get
|
||||
* first priority next time the socket is writable)
|
||||
*/
|
||||
lwsl_info("***** %x new partial sent %d from %d total\n",
|
||||
wsi, n, real_len);
|
||||
|
||||
/*
|
||||
* - if we still have a suitable malloc lying around, use it
|
||||
* - or, if too small, reallocate it
|
||||
* - or, if no buffer, create it
|
||||
*/
|
||||
if (!wsi->truncated_send_malloc ||
|
||||
real_len - n > wsi->truncated_send_allocation) {
|
||||
if (wsi->truncated_send_malloc)
|
||||
free(wsi->truncated_send_malloc);
|
||||
|
||||
wsi->truncated_send_allocation = real_len - n;
|
||||
wsi->truncated_send_malloc = malloc(real_len - n);
|
||||
if (!wsi->truncated_send_malloc) {
|
||||
lwsl_err("truncated send: unable to malloc %d\n",
|
||||
real_len - n);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
wsi->truncated_send_offset = 0;
|
||||
wsi->truncated_send_len = real_len - n;
|
||||
memcpy(wsi->truncated_send_malloc, buf + n, real_len - n);
|
||||
|
||||
/* since something buffered, force it to get another chance to send */
|
||||
libwebsocket_callback_on_writable(wsi->protocol->owning_server, wsi);
|
||||
|
||||
return real_len;
|
||||
}
|
||||
|
||||
/**
|
||||
* libwebsocket_write() - Apply protocol then write data to client
|
||||
* @wsi: Websocket instance (available from user callback)
|
||||
* @buf: The data to send. For data being sent on a websocket
|
||||
* connection (ie, not default http), this buffer MUST have
|
||||
* LWS_SEND_BUFFER_PRE_PADDING bytes valid BEFORE the pointer
|
||||
* and an additional LWS_SEND_BUFFER_POST_PADDING bytes valid
|
||||
* in the buffer after (buf + len). This is so the protocol
|
||||
* header and trailer data can be added in-situ.
|
||||
* @len: Count of the data bytes in the payload starting from buf
|
||||
* @protocol: Use LWS_WRITE_HTTP to reply to an http connection, and one
|
||||
* of LWS_WRITE_BINARY or LWS_WRITE_TEXT to send appropriate
|
||||
* data on a websockets connection. Remember to allow the extra
|
||||
* bytes before and after buf if LWS_WRITE_BINARY or LWS_WRITE_TEXT
|
||||
* are used.
|
||||
*
|
||||
* This function provides the way to issue data back to the client
|
||||
* for both http and websocket protocols.
|
||||
*
|
||||
* In the case of sending using websocket protocol, be sure to allocate
|
||||
* valid storage before and after buf as explained above. This scheme
|
||||
* allows maximum efficiency of sending data and protocol in a single
|
||||
* packet while not burdening the user code with any protocol knowledge.
|
||||
*
|
||||
* Return may be -1 for a fatal error needing connection close, or a
|
||||
* positive number reflecting the amount of bytes actually sent. This
|
||||
* can be less than the requested number of bytes due to OS memory
|
||||
* pressure at any given time.
|
||||
*/
|
||||
|
||||
LWS_VISIBLE int libwebsocket_write(struct libwebsocket *wsi, unsigned char *buf,
|
||||
size_t len, enum libwebsocket_write_protocol protocol)
|
||||
{
|
||||
int n;
|
||||
int pre = 0;
|
||||
int post = 0;
|
||||
int masked7 = wsi->mode == LWS_CONNMODE_WS_CLIENT;
|
||||
unsigned char *dropmask = NULL;
|
||||
unsigned char is_masked_bit = 0;
|
||||
size_t orig_len = len;
|
||||
struct lws_tokens eff_buf;
|
||||
|
||||
if (len == 0 && protocol != LWS_WRITE_CLOSE &&
|
||||
protocol != LWS_WRITE_PING && protocol != LWS_WRITE_PONG) {
|
||||
lwsl_warn("zero length libwebsocket_write attempt\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (protocol == LWS_WRITE_HTTP)
|
||||
goto send_raw;
|
||||
|
||||
/* websocket protocol, either binary or text */
|
||||
|
||||
if (wsi->state != WSI_STATE_ESTABLISHED)
|
||||
return -1;
|
||||
|
||||
/* if we are continuing a frame that already had its header done */
|
||||
|
||||
if (wsi->u.ws.inside_frame)
|
||||
goto do_more_inside_frame;
|
||||
|
||||
/* if he wants all partials buffered, never have a clean_buffer */
|
||||
wsi->u.ws.clean_buffer = !wsi->protocol->no_buffer_all_partial_tx;
|
||||
|
||||
/*
|
||||
* give a chance to the extensions to modify payload
|
||||
* pre-TX mangling is not allowed to truncate
|
||||
*/
|
||||
eff_buf.token = (char *)buf;
|
||||
eff_buf.token_len = len;
|
||||
|
||||
switch (protocol) {
|
||||
case LWS_WRITE_PING:
|
||||
case LWS_WRITE_PONG:
|
||||
case LWS_WRITE_CLOSE:
|
||||
break;
|
||||
default:
|
||||
if (lws_ext_callback_for_each_active(wsi,
|
||||
LWS_EXT_CALLBACK_PAYLOAD_TX, &eff_buf, 0) < 0)
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* an extension did something we need to keep... for example, if
|
||||
* compression extension, it has already updated its state according
|
||||
* to this being issued
|
||||
*/
|
||||
if ((char *)buf != eff_buf.token)
|
||||
/*
|
||||
* extension recreated it:
|
||||
* need to buffer this if not all sent
|
||||
*/
|
||||
wsi->u.ws.clean_buffer = 0;
|
||||
|
||||
buf = (unsigned char *)eff_buf.token;
|
||||
len = eff_buf.token_len;
|
||||
|
||||
switch (wsi->ietf_spec_revision) {
|
||||
case 13:
|
||||
|
||||
if (masked7) {
|
||||
pre += 4;
|
||||
dropmask = &buf[0 - pre];
|
||||
is_masked_bit = 0x80;
|
||||
}
|
||||
|
||||
switch (protocol & 0xf) {
|
||||
case LWS_WRITE_TEXT:
|
||||
n = LWS_WS_OPCODE_07__TEXT_FRAME;
|
||||
break;
|
||||
case LWS_WRITE_BINARY:
|
||||
n = LWS_WS_OPCODE_07__BINARY_FRAME;
|
||||
break;
|
||||
case LWS_WRITE_CONTINUATION:
|
||||
n = LWS_WS_OPCODE_07__CONTINUATION;
|
||||
break;
|
||||
|
||||
case LWS_WRITE_CLOSE:
|
||||
n = LWS_WS_OPCODE_07__CLOSE;
|
||||
|
||||
/*
|
||||
* 06+ has a 2-byte status code in network order
|
||||
* we can do this because we demand post-buf
|
||||
*/
|
||||
|
||||
if (wsi->u.ws.close_reason) {
|
||||
/* reason codes count as data bytes */
|
||||
buf -= 2;
|
||||
buf[0] = wsi->u.ws.close_reason >> 8;
|
||||
buf[1] = wsi->u.ws.close_reason;
|
||||
len += 2;
|
||||
}
|
||||
break;
|
||||
case LWS_WRITE_PING:
|
||||
n = LWS_WS_OPCODE_07__PING;
|
||||
break;
|
||||
case LWS_WRITE_PONG:
|
||||
n = LWS_WS_OPCODE_07__PONG;
|
||||
break;
|
||||
default:
|
||||
lwsl_warn("lws_write: unknown write opc / protocol\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!(protocol & LWS_WRITE_NO_FIN))
|
||||
n |= 1 << 7;
|
||||
|
||||
if (len < 126) {
|
||||
pre += 2;
|
||||
buf[-pre] = n;
|
||||
buf[-pre + 1] = len | is_masked_bit;
|
||||
} else {
|
||||
if (len < 65536) {
|
||||
pre += 4;
|
||||
buf[-pre] = n;
|
||||
buf[-pre + 1] = 126 | is_masked_bit;
|
||||
buf[-pre + 2] = len >> 8;
|
||||
buf[-pre + 3] = len;
|
||||
} else {
|
||||
pre += 10;
|
||||
buf[-pre] = n;
|
||||
buf[-pre + 1] = 127 | is_masked_bit;
|
||||
#if defined __LP64__
|
||||
buf[-pre + 2] = (len >> 56) & 0x7f;
|
||||
buf[-pre + 3] = len >> 48;
|
||||
buf[-pre + 4] = len >> 40;
|
||||
buf[-pre + 5] = len >> 32;
|
||||
#else
|
||||
buf[-pre + 2] = 0;
|
||||
buf[-pre + 3] = 0;
|
||||
buf[-pre + 4] = 0;
|
||||
buf[-pre + 5] = 0;
|
||||
#endif
|
||||
buf[-pre + 6] = len >> 24;
|
||||
buf[-pre + 7] = len >> 16;
|
||||
buf[-pre + 8] = len >> 8;
|
||||
buf[-pre + 9] = len;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
do_more_inside_frame:
|
||||
|
||||
/*
|
||||
* Deal with masking if we are in client -> server direction and
|
||||
* the protocol demands it
|
||||
*/
|
||||
|
||||
if (wsi->mode == LWS_CONNMODE_WS_CLIENT) {
|
||||
|
||||
if (!wsi->u.ws.inside_frame)
|
||||
if (libwebsocket_0405_frame_mask_generate(wsi)) {
|
||||
lwsl_err("frame mask generation failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* in v7, just mask the payload
|
||||
*/
|
||||
if (dropmask) { /* never set if already inside frame */
|
||||
for (n = 4; n < (int)len + 4; n++)
|
||||
dropmask[n] = dropmask[n] ^
|
||||
wsi->u.ws.frame_masking_nonce_04[
|
||||
(wsi->u.ws.frame_mask_index++) & 3];
|
||||
|
||||
/* copy the frame nonce into place */
|
||||
memcpy(dropmask, wsi->u.ws.frame_masking_nonce_04, 4);
|
||||
}
|
||||
}
|
||||
|
||||
send_raw:
|
||||
switch (protocol) {
|
||||
case LWS_WRITE_CLOSE:
|
||||
/* lwsl_hexdump(&buf[-pre], len + post); */
|
||||
case LWS_WRITE_HTTP:
|
||||
case LWS_WRITE_PONG:
|
||||
case LWS_WRITE_PING:
|
||||
return lws_issue_raw(wsi, (unsigned char *)buf - pre,
|
||||
len + pre + post);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
wsi->u.ws.inside_frame = 1;
|
||||
|
||||
/*
|
||||
* give any active extensions a chance to munge the buffer
|
||||
* before send. We pass in a pointer to an lws_tokens struct
|
||||
* prepared with the default buffer and content length that's in
|
||||
* there. Rather than rewrite the default buffer, extensions
|
||||
* that expect to grow the buffer can adapt .token to
|
||||
* point to their own per-connection buffer in the extension
|
||||
* user allocation. By default with no extensions or no
|
||||
* extension callback handling, just the normal input buffer is
|
||||
* used then so it is efficient.
|
||||
*
|
||||
* callback returns 1 in case it wants to spill more buffers
|
||||
*
|
||||
* This takes care of holding the buffer if send is incomplete, ie,
|
||||
* if wsi->u.ws.clean_buffer is 0 (meaning an extension meddled with
|
||||
* the buffer). If wsi->u.ws.clean_buffer is 1, it will instead
|
||||
* return to the user code how much OF THE USER BUFFER was consumed.
|
||||
*/
|
||||
|
||||
n = lws_issue_raw_ext_access(wsi, buf - pre, len + pre + post);
|
||||
if (n <= 0)
|
||||
return n;
|
||||
|
||||
if (n == len + pre + post) {
|
||||
/* everything in the buffer was handled (or rebuffered...) */
|
||||
wsi->u.ws.inside_frame = 0;
|
||||
return orig_len;
|
||||
}
|
||||
|
||||
/*
|
||||
* it is how many bytes of user buffer got sent... may be < orig_len
|
||||
* in which case callback when writable has already been arranged
|
||||
* and user code can call libwebsocket_write() again with the rest
|
||||
* later.
|
||||
*/
|
||||
|
||||
return n - (pre + post);
|
||||
}
|
||||
|
||||
LWS_VISIBLE int libwebsockets_serve_http_file_fragment(
|
||||
struct libwebsocket_context *context, struct libwebsocket *wsi)
|
||||
{
|
||||
int n;
|
||||
int m;
|
||||
|
||||
while (!lws_send_pipe_choked(wsi)) {
|
||||
|
||||
if (wsi->truncated_send_len) {
|
||||
if (lws_issue_raw(wsi, wsi->truncated_send_malloc +
|
||||
wsi->truncated_send_offset,
|
||||
wsi->truncated_send_len) < 0) {
|
||||
lwsl_info("closing from libwebsockets_serve_http_file_fragment\n");
|
||||
return -1;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (wsi->u.http.filepos == wsi->u.http.filelen)
|
||||
goto all_sent;
|
||||
|
||||
compatible_file_read(n, wsi->u.http.fd, context->service_buffer,
|
||||
sizeof(context->service_buffer));
|
||||
if (n < 0)
|
||||
return -1; /* caller will close */
|
||||
if (n) {
|
||||
m = libwebsocket_write(wsi, context->service_buffer, n,
|
||||
LWS_WRITE_HTTP);
|
||||
if (m < 0)
|
||||
return -1;
|
||||
|
||||
wsi->u.http.filepos += m;
|
||||
if (m != n)
|
||||
/* adjust for what was not sent */
|
||||
compatible_file_seek_cur(wsi->u.http.fd, m - n);
|
||||
}
|
||||
all_sent:
|
||||
if (!wsi->truncated_send_len &&
|
||||
wsi->u.http.filepos == wsi->u.http.filelen) {
|
||||
wsi->state = WSI_STATE_HTTP;
|
||||
|
||||
if (wsi->protocol->callback)
|
||||
/* ignore callback returned value */
|
||||
user_callback_handle_rxflow(
|
||||
wsi->protocol->callback, context, wsi,
|
||||
LWS_CALLBACK_HTTP_FILE_COMPLETION,
|
||||
wsi->user_space, NULL, 0);
|
||||
return 1; /* >0 indicates completed */
|
||||
}
|
||||
}
|
||||
|
||||
lwsl_info("choked before able to send whole file (post)\n");
|
||||
libwebsocket_callback_on_writable(context, wsi);
|
||||
|
||||
return 0; /* indicates further processing must be done */
|
||||
}
|
||||
|
||||
LWS_VISIBLE int
|
||||
lws_ssl_capable_read_no_ssl(struct libwebsocket *wsi, unsigned char *buf, int len)
|
||||
{
|
||||
int n;
|
||||
|
||||
n = recv(wsi->sock, buf, len, 0);
|
||||
if (n >= 0)
|
||||
return n;
|
||||
|
||||
lwsl_warn("error on reading from skt\n");
|
||||
return LWS_SSL_CAPABLE_ERROR;
|
||||
}
|
||||
|
||||
LWS_VISIBLE int
|
||||
lws_ssl_capable_write_no_ssl(struct libwebsocket *wsi, unsigned char *buf, int len)
|
||||
{
|
||||
int n;
|
||||
|
||||
n = send(wsi->sock, buf, len, 0);
|
||||
if (n >= 0)
|
||||
return n;
|
||||
|
||||
if (LWS_ERRNO == LWS_EAGAIN ||
|
||||
LWS_ERRNO == LWS_EWOULDBLOCK ||
|
||||
LWS_ERRNO == LWS_EINTR) {
|
||||
if (LWS_ERRNO == LWS_EWOULDBLOCK)
|
||||
lws_set_blocking_send(wsi);
|
||||
|
||||
return LWS_SSL_CAPABLE_MORE_SERVICE;
|
||||
}
|
||||
lwsl_debug("ERROR writing len %d to skt %d\n", len, n);
|
||||
return LWS_SSL_CAPABLE_ERROR;
|
||||
}
|
||||
1008
dependencies/libwebsockets/lib/parsers.c
vendored
Normal file
1008
dependencies/libwebsockets/lib/parsers.c
vendored
Normal file
File diff suppressed because it is too large
Load Diff
239
dependencies/libwebsockets/lib/pollfd.c
vendored
Normal file
239
dependencies/libwebsockets/lib/pollfd.c
vendored
Normal file
@ -0,0 +1,239 @@
|
||||
/*
|
||||
* libwebsockets - small server side websockets and web server implementation
|
||||
*
|
||||
* Copyright (C) 2010-2014 Andy Green <andy@warmcat.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation:
|
||||
* version 2.1 of the License.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
* MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "private-libwebsockets.h"
|
||||
|
||||
int
|
||||
insert_wsi_socket_into_fds(struct libwebsocket_context *context,
|
||||
struct libwebsocket *wsi)
|
||||
{
|
||||
struct libwebsocket_pollargs pa = { wsi->sock, LWS_POLLIN, 0 };
|
||||
|
||||
if (context->fds_count >= context->max_fds) {
|
||||
lwsl_err("Too many fds (%d)\n", context->max_fds);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (wsi->sock >= context->max_fds) {
|
||||
lwsl_err("Socket fd %d is too high (%d)\n",
|
||||
wsi->sock, context->max_fds);
|
||||
return 1;
|
||||
}
|
||||
|
||||
assert(wsi);
|
||||
assert(wsi->sock >= 0);
|
||||
|
||||
lwsl_info("insert_wsi_socket_into_fds: wsi=%p, sock=%d, fds pos=%d\n",
|
||||
wsi, wsi->sock, context->fds_count);
|
||||
|
||||
context->protocols[0].callback(context, wsi,
|
||||
LWS_CALLBACK_LOCK_POLL,
|
||||
wsi->user_space, (void *) &pa, 0);
|
||||
|
||||
context->lws_lookup[wsi->sock] = wsi;
|
||||
wsi->position_in_fds_table = context->fds_count;
|
||||
context->fds[context->fds_count].fd = wsi->sock;
|
||||
context->fds[context->fds_count].events = LWS_POLLIN;
|
||||
|
||||
lws_plat_insert_socket_into_fds(context, wsi);
|
||||
|
||||
/* external POLL support via protocol 0 */
|
||||
context->protocols[0].callback(context, wsi,
|
||||
LWS_CALLBACK_ADD_POLL_FD,
|
||||
wsi->user_space, (void *) &pa, 0);
|
||||
|
||||
context->protocols[0].callback(context, wsi,
|
||||
LWS_CALLBACK_UNLOCK_POLL,
|
||||
wsi->user_space, (void *)&pa, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
remove_wsi_socket_from_fds(struct libwebsocket_context *context,
|
||||
struct libwebsocket *wsi)
|
||||
{
|
||||
int m;
|
||||
struct libwebsocket_pollargs pa = { wsi->sock, 0, 0 };
|
||||
|
||||
lws_libev_io(context, wsi, LWS_EV_STOP | LWS_EV_READ | LWS_EV_WRITE);
|
||||
|
||||
if (!--context->fds_count) {
|
||||
context->protocols[0].callback(context, wsi,
|
||||
LWS_CALLBACK_LOCK_POLL,
|
||||
wsi->user_space, (void *) &pa, 0);
|
||||
goto do_ext;
|
||||
}
|
||||
|
||||
if (wsi->sock > context->max_fds) {
|
||||
lwsl_err("Socket fd %d too high (%d)\n",
|
||||
wsi->sock, context->max_fds);
|
||||
return 1;
|
||||
}
|
||||
|
||||
lwsl_info("%s: wsi=%p, sock=%d, fds pos=%d\n", __func__,
|
||||
wsi, wsi->sock, wsi->position_in_fds_table);
|
||||
|
||||
context->protocols[0].callback(context, wsi,
|
||||
LWS_CALLBACK_LOCK_POLL,
|
||||
wsi->user_space, (void *)&pa, 0);
|
||||
|
||||
m = wsi->position_in_fds_table; /* replace the contents for this */
|
||||
|
||||
/* have the last guy take up the vacant slot */
|
||||
context->fds[m] = context->fds[context->fds_count];
|
||||
|
||||
lws_plat_delete_socket_from_fds(context, wsi, m);
|
||||
|
||||
/*
|
||||
* end guy's fds_lookup entry remains unchanged
|
||||
* (still same fd pointing to same wsi)
|
||||
*/
|
||||
/* end guy's "position in fds table" changed */
|
||||
context->lws_lookup[context->fds[context->fds_count].fd]->
|
||||
position_in_fds_table = m;
|
||||
/* deletion guy's lws_lookup entry needs nuking */
|
||||
context->lws_lookup[wsi->sock] = NULL;
|
||||
/* removed wsi has no position any more */
|
||||
wsi->position_in_fds_table = -1;
|
||||
|
||||
do_ext:
|
||||
/* remove also from external POLL support via protocol 0 */
|
||||
if (wsi->sock) {
|
||||
context->protocols[0].callback(context, wsi,
|
||||
LWS_CALLBACK_DEL_POLL_FD, wsi->user_space,
|
||||
(void *) &pa, 0);
|
||||
}
|
||||
context->protocols[0].callback(context, wsi,
|
||||
LWS_CALLBACK_UNLOCK_POLL,
|
||||
wsi->user_space, (void *) &pa, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
lws_change_pollfd(struct libwebsocket *wsi, int _and, int _or)
|
||||
{
|
||||
struct libwebsocket_context *context = wsi->protocol->owning_server;
|
||||
int tid;
|
||||
int sampled_tid;
|
||||
struct libwebsocket_pollfd *pfd;
|
||||
struct libwebsocket_pollargs pa;
|
||||
|
||||
pfd = &context->fds[wsi->position_in_fds_table];
|
||||
pa.fd = wsi->sock;
|
||||
|
||||
context->protocols[0].callback(context, wsi,
|
||||
LWS_CALLBACK_LOCK_POLL, wsi->user_space, (void *) &pa, 0);
|
||||
|
||||
pa.prev_events = pfd->events;
|
||||
pa.events = pfd->events = (pfd->events & ~_and) | _or;
|
||||
|
||||
context->protocols[0].callback(context, wsi,
|
||||
LWS_CALLBACK_CHANGE_MODE_POLL_FD,
|
||||
wsi->user_space, (void *) &pa, 0);
|
||||
|
||||
/*
|
||||
* if we changed something in this pollfd...
|
||||
* ... and we're running in a different thread context
|
||||
* than the service thread...
|
||||
* ... and the service thread is waiting ...
|
||||
* then cancel it to force a restart with our changed events
|
||||
*/
|
||||
if (pa.prev_events != pa.events) {
|
||||
|
||||
if (lws_plat_change_pollfd(context, wsi, pfd)) {
|
||||
lwsl_info("%s failed\n", __func__);
|
||||
return 1;
|
||||
}
|
||||
|
||||
sampled_tid = context->service_tid;
|
||||
if (sampled_tid) {
|
||||
tid = context->protocols[0].callback(context, NULL,
|
||||
LWS_CALLBACK_GET_THREAD_ID, NULL, NULL, 0);
|
||||
if (tid != sampled_tid)
|
||||
libwebsocket_cancel_service(context);
|
||||
}
|
||||
}
|
||||
|
||||
context->protocols[0].callback(context, wsi,
|
||||
LWS_CALLBACK_UNLOCK_POLL, wsi->user_space, (void *) &pa, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* libwebsocket_callback_on_writable() - Request a callback when this socket
|
||||
* becomes able to be written to without
|
||||
* blocking
|
||||
*
|
||||
* @context: libwebsockets context
|
||||
* @wsi: Websocket connection instance to get callback for
|
||||
*/
|
||||
|
||||
LWS_VISIBLE int
|
||||
libwebsocket_callback_on_writable(struct libwebsocket_context *context,
|
||||
struct libwebsocket *wsi)
|
||||
{
|
||||
if (lws_ext_callback_for_each_active(wsi,
|
||||
LWS_EXT_CALLBACK_REQUEST_ON_WRITEABLE, NULL, 0))
|
||||
return 1;
|
||||
|
||||
if (wsi->position_in_fds_table < 0) {
|
||||
lwsl_err("%s: failed to find socket %d\n", __func__, wsi->sock);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (lws_change_pollfd(wsi, 0, LWS_POLLOUT))
|
||||
return -1;
|
||||
|
||||
lws_libev_io(context, wsi, LWS_EV_START | LWS_EV_WRITE);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* libwebsocket_callback_on_writable_all_protocol() - Request a callback for
|
||||
* all connections using the given protocol when it
|
||||
* becomes possible to write to each socket without
|
||||
* blocking in turn.
|
||||
*
|
||||
* @protocol: Protocol whose connections will get callbacks
|
||||
*/
|
||||
|
||||
LWS_VISIBLE int
|
||||
libwebsocket_callback_on_writable_all_protocol(
|
||||
const struct libwebsocket_protocols *protocol)
|
||||
{
|
||||
struct libwebsocket_context *context = protocol->owning_server;
|
||||
int n;
|
||||
struct libwebsocket *wsi;
|
||||
|
||||
for (n = 0; n < context->fds_count; n++) {
|
||||
wsi = context->lws_lookup[context->fds[n].fd];
|
||||
if (!wsi)
|
||||
continue;
|
||||
if (wsi->protocol == protocol)
|
||||
libwebsocket_callback_on_writable(context, wsi);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
912
dependencies/libwebsockets/lib/private-libwebsockets.h
vendored
Normal file
912
dependencies/libwebsockets/lib/private-libwebsockets.h
vendored
Normal file
@ -0,0 +1,912 @@
|
||||
/*
|
||||
* libwebsockets - small server side websockets and web server implementation
|
||||
*
|
||||
* Copyright (C) 2010 - 2013 Andy Green <andy@warmcat.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation:
|
||||
* version 2.1 of the License.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
* MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
/* System introspection configs */
|
||||
#ifdef CMAKE_BUILD
|
||||
#include "lws_config.h"
|
||||
#else
|
||||
#if defined(WIN32) || defined(_WIN32)
|
||||
#define inline __inline
|
||||
#else /* not WIN32 */
|
||||
#include "config.h"
|
||||
|
||||
#endif /* not WIN32 */
|
||||
#endif /* not CMAKE */
|
||||
|
||||
#ifdef HAVE_SYS_TYPES_H
|
||||
#include <sys/types.h>
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <ctype.h>
|
||||
#include <limits.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#ifdef HAVE_SYS_STAT_H
|
||||
#include <sys/stat.h>
|
||||
#endif
|
||||
|
||||
#if defined(WIN32) || defined(_WIN32)
|
||||
#define LWS_NO_DAEMONIZE
|
||||
#define LWS_ERRNO WSAGetLastError()
|
||||
#define LWS_EAGAIN WSAEWOULDBLOCK
|
||||
#define LWS_EALREADY WSAEALREADY
|
||||
#define LWS_EINPROGRESS WSAEINPROGRESS
|
||||
#define LWS_EINTR WSAEINTR
|
||||
#define LWS_EISCONN WSAEISCONN
|
||||
#define LWS_EWOULDBLOCK WSAEWOULDBLOCK
|
||||
#define LWS_POLLHUP (FD_CLOSE)
|
||||
#define LWS_POLLIN (FD_READ | FD_ACCEPT)
|
||||
#define LWS_POLLOUT (FD_WRITE)
|
||||
#define MSG_NOSIGNAL 0
|
||||
#define SHUT_RDWR SD_BOTH
|
||||
#define SOL_TCP IPPROTO_TCP
|
||||
|
||||
#define compatible_close(fd) closesocket(fd)
|
||||
#define compatible_file_close(fd) CloseHandle(fd)
|
||||
#define compatible_file_seek_cur(fd, offset) SetFilePointer(fd, offset, NULL, FILE_CURRENT)
|
||||
#define compatible_file_read(amount, fd, buf, len) {\
|
||||
DWORD _amount; \
|
||||
if (!ReadFile(fd, buf, len, &_amount, NULL)) \
|
||||
amount = -1; \
|
||||
else \
|
||||
amount = _amount; \
|
||||
}
|
||||
#define lws_set_blocking_send(wsi) wsi->sock_send_blocking = TRUE
|
||||
#include <winsock2.h>
|
||||
#include <windows.h>
|
||||
#include <tchar.h>
|
||||
#ifdef HAVE_IN6ADDR_H
|
||||
#include <in6addr.h>
|
||||
#endif
|
||||
#include <mstcpip.h>
|
||||
|
||||
#ifndef __func__
|
||||
#define __func__ __FUNCTION__
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32_WCE
|
||||
#define vsnprintf _vsnprintf
|
||||
#endif
|
||||
|
||||
#define LWS_INVALID_FILE INVALID_HANDLE_VALUE
|
||||
#else /* not windows --> */
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <netdb.h>
|
||||
#include <signal.h>
|
||||
#include <strings.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#ifdef LWS_BUILTIN_GETIFADDRS
|
||||
#include <getifaddrs.h>
|
||||
#else
|
||||
#include <ifaddrs.h>
|
||||
#endif
|
||||
#include <sys/syslog.h>
|
||||
#include <sys/un.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netdb.h>
|
||||
#ifndef LWS_NO_FORK
|
||||
#ifdef HAVE_SYS_PRCTL_H
|
||||
#include <sys/prctl.h>
|
||||
#endif
|
||||
#endif
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/tcp.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <poll.h>
|
||||
#ifdef LWS_USE_LIBEV
|
||||
#include <ev.h>
|
||||
#endif /* LWS_USE_LIBEV */
|
||||
|
||||
#include <sys/mman.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#define LWS_ERRNO errno
|
||||
#define LWS_EAGAIN EAGAIN
|
||||
#define LWS_EALREADY EALREADY
|
||||
#define LWS_EINPROGRESS EINPROGRESS
|
||||
#define LWS_EINTR EINTR
|
||||
#define LWS_EISCONN EISCONN
|
||||
#define LWS_EWOULDBLOCK EWOULDBLOCK
|
||||
#define LWS_INVALID_FILE -1
|
||||
#define LWS_POLLHUP (POLLHUP|POLLERR)
|
||||
#define LWS_POLLIN (POLLIN)
|
||||
#define LWS_POLLOUT (POLLOUT)
|
||||
#define compatible_close(fd) close(fd)
|
||||
#define compatible_file_close(fd) close(fd)
|
||||
#define compatible_file_seek_cur(fd, offset) lseek(fd, offset, SEEK_CUR)
|
||||
#define compatible_file_read(amount, fd, buf, len) \
|
||||
amount = read(fd, buf, len);
|
||||
#define lws_set_blocking_send(wsi)
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_BZERO
|
||||
#define bzero(b, len) (memset((b), '\0', (len)), (void) 0)
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_STRERROR
|
||||
#define strerror(x) ""
|
||||
#endif
|
||||
|
||||
#ifdef LWS_OPENSSL_SUPPORT
|
||||
#ifdef USE_CYASSL
|
||||
#include <cyassl/openssl/ssl.h>
|
||||
#include <cyassl/error.h>
|
||||
unsigned char *
|
||||
SHA1(const unsigned char *d, size_t n, unsigned char *md);
|
||||
#else
|
||||
#include <openssl/ssl.h>
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/md5.h>
|
||||
#include <openssl/sha.h>
|
||||
#endif /* not USE_CYASSL */
|
||||
#endif
|
||||
|
||||
#include "libwebsockets.h"
|
||||
|
||||
#if defined(WIN32) || defined(_WIN32)
|
||||
|
||||
#ifndef BIG_ENDIAN
|
||||
#define BIG_ENDIAN 4321 /* to show byte order (taken from gcc) */
|
||||
#endif
|
||||
#ifndef LITTLE_ENDIAN
|
||||
#define LITTLE_ENDIAN 1234
|
||||
#endif
|
||||
#ifndef BYTE_ORDER
|
||||
#define BYTE_ORDER LITTLE_ENDIAN
|
||||
#endif
|
||||
typedef unsigned __int64 u_int64_t;
|
||||
|
||||
#undef __P
|
||||
#ifndef __P
|
||||
#if __STDC__
|
||||
#define __P(protos) protos
|
||||
#else
|
||||
#define __P(protos) ()
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#else
|
||||
|
||||
#include <sys/stat.h>
|
||||
#include <sys/cdefs.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#if defined(__APPLE__)
|
||||
#include <machine/endian.h>
|
||||
#elif defined(__FreeBSD__)
|
||||
#include <sys/endian.h>
|
||||
#elif defined(__linux__)
|
||||
#include <endian.h>
|
||||
#endif
|
||||
|
||||
#if !defined(BYTE_ORDER)
|
||||
# define BYTE_ORDER __BYTE_ORDER
|
||||
#endif
|
||||
#if !defined(LITTLE_ENDIAN)
|
||||
# define LITTLE_ENDIAN __LITTLE_ENDIAN
|
||||
#endif
|
||||
#if !defined(BIG_ENDIAN)
|
||||
# define BIG_ENDIAN __BIG_ENDIAN
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Mac OSX as well as iOS do not define the MSG_NOSIGNAL flag,
|
||||
* but happily have something equivalent in the SO_NOSIGPIPE flag.
|
||||
*/
|
||||
#ifdef __APPLE__
|
||||
#define MSG_NOSIGNAL SO_NOSIGPIPE
|
||||
#endif
|
||||
|
||||
#ifndef LWS_MAX_HEADER_LEN
|
||||
#define LWS_MAX_HEADER_LEN 1024
|
||||
#endif
|
||||
#ifndef LWS_MAX_PROTOCOLS
|
||||
#define LWS_MAX_PROTOCOLS 5
|
||||
#endif
|
||||
#ifndef LWS_MAX_EXTENSIONS_ACTIVE
|
||||
#define LWS_MAX_EXTENSIONS_ACTIVE 3
|
||||
#endif
|
||||
#ifndef SPEC_LATEST_SUPPORTED
|
||||
#define SPEC_LATEST_SUPPORTED 13
|
||||
#endif
|
||||
#ifndef AWAITING_TIMEOUT
|
||||
#define AWAITING_TIMEOUT 5
|
||||
#endif
|
||||
#ifndef CIPHERS_LIST_STRING
|
||||
#define CIPHERS_LIST_STRING "DEFAULT"
|
||||
#endif
|
||||
#ifndef LWS_SOMAXCONN
|
||||
#define LWS_SOMAXCONN SOMAXCONN
|
||||
#endif
|
||||
|
||||
#define MAX_WEBSOCKET_04_KEY_LEN 128
|
||||
#define LWS_MAX_SOCKET_IO_BUF 4096
|
||||
|
||||
#ifndef SYSTEM_RANDOM_FILEPATH
|
||||
#define SYSTEM_RANDOM_FILEPATH "/dev/urandom"
|
||||
#endif
|
||||
#ifndef LWS_MAX_ZLIB_CONN_BUFFER
|
||||
#define LWS_MAX_ZLIB_CONN_BUFFER (64 * 1024)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* if not in a connection storm, check for incoming
|
||||
* connections this many normal connection services
|
||||
*/
|
||||
#define LWS_LISTEN_SERVICE_MODULO 10
|
||||
|
||||
enum lws_websocket_opcodes_07 {
|
||||
LWS_WS_OPCODE_07__CONTINUATION = 0,
|
||||
LWS_WS_OPCODE_07__TEXT_FRAME = 1,
|
||||
LWS_WS_OPCODE_07__BINARY_FRAME = 2,
|
||||
|
||||
LWS_WS_OPCODE_07__NOSPEC__MUX = 7,
|
||||
|
||||
/* control extensions 8+ */
|
||||
|
||||
LWS_WS_OPCODE_07__CLOSE = 8,
|
||||
LWS_WS_OPCODE_07__PING = 9,
|
||||
LWS_WS_OPCODE_07__PONG = 0xa,
|
||||
};
|
||||
|
||||
|
||||
enum lws_connection_states {
|
||||
WSI_STATE_HTTP,
|
||||
WSI_STATE_HTTP_ISSUING_FILE,
|
||||
WSI_STATE_HTTP_HEADERS,
|
||||
WSI_STATE_HTTP_BODY,
|
||||
WSI_STATE_DEAD_SOCKET,
|
||||
WSI_STATE_ESTABLISHED,
|
||||
WSI_STATE_CLIENT_UNCONNECTED,
|
||||
WSI_STATE_RETURNED_CLOSE_ALREADY,
|
||||
WSI_STATE_AWAITING_CLOSE_ACK,
|
||||
WSI_STATE_FLUSHING_STORED_SEND_BEFORE_CLOSE,
|
||||
};
|
||||
|
||||
enum lws_rx_parse_state {
|
||||
LWS_RXPS_NEW,
|
||||
|
||||
LWS_RXPS_04_MASK_NONCE_1,
|
||||
LWS_RXPS_04_MASK_NONCE_2,
|
||||
LWS_RXPS_04_MASK_NONCE_3,
|
||||
|
||||
LWS_RXPS_04_FRAME_HDR_1,
|
||||
LWS_RXPS_04_FRAME_HDR_LEN,
|
||||
LWS_RXPS_04_FRAME_HDR_LEN16_2,
|
||||
LWS_RXPS_04_FRAME_HDR_LEN16_1,
|
||||
LWS_RXPS_04_FRAME_HDR_LEN64_8,
|
||||
LWS_RXPS_04_FRAME_HDR_LEN64_7,
|
||||
LWS_RXPS_04_FRAME_HDR_LEN64_6,
|
||||
LWS_RXPS_04_FRAME_HDR_LEN64_5,
|
||||
LWS_RXPS_04_FRAME_HDR_LEN64_4,
|
||||
LWS_RXPS_04_FRAME_HDR_LEN64_3,
|
||||
LWS_RXPS_04_FRAME_HDR_LEN64_2,
|
||||
LWS_RXPS_04_FRAME_HDR_LEN64_1,
|
||||
|
||||
LWS_RXPS_07_COLLECT_FRAME_KEY_1,
|
||||
LWS_RXPS_07_COLLECT_FRAME_KEY_2,
|
||||
LWS_RXPS_07_COLLECT_FRAME_KEY_3,
|
||||
LWS_RXPS_07_COLLECT_FRAME_KEY_4,
|
||||
|
||||
LWS_RXPS_PAYLOAD_UNTIL_LENGTH_EXHAUSTED
|
||||
};
|
||||
|
||||
|
||||
enum connection_mode {
|
||||
LWS_CONNMODE_HTTP_SERVING,
|
||||
LWS_CONNMODE_HTTP_SERVING_ACCEPTED, /* actual HTTP service going on */
|
||||
LWS_CONNMODE_PRE_WS_SERVING_ACCEPT,
|
||||
|
||||
LWS_CONNMODE_WS_SERVING,
|
||||
LWS_CONNMODE_WS_CLIENT,
|
||||
|
||||
/* transient, ssl delay hiding */
|
||||
LWS_CONNMODE_SSL_ACK_PENDING,
|
||||
|
||||
/* transient modes */
|
||||
LWS_CONNMODE_WS_CLIENT_WAITING_CONNECT,
|
||||
LWS_CONNMODE_WS_CLIENT_WAITING_PROXY_REPLY,
|
||||
LWS_CONNMODE_WS_CLIENT_ISSUE_HANDSHAKE,
|
||||
LWS_CONNMODE_WS_CLIENT_ISSUE_HANDSHAKE2,
|
||||
LWS_CONNMODE_WS_CLIENT_WAITING_SSL,
|
||||
LWS_CONNMODE_WS_CLIENT_WAITING_SERVER_REPLY,
|
||||
LWS_CONNMODE_WS_CLIENT_WAITING_EXTENSION_CONNECT,
|
||||
LWS_CONNMODE_WS_CLIENT_PENDING_CANDIDATE_CHILD,
|
||||
|
||||
/* special internal types */
|
||||
LWS_CONNMODE_SERVER_LISTENER,
|
||||
};
|
||||
|
||||
enum {
|
||||
LWS_RXFLOW_ALLOW = (1 << 0),
|
||||
LWS_RXFLOW_PENDING_CHANGE = (1 << 1),
|
||||
};
|
||||
|
||||
struct libwebsocket_protocols;
|
||||
struct libwebsocket;
|
||||
|
||||
#ifdef LWS_USE_LIBEV
|
||||
struct lws_io_watcher {
|
||||
struct ev_io watcher;
|
||||
struct libwebsocket_context* context;
|
||||
};
|
||||
|
||||
struct lws_signal_watcher {
|
||||
struct ev_signal watcher;
|
||||
struct libwebsocket_context* context;
|
||||
};
|
||||
#endif /* LWS_USE_LIBEV */
|
||||
|
||||
struct libwebsocket_context {
|
||||
#ifdef _WIN32
|
||||
WSAEVENT *events;
|
||||
#endif
|
||||
struct libwebsocket_pollfd *fds;
|
||||
struct libwebsocket **lws_lookup; /* fd to wsi */
|
||||
int fds_count;
|
||||
#ifdef LWS_USE_LIBEV
|
||||
struct ev_loop* io_loop;
|
||||
struct lws_io_watcher w_accept;
|
||||
struct lws_signal_watcher w_sigint;
|
||||
#endif /* LWS_USE_LIBEV */
|
||||
int max_fds;
|
||||
int listen_port;
|
||||
const char *iface;
|
||||
char http_proxy_address[128];
|
||||
char canonical_hostname[128];
|
||||
unsigned int http_proxy_port;
|
||||
unsigned int options;
|
||||
time_t last_timeout_check_s;
|
||||
|
||||
/*
|
||||
* usable by anything in the service code, but only if the scope
|
||||
* does not last longer than the service action (since next service
|
||||
* of any socket can likewise use it and overwrite)
|
||||
*/
|
||||
unsigned char service_buffer[LWS_MAX_SOCKET_IO_BUF];
|
||||
|
||||
int started_with_parent;
|
||||
|
||||
int fd_random;
|
||||
int listen_service_modulo;
|
||||
int listen_service_count;
|
||||
int listen_service_fd;
|
||||
int listen_service_extraseen;
|
||||
|
||||
/*
|
||||
* set to the Thread ID that's doing the service loop just before entry
|
||||
* to poll indicates service thread likely idling in poll()
|
||||
* volatile because other threads may check it as part of processing
|
||||
* for pollfd event change.
|
||||
*/
|
||||
volatile int service_tid;
|
||||
#ifndef _WIN32
|
||||
int dummy_pipe_fds[2];
|
||||
#endif
|
||||
|
||||
int ka_time;
|
||||
int ka_probes;
|
||||
int ka_interval;
|
||||
|
||||
#ifdef LWS_LATENCY
|
||||
unsigned long worst_latency;
|
||||
char worst_latency_info[256];
|
||||
#endif
|
||||
|
||||
#ifdef LWS_OPENSSL_SUPPORT
|
||||
int use_ssl;
|
||||
int allow_non_ssl_on_ssl_port;
|
||||
SSL_CTX *ssl_ctx;
|
||||
SSL_CTX *ssl_client_ctx;
|
||||
#endif
|
||||
struct libwebsocket_protocols *protocols;
|
||||
int count_protocols;
|
||||
#ifndef LWS_NO_EXTENSIONS
|
||||
struct libwebsocket_extension *extensions;
|
||||
#endif
|
||||
struct lws_token_limits *token_limits;
|
||||
void *user_space;
|
||||
};
|
||||
|
||||
enum {
|
||||
LWS_EV_READ = (1 << 0),
|
||||
LWS_EV_WRITE = (1 << 1),
|
||||
LWS_EV_START = (1 << 2),
|
||||
LWS_EV_STOP = (1 << 3),
|
||||
};
|
||||
|
||||
#ifdef LWS_USE_LIBEV
|
||||
#define LWS_LIBEV_ENABLED(context) (context->options & LWS_SERVER_OPTION_LIBEV)
|
||||
LWS_EXTERN void lws_feature_status_libev(struct lws_context_creation_info *info);
|
||||
LWS_EXTERN void
|
||||
lws_libev_accept(struct libwebsocket_context *context,
|
||||
struct libwebsocket *new_wsi, int accept_fd);
|
||||
LWS_EXTERN void
|
||||
lws_libev_io(struct libwebsocket_context *context,
|
||||
struct libwebsocket *wsi, int flags);
|
||||
LWS_EXTERN int
|
||||
lws_libev_init_fd_table(struct libwebsocket_context *context);
|
||||
LWS_EXTERN void
|
||||
lws_libev_run(struct libwebsocket_context *context);
|
||||
#else
|
||||
#define LWS_LIBEV_ENABLED(context) (0)
|
||||
#define lws_feature_status_libev(_a) \
|
||||
lwsl_notice("libev support not compiled in\n")
|
||||
#define lws_libev_accept(_a, _b, _c) ((void) 0)
|
||||
#define lws_libev_io(_a, _b, _c) ((void) 0)
|
||||
#define lws_libev_init_fd_table(_a) (0)
|
||||
#define lws_libev_run(_a) ((void) 0)
|
||||
#endif
|
||||
|
||||
#ifdef LWS_USE_IPV6
|
||||
#define LWS_IPV6_ENABLED(context) (!(context->options & LWS_SERVER_OPTION_DISABLE_IPV6))
|
||||
#else
|
||||
#define LWS_IPV6_ENABLED(context) (0)
|
||||
#endif
|
||||
|
||||
enum uri_path_states {
|
||||
URIPS_IDLE,
|
||||
URIPS_SEEN_SLASH,
|
||||
URIPS_SEEN_SLASH_DOT,
|
||||
URIPS_SEEN_SLASH_DOT_DOT,
|
||||
URIPS_ARGUMENTS,
|
||||
};
|
||||
|
||||
enum uri_esc_states {
|
||||
URIES_IDLE,
|
||||
URIES_SEEN_PERCENT,
|
||||
URIES_SEEN_PERCENT_H1,
|
||||
};
|
||||
|
||||
/*
|
||||
* This is totally opaque to code using the library. It's exported as a
|
||||
* forward-reference pointer-only declaration; the user can use the pointer with
|
||||
* other APIs to get information out of it.
|
||||
*/
|
||||
|
||||
struct lws_fragments {
|
||||
unsigned short offset;
|
||||
unsigned short len;
|
||||
unsigned char next_frag_index;
|
||||
};
|
||||
|
||||
struct allocated_headers {
|
||||
unsigned short next_frag_index;
|
||||
unsigned short pos;
|
||||
unsigned char frag_index[WSI_TOKEN_COUNT];
|
||||
struct lws_fragments frags[WSI_TOKEN_COUNT * 2];
|
||||
char data[LWS_MAX_HEADER_LEN];
|
||||
#ifndef LWS_NO_CLIENT
|
||||
char initial_handshake_hash_base64[30];
|
||||
unsigned short c_port;
|
||||
#endif
|
||||
};
|
||||
|
||||
struct _lws_http_mode_related {
|
||||
struct allocated_headers *ah; /* mirroring _lws_header_related */
|
||||
#if defined(WIN32) || defined(_WIN32)
|
||||
HANDLE fd;
|
||||
#else
|
||||
int fd;
|
||||
#endif
|
||||
unsigned long filepos;
|
||||
unsigned long filelen;
|
||||
|
||||
int content_length;
|
||||
int content_length_seen;
|
||||
int body_index;
|
||||
unsigned char *post_buffer;
|
||||
};
|
||||
|
||||
struct _lws_header_related {
|
||||
struct allocated_headers *ah;
|
||||
short lextable_pos;
|
||||
unsigned short current_token_limit;
|
||||
unsigned char parser_state; /* enum lws_token_indexes */
|
||||
enum uri_path_states ups;
|
||||
enum uri_esc_states ues;
|
||||
char esc_stash;
|
||||
};
|
||||
|
||||
struct _lws_websocket_related {
|
||||
char *rx_user_buffer;
|
||||
int rx_user_buffer_head;
|
||||
unsigned char frame_masking_nonce_04[4];
|
||||
unsigned char frame_mask_index;
|
||||
size_t rx_packet_length;
|
||||
unsigned char opcode;
|
||||
unsigned int final:1;
|
||||
unsigned char rsv;
|
||||
unsigned int frame_is_binary:1;
|
||||
unsigned int all_zero_nonce:1;
|
||||
short close_reason; /* enum lws_close_status */
|
||||
unsigned char *rxflow_buffer;
|
||||
int rxflow_len;
|
||||
int rxflow_pos;
|
||||
unsigned int rxflow_change_to:2;
|
||||
unsigned int this_frame_masked:1;
|
||||
unsigned int inside_frame:1; /* next write will be more of frame */
|
||||
unsigned int clean_buffer:1; /* buffer not rewritten by extension */
|
||||
};
|
||||
|
||||
struct libwebsocket {
|
||||
|
||||
/* lifetime members */
|
||||
|
||||
#ifdef LWS_USE_LIBEV
|
||||
struct lws_io_watcher w_read;
|
||||
struct lws_io_watcher w_write;
|
||||
#endif /* LWS_USE_LIBEV */
|
||||
const struct libwebsocket_protocols *protocol;
|
||||
#ifndef LWS_NO_EXTENSIONS
|
||||
struct libwebsocket_extension *
|
||||
active_extensions[LWS_MAX_EXTENSIONS_ACTIVE];
|
||||
void *active_extensions_user[LWS_MAX_EXTENSIONS_ACTIVE];
|
||||
unsigned char count_active_extensions;
|
||||
unsigned int extension_data_pending:1;
|
||||
#endif
|
||||
unsigned char ietf_spec_revision;
|
||||
|
||||
char mode; /* enum connection_mode */
|
||||
char state; /* enum lws_connection_states */
|
||||
char lws_rx_parse_state; /* enum lws_rx_parse_state */
|
||||
char rx_frame_type; /* enum libwebsocket_write_protocol */
|
||||
|
||||
unsigned int hdr_parsing_completed:1;
|
||||
unsigned int user_space_externally_allocated:1;
|
||||
|
||||
char pending_timeout; /* enum pending_timeout */
|
||||
time_t pending_timeout_limit;
|
||||
|
||||
int sock;
|
||||
int position_in_fds_table;
|
||||
#ifdef LWS_LATENCY
|
||||
unsigned long action_start;
|
||||
unsigned long latency_start;
|
||||
#endif
|
||||
|
||||
/* truncated send handling */
|
||||
unsigned char *truncated_send_malloc; /* non-NULL means buffering in progress */
|
||||
unsigned int truncated_send_allocation; /* size of malloc */
|
||||
unsigned int truncated_send_offset; /* where we are in terms of spilling */
|
||||
unsigned int truncated_send_len; /* how much is buffered */
|
||||
|
||||
void *user_space;
|
||||
|
||||
/* members with mutually exclusive lifetimes are unionized */
|
||||
|
||||
union u {
|
||||
struct _lws_http_mode_related http;
|
||||
struct _lws_header_related hdr;
|
||||
struct _lws_websocket_related ws;
|
||||
} u;
|
||||
|
||||
#ifdef LWS_OPENSSL_SUPPORT
|
||||
SSL *ssl;
|
||||
BIO *client_bio;
|
||||
unsigned int use_ssl:2;
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
BOOL sock_send_blocking;
|
||||
#endif
|
||||
};
|
||||
|
||||
LWS_EXTERN int log_level;
|
||||
|
||||
LWS_EXTERN void
|
||||
libwebsocket_close_and_free_session(struct libwebsocket_context *context,
|
||||
struct libwebsocket *wsi, enum lws_close_status);
|
||||
|
||||
LWS_EXTERN int
|
||||
remove_wsi_socket_from_fds(struct libwebsocket_context *context,
|
||||
struct libwebsocket *wsi);
|
||||
|
||||
#ifndef LWS_LATENCY
|
||||
static inline void lws_latency(struct libwebsocket_context *context,
|
||||
struct libwebsocket *wsi, const char *action,
|
||||
int ret, int completion) { while (0); }
|
||||
static inline void lws_latency_pre(struct libwebsocket_context *context,
|
||||
struct libwebsocket *wsi) { while (0); }
|
||||
#else
|
||||
#define lws_latency_pre(_context, _wsi) lws_latency(_context, _wsi, NULL, 0, 0)
|
||||
extern void
|
||||
lws_latency(struct libwebsocket_context *context,
|
||||
struct libwebsocket *wsi, const char *action,
|
||||
int ret, int completion);
|
||||
#endif
|
||||
|
||||
LWS_EXTERN int
|
||||
libwebsocket_client_rx_sm(struct libwebsocket *wsi, unsigned char c);
|
||||
|
||||
LWS_EXTERN int
|
||||
libwebsocket_parse(struct libwebsocket_context *context,
|
||||
struct libwebsocket *wsi, unsigned char c);
|
||||
|
||||
LWS_EXTERN int
|
||||
lws_b64_selftest(void);
|
||||
|
||||
LWS_EXTERN struct libwebsocket *
|
||||
wsi_from_fd(struct libwebsocket_context *context, int fd);
|
||||
|
||||
LWS_EXTERN int
|
||||
insert_wsi_socket_into_fds(struct libwebsocket_context *context,
|
||||
struct libwebsocket *wsi);
|
||||
|
||||
LWS_EXTERN int
|
||||
lws_issue_raw(struct libwebsocket *wsi, unsigned char *buf, size_t len);
|
||||
|
||||
|
||||
LWS_EXTERN int
|
||||
libwebsocket_service_timeout_check(struct libwebsocket_context *context,
|
||||
struct libwebsocket *wsi, unsigned int sec);
|
||||
|
||||
LWS_EXTERN struct libwebsocket *
|
||||
libwebsocket_client_connect_2(struct libwebsocket_context *context,
|
||||
struct libwebsocket *wsi);
|
||||
|
||||
LWS_EXTERN struct libwebsocket *
|
||||
libwebsocket_create_new_server_wsi(struct libwebsocket_context *context);
|
||||
|
||||
LWS_EXTERN char *
|
||||
libwebsockets_generate_client_handshake(struct libwebsocket_context *context,
|
||||
struct libwebsocket *wsi, char *pkt);
|
||||
|
||||
LWS_EXTERN int
|
||||
lws_handle_POLLOUT_event(struct libwebsocket_context *context,
|
||||
struct libwebsocket *wsi, struct libwebsocket_pollfd *pollfd);
|
||||
/*
|
||||
* EXTENSIONS
|
||||
*/
|
||||
|
||||
#ifndef LWS_NO_EXTENSIONS
|
||||
LWS_VISIBLE void
|
||||
lws_context_init_extensions(struct lws_context_creation_info *info,
|
||||
struct libwebsocket_context *context);
|
||||
LWS_EXTERN int
|
||||
lws_any_extension_handled(struct libwebsocket_context *context,
|
||||
struct libwebsocket *wsi,
|
||||
enum libwebsocket_extension_callback_reasons r,
|
||||
void *v, size_t len);
|
||||
|
||||
LWS_EXTERN int
|
||||
lws_ext_callback_for_each_active(struct libwebsocket *wsi, int reason,
|
||||
void *buf, int len);
|
||||
LWS_EXTERN int
|
||||
lws_ext_callback_for_each_extension_type(
|
||||
struct libwebsocket_context *context, struct libwebsocket *wsi,
|
||||
int reason, void *arg, int len);
|
||||
#else
|
||||
#define lws_any_extension_handled(_a, _b, _c, _d, _e) (0)
|
||||
#define lws_ext_callback_for_each_active(_a, _b, _c, _d) (0)
|
||||
#define lws_ext_callback_for_each_extension_type(_a, _b, _c, _d, _e) (0)
|
||||
#define lws_issue_raw_ext_access lws_issue_raw
|
||||
#define lws_context_init_extensions(_a, _b)
|
||||
#endif
|
||||
|
||||
LWS_EXTERN int
|
||||
lws_client_interpret_server_handshake(struct libwebsocket_context *context,
|
||||
struct libwebsocket *wsi);
|
||||
|
||||
LWS_EXTERN int
|
||||
libwebsocket_rx_sm(struct libwebsocket *wsi, unsigned char c);
|
||||
|
||||
LWS_EXTERN int
|
||||
lws_issue_raw_ext_access(struct libwebsocket *wsi,
|
||||
unsigned char *buf, size_t len);
|
||||
|
||||
LWS_EXTERN int
|
||||
_libwebsocket_rx_flow_control(struct libwebsocket *wsi);
|
||||
|
||||
LWS_EXTERN int
|
||||
user_callback_handle_rxflow(callback_function,
|
||||
struct libwebsocket_context *context,
|
||||
struct libwebsocket *wsi,
|
||||
enum libwebsocket_callback_reasons reason, void *user,
|
||||
void *in, size_t len);
|
||||
|
||||
LWS_EXTERN int
|
||||
lws_plat_set_socket_options(struct libwebsocket_context *context, int fd);
|
||||
|
||||
LWS_EXTERN int
|
||||
lws_allocate_header_table(struct libwebsocket *wsi);
|
||||
|
||||
LWS_EXTERN char *
|
||||
lws_hdr_simple_ptr(struct libwebsocket *wsi, enum lws_token_indexes h);
|
||||
|
||||
LWS_EXTERN int
|
||||
lws_hdr_simple_create(struct libwebsocket *wsi,
|
||||
enum lws_token_indexes h, const char *s);
|
||||
|
||||
LWS_EXTERN int
|
||||
libwebsocket_ensure_user_space(struct libwebsocket *wsi);
|
||||
|
||||
LWS_EXTERN int
|
||||
lws_change_pollfd(struct libwebsocket *wsi, int _and, int _or);
|
||||
|
||||
#ifndef LWS_NO_SERVER
|
||||
int lws_context_init_server(struct lws_context_creation_info *info,
|
||||
struct libwebsocket_context *context);
|
||||
LWS_EXTERN int handshake_0405(struct libwebsocket_context *context,
|
||||
struct libwebsocket *wsi);
|
||||
LWS_EXTERN int
|
||||
libwebsocket_interpret_incoming_packet(struct libwebsocket *wsi,
|
||||
unsigned char *buf, size_t len);
|
||||
LWS_EXTERN void
|
||||
lws_server_get_canonical_hostname(struct libwebsocket_context *context,
|
||||
struct lws_context_creation_info *info);
|
||||
#else
|
||||
#define lws_context_init_server(_a, _b) (0)
|
||||
#define libwebsocket_interpret_incoming_packet(_a, _b, _c) (0)
|
||||
#define lws_server_get_canonical_hostname(_a, _b)
|
||||
#endif
|
||||
|
||||
#ifndef LWS_NO_DAEMONIZE
|
||||
LWS_EXTERN int get_daemonize_pid();
|
||||
#else
|
||||
#define get_daemonize_pid() (0)
|
||||
#endif
|
||||
|
||||
LWS_EXTERN int interface_to_sa(struct libwebsocket_context *context,
|
||||
const char *ifname, struct sockaddr_in *addr, size_t addrlen);
|
||||
|
||||
LWS_EXTERN void lwsl_emit_stderr(int level, const char *line);
|
||||
|
||||
#ifdef _WIN32
|
||||
LWS_EXTERN HANDLE lws_plat_open_file(const char* filename, unsigned long* filelen);
|
||||
#else
|
||||
LWS_EXTERN int lws_plat_open_file(const char* filename, unsigned long* filelen);
|
||||
#endif
|
||||
|
||||
enum lws_ssl_capable_status {
|
||||
LWS_SSL_CAPABLE_ERROR = -1,
|
||||
LWS_SSL_CAPABLE_MORE_SERVICE = -2,
|
||||
};
|
||||
|
||||
#ifndef LWS_OPENSSL_SUPPORT
|
||||
#define LWS_SSL_ENABLED(context) (0)
|
||||
unsigned char *
|
||||
SHA1(const unsigned char *d, size_t n, unsigned char *md);
|
||||
#define lws_context_init_server_ssl(_a, _b) (0)
|
||||
#define lws_ssl_destroy(_a)
|
||||
#define lws_context_init_http2_ssl(_a)
|
||||
#define lws_ssl_pending(_a) (0)
|
||||
#define lws_ssl_capable_read lws_ssl_capable_read_no_ssl
|
||||
#define lws_ssl_capable_write lws_ssl_capable_write_no_ssl
|
||||
#define lws_server_socket_service_ssl(_a, _b, _c, _d, _e) (0)
|
||||
#define lws_ssl_close(_a) (0)
|
||||
#define lws_ssl_context_destroy(_a)
|
||||
#else
|
||||
#define LWS_SSL_ENABLED(context) (context->use_ssl)
|
||||
LWS_EXTERN int lws_ssl_pending(struct libwebsocket *wsi);
|
||||
LWS_EXTERN int openssl_websocket_private_data_index;
|
||||
LWS_EXTERN int
|
||||
lws_ssl_capable_read(struct libwebsocket *wsi, unsigned char *buf, int len);
|
||||
|
||||
LWS_EXTERN int
|
||||
lws_ssl_capable_write(struct libwebsocket *wsi, unsigned char *buf, int len);
|
||||
LWS_EXTERN int
|
||||
lws_server_socket_service_ssl(struct libwebsocket_context *context,
|
||||
struct libwebsocket **wsi, struct libwebsocket *new_wsi,
|
||||
int accept_fd, struct libwebsocket_pollfd *pollfd);
|
||||
LWS_EXTERN int
|
||||
lws_ssl_close(struct libwebsocket *wsi);
|
||||
LWS_EXTERN void
|
||||
lws_ssl_context_destroy(struct libwebsocket_context *context);
|
||||
#ifndef LWS_NO_SERVER
|
||||
LWS_EXTERN int
|
||||
lws_context_init_server_ssl(struct lws_context_creation_info *info,
|
||||
struct libwebsocket_context *context);
|
||||
#else
|
||||
#define lws_context_init_server_ssl(_a, _b) (0)
|
||||
#endif
|
||||
LWS_EXTERN void
|
||||
lws_ssl_destroy(struct libwebsocket_context *context);
|
||||
|
||||
/* HTTP2-related */
|
||||
|
||||
#ifdef LWS_USE_HTTP2
|
||||
LWS_EXTERN void
|
||||
lws_context_init_http2_ssl(struct libwebsocket_context *context);
|
||||
#else
|
||||
#define lws_context_init_http2_ssl(_a)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
LWS_EXTERN int
|
||||
lws_ssl_capable_read_no_ssl(struct libwebsocket *wsi, unsigned char *buf, int len);
|
||||
|
||||
LWS_EXTERN int
|
||||
lws_ssl_capable_write_no_ssl(struct libwebsocket *wsi, unsigned char *buf, int len);
|
||||
|
||||
#ifndef LWS_NO_CLIENT
|
||||
LWS_EXTERN int lws_client_socket_service(
|
||||
struct libwebsocket_context *context,
|
||||
struct libwebsocket *wsi, struct libwebsocket_pollfd *pollfd);
|
||||
#ifdef LWS_OPENSSL_SUPPORT
|
||||
LWS_EXTERN int lws_context_init_client_ssl(struct lws_context_creation_info *info,
|
||||
struct libwebsocket_context *context);
|
||||
#else
|
||||
#define lws_context_init_client_ssl(_a, _b) (0)
|
||||
#endif
|
||||
LWS_EXTERN int lws_handshake_client(struct libwebsocket *wsi, unsigned char **buf, size_t len);
|
||||
LWS_EXTERN void
|
||||
libwebsockets_decode_ssl_error(void);
|
||||
#else
|
||||
#define lws_context_init_client_ssl(_a, _b) (0)
|
||||
#define lws_handshake_client(_a, _b, _c) (0)
|
||||
#endif
|
||||
#ifndef LWS_NO_SERVER
|
||||
LWS_EXTERN int lws_server_socket_service(
|
||||
struct libwebsocket_context *context,
|
||||
struct libwebsocket *wsi, struct libwebsocket_pollfd *pollfd);
|
||||
LWS_EXTERN int _libwebsocket_rx_flow_control(struct libwebsocket *wsi);
|
||||
LWS_EXTERN int lws_handshake_server(struct libwebsocket_context *context,
|
||||
struct libwebsocket *wsi, unsigned char **buf, size_t len);
|
||||
#else
|
||||
#define lws_server_socket_service(_a, _b, _c) (0)
|
||||
#define _libwebsocket_rx_flow_control(_a) (0)
|
||||
#define lws_handshake_server(_a, _b, _c, _d) (0)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* lws_plat_
|
||||
*/
|
||||
LWS_EXTERN void
|
||||
lws_plat_delete_socket_from_fds(struct libwebsocket_context *context,
|
||||
struct libwebsocket *wsi, int m);
|
||||
LWS_EXTERN void
|
||||
lws_plat_insert_socket_into_fds(struct libwebsocket_context *context,
|
||||
struct libwebsocket *wsi);
|
||||
LWS_EXTERN void
|
||||
lws_plat_service_periodic(struct libwebsocket_context *context);
|
||||
|
||||
LWS_EXTERN int
|
||||
lws_plat_change_pollfd(struct libwebsocket_context *context,
|
||||
struct libwebsocket *wsi, struct libwebsocket_pollfd *pfd);
|
||||
LWS_EXTERN int
|
||||
lws_plat_context_early_init(void);
|
||||
LWS_EXTERN void
|
||||
lws_plat_context_early_destroy(struct libwebsocket_context *context);
|
||||
LWS_EXTERN void
|
||||
lws_plat_context_late_destroy(struct libwebsocket_context *context);
|
||||
LWS_EXTERN int
|
||||
lws_poll_listen_fd(struct libwebsocket_pollfd *fd);
|
||||
LWS_EXTERN int
|
||||
lws_plat_service(struct libwebsocket_context *context, int timeout_ms);
|
||||
LWS_EXTERN int
|
||||
lws_plat_init_fd_tables(struct libwebsocket_context *context);
|
||||
LWS_EXTERN void
|
||||
lws_plat_drop_app_privileges(struct lws_context_creation_info *info);
|
||||
LWS_EXTERN unsigned long long
|
||||
time_in_microseconds(void);
|
||||
LWS_EXTERN const char *
|
||||
lws_plat_inet_ntop(int af, const void *src, char *dst, int cnt);
|
||||
280
dependencies/libwebsockets/lib/server-handshake.c
vendored
Normal file
280
dependencies/libwebsockets/lib/server-handshake.c
vendored
Normal file
@ -0,0 +1,280 @@
|
||||
/*
|
||||
* libwebsockets - small server side websockets and web server implementation
|
||||
*
|
||||
* Copyright (C) 2010-2013 Andy Green <andy@warmcat.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation:
|
||||
* version 2.1 of the License.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
* MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "private-libwebsockets.h"
|
||||
|
||||
#define LWS_CPYAPP(ptr, str) { strcpy(ptr, str); ptr += strlen(str); }
|
||||
#ifndef LWS_NO_EXTENSIONS
|
||||
LWS_VISIBLE int
|
||||
lws_extension_server_handshake(struct libwebsocket_context *context,
|
||||
struct libwebsocket *wsi, char **p)
|
||||
{
|
||||
int n;
|
||||
char *c;
|
||||
char ext_name[128];
|
||||
struct libwebsocket_extension *ext;
|
||||
int ext_count = 0;
|
||||
int more = 1;
|
||||
|
||||
/*
|
||||
* Figure out which extensions the client has that we want to
|
||||
* enable on this connection, and give him back the list
|
||||
*/
|
||||
|
||||
if (!lws_hdr_total_length(wsi, WSI_TOKEN_EXTENSIONS))
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* break down the list of client extensions
|
||||
* and go through them
|
||||
*/
|
||||
|
||||
if (lws_hdr_copy(wsi, (char *)context->service_buffer,
|
||||
sizeof(context->service_buffer),
|
||||
WSI_TOKEN_EXTENSIONS) < 0)
|
||||
return 1;
|
||||
|
||||
c = (char *)context->service_buffer;
|
||||
lwsl_parser("WSI_TOKEN_EXTENSIONS = '%s'\n", c);
|
||||
wsi->count_active_extensions = 0;
|
||||
n = 0;
|
||||
while (more) {
|
||||
|
||||
if (*c && (*c != ',' && *c != ' ' && *c != '\t')) {
|
||||
ext_name[n] = *c++;
|
||||
if (n < sizeof(ext_name) - 1)
|
||||
n++;
|
||||
continue;
|
||||
}
|
||||
ext_name[n] = '\0';
|
||||
if (!*c)
|
||||
more = 0;
|
||||
else {
|
||||
c++;
|
||||
if (!n)
|
||||
continue;
|
||||
}
|
||||
|
||||
/* check a client's extension against our support */
|
||||
|
||||
ext = wsi->protocol->owning_server->extensions;
|
||||
|
||||
while (ext && ext->callback) {
|
||||
|
||||
if (strcmp(ext_name, ext->name)) {
|
||||
ext++;
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* oh, we do support this one he
|
||||
* asked for... but let's ask user
|
||||
* code if it's OK to apply it on this
|
||||
* particular connection + protocol
|
||||
*/
|
||||
|
||||
n = wsi->protocol->owning_server->
|
||||
protocols[0].callback(
|
||||
wsi->protocol->owning_server,
|
||||
wsi,
|
||||
LWS_CALLBACK_CONFIRM_EXTENSION_OKAY,
|
||||
wsi->user_space, ext_name, 0);
|
||||
|
||||
/*
|
||||
* zero return from callback means
|
||||
* go ahead and allow the extension,
|
||||
* it's what we get if the callback is
|
||||
* unhandled
|
||||
*/
|
||||
|
||||
if (n) {
|
||||
ext++;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* apply it */
|
||||
|
||||
if (ext_count)
|
||||
*(*p)++ = ',';
|
||||
else
|
||||
LWS_CPYAPP(*p,
|
||||
"\x0d\x0aSec-WebSocket-Extensions: ");
|
||||
*p += sprintf(*p, "%s", ext_name);
|
||||
ext_count++;
|
||||
|
||||
/* instantiate the extension on this conn */
|
||||
|
||||
wsi->active_extensions_user[
|
||||
wsi->count_active_extensions] =
|
||||
malloc(ext->per_session_data_size);
|
||||
if (wsi->active_extensions_user[
|
||||
wsi->count_active_extensions] == NULL) {
|
||||
lwsl_err("Out of mem\n");
|
||||
return 1;
|
||||
}
|
||||
memset(wsi->active_extensions_user[
|
||||
wsi->count_active_extensions], 0,
|
||||
ext->per_session_data_size);
|
||||
|
||||
wsi->active_extensions[
|
||||
wsi->count_active_extensions] = ext;
|
||||
|
||||
/* allow him to construct his context */
|
||||
|
||||
ext->callback(wsi->protocol->owning_server,
|
||||
ext, wsi,
|
||||
LWS_EXT_CALLBACK_CONSTRUCT,
|
||||
wsi->active_extensions_user[
|
||||
wsi->count_active_extensions], NULL, 0);
|
||||
|
||||
wsi->count_active_extensions++;
|
||||
lwsl_parser("count_active_extensions <- %d\n",
|
||||
wsi->count_active_extensions);
|
||||
|
||||
ext++;
|
||||
}
|
||||
|
||||
n = 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
int
|
||||
handshake_0405(struct libwebsocket_context *context, struct libwebsocket *wsi)
|
||||
{
|
||||
unsigned char hash[20];
|
||||
int n;
|
||||
char *response;
|
||||
char *p;
|
||||
int accept_len;
|
||||
|
||||
if (!lws_hdr_total_length(wsi, WSI_TOKEN_HOST) ||
|
||||
!lws_hdr_total_length(wsi, WSI_TOKEN_KEY)) {
|
||||
lwsl_parser("handshake_04 missing pieces\n");
|
||||
/* completed header processing, but missing some bits */
|
||||
goto bail;
|
||||
}
|
||||
|
||||
if (lws_hdr_total_length(wsi, WSI_TOKEN_KEY) >=
|
||||
MAX_WEBSOCKET_04_KEY_LEN) {
|
||||
lwsl_warn("Client key too long %d\n", MAX_WEBSOCKET_04_KEY_LEN);
|
||||
goto bail;
|
||||
}
|
||||
|
||||
/*
|
||||
* since key length is restricted above (currently 128), cannot
|
||||
* overflow
|
||||
*/
|
||||
n = sprintf((char *)context->service_buffer,
|
||||
"%s258EAFA5-E914-47DA-95CA-C5AB0DC85B11",
|
||||
lws_hdr_simple_ptr(wsi, WSI_TOKEN_KEY));
|
||||
|
||||
SHA1(context->service_buffer, n, hash);
|
||||
|
||||
accept_len = lws_b64_encode_string((char *)hash, 20,
|
||||
(char *)context->service_buffer,
|
||||
sizeof(context->service_buffer));
|
||||
if (accept_len < 0) {
|
||||
lwsl_warn("Base64 encoded hash too long\n");
|
||||
goto bail;
|
||||
}
|
||||
|
||||
/* allocate the per-connection user memory (if any) */
|
||||
if (libwebsocket_ensure_user_space(wsi))
|
||||
goto bail;
|
||||
|
||||
/* create the response packet */
|
||||
|
||||
/* make a buffer big enough for everything */
|
||||
|
||||
response = (char *)context->service_buffer + MAX_WEBSOCKET_04_KEY_LEN;
|
||||
p = response;
|
||||
LWS_CPYAPP(p, "HTTP/1.1 101 Switching Protocols\x0d\x0a"
|
||||
"Upgrade: WebSocket\x0d\x0a"
|
||||
"Connection: Upgrade\x0d\x0a"
|
||||
"Sec-WebSocket-Accept: ");
|
||||
strcpy(p, (char *)context->service_buffer);
|
||||
p += accept_len;
|
||||
|
||||
if (lws_hdr_total_length(wsi, WSI_TOKEN_PROTOCOL)) {
|
||||
LWS_CPYAPP(p, "\x0d\x0aSec-WebSocket-Protocol: ");
|
||||
n = lws_hdr_copy(wsi, p, 128, WSI_TOKEN_PROTOCOL);
|
||||
if (n < 0)
|
||||
goto bail;
|
||||
p += n;
|
||||
}
|
||||
|
||||
#ifndef LWS_NO_EXTENSIONS
|
||||
/*
|
||||
* Figure out which extensions the client has that we want to
|
||||
* enable on this connection, and give him back the list
|
||||
*/
|
||||
if (lws_extension_server_handshake(context, wsi, &p))
|
||||
goto bail;
|
||||
#endif
|
||||
/* end of response packet */
|
||||
|
||||
LWS_CPYAPP(p, "\x0d\x0a\x0d\x0a");
|
||||
|
||||
if (!lws_any_extension_handled(context, wsi,
|
||||
LWS_EXT_CALLBACK_HANDSHAKE_REPLY_TX,
|
||||
response, p - response)) {
|
||||
|
||||
/* okay send the handshake response accepting the connection */
|
||||
|
||||
lwsl_parser("issuing resp pkt %d len\n", (int)(p - response));
|
||||
#ifdef DEBUG
|
||||
fwrite(response, 1, p - response, stderr);
|
||||
#endif
|
||||
n = libwebsocket_write(wsi, (unsigned char *)response,
|
||||
p - response, LWS_WRITE_HTTP);
|
||||
if (n != (p - response)) {
|
||||
lwsl_debug("handshake_0405: ERROR writing to socket\n");
|
||||
goto bail;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* alright clean up and set ourselves into established state */
|
||||
|
||||
wsi->state = WSI_STATE_ESTABLISHED;
|
||||
wsi->lws_rx_parse_state = LWS_RXPS_NEW;
|
||||
|
||||
/* notify user code that we're ready to roll */
|
||||
|
||||
if (wsi->protocol->callback)
|
||||
wsi->protocol->callback(wsi->protocol->owning_server,
|
||||
wsi, LWS_CALLBACK_ESTABLISHED,
|
||||
wsi->user_space, NULL, 0);
|
||||
|
||||
return 0;
|
||||
|
||||
|
||||
bail:
|
||||
/* free up his parsing allocations */
|
||||
|
||||
if (wsi->u.hdr.ah)
|
||||
free(wsi->u.hdr.ah);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
876
dependencies/libwebsockets/lib/server.c
vendored
Normal file
876
dependencies/libwebsockets/lib/server.c
vendored
Normal file
@ -0,0 +1,876 @@
|
||||
/*
|
||||
* libwebsockets - small server side websockets and web server implementation
|
||||
*
|
||||
* Copyright (C) 2010-2013 Andy Green <andy@warmcat.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation:
|
||||
* version 2.1 of the License.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
* MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
|
||||
#include "private-libwebsockets.h"
|
||||
|
||||
int lws_context_init_server(struct lws_context_creation_info *info,
|
||||
struct libwebsocket_context *context)
|
||||
{
|
||||
int n;
|
||||
int sockfd;
|
||||
struct sockaddr_in sin;
|
||||
socklen_t len = sizeof(sin);
|
||||
int opt = 1;
|
||||
struct libwebsocket *wsi;
|
||||
#ifdef LWS_USE_IPV6
|
||||
struct sockaddr_in6 serv_addr6;
|
||||
#endif
|
||||
struct sockaddr_in serv_addr4;
|
||||
struct sockaddr *v;
|
||||
|
||||
/* set up our external listening socket we serve on */
|
||||
|
||||
if (info->port == CONTEXT_PORT_NO_LISTEN)
|
||||
return 0;
|
||||
|
||||
#ifdef LWS_USE_IPV6
|
||||
if (LWS_IPV6_ENABLED(context))
|
||||
sockfd = socket(AF_INET6, SOCK_STREAM, 0);
|
||||
else
|
||||
#endif
|
||||
sockfd = socket(AF_INET, SOCK_STREAM, 0);
|
||||
|
||||
if (sockfd < 0) {
|
||||
lwsl_err("ERROR opening socket\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* allow us to restart even if old sockets in TIME_WAIT
|
||||
*/
|
||||
setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR,
|
||||
(const void *)&opt, sizeof(opt));
|
||||
|
||||
lws_plat_set_socket_options(context, sockfd);
|
||||
|
||||
#ifdef LWS_USE_IPV6
|
||||
if (LWS_IPV6_ENABLED(context)) {
|
||||
v = (struct sockaddr *)&serv_addr6;
|
||||
n = sizeof(struct sockaddr_in6);
|
||||
bzero((char *) &serv_addr6, sizeof(serv_addr6));
|
||||
serv_addr6.sin6_addr = in6addr_any;
|
||||
serv_addr6.sin6_family = AF_INET6;
|
||||
serv_addr6.sin6_port = htons(info->port);
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
v = (struct sockaddr *)&serv_addr4;
|
||||
n = sizeof(serv_addr4);
|
||||
bzero((char *) &serv_addr4, sizeof(serv_addr4));
|
||||
serv_addr4.sin_addr.s_addr = INADDR_ANY;
|
||||
serv_addr4.sin_family = AF_INET;
|
||||
|
||||
if (info->iface) {
|
||||
if (interface_to_sa(context, info->iface,
|
||||
(struct sockaddr_in *)v, n) < 0) {
|
||||
lwsl_err("Unable to find interface %s\n",
|
||||
info->iface);
|
||||
compatible_close(sockfd);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
serv_addr4.sin_port = htons(info->port);
|
||||
} /* ipv4 */
|
||||
|
||||
n = bind(sockfd, v, n);
|
||||
if (n < 0) {
|
||||
lwsl_err("ERROR on binding to port %d (%d %d)\n",
|
||||
info->port, n, LWS_ERRNO);
|
||||
compatible_close(sockfd);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (getsockname(sockfd, (struct sockaddr *)&sin, &len) == -1)
|
||||
lwsl_warn("getsockname: %s\n", strerror(LWS_ERRNO));
|
||||
else
|
||||
info->port = ntohs(sin.sin_port);
|
||||
|
||||
context->listen_port = info->port;
|
||||
|
||||
wsi = (struct libwebsocket *)malloc(sizeof(struct libwebsocket));
|
||||
if (wsi == NULL) {
|
||||
lwsl_err("Out of mem\n");
|
||||
compatible_close(sockfd);
|
||||
return 1;
|
||||
}
|
||||
memset(wsi, 0, sizeof(struct libwebsocket));
|
||||
wsi->sock = sockfd;
|
||||
wsi->mode = LWS_CONNMODE_SERVER_LISTENER;
|
||||
|
||||
insert_wsi_socket_into_fds(context, wsi);
|
||||
|
||||
context->listen_service_modulo = LWS_LISTEN_SERVICE_MODULO;
|
||||
context->listen_service_count = 0;
|
||||
context->listen_service_fd = sockfd;
|
||||
|
||||
listen(sockfd, LWS_SOMAXCONN);
|
||||
lwsl_notice(" Listening on port %d\n", info->port);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
_libwebsocket_rx_flow_control(struct libwebsocket *wsi)
|
||||
{
|
||||
struct libwebsocket_context *context = wsi->protocol->owning_server;
|
||||
|
||||
/* there is no pending change */
|
||||
if (!(wsi->u.ws.rxflow_change_to & LWS_RXFLOW_PENDING_CHANGE))
|
||||
return 0;
|
||||
|
||||
/* stuff is still buffered, not ready to really accept new input */
|
||||
if (wsi->u.ws.rxflow_buffer) {
|
||||
/* get ourselves called back to deal with stashed buffer */
|
||||
libwebsocket_callback_on_writable(context, wsi);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* pending is cleared, we can change rxflow state */
|
||||
|
||||
wsi->u.ws.rxflow_change_to &= ~LWS_RXFLOW_PENDING_CHANGE;
|
||||
|
||||
lwsl_info("rxflow: wsi %p change_to %d\n", wsi,
|
||||
wsi->u.ws.rxflow_change_to & LWS_RXFLOW_ALLOW);
|
||||
|
||||
/* adjust the pollfd for this wsi */
|
||||
|
||||
if (wsi->u.ws.rxflow_change_to & LWS_RXFLOW_ALLOW) {
|
||||
if (lws_change_pollfd(wsi, 0, LWS_POLLIN)) {
|
||||
lwsl_info("%s: fail\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
} else
|
||||
if (lws_change_pollfd(wsi, LWS_POLLIN, 0))
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int lws_handshake_server(struct libwebsocket_context *context,
|
||||
struct libwebsocket *wsi, unsigned char **buf, size_t len)
|
||||
{
|
||||
struct allocated_headers *ah;
|
||||
char *uri_ptr = NULL;
|
||||
int uri_len = 0;
|
||||
char content_length_str[32];
|
||||
int n;
|
||||
|
||||
/* LWS_CONNMODE_WS_SERVING */
|
||||
|
||||
while (len--) {
|
||||
if (libwebsocket_parse(context, wsi, *(*buf)++)) {
|
||||
lwsl_info("libwebsocket_parse failed\n");
|
||||
goto bail_nuke_ah;
|
||||
}
|
||||
|
||||
if (wsi->u.hdr.parser_state != WSI_PARSING_COMPLETE)
|
||||
continue;
|
||||
|
||||
lwsl_parser("libwebsocket_parse sees parsing complete\n");
|
||||
|
||||
wsi->mode = LWS_CONNMODE_PRE_WS_SERVING_ACCEPT;
|
||||
libwebsocket_set_timeout(wsi, NO_PENDING_TIMEOUT, 0);
|
||||
|
||||
/* is this websocket protocol or normal http 1.0? */
|
||||
|
||||
if (!lws_hdr_total_length(wsi, WSI_TOKEN_UPGRADE) ||
|
||||
!lws_hdr_total_length(wsi, WSI_TOKEN_CONNECTION)) {
|
||||
|
||||
/* it's not websocket.... shall we accept it as http? */
|
||||
|
||||
if (!lws_hdr_total_length(wsi, WSI_TOKEN_GET_URI) &&
|
||||
!lws_hdr_total_length(wsi, WSI_TOKEN_POST_URI) &&
|
||||
!lws_hdr_total_length(wsi, WSI_TOKEN_OPTIONS_URI)) {
|
||||
lwsl_warn("Missing URI in HTTP request\n");
|
||||
goto bail_nuke_ah;
|
||||
}
|
||||
|
||||
if (lws_hdr_total_length(wsi, WSI_TOKEN_GET_URI) &&
|
||||
lws_hdr_total_length(wsi, WSI_TOKEN_POST_URI)) {
|
||||
lwsl_warn("GET and POST methods?\n");
|
||||
goto bail_nuke_ah;
|
||||
}
|
||||
|
||||
if (libwebsocket_ensure_user_space(wsi))
|
||||
goto bail_nuke_ah;
|
||||
|
||||
if (lws_hdr_total_length(wsi, WSI_TOKEN_GET_URI)) {
|
||||
uri_ptr = lws_hdr_simple_ptr(wsi, WSI_TOKEN_GET_URI);
|
||||
uri_len = lws_hdr_total_length(wsi, WSI_TOKEN_GET_URI);
|
||||
lwsl_info("HTTP GET request for '%s'\n",
|
||||
lws_hdr_simple_ptr(wsi, WSI_TOKEN_GET_URI));
|
||||
|
||||
}
|
||||
if (lws_hdr_total_length(wsi, WSI_TOKEN_POST_URI)) {
|
||||
lwsl_info("HTTP POST request for '%s'\n",
|
||||
lws_hdr_simple_ptr(wsi, WSI_TOKEN_POST_URI));
|
||||
uri_ptr = lws_hdr_simple_ptr(wsi, WSI_TOKEN_POST_URI);
|
||||
uri_len = lws_hdr_total_length(wsi, WSI_TOKEN_POST_URI);
|
||||
}
|
||||
if (lws_hdr_total_length(wsi, WSI_TOKEN_OPTIONS_URI)) {
|
||||
lwsl_info("HTTP OPTIONS request for '%s'\n",
|
||||
lws_hdr_simple_ptr(wsi, WSI_TOKEN_OPTIONS_URI));
|
||||
uri_ptr = lws_hdr_simple_ptr(wsi, WSI_TOKEN_OPTIONS_URI);
|
||||
uri_len = lws_hdr_total_length(wsi, WSI_TOKEN_OPTIONS_URI);
|
||||
}
|
||||
|
||||
/*
|
||||
* Hm we still need the headers so the
|
||||
* callback can look at leaders like the URI, but we
|
||||
* need to transition to http union state.... hold a
|
||||
* copy of u.hdr.ah and deallocate afterwards
|
||||
*/
|
||||
ah = wsi->u.hdr.ah;
|
||||
|
||||
/* union transition */
|
||||
memset(&wsi->u, 0, sizeof(wsi->u));
|
||||
wsi->mode = LWS_CONNMODE_HTTP_SERVING_ACCEPTED;
|
||||
wsi->state = WSI_STATE_HTTP;
|
||||
wsi->u.http.fd = LWS_INVALID_FILE;
|
||||
|
||||
/* expose it at the same offset as u.hdr */
|
||||
wsi->u.http.ah = ah;
|
||||
|
||||
/* HTTP header had a content length? */
|
||||
|
||||
wsi->u.http.content_length = 0;
|
||||
if (lws_hdr_total_length(wsi, WSI_TOKEN_POST_URI))
|
||||
wsi->u.http.content_length = 100 * 1024 * 1024;
|
||||
|
||||
if (lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_CONTENT_LENGTH)) {
|
||||
lws_hdr_copy(wsi, content_length_str,
|
||||
sizeof(content_length_str) - 1,
|
||||
WSI_TOKEN_HTTP_CONTENT_LENGTH);
|
||||
wsi->u.http.content_length = atoi(content_length_str);
|
||||
}
|
||||
|
||||
if (wsi->u.http.content_length > 0) {
|
||||
wsi->u.http.body_index = 0;
|
||||
n = wsi->protocol->rx_buffer_size;
|
||||
if (!n)
|
||||
n = LWS_MAX_SOCKET_IO_BUF;
|
||||
wsi->u.http.post_buffer = malloc(n);
|
||||
if (!wsi->u.http.post_buffer) {
|
||||
lwsl_err("Unable to allocate post buffer\n");
|
||||
n = -1;
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
|
||||
n = 0;
|
||||
if (wsi->protocol->callback)
|
||||
n = wsi->protocol->callback(context, wsi,
|
||||
LWS_CALLBACK_FILTER_HTTP_CONNECTION,
|
||||
wsi->user_space, uri_ptr, uri_len);
|
||||
|
||||
if (!n) {
|
||||
/*
|
||||
* if there is content supposed to be coming,
|
||||
* put a timeout on it having arrived
|
||||
*/
|
||||
libwebsocket_set_timeout(wsi,
|
||||
PENDING_TIMEOUT_HTTP_CONTENT,
|
||||
AWAITING_TIMEOUT);
|
||||
|
||||
if (wsi->protocol->callback)
|
||||
n = wsi->protocol->callback(context, wsi,
|
||||
LWS_CALLBACK_HTTP,
|
||||
wsi->user_space, uri_ptr, uri_len);
|
||||
}
|
||||
|
||||
cleanup:
|
||||
/* now drop the header info we kept a pointer to */
|
||||
if (ah)
|
||||
free(ah);
|
||||
/* not possible to continue to use past here */
|
||||
wsi->u.http.ah = NULL;
|
||||
|
||||
if (n) {
|
||||
lwsl_info("LWS_CALLBACK_HTTP closing\n");
|
||||
return 1; /* struct ah ptr already nuked */
|
||||
}
|
||||
|
||||
/*
|
||||
* (if callback didn't start sending a file)
|
||||
* deal with anything else as body, whether
|
||||
* there was a content-length or not
|
||||
*/
|
||||
|
||||
if (wsi->state != WSI_STATE_HTTP_ISSUING_FILE)
|
||||
wsi->state = WSI_STATE_HTTP_BODY;
|
||||
return 2; /* goto http_postbody; */
|
||||
}
|
||||
|
||||
if (!wsi->protocol)
|
||||
lwsl_err("NULL protocol at libwebsocket_read\n");
|
||||
|
||||
/*
|
||||
* It's websocket
|
||||
*
|
||||
* Make sure user side is happy about protocol
|
||||
*/
|
||||
|
||||
while (wsi->protocol->callback) {
|
||||
|
||||
if (!lws_hdr_total_length(wsi, WSI_TOKEN_PROTOCOL)) {
|
||||
if (wsi->protocol->name == NULL)
|
||||
break;
|
||||
} else
|
||||
if (wsi->protocol->name && strcmp(
|
||||
lws_hdr_simple_ptr(wsi,
|
||||
WSI_TOKEN_PROTOCOL),
|
||||
wsi->protocol->name) == 0)
|
||||
break;
|
||||
|
||||
wsi->protocol++;
|
||||
}
|
||||
|
||||
/* we didn't find a protocol he wanted? */
|
||||
|
||||
if (wsi->protocol->callback == NULL) {
|
||||
if (lws_hdr_simple_ptr(wsi, WSI_TOKEN_PROTOCOL) ==
|
||||
NULL) {
|
||||
lwsl_info("no protocol -> prot 0 handler\n");
|
||||
wsi->protocol = &context->protocols[0];
|
||||
} else {
|
||||
lwsl_err("Req protocol %s not supported\n",
|
||||
lws_hdr_simple_ptr(wsi, WSI_TOKEN_PROTOCOL));
|
||||
goto bail_nuke_ah;
|
||||
}
|
||||
}
|
||||
|
||||
/* allocate wsi->user storage */
|
||||
if (libwebsocket_ensure_user_space(wsi))
|
||||
goto bail_nuke_ah;
|
||||
|
||||
/*
|
||||
* Give the user code a chance to study the request and
|
||||
* have the opportunity to deny it
|
||||
*/
|
||||
|
||||
if ((wsi->protocol->callback)(wsi->protocol->owning_server, wsi,
|
||||
LWS_CALLBACK_FILTER_PROTOCOL_CONNECTION,
|
||||
wsi->user_space,
|
||||
lws_hdr_simple_ptr(wsi, WSI_TOKEN_PROTOCOL), 0)) {
|
||||
lwsl_warn("User code denied connection\n");
|
||||
goto bail_nuke_ah;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Perform the handshake according to the protocol version the
|
||||
* client announced
|
||||
*/
|
||||
|
||||
switch (wsi->ietf_spec_revision) {
|
||||
case 13:
|
||||
lwsl_parser("lws_parse calling handshake_04\n");
|
||||
if (handshake_0405(context, wsi)) {
|
||||
lwsl_info("hs0405 has failed the connection\n");
|
||||
goto bail_nuke_ah;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
lwsl_warn("Unknown client spec version %d\n",
|
||||
wsi->ietf_spec_revision);
|
||||
goto bail_nuke_ah;
|
||||
}
|
||||
|
||||
/* drop the header info -- no bail_nuke_ah after this */
|
||||
|
||||
if (wsi->u.hdr.ah)
|
||||
free(wsi->u.hdr.ah);
|
||||
|
||||
wsi->mode = LWS_CONNMODE_WS_SERVING;
|
||||
|
||||
/* union transition */
|
||||
memset(&wsi->u, 0, sizeof(wsi->u));
|
||||
wsi->u.ws.rxflow_change_to = LWS_RXFLOW_ALLOW;
|
||||
|
||||
/*
|
||||
* create the frame buffer for this connection according to the
|
||||
* size mentioned in the protocol definition. If 0 there, use
|
||||
* a big default for compatibility
|
||||
*/
|
||||
|
||||
n = wsi->protocol->rx_buffer_size;
|
||||
if (!n)
|
||||
n = LWS_MAX_SOCKET_IO_BUF;
|
||||
n += LWS_SEND_BUFFER_PRE_PADDING + LWS_SEND_BUFFER_POST_PADDING;
|
||||
wsi->u.ws.rx_user_buffer = malloc(n);
|
||||
if (!wsi->u.ws.rx_user_buffer) {
|
||||
lwsl_err("Out of Mem allocating rx buffer %d\n", n);
|
||||
return 1;
|
||||
}
|
||||
lwsl_info("Allocating RX buffer %d\n", n);
|
||||
|
||||
if (setsockopt(wsi->sock, SOL_SOCKET, SO_SNDBUF, (const char *)&n, sizeof n)) {
|
||||
lwsl_warn("Failed to set SNDBUF to %d", n);
|
||||
return 1;
|
||||
}
|
||||
|
||||
lwsl_parser("accepted v%02d connection\n",
|
||||
wsi->ietf_spec_revision);
|
||||
} /* while all chars are handled */
|
||||
|
||||
return 0;
|
||||
|
||||
bail_nuke_ah:
|
||||
/* drop the header info */
|
||||
if (wsi->u.hdr.ah)
|
||||
free(wsi->u.hdr.ah);
|
||||
return 1;
|
||||
}
|
||||
|
||||
struct libwebsocket *
|
||||
libwebsocket_create_new_server_wsi(struct libwebsocket_context *context)
|
||||
{
|
||||
struct libwebsocket *new_wsi;
|
||||
|
||||
new_wsi = (struct libwebsocket *)malloc(sizeof(struct libwebsocket));
|
||||
if (new_wsi == NULL) {
|
||||
lwsl_err("Out of memory for new connection\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset(new_wsi, 0, sizeof(struct libwebsocket));
|
||||
new_wsi->pending_timeout = NO_PENDING_TIMEOUT;
|
||||
|
||||
/* intialize the instance struct */
|
||||
|
||||
new_wsi->state = WSI_STATE_HTTP;
|
||||
new_wsi->mode = LWS_CONNMODE_HTTP_SERVING;
|
||||
new_wsi->hdr_parsing_completed = 0;
|
||||
|
||||
if (lws_allocate_header_table(new_wsi)) {
|
||||
free(new_wsi);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* these can only be set once the protocol is known
|
||||
* we set an unestablished connection's protocol pointer
|
||||
* to the start of the supported list, so it can look
|
||||
* for matching ones during the handshake
|
||||
*/
|
||||
new_wsi->protocol = context->protocols;
|
||||
new_wsi->user_space = NULL;
|
||||
new_wsi->ietf_spec_revision = 0;
|
||||
|
||||
/*
|
||||
* outermost create notification for wsi
|
||||
* no user_space because no protocol selection
|
||||
*/
|
||||
context->protocols[0].callback(context, new_wsi,
|
||||
LWS_CALLBACK_WSI_CREATE, NULL, NULL, 0);
|
||||
|
||||
return new_wsi;
|
||||
}
|
||||
|
||||
int lws_server_socket_service(struct libwebsocket_context *context,
|
||||
struct libwebsocket *wsi, struct libwebsocket_pollfd *pollfd)
|
||||
{
|
||||
struct libwebsocket *new_wsi = NULL;
|
||||
int accept_fd = 0;
|
||||
socklen_t clilen;
|
||||
struct sockaddr_in cli_addr;
|
||||
int n;
|
||||
int len;
|
||||
|
||||
switch (wsi->mode) {
|
||||
|
||||
case LWS_CONNMODE_HTTP_SERVING:
|
||||
case LWS_CONNMODE_HTTP_SERVING_ACCEPTED:
|
||||
|
||||
/* handle http headers coming in */
|
||||
|
||||
/* pending truncated sends have uber priority */
|
||||
|
||||
if (wsi->truncated_send_malloc) {
|
||||
if (pollfd->revents & LWS_POLLOUT)
|
||||
if (lws_issue_raw(wsi, wsi->truncated_send_malloc +
|
||||
wsi->truncated_send_offset,
|
||||
wsi->truncated_send_len) < 0) {
|
||||
lwsl_info("closing from socket service\n");
|
||||
return -1;
|
||||
}
|
||||
/*
|
||||
* we can't afford to allow input processing send
|
||||
* something new, so spin around he event loop until
|
||||
* he doesn't have any partials
|
||||
*/
|
||||
break;
|
||||
}
|
||||
|
||||
/* any incoming data ready? */
|
||||
|
||||
if (pollfd->revents & LWS_POLLIN) {
|
||||
len = lws_ssl_capable_read(wsi,
|
||||
context->service_buffer,
|
||||
sizeof(context->service_buffer));
|
||||
switch (len) {
|
||||
case 0:
|
||||
lwsl_info("lws_server_skt_srv: read 0 len\n");
|
||||
/* lwsl_info(" state=%d\n", wsi->state); */
|
||||
if (!wsi->hdr_parsing_completed)
|
||||
free(wsi->u.hdr.ah);
|
||||
/* fallthru */
|
||||
case LWS_SSL_CAPABLE_ERROR:
|
||||
libwebsocket_close_and_free_session(
|
||||
context, wsi,
|
||||
LWS_CLOSE_STATUS_NOSTATUS);
|
||||
return 0;
|
||||
case LWS_SSL_CAPABLE_MORE_SERVICE:
|
||||
break;
|
||||
}
|
||||
|
||||
/* just ignore incoming if waiting for close */
|
||||
if (wsi->state != WSI_STATE_FLUSHING_STORED_SEND_BEFORE_CLOSE) {
|
||||
|
||||
/* hm this may want to send (via HTTP callback for example) */
|
||||
|
||||
n = libwebsocket_read(context, wsi,
|
||||
context->service_buffer, len);
|
||||
if (n < 0)
|
||||
/* we closed wsi */
|
||||
return 0;
|
||||
|
||||
/* hum he may have used up the writability above */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* this handles POLLOUT for http serving fragments */
|
||||
|
||||
if (!(pollfd->revents & LWS_POLLOUT))
|
||||
break;
|
||||
|
||||
/* one shot */
|
||||
if (lws_change_pollfd(wsi, LWS_POLLOUT, 0))
|
||||
goto fail;
|
||||
|
||||
lws_libev_io(context, wsi, LWS_EV_STOP | LWS_EV_WRITE);
|
||||
|
||||
if (wsi->state != WSI_STATE_HTTP_ISSUING_FILE) {
|
||||
n = user_callback_handle_rxflow(
|
||||
wsi->protocol->callback,
|
||||
wsi->protocol->owning_server,
|
||||
wsi, LWS_CALLBACK_HTTP_WRITEABLE,
|
||||
wsi->user_space,
|
||||
NULL,
|
||||
0);
|
||||
if (n < 0)
|
||||
libwebsocket_close_and_free_session(
|
||||
context, wsi, LWS_CLOSE_STATUS_NOSTATUS);
|
||||
break;
|
||||
}
|
||||
|
||||
/* nonzero for completion or error */
|
||||
if (libwebsockets_serve_http_file_fragment(context, wsi))
|
||||
libwebsocket_close_and_free_session(context, wsi,
|
||||
LWS_CLOSE_STATUS_NOSTATUS);
|
||||
break;
|
||||
|
||||
case LWS_CONNMODE_SERVER_LISTENER:
|
||||
|
||||
/* pollin means a client has connected to us then */
|
||||
|
||||
if (!(pollfd->revents & LWS_POLLIN))
|
||||
break;
|
||||
|
||||
/* listen socket got an unencrypted connection... */
|
||||
|
||||
clilen = sizeof(cli_addr);
|
||||
lws_latency_pre(context, wsi);
|
||||
accept_fd = accept(pollfd->fd, (struct sockaddr *)&cli_addr,
|
||||
&clilen);
|
||||
lws_latency(context, wsi,
|
||||
"unencrypted accept LWS_CONNMODE_SERVER_LISTENER",
|
||||
accept_fd, accept_fd >= 0);
|
||||
if (accept_fd < 0) {
|
||||
if (LWS_ERRNO == LWS_EAGAIN || LWS_ERRNO == LWS_EWOULDBLOCK) {
|
||||
lwsl_debug("accept asks to try again\n");
|
||||
break;
|
||||
}
|
||||
lwsl_warn("ERROR on accept: %s\n", strerror(LWS_ERRNO));
|
||||
break;
|
||||
}
|
||||
|
||||
lws_plat_set_socket_options(context, accept_fd);
|
||||
|
||||
/*
|
||||
* look at who we connected to and give user code a chance
|
||||
* to reject based on client IP. There's no protocol selected
|
||||
* yet so we issue this to protocols[0]
|
||||
*/
|
||||
|
||||
if ((context->protocols[0].callback)(context, wsi,
|
||||
LWS_CALLBACK_FILTER_NETWORK_CONNECTION,
|
||||
NULL, (void *)(long)accept_fd, 0)) {
|
||||
lwsl_debug("Callback denied network connection\n");
|
||||
compatible_close(accept_fd);
|
||||
break;
|
||||
}
|
||||
|
||||
new_wsi = libwebsocket_create_new_server_wsi(context);
|
||||
if (new_wsi == NULL) {
|
||||
compatible_close(accept_fd);
|
||||
break;
|
||||
}
|
||||
|
||||
new_wsi->sock = accept_fd;
|
||||
|
||||
/* the transport is accepted... give him time to negotiate */
|
||||
libwebsocket_set_timeout(new_wsi,
|
||||
PENDING_TIMEOUT_ESTABLISH_WITH_SERVER,
|
||||
AWAITING_TIMEOUT);
|
||||
|
||||
/*
|
||||
* A new connection was accepted. Give the user a chance to
|
||||
* set properties of the newly created wsi. There's no protocol
|
||||
* selected yet so we issue this to protocols[0]
|
||||
*/
|
||||
|
||||
(context->protocols[0].callback)(context, new_wsi,
|
||||
LWS_CALLBACK_SERVER_NEW_CLIENT_INSTANTIATED, NULL, NULL, 0);
|
||||
|
||||
lws_libev_accept(context, new_wsi, accept_fd);
|
||||
|
||||
if (!LWS_SSL_ENABLED(context)) {
|
||||
lwsl_debug("accepted new conn port %u on fd=%d\n",
|
||||
ntohs(cli_addr.sin_port), accept_fd);
|
||||
|
||||
insert_wsi_socket_into_fds(context, new_wsi);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (lws_server_socket_service_ssl(context, &wsi, new_wsi, accept_fd, pollfd))
|
||||
goto fail;
|
||||
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
libwebsocket_close_and_free_session(context, wsi,
|
||||
LWS_CLOSE_STATUS_NOSTATUS);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static const char *err400[] = {
|
||||
"Bad Request",
|
||||
"Unauthorized",
|
||||
"Payment Required",
|
||||
"Forbidden",
|
||||
"Not Found",
|
||||
"Method Not Allowed",
|
||||
"Not Acceptable",
|
||||
"Proxy Auth Required",
|
||||
"Request Timeout",
|
||||
"Conflict",
|
||||
"Gone",
|
||||
"Length Required",
|
||||
"Precondition Failed",
|
||||
"Request Entity Too Large",
|
||||
"Request URI too Long",
|
||||
"Unsupported Media Type",
|
||||
"Requested Range Not Satisfiable",
|
||||
"Expectation Failed"
|
||||
};
|
||||
|
||||
static const char *err500[] = {
|
||||
"Internal Server Error",
|
||||
"Not Implemented",
|
||||
"Bad Gateway",
|
||||
"Service Unavailable",
|
||||
"Gateway Timeout",
|
||||
"HTTP Version Not Supported"
|
||||
};
|
||||
|
||||
/**
|
||||
* libwebsockets_return_http_status() - Return simple http status
|
||||
* @context: libwebsockets context
|
||||
* @wsi: Websocket instance (available from user callback)
|
||||
* @code: Status index, eg, 404
|
||||
* @html_body: User-readable HTML description, or NULL
|
||||
*
|
||||
* Helper to report HTTP errors back to the client cleanly and
|
||||
* consistently
|
||||
*/
|
||||
LWS_VISIBLE int libwebsockets_return_http_status(
|
||||
struct libwebsocket_context *context, struct libwebsocket *wsi,
|
||||
unsigned int code, const char *html_body)
|
||||
{
|
||||
int n, m;
|
||||
const char *description = "";
|
||||
|
||||
if (!html_body)
|
||||
html_body = "";
|
||||
|
||||
if (code >= 400 && code < (400 + ARRAY_SIZE(err400)))
|
||||
description = err400[code - 400];
|
||||
if (code >= 500 && code < (500 + ARRAY_SIZE(err500)))
|
||||
description = err500[code - 500];
|
||||
|
||||
n = sprintf((char *)context->service_buffer,
|
||||
"HTTP/1.0 %u %s\x0d\x0a"
|
||||
"Server: libwebsockets\x0d\x0a"
|
||||
"Content-Type: text/html\x0d\x0a\x0d\x0a"
|
||||
"<h1>%u %s</h1>%s",
|
||||
code, description, code, description, html_body);
|
||||
|
||||
lwsl_info((const char *)context->service_buffer);
|
||||
|
||||
m = libwebsocket_write(wsi, context->service_buffer, n, LWS_WRITE_HTTP);
|
||||
|
||||
return m;
|
||||
}
|
||||
|
||||
/**
|
||||
* libwebsockets_serve_http_file() - Send a file back to the client using http
|
||||
* @context: libwebsockets context
|
||||
* @wsi: Websocket instance (available from user callback)
|
||||
* @file: The file to issue over http
|
||||
* @content_type: The http content type, eg, text/html
|
||||
* @other_headers: NULL or pointer to \0-terminated other header string
|
||||
*
|
||||
* This function is intended to be called from the callback in response
|
||||
* to http requests from the client. It allows the callback to issue
|
||||
* local files down the http link in a single step.
|
||||
*
|
||||
* Returning <0 indicates error and the wsi should be closed. Returning
|
||||
* >0 indicates the file was completely sent and the wsi should be closed.
|
||||
* ==0 indicates the file transfer is started and needs more service later,
|
||||
* the wsi should be left alone.
|
||||
*/
|
||||
|
||||
LWS_VISIBLE int libwebsockets_serve_http_file(
|
||||
struct libwebsocket_context *context,
|
||||
struct libwebsocket *wsi, const char *file,
|
||||
const char *content_type, const char *other_headers)
|
||||
{
|
||||
unsigned char *p = context->service_buffer;
|
||||
int ret = 0;
|
||||
int n;
|
||||
|
||||
wsi->u.http.fd = lws_plat_open_file(file, &wsi->u.http.filelen);
|
||||
|
||||
if (wsi->u.http.fd == LWS_INVALID_FILE) {
|
||||
lwsl_err("Unable to open '%s'\n", file);
|
||||
libwebsockets_return_http_status(context, wsi,
|
||||
HTTP_STATUS_NOT_FOUND, NULL);
|
||||
return -1;
|
||||
}
|
||||
|
||||
p += sprintf((char *)p,
|
||||
"HTTP/1.0 200 OK\x0d\x0aServer: libwebsockets\x0d\x0a""Content-Type: %s\x0d\x0a",
|
||||
content_type);
|
||||
if (other_headers) {
|
||||
n = strlen(other_headers);
|
||||
memcpy(p, other_headers, n);
|
||||
p += n;
|
||||
}
|
||||
p += sprintf((char *)p,
|
||||
"Content-Length: %lu\x0d\x0a\x0d\x0a", wsi->u.http.filelen);
|
||||
|
||||
ret = libwebsocket_write(wsi, context->service_buffer,
|
||||
p - context->service_buffer, LWS_WRITE_HTTP);
|
||||
if (ret != (p - context->service_buffer)) {
|
||||
lwsl_err("_write returned %d from %d\n", ret, (p - context->service_buffer));
|
||||
return -1;
|
||||
}
|
||||
|
||||
wsi->u.http.filepos = 0;
|
||||
wsi->state = WSI_STATE_HTTP_ISSUING_FILE;
|
||||
|
||||
return libwebsockets_serve_http_file_fragment(context, wsi);
|
||||
}
|
||||
|
||||
|
||||
int libwebsocket_interpret_incoming_packet(struct libwebsocket *wsi,
|
||||
unsigned char *buf, size_t len)
|
||||
{
|
||||
size_t n = 0;
|
||||
int m;
|
||||
|
||||
#if 0
|
||||
lwsl_parser("received %d byte packet\n", (int)len);
|
||||
lwsl_hexdump(buf, len);
|
||||
#endif
|
||||
|
||||
/* let the rx protocol state machine have as much as it needs */
|
||||
|
||||
while (n < len) {
|
||||
/*
|
||||
* we were accepting input but now we stopped doing so
|
||||
*/
|
||||
if (!(wsi->u.ws.rxflow_change_to & LWS_RXFLOW_ALLOW)) {
|
||||
/* his RX is flowcontrolled, don't send remaining now */
|
||||
if (!wsi->u.ws.rxflow_buffer) {
|
||||
/* a new rxflow, buffer it and warn caller */
|
||||
lwsl_info("new rxflow input buffer len %d\n",
|
||||
len - n);
|
||||
wsi->u.ws.rxflow_buffer =
|
||||
(unsigned char *)malloc(len - n);
|
||||
wsi->u.ws.rxflow_len = len - n;
|
||||
wsi->u.ws.rxflow_pos = 0;
|
||||
memcpy(wsi->u.ws.rxflow_buffer,
|
||||
buf + n, len - n);
|
||||
} else
|
||||
/* rxflow while we were spilling prev rxflow */
|
||||
lwsl_info("stalling in existing rxflow buf\n");
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* account for what we're using in rxflow buffer */
|
||||
if (wsi->u.ws.rxflow_buffer)
|
||||
wsi->u.ws.rxflow_pos++;
|
||||
|
||||
/* process the byte */
|
||||
m = libwebsocket_rx_sm(wsi, buf[n++]);
|
||||
if (m < 0)
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
LWS_VISIBLE void
|
||||
lws_server_get_canonical_hostname(struct libwebsocket_context *context,
|
||||
struct lws_context_creation_info *info)
|
||||
{
|
||||
if (info->options & LWS_SERVER_OPTION_SKIP_SERVER_CANONICAL_NAME)
|
||||
return;
|
||||
|
||||
/* find canonical hostname */
|
||||
gethostname((char *)context->canonical_hostname,
|
||||
sizeof(context->canonical_hostname) - 1);
|
||||
|
||||
lwsl_notice(" canonical_hostname = %s\n", context->canonical_hostname);
|
||||
}
|
||||
517
dependencies/libwebsockets/lib/service.c
vendored
Normal file
517
dependencies/libwebsockets/lib/service.c
vendored
Normal file
@ -0,0 +1,517 @@
|
||||
/*
|
||||
* libwebsockets - small server side websockets and web server implementation
|
||||
*
|
||||
* Copyright (C) 2010-2014 Andy Green <andy@warmcat.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation:
|
||||
* version 2.1 of the License.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
* MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "private-libwebsockets.h"
|
||||
|
||||
int
|
||||
lws_handle_POLLOUT_event(struct libwebsocket_context *context,
|
||||
struct libwebsocket *wsi, struct libwebsocket_pollfd *pollfd)
|
||||
{
|
||||
int n;
|
||||
struct lws_tokens eff_buf;
|
||||
int ret;
|
||||
int m;
|
||||
int handled = 0;
|
||||
|
||||
/* pending truncated sends have uber priority */
|
||||
|
||||
if (wsi->truncated_send_len) {
|
||||
if (lws_issue_raw(wsi, wsi->truncated_send_malloc +
|
||||
wsi->truncated_send_offset,
|
||||
wsi->truncated_send_len) < 0) {
|
||||
lwsl_info("lws_handle_POLLOUT_event signalling to close\n");
|
||||
return -1;
|
||||
}
|
||||
/* leave POLLOUT active either way */
|
||||
return 0;
|
||||
} else
|
||||
if (wsi->state == WSI_STATE_FLUSHING_STORED_SEND_BEFORE_CLOSE) {
|
||||
lwsl_info("***** %x signalling to close in POLLOUT handler\n", wsi);
|
||||
return -1; /* retry closing now */
|
||||
}
|
||||
|
||||
|
||||
m = lws_ext_callback_for_each_active(wsi, LWS_EXT_CALLBACK_IS_WRITEABLE,
|
||||
NULL, 0);
|
||||
if (handled == 1)
|
||||
goto notify_action;
|
||||
#ifndef LWS_NO_EXTENSIONS
|
||||
if (!wsi->extension_data_pending || handled == 2)
|
||||
goto user_service;
|
||||
#endif
|
||||
/*
|
||||
* check in on the active extensions, see if they
|
||||
* had pending stuff to spill... they need to get the
|
||||
* first look-in otherwise sequence will be disordered
|
||||
*
|
||||
* NULL, zero-length eff_buf means just spill pending
|
||||
*/
|
||||
|
||||
ret = 1;
|
||||
while (ret == 1) {
|
||||
|
||||
/* default to nobody has more to spill */
|
||||
|
||||
ret = 0;
|
||||
eff_buf.token = NULL;
|
||||
eff_buf.token_len = 0;
|
||||
|
||||
/* give every extension a chance to spill */
|
||||
|
||||
m = lws_ext_callback_for_each_active(wsi,
|
||||
LWS_EXT_CALLBACK_PACKET_TX_PRESEND,
|
||||
&eff_buf, 0);
|
||||
if (m < 0) {
|
||||
lwsl_err("ext reports fatal error\n");
|
||||
return -1;
|
||||
}
|
||||
if (m)
|
||||
/*
|
||||
* at least one extension told us he has more
|
||||
* to spill, so we will go around again after
|
||||
*/
|
||||
ret = 1;
|
||||
|
||||
/* assuming they gave us something to send, send it */
|
||||
|
||||
if (eff_buf.token_len) {
|
||||
n = lws_issue_raw(wsi, (unsigned char *)eff_buf.token,
|
||||
eff_buf.token_len);
|
||||
if (n < 0) {
|
||||
lwsl_info("closing from POLLOUT spill\n");
|
||||
return -1;
|
||||
}
|
||||
/*
|
||||
* Keep amount spilled small to minimize chance of this
|
||||
*/
|
||||
if (n != eff_buf.token_len) {
|
||||
lwsl_err("Unable to spill ext %d vs %s\n",
|
||||
eff_buf.token_len, n);
|
||||
return -1;
|
||||
}
|
||||
} else
|
||||
continue;
|
||||
|
||||
/* no extension has more to spill */
|
||||
|
||||
if (!ret)
|
||||
continue;
|
||||
|
||||
/*
|
||||
* There's more to spill from an extension, but we just sent
|
||||
* something... did that leave the pipe choked?
|
||||
*/
|
||||
|
||||
if (!lws_send_pipe_choked(wsi))
|
||||
/* no we could add more */
|
||||
continue;
|
||||
|
||||
lwsl_info("choked in POLLOUT service\n");
|
||||
|
||||
/*
|
||||
* Yes, he's choked. Leave the POLLOUT masked on so we will
|
||||
* come back here when he is unchoked. Don't call the user
|
||||
* callback to enforce ordering of spilling, he'll get called
|
||||
* when we come back here and there's nothing more to spill.
|
||||
*/
|
||||
|
||||
return 0;
|
||||
}
|
||||
#ifndef LWS_NO_EXTENSIONS
|
||||
wsi->extension_data_pending = 0;
|
||||
|
||||
user_service:
|
||||
#endif
|
||||
/* one shot */
|
||||
|
||||
if (pollfd) {
|
||||
if (lws_change_pollfd(wsi, LWS_POLLOUT, 0))
|
||||
return 1;
|
||||
|
||||
lws_libev_io(context, wsi, LWS_EV_STOP | LWS_EV_WRITE);
|
||||
}
|
||||
|
||||
notify_action:
|
||||
if (wsi->mode == LWS_CONNMODE_WS_CLIENT)
|
||||
n = LWS_CALLBACK_CLIENT_WRITEABLE;
|
||||
else
|
||||
n = LWS_CALLBACK_SERVER_WRITEABLE;
|
||||
|
||||
return user_callback_handle_rxflow(wsi->protocol->callback, context,
|
||||
wsi, (enum libwebsocket_callback_reasons) n,
|
||||
wsi->user_space, NULL, 0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
int
|
||||
libwebsocket_service_timeout_check(struct libwebsocket_context *context,
|
||||
struct libwebsocket *wsi, unsigned int sec)
|
||||
{
|
||||
/*
|
||||
* if extensions want in on it (eg, we are a mux parent)
|
||||
* give them a chance to service child timeouts
|
||||
*/
|
||||
if (lws_ext_callback_for_each_active(wsi, LWS_EXT_CALLBACK_1HZ, NULL, sec) < 0)
|
||||
return 0;
|
||||
|
||||
if (!wsi->pending_timeout)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* if we went beyond the allowed time, kill the
|
||||
* connection
|
||||
*/
|
||||
if (sec > wsi->pending_timeout_limit) {
|
||||
lwsl_info("TIMEDOUT WAITING on %d\n", wsi->pending_timeout);
|
||||
libwebsocket_close_and_free_session(context,
|
||||
wsi, LWS_CLOSE_STATUS_NOSTATUS);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* libwebsocket_service_fd() - Service polled socket with something waiting
|
||||
* @context: Websocket context
|
||||
* @pollfd: The pollfd entry describing the socket fd and which events
|
||||
* happened.
|
||||
*
|
||||
* This function takes a pollfd that has POLLIN or POLLOUT activity and
|
||||
* services it according to the state of the associated
|
||||
* struct libwebsocket.
|
||||
*
|
||||
* The one call deals with all "service" that might happen on a socket
|
||||
* including listen accepts, http files as well as websocket protocol.
|
||||
*
|
||||
* If a pollfd says it has something, you can just pass it to
|
||||
* libwebsocket_serice_fd() whether it is a socket handled by lws or not.
|
||||
* If it sees it is a lws socket, the traffic will be handled and
|
||||
* pollfd->revents will be zeroed now.
|
||||
*
|
||||
* If the socket is foreign to lws, it leaves revents alone. So you can
|
||||
* see if you should service yourself by checking the pollfd revents
|
||||
* after letting lws try to service it.
|
||||
*/
|
||||
|
||||
LWS_VISIBLE int
|
||||
libwebsocket_service_fd(struct libwebsocket_context *context,
|
||||
struct libwebsocket_pollfd *pollfd)
|
||||
{
|
||||
struct libwebsocket *wsi;
|
||||
int n;
|
||||
int m;
|
||||
int listen_socket_fds_index = 0;
|
||||
time_t now;
|
||||
int timed_out = 0;
|
||||
int our_fd = 0;
|
||||
char draining_flow = 0;
|
||||
int more;
|
||||
struct lws_tokens eff_buf;
|
||||
|
||||
if (context->listen_service_fd)
|
||||
listen_socket_fds_index = context->lws_lookup[
|
||||
context->listen_service_fd]->position_in_fds_table;
|
||||
|
||||
/*
|
||||
* you can call us with pollfd = NULL to just allow the once-per-second
|
||||
* global timeout checks; if less than a second since the last check
|
||||
* it returns immediately then.
|
||||
*/
|
||||
|
||||
time(&now);
|
||||
|
||||
/* TODO: if using libev, we should probably use timeout watchers... */
|
||||
if (context->last_timeout_check_s != now) {
|
||||
context->last_timeout_check_s = now;
|
||||
|
||||
lws_plat_service_periodic(context);
|
||||
|
||||
/* global timeout check once per second */
|
||||
|
||||
if (pollfd)
|
||||
our_fd = pollfd->fd;
|
||||
|
||||
for (n = 0; n < context->fds_count; n++) {
|
||||
m = context->fds[n].fd;
|
||||
wsi = context->lws_lookup[m];
|
||||
if (!wsi)
|
||||
continue;
|
||||
|
||||
if (libwebsocket_service_timeout_check(context, wsi, now))
|
||||
/* he did time out... */
|
||||
if (m == our_fd) {
|
||||
/* it was the guy we came to service! */
|
||||
timed_out = 1;
|
||||
/* mark as handled */
|
||||
pollfd->revents = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* the socket we came to service timed out, nothing to do */
|
||||
if (timed_out)
|
||||
return 0;
|
||||
|
||||
/* just here for timeout management? */
|
||||
if (pollfd == NULL)
|
||||
return 0;
|
||||
|
||||
/* no, here to service a socket descriptor */
|
||||
wsi = context->lws_lookup[pollfd->fd];
|
||||
if (wsi == NULL)
|
||||
/* not lws connection ... leave revents alone and return */
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* so that caller can tell we handled, past here we need to
|
||||
* zero down pollfd->revents after handling
|
||||
*/
|
||||
|
||||
/*
|
||||
* deal with listen service piggybacking
|
||||
* every listen_service_modulo services of other fds, we
|
||||
* sneak one in to service the listen socket if there's anything waiting
|
||||
*
|
||||
* To handle connection storms, as found in ab, if we previously saw a
|
||||
* pending connection here, it causes us to check again next time.
|
||||
*/
|
||||
|
||||
if (context->listen_service_fd && pollfd !=
|
||||
&context->fds[listen_socket_fds_index]) {
|
||||
context->listen_service_count++;
|
||||
if (context->listen_service_extraseen ||
|
||||
context->listen_service_count ==
|
||||
context->listen_service_modulo) {
|
||||
context->listen_service_count = 0;
|
||||
m = 1;
|
||||
if (context->listen_service_extraseen > 5)
|
||||
m = 2;
|
||||
while (m--) {
|
||||
/*
|
||||
* even with extpoll, we prepared this
|
||||
* internal fds for listen
|
||||
*/
|
||||
n = lws_poll_listen_fd(&context->fds[listen_socket_fds_index]);
|
||||
if (n > 0) { /* there's a conn waiting for us */
|
||||
libwebsocket_service_fd(context,
|
||||
&context->
|
||||
fds[listen_socket_fds_index]);
|
||||
context->listen_service_extraseen++;
|
||||
} else {
|
||||
if (context->listen_service_extraseen)
|
||||
context->
|
||||
listen_service_extraseen--;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* handle session socket closed */
|
||||
|
||||
if ((!(pollfd->revents & LWS_POLLIN)) &&
|
||||
(pollfd->revents & LWS_POLLHUP)) {
|
||||
|
||||
lwsl_debug("Session Socket %p (fd=%d) dead\n",
|
||||
(void *)wsi, pollfd->fd);
|
||||
|
||||
goto close_and_handled;
|
||||
}
|
||||
|
||||
/* okay, what we came here to do... */
|
||||
|
||||
switch (wsi->mode) {
|
||||
case LWS_CONNMODE_HTTP_SERVING:
|
||||
case LWS_CONNMODE_HTTP_SERVING_ACCEPTED:
|
||||
case LWS_CONNMODE_SERVER_LISTENER:
|
||||
case LWS_CONNMODE_SSL_ACK_PENDING:
|
||||
n = lws_server_socket_service(context, wsi, pollfd);
|
||||
if (n < 0)
|
||||
goto close_and_handled;
|
||||
goto handled;
|
||||
|
||||
case LWS_CONNMODE_WS_SERVING:
|
||||
case LWS_CONNMODE_WS_CLIENT:
|
||||
|
||||
/* the guy requested a callback when it was OK to write */
|
||||
|
||||
if ((pollfd->revents & LWS_POLLOUT) &&
|
||||
(wsi->state == WSI_STATE_ESTABLISHED ||
|
||||
wsi->state == WSI_STATE_FLUSHING_STORED_SEND_BEFORE_CLOSE) &&
|
||||
lws_handle_POLLOUT_event(context, wsi, pollfd)) {
|
||||
lwsl_info("libwebsocket_service_fd: closing\n");
|
||||
goto close_and_handled;
|
||||
}
|
||||
|
||||
if (wsi->u.ws.rxflow_buffer &&
|
||||
(wsi->u.ws.rxflow_change_to & LWS_RXFLOW_ALLOW)) {
|
||||
lwsl_info("draining rxflow\n");
|
||||
/* well, drain it */
|
||||
eff_buf.token = (char *)wsi->u.ws.rxflow_buffer +
|
||||
wsi->u.ws.rxflow_pos;
|
||||
eff_buf.token_len = wsi->u.ws.rxflow_len -
|
||||
wsi->u.ws.rxflow_pos;
|
||||
draining_flow = 1;
|
||||
goto drain;
|
||||
}
|
||||
|
||||
/* any incoming data ready? */
|
||||
|
||||
if (!(pollfd->revents & LWS_POLLIN))
|
||||
break;
|
||||
|
||||
read_pending:
|
||||
eff_buf.token_len = lws_ssl_capable_read(wsi,
|
||||
context->service_buffer,
|
||||
sizeof(context->service_buffer));
|
||||
switch (eff_buf.token_len) {
|
||||
case 0:
|
||||
lwsl_info("service_fd: closing due to 0 length read\n");
|
||||
goto close_and_handled;
|
||||
case LWS_SSL_CAPABLE_MORE_SERVICE:
|
||||
lwsl_info("SSL Capable more service\n");
|
||||
n = 0;
|
||||
goto handled;
|
||||
case LWS_SSL_CAPABLE_ERROR:
|
||||
lwsl_info("Closing when error\n");
|
||||
goto close_and_handled;
|
||||
}
|
||||
|
||||
/*
|
||||
* give any active extensions a chance to munge the buffer
|
||||
* before parse. We pass in a pointer to an lws_tokens struct
|
||||
* prepared with the default buffer and content length that's in
|
||||
* there. Rather than rewrite the default buffer, extensions
|
||||
* that expect to grow the buffer can adapt .token to
|
||||
* point to their own per-connection buffer in the extension
|
||||
* user allocation. By default with no extensions or no
|
||||
* extension callback handling, just the normal input buffer is
|
||||
* used then so it is efficient.
|
||||
*/
|
||||
|
||||
eff_buf.token = (char *)context->service_buffer;
|
||||
drain:
|
||||
|
||||
do {
|
||||
|
||||
more = 0;
|
||||
|
||||
m = lws_ext_callback_for_each_active(wsi,
|
||||
LWS_EXT_CALLBACK_PACKET_RX_PREPARSE, &eff_buf, 0);
|
||||
if (m < 0)
|
||||
goto close_and_handled;
|
||||
if (m)
|
||||
more = 1;
|
||||
|
||||
/* service incoming data */
|
||||
|
||||
if (eff_buf.token_len) {
|
||||
n = libwebsocket_read(context, wsi,
|
||||
(unsigned char *)eff_buf.token,
|
||||
eff_buf.token_len);
|
||||
if (n < 0) {
|
||||
/* we closed wsi */
|
||||
n = 0;
|
||||
goto handled;
|
||||
}
|
||||
}
|
||||
|
||||
eff_buf.token = NULL;
|
||||
eff_buf.token_len = 0;
|
||||
} while (more);
|
||||
|
||||
if (draining_flow && wsi->u.ws.rxflow_buffer &&
|
||||
wsi->u.ws.rxflow_pos == wsi->u.ws.rxflow_len) {
|
||||
lwsl_info("flow buffer: drained\n");
|
||||
free(wsi->u.ws.rxflow_buffer);
|
||||
wsi->u.ws.rxflow_buffer = NULL;
|
||||
/* having drained the rxflow buffer, can rearm POLLIN */
|
||||
n = _libwebsocket_rx_flow_control(wsi); /* n ignored, needed for NO_SERVER case */
|
||||
}
|
||||
|
||||
if (lws_ssl_pending(wsi))
|
||||
goto read_pending;
|
||||
break;
|
||||
|
||||
default:
|
||||
#ifdef LWS_NO_CLIENT
|
||||
break;
|
||||
#else
|
||||
n = lws_client_socket_service(context, wsi, pollfd);
|
||||
goto handled;
|
||||
#endif
|
||||
}
|
||||
|
||||
n = 0;
|
||||
goto handled;
|
||||
|
||||
close_and_handled:
|
||||
lwsl_debug("Close and handled\n");
|
||||
libwebsocket_close_and_free_session(context, wsi,
|
||||
LWS_CLOSE_STATUS_NOSTATUS);
|
||||
n = 1;
|
||||
|
||||
handled:
|
||||
pollfd->revents = 0;
|
||||
return n;
|
||||
}
|
||||
|
||||
/**
|
||||
* libwebsocket_service() - Service any pending websocket activity
|
||||
* @context: Websocket context
|
||||
* @timeout_ms: Timeout for poll; 0 means return immediately if nothing needed
|
||||
* service otherwise block and service immediately, returning
|
||||
* after the timeout if nothing needed service.
|
||||
*
|
||||
* This function deals with any pending websocket traffic, for three
|
||||
* kinds of event. It handles these events on both server and client
|
||||
* types of connection the same.
|
||||
*
|
||||
* 1) Accept new connections to our context's server
|
||||
*
|
||||
* 2) Call the receive callback for incoming frame data received by
|
||||
* server or client connections.
|
||||
*
|
||||
* You need to call this service function periodically to all the above
|
||||
* functions to happen; if your application is single-threaded you can
|
||||
* just call it in your main event loop.
|
||||
*
|
||||
* Alternatively you can fork a new process that asynchronously handles
|
||||
* calling this service in a loop. In that case you are happy if this
|
||||
* call blocks your thread until it needs to take care of something and
|
||||
* would call it with a large nonzero timeout. Your loop then takes no
|
||||
* CPU while there is nothing happening.
|
||||
*
|
||||
* If you are calling it in a single-threaded app, you don't want it to
|
||||
* wait around blocking other things in your loop from happening, so you
|
||||
* would call it with a timeout_ms of 0, so it returns immediately if
|
||||
* nothing is pending, or as soon as it services whatever was pending.
|
||||
*/
|
||||
|
||||
LWS_VISIBLE int
|
||||
libwebsocket_service(struct libwebsocket_context *context, int timeout_ms)
|
||||
{
|
||||
return lws_plat_service(context, timeout_ms);
|
||||
}
|
||||
|
||||
301
dependencies/libwebsockets/lib/sha-1.c
vendored
Normal file
301
dependencies/libwebsockets/lib/sha-1.c
vendored
Normal file
@ -0,0 +1,301 @@
|
||||
/*
|
||||
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the project nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
/*
|
||||
* FIPS pub 180-1: Secure Hash Algorithm (SHA-1)
|
||||
* based on: http://csrc.nist.gov/fips/fip180-1.txt
|
||||
* implemented by Jun-ichiro itojun Itoh <itojun@itojun.org>
|
||||
*/
|
||||
|
||||
#include "private-libwebsockets.h"
|
||||
|
||||
#ifdef HAVE_SYS_TYPES_H
|
||||
#include <sys/types.h>
|
||||
#endif
|
||||
|
||||
struct sha1_ctxt {
|
||||
union {
|
||||
unsigned char b8[20];
|
||||
unsigned int b32[5];
|
||||
} h;
|
||||
union {
|
||||
unsigned char b8[8];
|
||||
u_int64_t b64[1];
|
||||
} c;
|
||||
union {
|
||||
unsigned char b8[64];
|
||||
unsigned int b32[16];
|
||||
} m;
|
||||
unsigned char count;
|
||||
};
|
||||
|
||||
/* sanity check */
|
||||
#if !defined(BYTE_ORDER) || !defined(LITTLE_ENDIAN) || !defined(BIG_ENDIAN)
|
||||
# define unsupported 1
|
||||
#elif BYTE_ORDER != BIG_ENDIAN
|
||||
# if BYTE_ORDER != LITTLE_ENDIAN
|
||||
# define unsupported 1
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef unsupported
|
||||
|
||||
/* constant table */
|
||||
static const unsigned int _K[] =
|
||||
{ 0x5a827999, 0x6ed9eba1, 0x8f1bbcdc, 0xca62c1d6 };
|
||||
#define K(t) _K[(t) / 20]
|
||||
|
||||
#define F0(b, c, d) (((b) & (c)) | ((~(b)) & (d)))
|
||||
#define F1(b, c, d) (((b) ^ (c)) ^ (d))
|
||||
#define F2(b, c, d) (((b) & (c)) | ((b) & (d)) | ((c) & (d)))
|
||||
#define F3(b, c, d) (((b) ^ (c)) ^ (d))
|
||||
|
||||
#define S(n, x) (((x) << (n)) | ((x) >> (32 - n)))
|
||||
|
||||
#define H(n) (ctxt->h.b32[(n)])
|
||||
#define COUNT (ctxt->count)
|
||||
#define BCOUNT (ctxt->c.b64[0] / 8)
|
||||
#define W(n) (ctxt->m.b32[(n)])
|
||||
|
||||
#define PUTBYTE(x) { \
|
||||
ctxt->m.b8[(COUNT % 64)] = (x); \
|
||||
COUNT++; \
|
||||
COUNT %= 64; \
|
||||
ctxt->c.b64[0] += 8; \
|
||||
if (COUNT % 64 == 0) \
|
||||
sha1_step(ctxt); \
|
||||
}
|
||||
|
||||
#define PUTPAD(x) { \
|
||||
ctxt->m.b8[(COUNT % 64)] = (x); \
|
||||
COUNT++; \
|
||||
COUNT %= 64; \
|
||||
if (COUNT % 64 == 0) \
|
||||
sha1_step(ctxt); \
|
||||
}
|
||||
|
||||
static void sha1_step __P((struct sha1_ctxt *));
|
||||
|
||||
static void
|
||||
sha1_step(struct sha1_ctxt *ctxt)
|
||||
{
|
||||
unsigned int a, b, c, d, e, tmp;
|
||||
size_t t, s;
|
||||
|
||||
#if BYTE_ORDER == LITTLE_ENDIAN
|
||||
struct sha1_ctxt tctxt;
|
||||
|
||||
memcpy(&tctxt.m.b8[0], &ctxt->m.b8[0], 64);
|
||||
ctxt->m.b8[0] = tctxt.m.b8[3]; ctxt->m.b8[1] = tctxt.m.b8[2];
|
||||
ctxt->m.b8[2] = tctxt.m.b8[1]; ctxt->m.b8[3] = tctxt.m.b8[0];
|
||||
ctxt->m.b8[4] = tctxt.m.b8[7]; ctxt->m.b8[5] = tctxt.m.b8[6];
|
||||
ctxt->m.b8[6] = tctxt.m.b8[5]; ctxt->m.b8[7] = tctxt.m.b8[4];
|
||||
ctxt->m.b8[8] = tctxt.m.b8[11]; ctxt->m.b8[9] = tctxt.m.b8[10];
|
||||
ctxt->m.b8[10] = tctxt.m.b8[9]; ctxt->m.b8[11] = tctxt.m.b8[8];
|
||||
ctxt->m.b8[12] = tctxt.m.b8[15]; ctxt->m.b8[13] = tctxt.m.b8[14];
|
||||
ctxt->m.b8[14] = tctxt.m.b8[13]; ctxt->m.b8[15] = tctxt.m.b8[12];
|
||||
ctxt->m.b8[16] = tctxt.m.b8[19]; ctxt->m.b8[17] = tctxt.m.b8[18];
|
||||
ctxt->m.b8[18] = tctxt.m.b8[17]; ctxt->m.b8[19] = tctxt.m.b8[16];
|
||||
ctxt->m.b8[20] = tctxt.m.b8[23]; ctxt->m.b8[21] = tctxt.m.b8[22];
|
||||
ctxt->m.b8[22] = tctxt.m.b8[21]; ctxt->m.b8[23] = tctxt.m.b8[20];
|
||||
ctxt->m.b8[24] = tctxt.m.b8[27]; ctxt->m.b8[25] = tctxt.m.b8[26];
|
||||
ctxt->m.b8[26] = tctxt.m.b8[25]; ctxt->m.b8[27] = tctxt.m.b8[24];
|
||||
ctxt->m.b8[28] = tctxt.m.b8[31]; ctxt->m.b8[29] = tctxt.m.b8[30];
|
||||
ctxt->m.b8[30] = tctxt.m.b8[29]; ctxt->m.b8[31] = tctxt.m.b8[28];
|
||||
ctxt->m.b8[32] = tctxt.m.b8[35]; ctxt->m.b8[33] = tctxt.m.b8[34];
|
||||
ctxt->m.b8[34] = tctxt.m.b8[33]; ctxt->m.b8[35] = tctxt.m.b8[32];
|
||||
ctxt->m.b8[36] = tctxt.m.b8[39]; ctxt->m.b8[37] = tctxt.m.b8[38];
|
||||
ctxt->m.b8[38] = tctxt.m.b8[37]; ctxt->m.b8[39] = tctxt.m.b8[36];
|
||||
ctxt->m.b8[40] = tctxt.m.b8[43]; ctxt->m.b8[41] = tctxt.m.b8[42];
|
||||
ctxt->m.b8[42] = tctxt.m.b8[41]; ctxt->m.b8[43] = tctxt.m.b8[40];
|
||||
ctxt->m.b8[44] = tctxt.m.b8[47]; ctxt->m.b8[45] = tctxt.m.b8[46];
|
||||
ctxt->m.b8[46] = tctxt.m.b8[45]; ctxt->m.b8[47] = tctxt.m.b8[44];
|
||||
ctxt->m.b8[48] = tctxt.m.b8[51]; ctxt->m.b8[49] = tctxt.m.b8[50];
|
||||
ctxt->m.b8[50] = tctxt.m.b8[49]; ctxt->m.b8[51] = tctxt.m.b8[48];
|
||||
ctxt->m.b8[52] = tctxt.m.b8[55]; ctxt->m.b8[53] = tctxt.m.b8[54];
|
||||
ctxt->m.b8[54] = tctxt.m.b8[53]; ctxt->m.b8[55] = tctxt.m.b8[52];
|
||||
ctxt->m.b8[56] = tctxt.m.b8[59]; ctxt->m.b8[57] = tctxt.m.b8[58];
|
||||
ctxt->m.b8[58] = tctxt.m.b8[57]; ctxt->m.b8[59] = tctxt.m.b8[56];
|
||||
ctxt->m.b8[60] = tctxt.m.b8[63]; ctxt->m.b8[61] = tctxt.m.b8[62];
|
||||
ctxt->m.b8[62] = tctxt.m.b8[61]; ctxt->m.b8[63] = tctxt.m.b8[60];
|
||||
#endif
|
||||
|
||||
a = H(0); b = H(1); c = H(2); d = H(3); e = H(4);
|
||||
|
||||
for (t = 0; t < 20; t++) {
|
||||
s = t & 0x0f;
|
||||
if (t >= 16)
|
||||
W(s) = S(1, W((s+13) & 0x0f) ^ W((s+8) & 0x0f) ^
|
||||
W((s+2) & 0x0f) ^ W(s));
|
||||
|
||||
tmp = S(5, a) + F0(b, c, d) + e + W(s) + K(t);
|
||||
e = d; d = c; c = S(30, b); b = a; a = tmp;
|
||||
}
|
||||
for (t = 20; t < 40; t++) {
|
||||
s = t & 0x0f;
|
||||
W(s) = S(1, W((s+13) & 0x0f) ^ W((s+8) & 0x0f) ^
|
||||
W((s+2) & 0x0f) ^ W(s));
|
||||
tmp = S(5, a) + F1(b, c, d) + e + W(s) + K(t);
|
||||
e = d; d = c; c = S(30, b); b = a; a = tmp;
|
||||
}
|
||||
for (t = 40; t < 60; t++) {
|
||||
s = t & 0x0f;
|
||||
W(s) = S(1, W((s+13) & 0x0f) ^ W((s+8) & 0x0f) ^
|
||||
W((s+2) & 0x0f) ^ W(s));
|
||||
tmp = S(5, a) + F2(b, c, d) + e + W(s) + K(t);
|
||||
e = d; d = c; c = S(30, b); b = a; a = tmp;
|
||||
}
|
||||
for (t = 60; t < 80; t++) {
|
||||
s = t & 0x0f;
|
||||
W(s) = S(1, W((s+13) & 0x0f) ^ W((s+8) & 0x0f) ^
|
||||
W((s+2) & 0x0f) ^ W(s));
|
||||
tmp = S(5, a) + F3(b, c, d) + e + W(s) + K(t);
|
||||
e = d; d = c; c = S(30, b); b = a; a = tmp;
|
||||
}
|
||||
|
||||
H(0) = H(0) + a;
|
||||
H(1) = H(1) + b;
|
||||
H(2) = H(2) + c;
|
||||
H(3) = H(3) + d;
|
||||
H(4) = H(4) + e;
|
||||
|
||||
bzero(&ctxt->m.b8[0], 64);
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------*/
|
||||
|
||||
static void
|
||||
sha1_init(struct sha1_ctxt *ctxt)
|
||||
{
|
||||
bzero(ctxt, sizeof(struct sha1_ctxt));
|
||||
H(0) = 0x67452301;
|
||||
H(1) = 0xefcdab89;
|
||||
H(2) = 0x98badcfe;
|
||||
H(3) = 0x10325476;
|
||||
H(4) = 0xc3d2e1f0;
|
||||
}
|
||||
|
||||
void
|
||||
sha1_pad(struct sha1_ctxt *ctxt)
|
||||
{
|
||||
size_t padlen; /*pad length in bytes*/
|
||||
size_t padstart;
|
||||
|
||||
PUTPAD(0x80);
|
||||
|
||||
padstart = COUNT % 64;
|
||||
padlen = 64 - padstart;
|
||||
if (padlen < 8) {
|
||||
bzero(&ctxt->m.b8[padstart], padlen);
|
||||
COUNT += padlen;
|
||||
COUNT %= 64;
|
||||
sha1_step(ctxt);
|
||||
padstart = COUNT % 64; /* should be 0 */
|
||||
padlen = 64 - padstart; /* should be 64 */
|
||||
}
|
||||
bzero(&ctxt->m.b8[padstart], padlen - 8);
|
||||
COUNT += (padlen - 8);
|
||||
COUNT %= 64;
|
||||
#if BYTE_ORDER == BIG_ENDIAN
|
||||
PUTPAD(ctxt->c.b8[0]); PUTPAD(ctxt->c.b8[1]);
|
||||
PUTPAD(ctxt->c.b8[2]); PUTPAD(ctxt->c.b8[3]);
|
||||
PUTPAD(ctxt->c.b8[4]); PUTPAD(ctxt->c.b8[5]);
|
||||
PUTPAD(ctxt->c.b8[6]); PUTPAD(ctxt->c.b8[7]);
|
||||
#else
|
||||
PUTPAD(ctxt->c.b8[7]); PUTPAD(ctxt->c.b8[6]);
|
||||
PUTPAD(ctxt->c.b8[5]); PUTPAD(ctxt->c.b8[4]);
|
||||
PUTPAD(ctxt->c.b8[3]); PUTPAD(ctxt->c.b8[2]);
|
||||
PUTPAD(ctxt->c.b8[1]); PUTPAD(ctxt->c.b8[0]);
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
sha1_loop(struct sha1_ctxt *ctxt, const unsigned char *input, size_t len)
|
||||
{
|
||||
size_t gaplen;
|
||||
size_t gapstart;
|
||||
size_t off;
|
||||
size_t copysiz;
|
||||
|
||||
off = 0;
|
||||
|
||||
while (off < len) {
|
||||
gapstart = COUNT % 64;
|
||||
gaplen = 64 - gapstart;
|
||||
|
||||
copysiz = (gaplen < len - off) ? gaplen : len - off;
|
||||
memcpy(&ctxt->m.b8[gapstart], &input[off], copysiz);
|
||||
COUNT += copysiz;
|
||||
COUNT %= 64;
|
||||
ctxt->c.b64[0] += copysiz * 8;
|
||||
if (COUNT % 64 == 0)
|
||||
sha1_step(ctxt);
|
||||
off += copysiz;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
sha1_result(struct sha1_ctxt *ctxt, void *digest0)
|
||||
{
|
||||
unsigned char *digest;
|
||||
|
||||
digest = (unsigned char *)digest0;
|
||||
sha1_pad(ctxt);
|
||||
#if BYTE_ORDER == BIG_ENDIAN
|
||||
memcpy(digest, &ctxt->h.b8[0], 20);
|
||||
#else
|
||||
digest[0] = ctxt->h.b8[3]; digest[1] = ctxt->h.b8[2];
|
||||
digest[2] = ctxt->h.b8[1]; digest[3] = ctxt->h.b8[0];
|
||||
digest[4] = ctxt->h.b8[7]; digest[5] = ctxt->h.b8[6];
|
||||
digest[6] = ctxt->h.b8[5]; digest[7] = ctxt->h.b8[4];
|
||||
digest[8] = ctxt->h.b8[11]; digest[9] = ctxt->h.b8[10];
|
||||
digest[10] = ctxt->h.b8[9]; digest[11] = ctxt->h.b8[8];
|
||||
digest[12] = ctxt->h.b8[15]; digest[13] = ctxt->h.b8[14];
|
||||
digest[14] = ctxt->h.b8[13]; digest[15] = ctxt->h.b8[12];
|
||||
digest[16] = ctxt->h.b8[19]; digest[17] = ctxt->h.b8[18];
|
||||
digest[18] = ctxt->h.b8[17]; digest[19] = ctxt->h.b8[16];
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* This should look and work like the libcrypto implementation
|
||||
*/
|
||||
|
||||
unsigned char *
|
||||
SHA1(const unsigned char *d, size_t n, unsigned char *md)
|
||||
{
|
||||
struct sha1_ctxt ctx;
|
||||
|
||||
sha1_init(&ctx);
|
||||
sha1_loop(&ctx, d, n);
|
||||
sha1_result(&ctx, (void *)md);
|
||||
|
||||
return md;
|
||||
}
|
||||
|
||||
#endif /*unsupported*/
|
||||
78
dependencies/libwebsockets/lib/ssl-http2.c
vendored
Normal file
78
dependencies/libwebsockets/lib/ssl-http2.c
vendored
Normal file
@ -0,0 +1,78 @@
|
||||
/*
|
||||
* libwebsockets - small server side websockets and web server implementation
|
||||
*
|
||||
* Copyright (C) 2010-2014 Andy Green <andy@warmcat.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation:
|
||||
* version 2.1 of the License.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
* MA 02110-1301 USA
|
||||
*
|
||||
* Some or all of this file is based on code from nghttp2, which has the
|
||||
* following license. Since it's more liberal than lws license, you're also
|
||||
* at liberty to get the original code from
|
||||
* https://github.com/tatsuhiro-t/nghttp2 under his liberal terms alone.
|
||||
*
|
||||
* nghttp2 - HTTP/2.0 C Library
|
||||
*
|
||||
* Copyright (c) 2012 Tatsuhiro Tsujikawa
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "private-libwebsockets.h"
|
||||
|
||||
#ifndef LWS_NO_SERVER
|
||||
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x10002000L
|
||||
static int alpn_select_proto_cb(SSL* ssl,
|
||||
const unsigned char **out,
|
||||
unsigned char *outlen,
|
||||
const unsigned char *in, unsigned int inlen,
|
||||
void *arg)
|
||||
{
|
||||
lwsl_err((char *)in);
|
||||
return SSL_TLSEXT_ERR_OK; /* SSL_TLSEXT_ERR_NOACK */
|
||||
}
|
||||
#endif
|
||||
|
||||
LWS_VISIBLE void
|
||||
lws_context_init_http2_ssl(struct libwebsocket_context *context)
|
||||
{
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x10002000L
|
||||
// ALPN selection callback
|
||||
SSL_CTX_set_alpn_select_cb(context->ssl_ctx, alpn_select_proto_cb, NULL);
|
||||
lwsl_notice(" HTTP2 / ALPN enabled\n");
|
||||
#else
|
||||
lwsl_notice(" HTTP2 / ALPN configured but not supported by OpenSSL version\n");
|
||||
#endif // OPENSSL_VERSION_NUMBER >= 0x10002000L
|
||||
}
|
||||
|
||||
#endif
|
||||
571
dependencies/libwebsockets/lib/ssl.c
vendored
Normal file
571
dependencies/libwebsockets/lib/ssl.c
vendored
Normal file
@ -0,0 +1,571 @@
|
||||
/*
|
||||
* libwebsockets - small server side websockets and web server implementation
|
||||
*
|
||||
* Copyright (C) 2010-2014 Andy Green <andy@warmcat.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation:
|
||||
* version 2.1 of the License.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
* MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "private-libwebsockets.h"
|
||||
|
||||
int openssl_websocket_private_data_index;
|
||||
|
||||
static int
|
||||
OpenSSL_verify_callback(int preverify_ok, X509_STORE_CTX *x509_ctx)
|
||||
{
|
||||
SSL *ssl;
|
||||
int n;
|
||||
struct libwebsocket_context *context;
|
||||
|
||||
ssl = X509_STORE_CTX_get_ex_data(x509_ctx,
|
||||
SSL_get_ex_data_X509_STORE_CTX_idx());
|
||||
|
||||
/*
|
||||
* !!! nasty openssl requires the index to come as a library-scope
|
||||
* static
|
||||
*/
|
||||
context = SSL_get_ex_data(ssl, openssl_websocket_private_data_index);
|
||||
|
||||
n = context->protocols[0].callback(NULL, NULL,
|
||||
LWS_CALLBACK_OPENSSL_PERFORM_CLIENT_CERT_VERIFICATION,
|
||||
x509_ctx, ssl, preverify_ok);
|
||||
|
||||
/* convert return code from 0 = OK to 1 = OK */
|
||||
return !n;
|
||||
}
|
||||
|
||||
LWS_VISIBLE int
|
||||
lws_context_init_server_ssl(struct lws_context_creation_info *info,
|
||||
struct libwebsocket_context *context)
|
||||
{
|
||||
SSL_METHOD *method;
|
||||
int error;
|
||||
int n;
|
||||
|
||||
#ifndef LWS_NO_SERVER
|
||||
if (info->port != CONTEXT_PORT_NO_LISTEN) {
|
||||
|
||||
context->use_ssl = info->ssl_cert_filepath != NULL &&
|
||||
info->ssl_private_key_filepath != NULL;
|
||||
#ifdef USE_CYASSL
|
||||
lwsl_notice(" Compiled with CYASSL support\n");
|
||||
#else
|
||||
lwsl_notice(" Compiled with OpenSSL support\n");
|
||||
#endif
|
||||
|
||||
if (info->ssl_cipher_list)
|
||||
lwsl_notice(" SSL ciphers: '%s'\n", info->ssl_cipher_list);
|
||||
|
||||
if (context->use_ssl)
|
||||
lwsl_notice(" Using SSL mode\n");
|
||||
else
|
||||
lwsl_notice(" Using non-SSL mode\n");
|
||||
}
|
||||
|
||||
#else
|
||||
if (info->ssl_cert_filepath != NULL &&
|
||||
info->ssl_private_key_filepath != NULL) {
|
||||
lwsl_notice(" Not compiled for OpenSSl support!\n");
|
||||
return 1;
|
||||
}
|
||||
lwsl_notice(" Compiled without SSL support\n");
|
||||
}
|
||||
#endif /* no server */
|
||||
|
||||
/* basic openssl init */
|
||||
|
||||
SSL_library_init();
|
||||
|
||||
OpenSSL_add_all_algorithms();
|
||||
SSL_load_error_strings();
|
||||
|
||||
openssl_websocket_private_data_index =
|
||||
SSL_get_ex_new_index(0, "libwebsockets", NULL, NULL, NULL);
|
||||
|
||||
/*
|
||||
* Firefox insists on SSLv23 not SSLv3
|
||||
* Konq disables SSLv2 by default now, SSLv23 works
|
||||
*/
|
||||
|
||||
method = (SSL_METHOD *)SSLv23_server_method();
|
||||
if (!method) {
|
||||
error = ERR_get_error();
|
||||
lwsl_err("problem creating ssl method %lu: %s\n",
|
||||
error, ERR_error_string(error,
|
||||
(char *)context->service_buffer));
|
||||
return 1;
|
||||
}
|
||||
context->ssl_ctx = SSL_CTX_new(method); /* create context */
|
||||
if (!context->ssl_ctx) {
|
||||
error = ERR_get_error();
|
||||
lwsl_err("problem creating ssl context %lu: %s\n",
|
||||
error, ERR_error_string(error,
|
||||
(char *)context->service_buffer));
|
||||
return 1;
|
||||
}
|
||||
|
||||
#ifdef SSL_OP_NO_COMPRESSION
|
||||
SSL_CTX_set_options(context->ssl_ctx, SSL_OP_NO_COMPRESSION);
|
||||
#endif
|
||||
SSL_CTX_set_options(context->ssl_ctx, SSL_OP_CIPHER_SERVER_PREFERENCE);
|
||||
if (info->ssl_cipher_list)
|
||||
SSL_CTX_set_cipher_list(context->ssl_ctx,
|
||||
info->ssl_cipher_list);
|
||||
|
||||
/* as a server, are we requiring clients to identify themselves? */
|
||||
|
||||
if (info->options &
|
||||
LWS_SERVER_OPTION_REQUIRE_VALID_OPENSSL_CLIENT_CERT) {
|
||||
|
||||
/* absolutely require the client cert */
|
||||
|
||||
SSL_CTX_set_verify(context->ssl_ctx,
|
||||
SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT,
|
||||
OpenSSL_verify_callback);
|
||||
|
||||
/*
|
||||
* give user code a chance to load certs into the server
|
||||
* allowing it to verify incoming client certs
|
||||
*/
|
||||
|
||||
context->protocols[0].callback(context, NULL,
|
||||
LWS_CALLBACK_OPENSSL_LOAD_EXTRA_SERVER_VERIFY_CERTS,
|
||||
context->ssl_ctx, NULL, 0);
|
||||
}
|
||||
|
||||
if (info->options & LWS_SERVER_OPTION_ALLOW_NON_SSL_ON_SSL_PORT) {
|
||||
/* Normally SSL listener rejects non-ssl, optionally allow */
|
||||
context->allow_non_ssl_on_ssl_port = 1;
|
||||
}
|
||||
|
||||
if (context->use_ssl) {
|
||||
|
||||
/* openssl init for server sockets */
|
||||
|
||||
/* set the local certificate from CertFile */
|
||||
n = SSL_CTX_use_certificate_chain_file(context->ssl_ctx,
|
||||
info->ssl_cert_filepath);
|
||||
if (n != 1) {
|
||||
error = ERR_get_error();
|
||||
lwsl_err("problem getting cert '%s' %lu: %s\n",
|
||||
info->ssl_cert_filepath,
|
||||
error,
|
||||
ERR_error_string(error,
|
||||
(char *)context->service_buffer));
|
||||
return 1;
|
||||
}
|
||||
/* set the private key from KeyFile */
|
||||
if (SSL_CTX_use_PrivateKey_file(context->ssl_ctx,
|
||||
info->ssl_private_key_filepath,
|
||||
SSL_FILETYPE_PEM) != 1) {
|
||||
error = ERR_get_error();
|
||||
lwsl_err("ssl problem getting key '%s' %lu: %s\n",
|
||||
info->ssl_private_key_filepath,
|
||||
error,
|
||||
ERR_error_string(error,
|
||||
(char *)context->service_buffer));
|
||||
return 1;
|
||||
}
|
||||
/* verify private key */
|
||||
if (!SSL_CTX_check_private_key(context->ssl_ctx)) {
|
||||
lwsl_err("Private SSL key doesn't match cert\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* SSL is happy and has a cert it's content with
|
||||
* If we're supporting HTTP2, initialize that
|
||||
*/
|
||||
|
||||
lws_context_init_http2_ssl(context);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
LWS_VISIBLE void
|
||||
lws_ssl_destroy(struct libwebsocket_context *context)
|
||||
{
|
||||
if (context->ssl_ctx)
|
||||
SSL_CTX_free(context->ssl_ctx);
|
||||
if (context->ssl_client_ctx)
|
||||
SSL_CTX_free(context->ssl_client_ctx);
|
||||
|
||||
ERR_remove_state(0);
|
||||
ERR_free_strings();
|
||||
EVP_cleanup();
|
||||
CRYPTO_cleanup_all_ex_data();
|
||||
}
|
||||
|
||||
LWS_VISIBLE void
|
||||
libwebsockets_decode_ssl_error(void)
|
||||
{
|
||||
char buf[256];
|
||||
u_long err;
|
||||
|
||||
while ((err = ERR_get_error()) != 0) {
|
||||
ERR_error_string_n(err, buf, sizeof(buf));
|
||||
lwsl_err("*** %lu %s\n", err, buf);
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef LWS_NO_CLIENT
|
||||
int lws_context_init_client_ssl(struct lws_context_creation_info *info,
|
||||
struct libwebsocket_context *context)
|
||||
{
|
||||
int error;
|
||||
int n;
|
||||
SSL_METHOD *method;
|
||||
|
||||
if (info->port != CONTEXT_PORT_NO_LISTEN)
|
||||
return 0;
|
||||
|
||||
method = (SSL_METHOD *)SSLv23_client_method();
|
||||
if (!method) {
|
||||
error = ERR_get_error();
|
||||
lwsl_err("problem creating ssl method %lu: %s\n",
|
||||
error, ERR_error_string(error,
|
||||
(char *)context->service_buffer));
|
||||
return 1;
|
||||
}
|
||||
/* create context */
|
||||
context->ssl_client_ctx = SSL_CTX_new(method);
|
||||
if (!context->ssl_client_ctx) {
|
||||
error = ERR_get_error();
|
||||
lwsl_err("problem creating ssl context %lu: %s\n",
|
||||
error, ERR_error_string(error,
|
||||
(char *)context->service_buffer));
|
||||
return 1;
|
||||
}
|
||||
|
||||
#ifdef SSL_OP_NO_COMPRESSION
|
||||
SSL_CTX_set_options(context->ssl_client_ctx,
|
||||
SSL_OP_NO_COMPRESSION);
|
||||
#endif
|
||||
SSL_CTX_set_options(context->ssl_client_ctx,
|
||||
SSL_OP_CIPHER_SERVER_PREFERENCE);
|
||||
if (info->ssl_cipher_list)
|
||||
SSL_CTX_set_cipher_list(context->ssl_client_ctx,
|
||||
info->ssl_cipher_list);
|
||||
|
||||
#ifdef LWS_SSL_CLIENT_USE_OS_CA_CERTS
|
||||
if (!(info->options & LWS_SERVER_OPTION_DISABLE_OS_CA_CERTS))
|
||||
/* loads OS default CA certs */
|
||||
SSL_CTX_set_default_verify_paths(context->ssl_client_ctx);
|
||||
#endif
|
||||
|
||||
/* openssl init for cert verification (for client sockets) */
|
||||
if (!info->ssl_ca_filepath) {
|
||||
if (!SSL_CTX_load_verify_locations(
|
||||
context->ssl_client_ctx, NULL,
|
||||
LWS_OPENSSL_CLIENT_CERTS))
|
||||
lwsl_err(
|
||||
"Unable to load SSL Client certs from %s "
|
||||
"(set by --with-client-cert-dir= "
|
||||
"in configure) -- client ssl isn't "
|
||||
"going to work", LWS_OPENSSL_CLIENT_CERTS);
|
||||
} else
|
||||
if (!SSL_CTX_load_verify_locations(
|
||||
context->ssl_client_ctx, info->ssl_ca_filepath,
|
||||
NULL))
|
||||
lwsl_err(
|
||||
"Unable to load SSL Client certs "
|
||||
"file from %s -- client ssl isn't "
|
||||
"going to work", info->ssl_ca_filepath);
|
||||
|
||||
/*
|
||||
* callback allowing user code to load extra verification certs
|
||||
* helping the client to verify server identity
|
||||
*/
|
||||
|
||||
/* support for client-side certificate authentication */
|
||||
if (info->ssl_cert_filepath) {
|
||||
n = SSL_CTX_use_certificate_chain_file(
|
||||
context->ssl_client_ctx,
|
||||
info->ssl_cert_filepath);
|
||||
if (n != 1) {
|
||||
lwsl_err("problem getting cert '%s' %lu: %s\n",
|
||||
info->ssl_cert_filepath,
|
||||
ERR_get_error(),
|
||||
ERR_error_string(ERR_get_error(),
|
||||
(char *)context->service_buffer));
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
if (info->ssl_private_key_filepath) {
|
||||
/* set the private key from KeyFile */
|
||||
if (SSL_CTX_use_PrivateKey_file(context->ssl_client_ctx,
|
||||
info->ssl_private_key_filepath,
|
||||
SSL_FILETYPE_PEM) != 1) {
|
||||
lwsl_err("use_PrivateKey_file '%s' %lu: %s\n",
|
||||
info->ssl_private_key_filepath,
|
||||
ERR_get_error(),
|
||||
ERR_error_string(ERR_get_error(),
|
||||
(char *)context->service_buffer));
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* verify private key */
|
||||
if (!SSL_CTX_check_private_key(
|
||||
context->ssl_client_ctx)) {
|
||||
lwsl_err("Private SSL key doesn't match cert\n");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
context->protocols[0].callback(context, NULL,
|
||||
LWS_CALLBACK_OPENSSL_LOAD_EXTRA_CLIENT_VERIFY_CERTS,
|
||||
context->ssl_client_ctx, NULL, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
LWS_VISIBLE int
|
||||
lws_ssl_capable_read(struct libwebsocket *wsi, unsigned char *buf, int len)
|
||||
{
|
||||
int n;
|
||||
|
||||
if (!wsi->ssl)
|
||||
return lws_ssl_capable_read_no_ssl(wsi, buf, len);
|
||||
|
||||
n = SSL_read(wsi->ssl, buf, len);
|
||||
if (n >= 0)
|
||||
return n;
|
||||
|
||||
n = SSL_get_error(wsi->ssl, n);
|
||||
if (n == SSL_ERROR_WANT_READ || n == SSL_ERROR_WANT_WRITE)
|
||||
return LWS_SSL_CAPABLE_MORE_SERVICE;
|
||||
|
||||
return LWS_SSL_CAPABLE_ERROR;
|
||||
}
|
||||
|
||||
LWS_VISIBLE int
|
||||
lws_ssl_capable_write(struct libwebsocket *wsi, unsigned char *buf, int len)
|
||||
{
|
||||
int n;
|
||||
|
||||
if (!wsi->ssl)
|
||||
return lws_ssl_capable_write_no_ssl(wsi, buf, len);
|
||||
|
||||
n = SSL_write(wsi->ssl, buf, len);
|
||||
if (n >= 0)
|
||||
return n;
|
||||
|
||||
n = SSL_get_error(wsi->ssl, n);
|
||||
if (n == SSL_ERROR_WANT_READ || n == SSL_ERROR_WANT_WRITE) {
|
||||
if (n == SSL_ERROR_WANT_WRITE)
|
||||
lws_set_blocking_send(wsi);
|
||||
return LWS_SSL_CAPABLE_MORE_SERVICE;
|
||||
}
|
||||
|
||||
return LWS_SSL_CAPABLE_ERROR;
|
||||
}
|
||||
|
||||
LWS_VISIBLE int
|
||||
lws_ssl_pending(struct libwebsocket *wsi)
|
||||
{
|
||||
if (wsi->ssl)
|
||||
return SSL_pending(wsi->ssl);
|
||||
return 0;
|
||||
}
|
||||
|
||||
LWS_VISIBLE int
|
||||
lws_ssl_close(struct libwebsocket *wsi)
|
||||
{
|
||||
int n;
|
||||
|
||||
if (!wsi->ssl)
|
||||
return 0; /* not handled */
|
||||
|
||||
n = SSL_get_fd(wsi->ssl);
|
||||
SSL_shutdown(wsi->ssl);
|
||||
compatible_close(n);
|
||||
SSL_free(wsi->ssl);
|
||||
|
||||
return 1; /* handled */
|
||||
}
|
||||
|
||||
LWS_VISIBLE int
|
||||
lws_server_socket_service_ssl(struct libwebsocket_context *context,
|
||||
struct libwebsocket **pwsi, struct libwebsocket *new_wsi,
|
||||
int accept_fd, struct libwebsocket_pollfd *pollfd)
|
||||
{
|
||||
int n, m;
|
||||
struct libwebsocket *wsi = *pwsi;
|
||||
#ifndef USE_CYASSL
|
||||
BIO *bio;
|
||||
#endif
|
||||
|
||||
if (!LWS_SSL_ENABLED(context))
|
||||
return 0;
|
||||
|
||||
switch (wsi->mode) {
|
||||
case LWS_CONNMODE_SERVER_LISTENER:
|
||||
|
||||
new_wsi->ssl = SSL_new(context->ssl_ctx);
|
||||
if (new_wsi->ssl == NULL) {
|
||||
lwsl_err("SSL_new failed: %s\n",
|
||||
ERR_error_string(SSL_get_error(
|
||||
new_wsi->ssl, 0), NULL));
|
||||
libwebsockets_decode_ssl_error();
|
||||
free(new_wsi);
|
||||
compatible_close(accept_fd);
|
||||
break;
|
||||
}
|
||||
|
||||
SSL_set_ex_data(new_wsi->ssl,
|
||||
openssl_websocket_private_data_index, context);
|
||||
|
||||
SSL_set_fd(new_wsi->ssl, accept_fd);
|
||||
|
||||
#ifdef USE_CYASSL
|
||||
CyaSSL_set_using_nonblock(new_wsi->ssl, 1);
|
||||
#else
|
||||
SSL_set_mode(new_wsi->ssl, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
|
||||
bio = SSL_get_rbio(new_wsi->ssl);
|
||||
if (bio)
|
||||
BIO_set_nbio(bio, 1); /* nonblocking */
|
||||
else
|
||||
lwsl_notice("NULL rbio\n");
|
||||
bio = SSL_get_wbio(new_wsi->ssl);
|
||||
if (bio)
|
||||
BIO_set_nbio(bio, 1); /* nonblocking */
|
||||
else
|
||||
lwsl_notice("NULL rbio\n");
|
||||
#endif
|
||||
|
||||
/*
|
||||
* we are not accepted yet, but we need to enter ourselves
|
||||
* as a live connection. That way we can retry when more
|
||||
* pieces come if we're not sorted yet
|
||||
*/
|
||||
|
||||
*pwsi = new_wsi;
|
||||
wsi = *pwsi;
|
||||
wsi->mode = LWS_CONNMODE_SSL_ACK_PENDING;
|
||||
insert_wsi_socket_into_fds(context, wsi);
|
||||
|
||||
libwebsocket_set_timeout(wsi, PENDING_TIMEOUT_SSL_ACCEPT,
|
||||
AWAITING_TIMEOUT);
|
||||
|
||||
lwsl_info("inserted SSL accept into fds, trying SSL_accept\n");
|
||||
|
||||
/* fallthru */
|
||||
|
||||
case LWS_CONNMODE_SSL_ACK_PENDING:
|
||||
|
||||
if (lws_change_pollfd(wsi, LWS_POLLOUT, 0))
|
||||
goto fail;
|
||||
|
||||
lws_libev_io(context, wsi, LWS_EV_STOP | LWS_EV_WRITE);
|
||||
|
||||
lws_latency_pre(context, wsi);
|
||||
|
||||
n = recv(wsi->sock, context->service_buffer,
|
||||
sizeof(context->service_buffer), MSG_PEEK);
|
||||
|
||||
/*
|
||||
* optionally allow non-SSL connect on SSL listening socket
|
||||
* This is disabled by default, if enabled it goes around any
|
||||
* SSL-level access control (eg, client-side certs) so leave
|
||||
* it disabled unless you know it's not a problem for you
|
||||
*/
|
||||
|
||||
if (context->allow_non_ssl_on_ssl_port && n >= 1 &&
|
||||
context->service_buffer[0] >= ' ') {
|
||||
/*
|
||||
* TLS content-type for Handshake is 0x16
|
||||
* TLS content-type for ChangeCipherSpec Record is 0x14
|
||||
*
|
||||
* A non-ssl session will start with the HTTP method in
|
||||
* ASCII. If we see it's not a legit SSL handshake
|
||||
* kill the SSL for this connection and try to handle
|
||||
* as a HTTP connection upgrade directly.
|
||||
*/
|
||||
wsi->use_ssl = 0;
|
||||
SSL_shutdown(wsi->ssl);
|
||||
SSL_free(wsi->ssl);
|
||||
wsi->ssl = NULL;
|
||||
goto accepted;
|
||||
}
|
||||
|
||||
/* normal SSL connection processing path */
|
||||
|
||||
n = SSL_accept(wsi->ssl);
|
||||
lws_latency(context, wsi,
|
||||
"SSL_accept LWS_CONNMODE_SSL_ACK_PENDING\n", n, n == 1);
|
||||
|
||||
if (n == 1)
|
||||
goto accepted;
|
||||
|
||||
m = SSL_get_error(wsi->ssl, n);
|
||||
lwsl_debug("SSL_accept failed %d / %s\n",
|
||||
m, ERR_error_string(m, NULL));
|
||||
|
||||
if (m == SSL_ERROR_WANT_READ) {
|
||||
if (lws_change_pollfd(wsi, 0, LWS_POLLIN))
|
||||
goto fail;
|
||||
|
||||
lws_libev_io(context, wsi, LWS_EV_START | LWS_EV_READ);
|
||||
|
||||
lwsl_info("SSL_ERROR_WANT_READ\n");
|
||||
break;
|
||||
}
|
||||
if (m == SSL_ERROR_WANT_WRITE) {
|
||||
if (lws_change_pollfd(wsi, 0, LWS_POLLOUT))
|
||||
goto fail;
|
||||
|
||||
lws_libev_io(context, wsi, LWS_EV_START | LWS_EV_WRITE);
|
||||
break;
|
||||
}
|
||||
lwsl_debug("SSL_accept failed skt %u: %s\n",
|
||||
pollfd->fd, ERR_error_string(m, NULL));
|
||||
libwebsocket_close_and_free_session(context, wsi,
|
||||
LWS_CLOSE_STATUS_NOSTATUS);
|
||||
break;
|
||||
|
||||
accepted:
|
||||
/* OK, we are accepted... give him some time to negotiate */
|
||||
libwebsocket_set_timeout(wsi,
|
||||
PENDING_TIMEOUT_ESTABLISH_WITH_SERVER,
|
||||
AWAITING_TIMEOUT);
|
||||
|
||||
wsi->mode = LWS_CONNMODE_HTTP_SERVING;
|
||||
|
||||
lwsl_debug("accepted new SSL conn\n");
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
return 1;
|
||||
}
|
||||
|
||||
LWS_VISIBLE void
|
||||
lws_ssl_context_destroy(struct libwebsocket_context *context)
|
||||
{
|
||||
if (context->ssl_ctx)
|
||||
SSL_CTX_free(context->ssl_ctx);
|
||||
if (context->ssl_client_ctx)
|
||||
SSL_CTX_free(context->ssl_client_ctx);
|
||||
|
||||
ERR_remove_state(0);
|
||||
ERR_free_strings();
|
||||
EVP_cleanup();
|
||||
CRYPTO_cleanup_all_ex_data();
|
||||
}
|
||||
1063
dependencies/libwebsockets/libwebsockets-api-doc.html
vendored
Normal file
1063
dependencies/libwebsockets/libwebsockets-api-doc.html
vendored
Normal file
File diff suppressed because it is too large
Load Diff
66
dependencies/libwebsockets/libwebsockets.spec
vendored
Normal file
66
dependencies/libwebsockets/libwebsockets.spec
vendored
Normal file
@ -0,0 +1,66 @@
|
||||
Name: libwebsockets
|
||||
Version: 1.3
|
||||
Release: 47.gmaster_b89f21c%{?dist}
|
||||
Summary: Websocket Server Library
|
||||
|
||||
Group: System
|
||||
License: GPL
|
||||
URL: http://warmcat.com
|
||||
Source0: %{name}-%{version}.tar.gz
|
||||
BuildRoot: %(mktemp -ud %{_tmppath}/%{name}-%{version}-%{release}-XXXXXX)
|
||||
|
||||
BuildRequires: openssl-devel
|
||||
Requires: openssl-devel
|
||||
|
||||
%description
|
||||
Webserver server library
|
||||
|
||||
%package devel
|
||||
Summary: Development files for libwebsockets
|
||||
Group: Development/Libraries
|
||||
Requires: %{name} = %{version}-%{release}
|
||||
Requires: openssl-devel
|
||||
|
||||
%description devel
|
||||
Development files for libwebsockets
|
||||
|
||||
%prep
|
||||
%setup -q
|
||||
|
||||
%build
|
||||
mkdir -p build
|
||||
cd build
|
||||
%cmake ..
|
||||
make
|
||||
|
||||
%install
|
||||
rm -rf $RPM_BUILD_ROOT
|
||||
cd build
|
||||
make install DESTDIR=$RPM_BUILD_ROOT
|
||||
|
||||
|
||||
%clean
|
||||
rm -rf $RPM_BUILD_ROOT
|
||||
|
||||
%files
|
||||
%defattr(-,root,root,-)
|
||||
%attr(755,root,root) /usr/bin/libwebsockets-test-server
|
||||
%attr(755,root,root) /usr/bin/libwebsockets-test-server-extpoll
|
||||
%attr(755,root,root) /usr/bin/libwebsockets-test-client
|
||||
%attr(755,root,root) /usr/bin/libwebsockets-test-ping
|
||||
%attr(755,root,root) /usr/bin/libwebsockets-test-echo
|
||||
%attr(755,root,root) /usr/bin/libwebsockets-test-fraggle
|
||||
%attr(755,root,root)
|
||||
/%{_libdir}/libwebsockets.so.4.0.0
|
||||
/%{_libdir}/libwebsockets.so
|
||||
%attr(755,root,root) /usr/share/libwebsockets-test-server
|
||||
%doc
|
||||
%files devel
|
||||
%defattr(-,root,root,-)
|
||||
/usr/include/*
|
||||
%attr(755,root,root)
|
||||
/%{_libdir}/libwebsockets.a
|
||||
/%{_libdir}/pkgconfig/libwebsockets.pc
|
||||
|
||||
%changelog
|
||||
|
||||
33
dependencies/libwebsockets/scripts/FindLibWebSockets.cmake
vendored
Normal file
33
dependencies/libwebsockets/scripts/FindLibWebSockets.cmake
vendored
Normal file
@ -0,0 +1,33 @@
|
||||
# This module tries to find libWebsockets library and include files
|
||||
#
|
||||
# LIBWEBSOCKETS_INCLUDE_DIR, path where to find libwebsockets.h
|
||||
# LIBWEBSOCKETS_LIBRARY_DIR, path where to find libwebsockets.so
|
||||
# LIBWEBSOCKETS_LIBRARIES, the library to link against
|
||||
# LIBWEBSOCKETS_FOUND, If false, do not try to use libWebSockets
|
||||
#
|
||||
# This currently works probably only for Linux
|
||||
|
||||
FIND_PATH ( LIBWEBSOCKETS_INCLUDE_DIR libwebsockets.h
|
||||
/usr/local/include
|
||||
/usr/include
|
||||
)
|
||||
|
||||
FIND_LIBRARY ( LIBWEBSOCKETS_LIBRARIES websockets
|
||||
/usr/local/lib
|
||||
/usr/lib
|
||||
)
|
||||
|
||||
GET_FILENAME_COMPONENT( LIBWEBSOCKETS_LIBRARY_DIR ${LIBWEBSOCKETS_LIBRARIES} PATH )
|
||||
|
||||
SET ( LIBWEBSOCKETS_FOUND "NO" )
|
||||
IF ( LIBWEBSOCKETS_INCLUDE_DIR )
|
||||
IF ( LIBWEBSOCKETS_LIBRARIES )
|
||||
SET ( LIBWEBSOCKETS_FOUND "YES" )
|
||||
ENDIF ( LIBWEBSOCKETS_LIBRARIES )
|
||||
ENDIF ( LIBWEBSOCKETS_INCLUDE_DIR )
|
||||
|
||||
MARK_AS_ADVANCED(
|
||||
LIBWEBSOCKETS_LIBRARY_DIR
|
||||
LIBWEBSOCKETS_INCLUDE_DIR
|
||||
LIBWEBSOCKETS_LIBRARIES
|
||||
)
|
||||
2239
dependencies/libwebsockets/scripts/kernel-doc
vendored
Normal file
2239
dependencies/libwebsockets/scripts/kernel-doc
vendored
Normal file
File diff suppressed because it is too large
Load Diff
9
dependencies/libwebsockets/test-server/.gitignore
vendored
Normal file
9
dependencies/libwebsockets/test-server/.gitignore
vendored
Normal file
@ -0,0 +1,9 @@
|
||||
#Ignore build files
|
||||
libwebsockets-test-*
|
||||
Makefile
|
||||
*.o
|
||||
*.lo
|
||||
*.la
|
||||
.libs
|
||||
.deps
|
||||
|
||||
217
dependencies/libwebsockets/test-server/attack.sh
vendored
Normal file
217
dependencies/libwebsockets/test-server/attack.sh
vendored
Normal file
@ -0,0 +1,217 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# attack the test server and try to make it fall over
|
||||
#
|
||||
SERVER=127.0.0.1
|
||||
PORT=7681
|
||||
LOG=/tmp/lwslog
|
||||
|
||||
CPID=
|
||||
LEN=0
|
||||
|
||||
function check {
|
||||
kill -0 $CPID
|
||||
if [ $? -ne 0 ] ; then
|
||||
echo "(killed it) *******"
|
||||
exit 1
|
||||
fi
|
||||
dd if=$LOG bs=1 skip=$LEN 2>/dev/null
|
||||
|
||||
if [ "$1" = "default" ] ; then
|
||||
diff /tmp/lwscap /usr/share/libwebsockets-test-server/test.html > /dev/null
|
||||
if [ $? -ne 0 ] ; then
|
||||
echo "FAIL: got something other than test.html back"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ "$1" = "forbidden" ] ; then
|
||||
if [ -z "`grep '<h1>403 Forbidden</h1>' /tmp/lwscap`" ] ; then
|
||||
echo "FAIL: should have told forbidden (test server has no dirs)"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ "$1" == "args" ] ; then
|
||||
a="`dd if=$LOG bs=1 skip=$LEN 2>/dev/null |grep Uri.Args\: | tr -s ' ' | cut -d' ' -f4-`"
|
||||
if [ "$a" != "$2" ] ; then
|
||||
echo "Args '$a' not $2"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
LEN=`stat $LOG -c %s`
|
||||
}
|
||||
|
||||
|
||||
rm -rf $LOG
|
||||
killall libwebsockets-test-server 2>/dev/null
|
||||
libwebsockets-test-server -d31 2>> $LOG &
|
||||
CPID=$!
|
||||
|
||||
while [ -z "`grep Listening $LOG`" ] ; do
|
||||
sleep 0.5s
|
||||
done
|
||||
check
|
||||
|
||||
echo
|
||||
echo "---- ? processing (%2f%2e%2e%2f%2e./test.html?arg=1)"
|
||||
rm -f /tmp/lwscap
|
||||
echo -e "GET %2f%2e%2e%2f%2e./test.html?arg=1 HTTP/1.1\x0d\x0a\x0d\x0a" | nc $SERVER $PORT | sed '1,/^\r$/d'> /tmp/lwscap
|
||||
check args "arg=1"
|
||||
|
||||
echo
|
||||
echo "---- ? processing (%2f%2e%2e%2f%2e./test.html?arg=/../.)"
|
||||
rm -f /tmp/lwscap
|
||||
echo -e "GET %2f%2e%2e%2f%2e./test.html?arg=/../. HTTP/1.1\x0d\x0a\x0d\x0a" | nc $SERVER $PORT | sed '1,/^\r$/d'> /tmp/lwscap
|
||||
check args "arg=/../."
|
||||
|
||||
|
||||
echo
|
||||
echo "---- spam enough crap to not be GET"
|
||||
echo "not GET" | nc $SERVER $PORT
|
||||
check
|
||||
|
||||
echo
|
||||
echo "---- spam more than the name buffer of crap"
|
||||
dd if=/dev/urandom bs=1 count=80 2>/dev/null | nc -i1s $SERVER $PORT
|
||||
check
|
||||
|
||||
echo
|
||||
echo "---- spam 10MB of crap"
|
||||
dd if=/dev/urandom bs=1 count=655360 | nc -i1s $SERVER $PORT
|
||||
check
|
||||
|
||||
echo
|
||||
echo "---- malformed URI"
|
||||
echo "GET nonsense................................................................................................................" \
|
||||
| nc -i1s $SERVER $PORT
|
||||
check
|
||||
|
||||
echo
|
||||
echo "---- missing URI"
|
||||
echo -e "GET HTTP/1.1\x0d\x0a\x0d\x0a" | nc -i1s $SERVER $PORT >/tmp/lwscap
|
||||
check
|
||||
|
||||
echo
|
||||
echo "---- repeated method"
|
||||
echo -e "GET blah HTTP/1.1\x0d\x0aGET blah HTTP/1.1\x0d\x0a\x0d\x0a" | nc $SERVER $PORT >/tmp/lwscap
|
||||
check
|
||||
|
||||
echo
|
||||
echo "---- crazy header name part"
|
||||
echo -e "GET blah HTTP/1.1\x0d\x0a................................................................................................................" \
|
||||
"......................................................................................................................." \
|
||||
"......................................................................................................................." \
|
||||
"......................................................................................................................." \
|
||||
"......................................................................................................................." \
|
||||
"......................................................................................................................." \
|
||||
"......................................................................................................................." \
|
||||
"......................................................................................................................." \
|
||||
"......................................................................................................................." \
|
||||
"......................................................................................................................." \
|
||||
"......................................................................................................................." \
|
||||
"......................................................................................................................." \
|
||||
"......................................................................................................................." \
|
||||
"......................................................................................................................." \
|
||||
"......................................................................................................................." \
|
||||
"......................................................................................................................." \
|
||||
"......................................................................................................................." \
|
||||
| nc -i1s $SERVER $PORT
|
||||
check
|
||||
|
||||
echo
|
||||
echo "---- excessive uri content"
|
||||
echo -e "GET ................................................................................................................" \
|
||||
"......................................................................................................................." \
|
||||
"......................................................................................................................." \
|
||||
"......................................................................................................................." \
|
||||
"......................................................................................................................." \
|
||||
"......................................................................................................................." \
|
||||
"......................................................................................................................." \
|
||||
"......................................................................................................................." \
|
||||
"......................................................................................................................." \
|
||||
"......................................................................................................................." \
|
||||
"......................................................................................................................." \
|
||||
"......................................................................................................................." \
|
||||
"......................................................................................................................." \
|
||||
"......................................................................................................................." \
|
||||
"......................................................................................................................." \
|
||||
"......................................................................................................................." \
|
||||
"......................................................................................................................." \
|
||||
| nc -i1s $SERVER $PORT
|
||||
check
|
||||
|
||||
echo
|
||||
echo "---- good request but http payload coming too (should be ignored and test.html served)"
|
||||
echo -e "GET /test.html HTTP/1.1\x0d\x0a\x0d\x0aILLEGAL-PAYLOAD........................................" \
|
||||
"......................................................................................................................." \
|
||||
"......................................................................................................................." \
|
||||
"......................................................................................................................." \
|
||||
"......................................................................................................................." \
|
||||
"......................................................................................................................." \
|
||||
"......................................................................................................................." \
|
||||
"......................................................................................................................." \
|
||||
"......................................................................................................................." \
|
||||
"......................................................................................................................." \
|
||||
"......................................................................................................................." \
|
||||
"......................................................................................................................." \
|
||||
"......................................................................................................................." \
|
||||
"......................................................................................................................." \
|
||||
"......................................................................................................................." \
|
||||
"......................................................................................................................." \
|
||||
| nc $SERVER $PORT | sed '1,/^\r$/d'> /tmp/lwscap
|
||||
check default
|
||||
|
||||
echo
|
||||
echo "---- directory attack 1 (/../../../../etc/passwd should be /etc/passswd)"
|
||||
rm -f /tmp/lwscap
|
||||
echo -e "GET /../../../../etc/passwd HTTP/1.1\x0d\x0a\x0d\x0a" | nc $SERVER $PORT | sed '1,/^\r$/d'> /tmp/lwscap
|
||||
check forbidden
|
||||
|
||||
echo
|
||||
echo "---- directory attack 2 (/../ should be /)"
|
||||
rm -f /tmp/lwscap
|
||||
echo -e "GET /../ HTTP/1.1\x0d\x0a\x0d\x0a" | nc $SERVER $PORT | sed '1,/^\r$/d'> /tmp/lwscap
|
||||
check default
|
||||
|
||||
echo
|
||||
echo "---- directory attack 3 (/./ should be /)"
|
||||
rm -f /tmp/lwscap
|
||||
echo -e "GET /./ HTTP/1.1\x0d\x0a\x0d\x0a" | nc $SERVER $PORT | sed '1,/^\r$/d'> /tmp/lwscap
|
||||
check default
|
||||
|
||||
echo
|
||||
echo "---- directory attack 4 (/blah/.. should be /)"
|
||||
rm -f /tmp/lwscap
|
||||
echo -e "GET /blah/.. HTTP/1.1\x0d\x0a\x0d\x0a" | nc $SERVER $PORT | sed '1,/^\r$/d'> /tmp/lwscap
|
||||
check default
|
||||
|
||||
echo
|
||||
echo "---- directory attack 5 (/blah/../ should be /)"
|
||||
rm -f /tmp/lwscap
|
||||
echo -e "GET /blah/../ HTTP/1.1\x0d\x0a\x0d\x0a" | nc $SERVER $PORT | sed '1,/^\r$/d'> /tmp/lwscap
|
||||
check default
|
||||
|
||||
echo
|
||||
echo "---- directory attack 6 (/blah/../. should be /)"
|
||||
rm -f /tmp/lwscap
|
||||
echo -e "GET /blah/../. HTTP/1.1\x0d\x0a\x0d\x0a" | nc $SERVER $PORT | sed '1,/^\r$/d'> /tmp/lwscap
|
||||
check default
|
||||
|
||||
echo
|
||||
echo "---- directory attack 7 (/%2e%2e%2f../../../etc/passwd should be /etc/passswd)"
|
||||
rm -f /tmp/lwscap
|
||||
echo -e "GET /%2e%2e%2f../../../etc/passwd HTTP/1.1\x0d\x0a\x0d\x0a" | nc $SERVER $PORT | sed '1,/^\r$/d'> /tmp/lwscap
|
||||
check forbidden
|
||||
|
||||
echo
|
||||
echo "---- directory attack 7 (%2f%2e%2e%2f%2e./.%2e/.%2e%2fetc/passwd should be /etc/passswd)"
|
||||
rm -f /tmp/lwscap
|
||||
echo -e "GET %2f%2e%2e%2f%2e./.%2e/.%2e%2fetc/passwd HTTP/1.1\x0d\x0a\x0d\x0a" | nc $SERVER $PORT | sed '1,/^\r$/d'> /tmp/lwscap
|
||||
check forbidden
|
||||
|
||||
|
||||
echo
|
||||
echo "--- survived OK ---"
|
||||
kill -2 $CPID
|
||||
|
||||
BIN
dependencies/libwebsockets/test-server/favicon.ico
vendored
Normal file
BIN
dependencies/libwebsockets/test-server/favicon.ico
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.4 KiB |
BIN
dependencies/libwebsockets/test-server/leaf.jpg
vendored
Normal file
BIN
dependencies/libwebsockets/test-server/leaf.jpg
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.4 MiB |
BIN
dependencies/libwebsockets/test-server/libwebsockets.org-logo.png
vendored
Normal file
BIN
dependencies/libwebsockets/test-server/libwebsockets.org-logo.png
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 6.9 KiB |
392
dependencies/libwebsockets/test-server/test-client.c
vendored
Normal file
392
dependencies/libwebsockets/test-server/test-client.c
vendored
Normal file
@ -0,0 +1,392 @@
|
||||
/*
|
||||
* libwebsockets-test-client - libwebsockets test implementation
|
||||
*
|
||||
* Copyright (C) 2011 Andy Green <andy@warmcat.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation:
|
||||
* version 2.1 of the License.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
* MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <getopt.h>
|
||||
#include <string.h>
|
||||
#include <signal.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
#define random rand
|
||||
#else
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#ifdef CMAKE_BUILD
|
||||
#include "lws_config.h"
|
||||
#endif
|
||||
|
||||
#include "../lib/libwebsockets.h"
|
||||
|
||||
static unsigned int opts;
|
||||
static int was_closed;
|
||||
static int deny_deflate;
|
||||
static int deny_mux;
|
||||
static struct libwebsocket *wsi_mirror;
|
||||
static int mirror_lifetime = 0;
|
||||
static volatile int force_exit = 0;
|
||||
static int longlived = 0;
|
||||
|
||||
/*
|
||||
* This demo shows how to connect multiple websockets simultaneously to a
|
||||
* websocket server (there is no restriction on their having to be the same
|
||||
* server just it simplifies the demo).
|
||||
*
|
||||
* dumb-increment-protocol: we connect to the server and print the number
|
||||
* we are given
|
||||
*
|
||||
* lws-mirror-protocol: draws random circles, which are mirrored on to every
|
||||
* client (see them being drawn in every browser
|
||||
* session also using the test server)
|
||||
*/
|
||||
|
||||
enum demo_protocols {
|
||||
|
||||
PROTOCOL_DUMB_INCREMENT,
|
||||
PROTOCOL_LWS_MIRROR,
|
||||
|
||||
/* always last */
|
||||
DEMO_PROTOCOL_COUNT
|
||||
};
|
||||
|
||||
|
||||
/* dumb_increment protocol */
|
||||
|
||||
static int
|
||||
callback_dumb_increment(struct libwebsocket_context *this,
|
||||
struct libwebsocket *wsi,
|
||||
enum libwebsocket_callback_reasons reason,
|
||||
void *user, void *in, size_t len)
|
||||
{
|
||||
switch (reason) {
|
||||
|
||||
case LWS_CALLBACK_CLIENT_ESTABLISHED:
|
||||
fprintf(stderr, "callback_dumb_increment: LWS_CALLBACK_CLIENT_ESTABLISHED\n");
|
||||
break;
|
||||
|
||||
case LWS_CALLBACK_CLIENT_CONNECTION_ERROR:
|
||||
fprintf(stderr, "LWS_CALLBACK_CLIENT_CONNECTION_ERROR\n");
|
||||
was_closed = 1;
|
||||
break;
|
||||
|
||||
case LWS_CALLBACK_CLOSED:
|
||||
fprintf(stderr, "LWS_CALLBACK_CLOSED\n");
|
||||
was_closed = 1;
|
||||
break;
|
||||
|
||||
case LWS_CALLBACK_CLIENT_RECEIVE:
|
||||
((char *)in)[len] = '\0';
|
||||
fprintf(stderr, "rx %d '%s'\n", (int)len, (char *)in);
|
||||
break;
|
||||
|
||||
/* because we are protocols[0] ... */
|
||||
|
||||
case LWS_CALLBACK_CLIENT_CONFIRM_EXTENSION_SUPPORTED:
|
||||
if ((strcmp(in, "deflate-stream") == 0) && deny_deflate) {
|
||||
fprintf(stderr, "denied deflate-stream extension\n");
|
||||
return 1;
|
||||
}
|
||||
if ((strcmp(in, "deflate-frame") == 0) && deny_deflate) {
|
||||
fprintf(stderr, "denied deflate-frame extension\n");
|
||||
return 1;
|
||||
}
|
||||
if ((strcmp(in, "x-google-mux") == 0) && deny_mux) {
|
||||
fprintf(stderr, "denied x-google-mux extension\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* lws-mirror_protocol */
|
||||
|
||||
|
||||
static int
|
||||
callback_lws_mirror(struct libwebsocket_context *context,
|
||||
struct libwebsocket *wsi,
|
||||
enum libwebsocket_callback_reasons reason,
|
||||
void *user, void *in, size_t len)
|
||||
{
|
||||
unsigned char buf[LWS_SEND_BUFFER_PRE_PADDING + 4096 +
|
||||
LWS_SEND_BUFFER_POST_PADDING];
|
||||
int l = 0;
|
||||
int n;
|
||||
|
||||
switch (reason) {
|
||||
|
||||
case LWS_CALLBACK_CLIENT_ESTABLISHED:
|
||||
|
||||
fprintf(stderr, "callback_lws_mirror: LWS_CALLBACK_CLIENT_ESTABLISHED\n");
|
||||
|
||||
mirror_lifetime = 10 + (random() & 1023);
|
||||
/* useful to test single connection stability */
|
||||
if (longlived)
|
||||
mirror_lifetime += 50000;
|
||||
|
||||
fprintf(stderr, "opened mirror connection with "
|
||||
"%d lifetime\n", mirror_lifetime);
|
||||
|
||||
/*
|
||||
* mirror_lifetime is decremented each send, when it reaches
|
||||
* zero the connection is closed in the send callback.
|
||||
* When the close callback comes, wsi_mirror is set to NULL
|
||||
* so a new connection will be opened
|
||||
*/
|
||||
|
||||
/*
|
||||
* start the ball rolling,
|
||||
* LWS_CALLBACK_CLIENT_WRITEABLE will come next service
|
||||
*/
|
||||
|
||||
libwebsocket_callback_on_writable(context, wsi);
|
||||
break;
|
||||
|
||||
case LWS_CALLBACK_CLOSED:
|
||||
fprintf(stderr, "mirror: LWS_CALLBACK_CLOSED mirror_lifetime=%d\n", mirror_lifetime);
|
||||
wsi_mirror = NULL;
|
||||
break;
|
||||
|
||||
case LWS_CALLBACK_CLIENT_RECEIVE:
|
||||
/* fprintf(stderr, "rx %d '%s'\n", (int)len, (char *)in); */
|
||||
break;
|
||||
|
||||
case LWS_CALLBACK_CLIENT_WRITEABLE:
|
||||
|
||||
for (n = 0; n < 1; n++)
|
||||
l += sprintf((char *)&buf[LWS_SEND_BUFFER_PRE_PADDING + l],
|
||||
"c #%06X %d %d %d;",
|
||||
(int)random() & 0xffffff,
|
||||
(int)random() % 500,
|
||||
(int)random() % 250,
|
||||
(int)random() % 24);
|
||||
|
||||
n = libwebsocket_write(wsi,
|
||||
&buf[LWS_SEND_BUFFER_PRE_PADDING], l, opts | LWS_WRITE_TEXT);
|
||||
|
||||
if (n < 0)
|
||||
return -1;
|
||||
if (n < l) {
|
||||
lwsl_err("Partial write LWS_CALLBACK_CLIENT_WRITEABLE\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
mirror_lifetime--;
|
||||
if (!mirror_lifetime) {
|
||||
fprintf(stderr, "closing mirror session\n");
|
||||
return -1;
|
||||
} else
|
||||
/* get notified as soon as we can write again */
|
||||
libwebsocket_callback_on_writable(context, wsi);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* list of supported protocols and callbacks */
|
||||
|
||||
static struct libwebsocket_protocols protocols[] = {
|
||||
{
|
||||
"dumb-increment-protocol",
|
||||
callback_dumb_increment,
|
||||
0,
|
||||
20,
|
||||
},
|
||||
{
|
||||
"lws-mirror-protocol",
|
||||
callback_lws_mirror,
|
||||
0,
|
||||
128,
|
||||
},
|
||||
{ NULL, NULL, 0, 0 } /* end */
|
||||
};
|
||||
|
||||
void sighandler(int sig)
|
||||
{
|
||||
force_exit = 1;
|
||||
}
|
||||
|
||||
static struct option options[] = {
|
||||
{ "help", no_argument, NULL, 'h' },
|
||||
{ "debug", required_argument, NULL, 'd' },
|
||||
{ "port", required_argument, NULL, 'p' },
|
||||
{ "ssl", no_argument, NULL, 's' },
|
||||
{ "version", required_argument, NULL, 'v' },
|
||||
{ "undeflated", no_argument, NULL, 'u' },
|
||||
{ "nomux", no_argument, NULL, 'n' },
|
||||
{ "longlived", no_argument, NULL, 'l' },
|
||||
{ NULL, 0, 0, 0 }
|
||||
};
|
||||
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int n = 0;
|
||||
int ret = 0;
|
||||
int port = 7681;
|
||||
int use_ssl = 0;
|
||||
struct libwebsocket_context *context;
|
||||
const char *address;
|
||||
struct libwebsocket *wsi_dumb;
|
||||
int ietf_version = -1; /* latest */
|
||||
struct lws_context_creation_info info;
|
||||
|
||||
memset(&info, 0, sizeof info);
|
||||
|
||||
fprintf(stderr, "libwebsockets test client\n"
|
||||
"(C) Copyright 2010-2013 Andy Green <andy@warmcat.com> "
|
||||
"licensed under LGPL2.1\n");
|
||||
|
||||
if (argc < 2)
|
||||
goto usage;
|
||||
|
||||
while (n >= 0) {
|
||||
n = getopt_long(argc, argv, "nuv:hsp:d:l", options, NULL);
|
||||
if (n < 0)
|
||||
continue;
|
||||
switch (n) {
|
||||
case 'd':
|
||||
lws_set_log_level(atoi(optarg), NULL);
|
||||
break;
|
||||
case 's':
|
||||
use_ssl = 2; /* 2 = allow selfsigned */
|
||||
break;
|
||||
case 'p':
|
||||
port = atoi(optarg);
|
||||
break;
|
||||
case 'l':
|
||||
longlived = 1;
|
||||
break;
|
||||
case 'v':
|
||||
ietf_version = atoi(optarg);
|
||||
break;
|
||||
case 'u':
|
||||
deny_deflate = 1;
|
||||
break;
|
||||
case 'n':
|
||||
deny_mux = 1;
|
||||
break;
|
||||
case 'h':
|
||||
goto usage;
|
||||
}
|
||||
}
|
||||
|
||||
if (optind >= argc)
|
||||
goto usage;
|
||||
|
||||
signal(SIGINT, sighandler);
|
||||
|
||||
address = argv[optind];
|
||||
|
||||
/*
|
||||
* create the websockets context. This tracks open connections and
|
||||
* knows how to route any traffic and which protocol version to use,
|
||||
* and if each connection is client or server side.
|
||||
*
|
||||
* For this client-only demo, we tell it to not listen on any port.
|
||||
*/
|
||||
|
||||
info.port = CONTEXT_PORT_NO_LISTEN;
|
||||
info.protocols = protocols;
|
||||
#ifndef LWS_NO_EXTENSIONS
|
||||
info.extensions = libwebsocket_get_internal_extensions();
|
||||
#endif
|
||||
info.gid = -1;
|
||||
info.uid = -1;
|
||||
|
||||
context = libwebsocket_create_context(&info);
|
||||
if (context == NULL) {
|
||||
fprintf(stderr, "Creating libwebsocket context failed\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* create a client websocket using dumb increment protocol */
|
||||
|
||||
wsi_dumb = libwebsocket_client_connect(context, address, port, use_ssl,
|
||||
"/", argv[optind], argv[optind],
|
||||
protocols[PROTOCOL_DUMB_INCREMENT].name, ietf_version);
|
||||
|
||||
if (wsi_dumb == NULL) {
|
||||
fprintf(stderr, "libwebsocket connect failed\n");
|
||||
ret = 1;
|
||||
goto bail;
|
||||
}
|
||||
|
||||
fprintf(stderr, "Waiting for connect...\n");
|
||||
|
||||
/*
|
||||
* sit there servicing the websocket context to handle incoming
|
||||
* packets, and drawing random circles on the mirror protocol websocket
|
||||
* nothing happens until the client websocket connection is
|
||||
* asynchronously established
|
||||
*/
|
||||
|
||||
n = 0;
|
||||
while (n >= 0 && !was_closed && !force_exit) {
|
||||
n = libwebsocket_service(context, 10);
|
||||
|
||||
if (n < 0)
|
||||
continue;
|
||||
|
||||
if (wsi_mirror)
|
||||
continue;
|
||||
|
||||
/* create a client websocket using mirror protocol */
|
||||
|
||||
wsi_mirror = libwebsocket_client_connect(context,
|
||||
address, port, use_ssl, "/",
|
||||
argv[optind], argv[optind],
|
||||
protocols[PROTOCOL_LWS_MIRROR].name, ietf_version);
|
||||
|
||||
if (wsi_mirror == NULL) {
|
||||
fprintf(stderr, "libwebsocket "
|
||||
"mirror connect failed\n");
|
||||
ret = 1;
|
||||
goto bail;
|
||||
}
|
||||
}
|
||||
|
||||
bail:
|
||||
fprintf(stderr, "Exiting\n");
|
||||
|
||||
libwebsocket_context_destroy(context);
|
||||
|
||||
return ret;
|
||||
|
||||
usage:
|
||||
fprintf(stderr, "Usage: libwebsockets-test-client "
|
||||
"<server address> [--port=<p>] "
|
||||
"[--ssl] [-k] [-v <ver>] "
|
||||
"[-d <log bitfield>] [-l]\n");
|
||||
return 1;
|
||||
}
|
||||
361
dependencies/libwebsockets/test-server/test-echo.c
vendored
Normal file
361
dependencies/libwebsockets/test-server/test-echo.c
vendored
Normal file
@ -0,0 +1,361 @@
|
||||
/*
|
||||
* libwebsockets-test-echo - libwebsockets echo test implementation
|
||||
*
|
||||
* This implements both the client and server sides. It defaults to
|
||||
* serving, use --client <remote address> to connect as client.
|
||||
*
|
||||
* Copyright (C) 2010-2013 Andy Green <andy@warmcat.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation:
|
||||
* version 2.1 of the License.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
* MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <getopt.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <signal.h>
|
||||
|
||||
#ifndef _WIN32
|
||||
#include <syslog.h>
|
||||
#include <sys/time.h>
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#ifdef CMAKE_BUILD
|
||||
#include "lws_config.h"
|
||||
#endif
|
||||
|
||||
#include "../lib/libwebsockets.h"
|
||||
|
||||
static volatile int force_exit = 0;
|
||||
|
||||
#define MAX_ECHO_PAYLOAD 1400
|
||||
#define LOCAL_RESOURCE_PATH INSTALL_DATADIR"/libwebsockets-test-server"
|
||||
|
||||
struct per_session_data__echo {
|
||||
unsigned char buf[LWS_SEND_BUFFER_PRE_PADDING + MAX_ECHO_PAYLOAD + LWS_SEND_BUFFER_POST_PADDING];
|
||||
unsigned int len;
|
||||
unsigned int index;
|
||||
};
|
||||
|
||||
static int
|
||||
callback_echo(struct libwebsocket_context *context,
|
||||
struct libwebsocket *wsi,
|
||||
enum libwebsocket_callback_reasons reason, void *user,
|
||||
void *in, size_t len)
|
||||
{
|
||||
struct per_session_data__echo *pss = (struct per_session_data__echo *)user;
|
||||
int n;
|
||||
|
||||
switch (reason) {
|
||||
|
||||
#ifndef LWS_NO_SERVER
|
||||
/* when the callback is used for server operations --> */
|
||||
|
||||
case LWS_CALLBACK_SERVER_WRITEABLE:
|
||||
n = libwebsocket_write(wsi, &pss->buf[LWS_SEND_BUFFER_PRE_PADDING], pss->len, LWS_WRITE_TEXT);
|
||||
if (n < 0) {
|
||||
lwsl_err("ERROR %d writing to socket, hanging up\n", n);
|
||||
return 1;
|
||||
}
|
||||
if (n < (int)pss->len) {
|
||||
lwsl_err("Partial write\n");
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
|
||||
case LWS_CALLBACK_RECEIVE:
|
||||
if (len > MAX_ECHO_PAYLOAD) {
|
||||
lwsl_err("Server received packet bigger than %u, hanging up\n", MAX_ECHO_PAYLOAD);
|
||||
return 1;
|
||||
}
|
||||
memcpy(&pss->buf[LWS_SEND_BUFFER_PRE_PADDING], in, len);
|
||||
pss->len = (unsigned int)len;
|
||||
libwebsocket_callback_on_writable(context, wsi);
|
||||
break;
|
||||
#endif
|
||||
|
||||
#ifndef LWS_NO_CLIENT
|
||||
/* when the callback is used for client operations --> */
|
||||
|
||||
case LWS_CALLBACK_CLIENT_ESTABLISHED:
|
||||
lwsl_notice("Client has connected\n");
|
||||
pss->index = 0;
|
||||
break;
|
||||
|
||||
case LWS_CALLBACK_CLIENT_RECEIVE:
|
||||
lwsl_notice("Client RX: %s", (char *)in);
|
||||
break;
|
||||
|
||||
case LWS_CALLBACK_CLIENT_WRITEABLE:
|
||||
/* we will send our packet... */
|
||||
pss->len = sprintf((char *)&pss->buf[LWS_SEND_BUFFER_PRE_PADDING], "hello from libwebsockets-test-echo client pid %d index %d\n", getpid(), pss->index++);
|
||||
lwsl_notice("Client TX: %s", &pss->buf[LWS_SEND_BUFFER_PRE_PADDING]);
|
||||
n = libwebsocket_write(wsi, &pss->buf[LWS_SEND_BUFFER_PRE_PADDING], pss->len, LWS_WRITE_TEXT);
|
||||
if (n < 0) {
|
||||
lwsl_err("ERROR %d writing to socket, hanging up\n", n);
|
||||
return -1;
|
||||
}
|
||||
if (n < (int)pss->len) {
|
||||
lwsl_err("Partial write\n");
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static struct libwebsocket_protocols protocols[] = {
|
||||
/* first protocol must always be HTTP handler */
|
||||
|
||||
{
|
||||
"default", /* name */
|
||||
callback_echo, /* callback */
|
||||
sizeof(struct per_session_data__echo) /* per_session_data_size */
|
||||
},
|
||||
{
|
||||
NULL, NULL, 0 /* End of list */
|
||||
}
|
||||
};
|
||||
|
||||
void sighandler(int sig)
|
||||
{
|
||||
force_exit = 1;
|
||||
}
|
||||
|
||||
static struct option options[] = {
|
||||
{ "help", no_argument, NULL, 'h' },
|
||||
{ "debug", required_argument, NULL, 'd' },
|
||||
{ "port", required_argument, NULL, 'p' },
|
||||
#ifndef LWS_NO_CLIENT
|
||||
{ "client", required_argument, NULL, 'c' },
|
||||
{ "ratems", required_argument, NULL, 'r' },
|
||||
#endif
|
||||
{ "ssl", no_argument, NULL, 's' },
|
||||
{ "interface", required_argument, NULL, 'i' },
|
||||
#ifndef LWS_NO_DAEMONIZE
|
||||
{ "daemonize", no_argument, NULL, 'D' },
|
||||
#endif
|
||||
{ NULL, 0, 0, 0 }
|
||||
};
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int n = 0;
|
||||
int port = 7681;
|
||||
int use_ssl = 0;
|
||||
struct libwebsocket_context *context;
|
||||
int opts = 0;
|
||||
char interface_name[128] = "";
|
||||
const char *interface = NULL;
|
||||
#ifndef WIN32
|
||||
int syslog_options = LOG_PID | LOG_PERROR;
|
||||
#endif
|
||||
int client = 0;
|
||||
int listen_port;
|
||||
struct lws_context_creation_info info;
|
||||
#ifndef LWS_NO_CLIENT
|
||||
char address[256];
|
||||
int rate_us = 250000;
|
||||
unsigned int oldus = 0;
|
||||
struct libwebsocket *wsi;
|
||||
#endif
|
||||
|
||||
int debug_level = 7;
|
||||
#ifndef LWS_NO_DAEMONIZE
|
||||
int daemonize = 0;
|
||||
#endif
|
||||
|
||||
memset(&info, 0, sizeof info);
|
||||
|
||||
#ifndef LWS_NO_CLIENT
|
||||
lwsl_notice("Built to support client operations\n");
|
||||
#endif
|
||||
#ifndef LWS_NO_SERVER
|
||||
lwsl_notice("Built to support server operations\n");
|
||||
#endif
|
||||
|
||||
while (n >= 0) {
|
||||
n = getopt_long(argc, argv, "i:hsp:d:D"
|
||||
#ifndef LWS_NO_CLIENT
|
||||
"c:r:"
|
||||
#endif
|
||||
, options, NULL);
|
||||
if (n < 0)
|
||||
continue;
|
||||
switch (n) {
|
||||
#ifndef LWS_NO_DAEMONIZE
|
||||
case 'D':
|
||||
daemonize = 1;
|
||||
#ifndef WIN32
|
||||
syslog_options &= ~LOG_PERROR;
|
||||
#endif
|
||||
break;
|
||||
#endif
|
||||
#ifndef LWS_NO_CLIENT
|
||||
case 'c':
|
||||
client = 1;
|
||||
strcpy(address, optarg);
|
||||
port = 80;
|
||||
break;
|
||||
case 'r':
|
||||
rate_us = atoi(optarg) * 1000;
|
||||
break;
|
||||
#endif
|
||||
case 'd':
|
||||
debug_level = atoi(optarg);
|
||||
break;
|
||||
case 's':
|
||||
use_ssl = 1; /* 1 = take care about cert verification, 2 = allow anything */
|
||||
break;
|
||||
case 'p':
|
||||
port = atoi(optarg);
|
||||
break;
|
||||
case 'i':
|
||||
strncpy(interface_name, optarg, sizeof interface_name);
|
||||
interface_name[(sizeof interface_name) - 1] = '\0';
|
||||
interface = interface_name;
|
||||
break;
|
||||
case '?':
|
||||
case 'h':
|
||||
fprintf(stderr, "Usage: libwebsockets-test-echo "
|
||||
"[--ssl] "
|
||||
#ifndef LWS_NO_CLIENT
|
||||
"[--client <remote ads>] "
|
||||
"[--ratems <ms>] "
|
||||
#endif
|
||||
"[--port=<p>] "
|
||||
"[-d <log bitfield>]\n");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef LWS_NO_DAEMONIZE
|
||||
/*
|
||||
* normally lock path would be /var/lock/lwsts or similar, to
|
||||
* simplify getting started without having to take care about
|
||||
* permissions or running as root, set to /tmp/.lwsts-lock
|
||||
*/
|
||||
#if defined(WIN32) || defined(_WIN32)
|
||||
#else
|
||||
if (!client && daemonize && lws_daemonize("/tmp/.lwstecho-lock")) {
|
||||
fprintf(stderr, "Failed to daemonize\n");
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef WIN32
|
||||
#else
|
||||
/* we will only try to log things according to our debug_level */
|
||||
setlogmask(LOG_UPTO (LOG_DEBUG));
|
||||
openlog("lwsts", syslog_options, LOG_DAEMON);
|
||||
|
||||
/* tell the library what debug level to emit and to send it to syslog */
|
||||
lws_set_log_level(debug_level, lwsl_emit_syslog);
|
||||
#endif
|
||||
lwsl_notice("libwebsockets echo test - "
|
||||
"(C) Copyright 2010-2013 Andy Green <andy@warmcat.com> - "
|
||||
"licensed under LGPL2.1\n");
|
||||
#ifndef LWS_NO_CLIENT
|
||||
if (client) {
|
||||
lwsl_notice("Running in client mode\n");
|
||||
listen_port = CONTEXT_PORT_NO_LISTEN;
|
||||
if (use_ssl)
|
||||
use_ssl = 2;
|
||||
} else {
|
||||
#endif
|
||||
#ifndef LWS_NO_SERVER
|
||||
lwsl_notice("Running in server mode\n");
|
||||
listen_port = port;
|
||||
#endif
|
||||
#ifndef LWS_NO_CLIENT
|
||||
}
|
||||
#endif
|
||||
|
||||
info.port = listen_port;
|
||||
info.iface = interface;
|
||||
info.protocols = protocols;
|
||||
#ifndef LWS_NO_EXTENSIONS
|
||||
info.extensions = libwebsocket_get_internal_extensions();
|
||||
#endif
|
||||
if (use_ssl && !client) {
|
||||
info.ssl_cert_filepath = LOCAL_RESOURCE_PATH"/libwebsockets-test-server.pem";
|
||||
info.ssl_private_key_filepath = LOCAL_RESOURCE_PATH"/libwebsockets-test-server.key.pem";
|
||||
}
|
||||
info.gid = -1;
|
||||
info.uid = -1;
|
||||
info.options = opts;
|
||||
|
||||
context = libwebsocket_create_context(&info);
|
||||
|
||||
if (context == NULL) {
|
||||
lwsl_err("libwebsocket init failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
#ifndef LWS_NO_CLIENT
|
||||
if (client) {
|
||||
lwsl_notice("Client connecting to %s:%u....\n", address, port);
|
||||
/* we are in client mode */
|
||||
wsi = libwebsocket_client_connect(context, address,
|
||||
port, use_ssl, "/", address,
|
||||
"origin", NULL, -1);
|
||||
if (!wsi) {
|
||||
lwsl_err("Client failed to connect to %s:%u\n", address, port);
|
||||
goto bail;
|
||||
}
|
||||
lwsl_notice("Client connected to %s:%u\n", address, port);
|
||||
}
|
||||
#endif
|
||||
signal(SIGINT, sighandler);
|
||||
|
||||
n = 0;
|
||||
while (n >= 0 && !force_exit) {
|
||||
#ifndef LWS_NO_CLIENT
|
||||
struct timeval tv;
|
||||
|
||||
if (client) {
|
||||
gettimeofday(&tv, NULL);
|
||||
|
||||
if (((unsigned int)tv.tv_usec - oldus) > (unsigned int)rate_us) {
|
||||
libwebsocket_callback_on_writable_all_protocol(&protocols[0]);
|
||||
oldus = tv.tv_usec;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
n = libwebsocket_service(context, 10);
|
||||
}
|
||||
#ifndef LWS_NO_CLIENT
|
||||
bail:
|
||||
#endif
|
||||
libwebsocket_context_destroy(context);
|
||||
|
||||
lwsl_notice("libwebsockets-test-echo exited cleanly\n");
|
||||
#ifdef WIN32
|
||||
#else
|
||||
closelog();
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
358
dependencies/libwebsockets/test-server/test-fraggle.c
vendored
Normal file
358
dependencies/libwebsockets/test-server/test-fraggle.c
vendored
Normal file
@ -0,0 +1,358 @@
|
||||
/*
|
||||
* libwebsockets-test-fraggle - random fragmentation test
|
||||
*
|
||||
* Copyright (C) 2010-2011 Andy Green <andy@warmcat.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation:
|
||||
* version 2.1 of the License.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
* MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <getopt.h>
|
||||
#include <string.h>
|
||||
#include "../lib/libwebsockets.h"
|
||||
|
||||
#define LOCAL_RESOURCE_PATH INSTALL_DATADIR"/libwebsockets-test-server"
|
||||
|
||||
static int client;
|
||||
static int terminate;
|
||||
|
||||
enum demo_protocols {
|
||||
PROTOCOL_FRAGGLE,
|
||||
|
||||
/* always last */
|
||||
DEMO_PROTOCOL_COUNT
|
||||
};
|
||||
|
||||
/* fraggle protocol */
|
||||
|
||||
enum fraggle_states {
|
||||
FRAGSTATE_START_MESSAGE,
|
||||
FRAGSTATE_RANDOM_PAYLOAD,
|
||||
FRAGSTATE_POST_PAYLOAD_SUM,
|
||||
};
|
||||
|
||||
struct per_session_data__fraggle {
|
||||
int packets_left;
|
||||
int total_message;
|
||||
unsigned long sum;
|
||||
enum fraggle_states state;
|
||||
};
|
||||
|
||||
static int
|
||||
callback_fraggle(struct libwebsocket_context *context,
|
||||
struct libwebsocket *wsi,
|
||||
enum libwebsocket_callback_reasons reason,
|
||||
void *user, void *in, size_t len)
|
||||
{
|
||||
int n;
|
||||
unsigned char buf[LWS_SEND_BUFFER_PRE_PADDING + 8000 +
|
||||
LWS_SEND_BUFFER_POST_PADDING];
|
||||
struct per_session_data__fraggle *psf = user;
|
||||
int chunk;
|
||||
int write_mode = LWS_WRITE_CONTINUATION;
|
||||
unsigned long sum;
|
||||
unsigned char *p = (unsigned char *)in;
|
||||
unsigned char *bp = &buf[LWS_SEND_BUFFER_PRE_PADDING];
|
||||
|
||||
switch (reason) {
|
||||
|
||||
case LWS_CALLBACK_ESTABLISHED:
|
||||
|
||||
fprintf(stderr, "server sees client connect\n");
|
||||
psf->state = FRAGSTATE_START_MESSAGE;
|
||||
/* start the ball rolling */
|
||||
libwebsocket_callback_on_writable(context, wsi);
|
||||
break;
|
||||
|
||||
case LWS_CALLBACK_CLIENT_ESTABLISHED:
|
||||
|
||||
fprintf(stderr, "client connects to server\n");
|
||||
psf->state = FRAGSTATE_START_MESSAGE;
|
||||
break;
|
||||
|
||||
case LWS_CALLBACK_CLIENT_RECEIVE:
|
||||
|
||||
switch (psf->state) {
|
||||
|
||||
case FRAGSTATE_START_MESSAGE:
|
||||
|
||||
psf->state = FRAGSTATE_RANDOM_PAYLOAD;
|
||||
psf->sum = 0;
|
||||
psf->total_message = 0;
|
||||
psf->packets_left = 0;
|
||||
|
||||
/* fallthru */
|
||||
|
||||
case FRAGSTATE_RANDOM_PAYLOAD:
|
||||
|
||||
for (n = 0; n < len; n++)
|
||||
psf->sum += p[n];
|
||||
|
||||
psf->total_message += len;
|
||||
psf->packets_left++;
|
||||
|
||||
if (libwebsocket_is_final_fragment(wsi))
|
||||
psf->state = FRAGSTATE_POST_PAYLOAD_SUM;
|
||||
break;
|
||||
|
||||
case FRAGSTATE_POST_PAYLOAD_SUM:
|
||||
|
||||
sum = p[0] << 24;
|
||||
sum |= p[1] << 16;
|
||||
sum |= p[2] << 8;
|
||||
sum |= p[3];
|
||||
if (sum == psf->sum)
|
||||
fprintf(stderr, "EOM received %d correctly "
|
||||
"from %d fragments\n",
|
||||
psf->total_message, psf->packets_left);
|
||||
else
|
||||
fprintf(stderr, "**** ERROR at EOM: "
|
||||
"length %d, rx sum = 0x%lX, "
|
||||
"server says it sent 0x%lX\n",
|
||||
psf->total_message, psf->sum, sum);
|
||||
|
||||
psf->state = FRAGSTATE_START_MESSAGE;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case LWS_CALLBACK_SERVER_WRITEABLE:
|
||||
|
||||
switch (psf->state) {
|
||||
|
||||
case FRAGSTATE_START_MESSAGE:
|
||||
|
||||
psf->packets_left = (random() % 1024) + 1;
|
||||
fprintf(stderr, "Spamming %d random fragments\n",
|
||||
psf->packets_left);
|
||||
psf->sum = 0;
|
||||
psf->total_message = 0;
|
||||
write_mode = LWS_WRITE_BINARY;
|
||||
psf->state = FRAGSTATE_RANDOM_PAYLOAD;
|
||||
|
||||
/* fallthru */
|
||||
|
||||
case FRAGSTATE_RANDOM_PAYLOAD:
|
||||
|
||||
/*
|
||||
* note how one chunk can be 8000, but we use the
|
||||
* default rx buffer size of 4096, so we exercise the
|
||||
* code for rx spill because the rx buffer is full
|
||||
*/
|
||||
|
||||
chunk = (random() % 8000) + 1;
|
||||
psf->total_message += chunk;
|
||||
|
||||
libwebsockets_get_random(context, bp, chunk);
|
||||
for (n = 0; n < chunk; n++)
|
||||
psf->sum += bp[n];
|
||||
|
||||
psf->packets_left--;
|
||||
if (psf->packets_left)
|
||||
write_mode |= LWS_WRITE_NO_FIN;
|
||||
else
|
||||
psf->state = FRAGSTATE_POST_PAYLOAD_SUM;
|
||||
|
||||
n = libwebsocket_write(wsi, bp, chunk, write_mode);
|
||||
if (n < 0)
|
||||
return -1;
|
||||
if (n < chunk) {
|
||||
lwsl_err("Partial write\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
libwebsocket_callback_on_writable(context, wsi);
|
||||
break;
|
||||
|
||||
case FRAGSTATE_POST_PAYLOAD_SUM:
|
||||
|
||||
fprintf(stderr, "Spamming session over, "
|
||||
"len = %d. sum = 0x%lX\n",
|
||||
psf->total_message, psf->sum);
|
||||
|
||||
bp[0] = psf->sum >> 24;
|
||||
bp[1] = psf->sum >> 16;
|
||||
bp[2] = psf->sum >> 8;
|
||||
bp[3] = psf->sum;
|
||||
|
||||
n = libwebsocket_write(wsi, (unsigned char *)bp,
|
||||
4, LWS_WRITE_BINARY);
|
||||
if (n < 0)
|
||||
return -1;
|
||||
if (n < 4) {
|
||||
lwsl_err("Partial write\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
psf->state = FRAGSTATE_START_MESSAGE;
|
||||
|
||||
libwebsocket_callback_on_writable(context, wsi);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case LWS_CALLBACK_CLOSED:
|
||||
|
||||
terminate = 1;
|
||||
break;
|
||||
|
||||
/* because we are protocols[0] ... */
|
||||
|
||||
case LWS_CALLBACK_CLIENT_CONFIRM_EXTENSION_SUPPORTED:
|
||||
if (strcmp(in, "deflate-stream") == 0) {
|
||||
fprintf(stderr, "denied deflate-stream extension\n");
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* list of supported protocols and callbacks */
|
||||
|
||||
static struct libwebsocket_protocols protocols[] = {
|
||||
{
|
||||
"fraggle-protocol",
|
||||
callback_fraggle,
|
||||
sizeof(struct per_session_data__fraggle),
|
||||
},
|
||||
{
|
||||
NULL, NULL, 0 /* End of list */
|
||||
}
|
||||
};
|
||||
|
||||
static struct option options[] = {
|
||||
{ "help", no_argument, NULL, 'h' },
|
||||
{ "debug", required_argument, NULL, 'd' },
|
||||
{ "port", required_argument, NULL, 'p' },
|
||||
{ "ssl", no_argument, NULL, 's' },
|
||||
{ "interface", required_argument, NULL, 'i' },
|
||||
{ "client", no_argument, NULL, 'c' },
|
||||
{ NULL, 0, 0, 0 }
|
||||
};
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int n = 0;
|
||||
int port = 7681;
|
||||
int use_ssl = 0;
|
||||
struct libwebsocket_context *context;
|
||||
int opts = 0;
|
||||
char interface_name[128] = "";
|
||||
const char *iface = NULL;
|
||||
struct libwebsocket *wsi;
|
||||
const char *address;
|
||||
int server_port = port;
|
||||
struct lws_context_creation_info info;
|
||||
|
||||
memset(&info, 0, sizeof info);
|
||||
|
||||
fprintf(stderr, "libwebsockets test fraggle\n"
|
||||
"(C) Copyright 2010-2013 Andy Green <andy@warmcat.com> "
|
||||
"licensed under LGPL2.1\n");
|
||||
|
||||
while (n >= 0) {
|
||||
n = getopt_long(argc, argv, "ci:hsp:d:", options, NULL);
|
||||
if (n < 0)
|
||||
continue;
|
||||
switch (n) {
|
||||
case 'd':
|
||||
lws_set_log_level(atoi(optarg), NULL);
|
||||
break;
|
||||
case 's':
|
||||
use_ssl = 1;
|
||||
break;
|
||||
case 'p':
|
||||
port = atoi(optarg);
|
||||
server_port = port;
|
||||
break;
|
||||
case 'i':
|
||||
strncpy(interface_name, optarg, sizeof interface_name);
|
||||
interface_name[(sizeof interface_name) - 1] = '\0';
|
||||
iface = interface_name;
|
||||
break;
|
||||
case 'c':
|
||||
client = 1;
|
||||
fprintf(stderr, " Client mode\n");
|
||||
break;
|
||||
case 'h':
|
||||
fprintf(stderr, "Usage: libwebsockets-test-fraggle "
|
||||
"[--port=<p>] [--ssl] "
|
||||
"[-d <log bitfield>] "
|
||||
"[--client]\n");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
if (client) {
|
||||
server_port = CONTEXT_PORT_NO_LISTEN;
|
||||
if (optind >= argc) {
|
||||
fprintf(stderr, "Must give address of server\n");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
info.port = server_port;
|
||||
info.iface = iface;
|
||||
info.protocols = protocols;
|
||||
#ifndef LWS_NO_EXTENSIONS
|
||||
info.extensions = libwebsocket_get_internal_extensions();
|
||||
#endif
|
||||
if (use_ssl) {
|
||||
info.ssl_cert_filepath = LOCAL_RESOURCE_PATH"/libwebsockets-test-server.pem";
|
||||
info.ssl_private_key_filepath = LOCAL_RESOURCE_PATH"/libwebsockets-test-server.key.pem";
|
||||
}
|
||||
info.gid = -1;
|
||||
info.uid = -1;
|
||||
info.options = opts;
|
||||
|
||||
context = libwebsocket_create_context(&info);
|
||||
if (context == NULL) {
|
||||
fprintf(stderr, "libwebsocket init failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (client) {
|
||||
address = argv[optind];
|
||||
fprintf(stderr, "Connecting to %s:%u\n", address, port);
|
||||
wsi = libwebsocket_client_connect(context, address,
|
||||
port, use_ssl, "/", address,
|
||||
"origin", protocols[PROTOCOL_FRAGGLE].name,
|
||||
-1);
|
||||
if (wsi == NULL) {
|
||||
fprintf(stderr, "Client connect to server failed\n");
|
||||
goto bail;
|
||||
}
|
||||
}
|
||||
|
||||
n = 0;
|
||||
while (!n && !terminate)
|
||||
n = libwebsocket_service(context, 50);
|
||||
|
||||
fprintf(stderr, "Terminating...\n");
|
||||
|
||||
bail:
|
||||
libwebsocket_context_destroy(context);
|
||||
|
||||
return 0;
|
||||
}
|
||||
543
dependencies/libwebsockets/test-server/test-ping.c
vendored
Normal file
543
dependencies/libwebsockets/test-server/test-ping.c
vendored
Normal file
@ -0,0 +1,543 @@
|
||||
/*
|
||||
* libwebsockets-test-ping - libwebsockets floodping
|
||||
*
|
||||
* Copyright (C) 2011 Andy Green <andy@warmcat.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation:
|
||||
* version 2.1 of the License.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
* MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <getopt.h>
|
||||
#include <string.h>
|
||||
#include <signal.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#ifndef _WIN32
|
||||
#include <netdb.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <poll.h>
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#ifdef CMAKE_BUILD
|
||||
#include "lws_config.h"
|
||||
#endif
|
||||
|
||||
#include "../lib/libwebsockets.h"
|
||||
|
||||
/*
|
||||
* this is specified in the 04 standard, control frames can only have small
|
||||
* payload length styles
|
||||
*/
|
||||
#define MAX_PING_PAYLOAD 125
|
||||
#define MAX_MIRROR_PAYLOAD 4096
|
||||
#define MAX_PING_CLIENTS 256
|
||||
#define PING_RINGBUFFER_SIZE 256
|
||||
|
||||
static struct libwebsocket *ping_wsi[MAX_PING_CLIENTS];
|
||||
static unsigned int interval_us = 1000000;
|
||||
static unsigned int size = 64;
|
||||
static int flood;
|
||||
static const char *address;
|
||||
static unsigned char pingbuf[LWS_SEND_BUFFER_PRE_PADDING + MAX_MIRROR_PAYLOAD +
|
||||
LWS_SEND_BUFFER_POST_PADDING];
|
||||
static char peer_name[128];
|
||||
static unsigned long started;
|
||||
static int screen_width = 80;
|
||||
static int use_mirror;
|
||||
static unsigned int write_options;
|
||||
|
||||
static unsigned long rtt_min = 100000000;
|
||||
static unsigned long rtt_max;
|
||||
static unsigned long rtt_avg;
|
||||
static unsigned long global_rx_count;
|
||||
static unsigned long global_tx_count;
|
||||
static int clients = 1;
|
||||
static unsigned long interrupted_time;
|
||||
|
||||
struct ping {
|
||||
unsigned long issue_timestamp;
|
||||
unsigned long index;
|
||||
unsigned int seen;
|
||||
};
|
||||
|
||||
struct per_session_data__ping {
|
||||
unsigned long ping_index;
|
||||
|
||||
struct ping ringbuffer[PING_RINGBUFFER_SIZE];
|
||||
int ringbuffer_head;
|
||||
int ringbuffer_tail;
|
||||
|
||||
unsigned long rx_count;
|
||||
};
|
||||
|
||||
/*
|
||||
* uses the ping pong protocol features to provide an equivalent for the
|
||||
* ping utility for 04+ websockets
|
||||
*/
|
||||
|
||||
enum demo_protocols {
|
||||
|
||||
PROTOCOL_LWS_MIRROR,
|
||||
|
||||
/* always last */
|
||||
DEMO_PROTOCOL_COUNT
|
||||
};
|
||||
|
||||
|
||||
static int
|
||||
callback_lws_mirror(struct libwebsocket_context * this,
|
||||
struct libwebsocket *wsi,
|
||||
enum libwebsocket_callback_reasons reason,
|
||||
void *user, void *in, size_t len)
|
||||
{
|
||||
struct timeval tv;
|
||||
unsigned char *p;
|
||||
int shift;
|
||||
unsigned long l;
|
||||
unsigned long iv;
|
||||
int n;
|
||||
int match = 0;
|
||||
struct per_session_data__ping *psd = user;
|
||||
|
||||
switch (reason) {
|
||||
case LWS_CALLBACK_CLOSED:
|
||||
|
||||
fprintf(stderr, "LWS_CALLBACK_CLOSED on %p\n", (void *)wsi);
|
||||
|
||||
/* remove closed guy */
|
||||
|
||||
for (n = 0; n < clients; n++)
|
||||
if (ping_wsi[n] == wsi) {
|
||||
clients--;
|
||||
while (n < clients) {
|
||||
ping_wsi[n] = ping_wsi[n + 1];
|
||||
n++;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case LWS_CALLBACK_CLIENT_ESTABLISHED:
|
||||
|
||||
psd->rx_count = 0;
|
||||
psd->ping_index = 1;
|
||||
psd->ringbuffer_head = 0;
|
||||
psd->ringbuffer_tail = 0;
|
||||
|
||||
/*
|
||||
* start the ball rolling,
|
||||
* LWS_CALLBACK_CLIENT_WRITEABLE will come next service
|
||||
*/
|
||||
|
||||
libwebsocket_callback_on_writable(this, wsi);
|
||||
break;
|
||||
|
||||
case LWS_CALLBACK_CLIENT_RECEIVE:
|
||||
case LWS_CALLBACK_CLIENT_RECEIVE_PONG:
|
||||
gettimeofday(&tv, NULL);
|
||||
iv = (tv.tv_sec * 1000000) + tv.tv_usec;
|
||||
|
||||
psd->rx_count++;
|
||||
|
||||
shift = 56;
|
||||
p = in;
|
||||
l = 0;
|
||||
|
||||
while (shift >= 0) {
|
||||
l |= (*p++) << shift;
|
||||
shift -= 8;
|
||||
}
|
||||
|
||||
/* find it in the ringbuffer, look backwards from head */
|
||||
n = psd->ringbuffer_head;
|
||||
while (!match) {
|
||||
|
||||
if (psd->ringbuffer[n].index == l) {
|
||||
psd->ringbuffer[n].seen++;
|
||||
match = 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (n == psd->ringbuffer_tail) {
|
||||
match = -1;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (n == 0)
|
||||
n = PING_RINGBUFFER_SIZE - 1;
|
||||
else
|
||||
n--;
|
||||
}
|
||||
|
||||
if (match < 1) {
|
||||
|
||||
if (!flood)
|
||||
fprintf(stderr, "%d bytes from %s: req=%ld "
|
||||
"time=(unknown)\n", (int)len, address, l);
|
||||
else
|
||||
fprintf(stderr, "\b \b");
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (psd->ringbuffer[n].seen > 1)
|
||||
fprintf(stderr, "DUP! ");
|
||||
|
||||
if ((iv - psd->ringbuffer[n].issue_timestamp) < rtt_min)
|
||||
rtt_min = iv - psd->ringbuffer[n].issue_timestamp;
|
||||
|
||||
if ((iv - psd->ringbuffer[n].issue_timestamp) > rtt_max)
|
||||
rtt_max = iv - psd->ringbuffer[n].issue_timestamp;
|
||||
|
||||
rtt_avg += iv - psd->ringbuffer[n].issue_timestamp;
|
||||
global_rx_count++;
|
||||
|
||||
if (!flood)
|
||||
fprintf(stderr, "%d bytes from %s: req=%ld "
|
||||
"time=%lu.%lums\n", (int)len, address, l,
|
||||
(iv - psd->ringbuffer[n].issue_timestamp) / 1000,
|
||||
((iv - psd->ringbuffer[n].issue_timestamp) / 100) % 10);
|
||||
else
|
||||
fprintf(stderr, "\b \b");
|
||||
break;
|
||||
|
||||
case LWS_CALLBACK_CLIENT_WRITEABLE:
|
||||
|
||||
shift = 56;
|
||||
p = &pingbuf[LWS_SEND_BUFFER_PRE_PADDING];
|
||||
|
||||
/* 64-bit ping index in network byte order */
|
||||
|
||||
while (shift >= 0) {
|
||||
*p++ = psd->ping_index >> shift;
|
||||
shift -= 8;
|
||||
}
|
||||
|
||||
while (p - &pingbuf[LWS_SEND_BUFFER_PRE_PADDING] < size)
|
||||
*p++ = 0;
|
||||
|
||||
gettimeofday(&tv, NULL);
|
||||
|
||||
psd->ringbuffer[psd->ringbuffer_head].issue_timestamp =
|
||||
(tv.tv_sec * 1000000) + tv.tv_usec;
|
||||
psd->ringbuffer[psd->ringbuffer_head].index = psd->ping_index++;
|
||||
psd->ringbuffer[psd->ringbuffer_head].seen = 0;
|
||||
|
||||
if (psd->ringbuffer_head == PING_RINGBUFFER_SIZE - 1)
|
||||
psd->ringbuffer_head = 0;
|
||||
else
|
||||
psd->ringbuffer_head++;
|
||||
|
||||
/* snip any re-used tail so we keep to the ring length */
|
||||
|
||||
if (psd->ringbuffer_tail == psd->ringbuffer_head) {
|
||||
if (psd->ringbuffer_tail == PING_RINGBUFFER_SIZE - 1)
|
||||
psd->ringbuffer_tail = 0;
|
||||
else
|
||||
psd->ringbuffer_tail++;
|
||||
}
|
||||
|
||||
global_tx_count++;
|
||||
|
||||
if (use_mirror)
|
||||
n = libwebsocket_write(wsi,
|
||||
&pingbuf[LWS_SEND_BUFFER_PRE_PADDING],
|
||||
size, write_options | LWS_WRITE_BINARY);
|
||||
else
|
||||
n = libwebsocket_write(wsi,
|
||||
&pingbuf[LWS_SEND_BUFFER_PRE_PADDING],
|
||||
size, write_options | LWS_WRITE_PING);
|
||||
|
||||
if (n < 0)
|
||||
return -1;
|
||||
if (n < size) {
|
||||
lwsl_err("Partial write\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (flood &&
|
||||
(psd->ping_index - psd->rx_count) < (screen_width - 1))
|
||||
fprintf(stderr, ".");
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* list of supported protocols and callbacks */
|
||||
|
||||
static struct libwebsocket_protocols protocols[] = {
|
||||
|
||||
{
|
||||
"lws-mirror-protocol",
|
||||
callback_lws_mirror,
|
||||
sizeof (struct per_session_data__ping),
|
||||
},
|
||||
{
|
||||
NULL, NULL, 0/* end of list */
|
||||
}
|
||||
};
|
||||
|
||||
static struct option options[] = {
|
||||
{ "help", no_argument, NULL, 'h' },
|
||||
{ "debug", required_argument, NULL, 'd' },
|
||||
{ "port", required_argument, NULL, 'p' },
|
||||
{ "ssl", no_argument, NULL, 't' },
|
||||
{ "interval", required_argument, NULL, 'i' },
|
||||
{ "size", required_argument, NULL, 's' },
|
||||
{ "protocol", required_argument, NULL, 'n' },
|
||||
{ "flood", no_argument, NULL, 'f' },
|
||||
{ "mirror", no_argument, NULL, 'm' },
|
||||
{ "replicate", required_argument, NULL, 'r' },
|
||||
{ "killmask", no_argument, NULL, 'k' },
|
||||
{ "version", required_argument, NULL, 'v' },
|
||||
{ NULL, 0, 0, 0 }
|
||||
};
|
||||
|
||||
#ifndef WIN32
|
||||
static void
|
||||
signal_handler(int sig, siginfo_t *si, void *v)
|
||||
{
|
||||
struct timeval tv;
|
||||
|
||||
gettimeofday(&tv, NULL);
|
||||
interrupted_time = (tv.tv_sec * 1000000) + tv.tv_usec;
|
||||
}
|
||||
#endif
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int n = 0;
|
||||
int port = 7681;
|
||||
int use_ssl = 0;
|
||||
struct libwebsocket_context *context;
|
||||
char protocol_name[256];
|
||||
char ip[30];
|
||||
#ifndef WIN32
|
||||
struct sigaction sa;
|
||||
struct winsize w;
|
||||
#endif
|
||||
struct timeval tv;
|
||||
unsigned long oldus = 0;
|
||||
unsigned long l;
|
||||
int ietf_version = -1;
|
||||
struct lws_context_creation_info info;
|
||||
|
||||
memset(&info, 0, sizeof info);
|
||||
|
||||
if (argc < 2)
|
||||
goto usage;
|
||||
|
||||
address = argv[1];
|
||||
optind++;
|
||||
|
||||
while (n >= 0) {
|
||||
n = getopt_long(argc, argv, "v:kr:hmfts:n:i:p:d:", options, NULL);
|
||||
if (n < 0)
|
||||
continue;
|
||||
switch (n) {
|
||||
case 'd':
|
||||
lws_set_log_level(atoi(optarg), NULL);
|
||||
break;
|
||||
case 'm':
|
||||
use_mirror = 1;
|
||||
break;
|
||||
case 't':
|
||||
use_ssl = 2; /* 2 = allow selfsigned */
|
||||
break;
|
||||
case 'p':
|
||||
port = atoi(optarg);
|
||||
break;
|
||||
case 'n':
|
||||
strncpy(protocol_name, optarg, sizeof protocol_name);
|
||||
protocol_name[(sizeof protocol_name) - 1] = '\0';
|
||||
protocols[PROTOCOL_LWS_MIRROR].name = protocol_name;
|
||||
break;
|
||||
case 'i':
|
||||
interval_us = 1000000.0 * atof(optarg);
|
||||
break;
|
||||
case 's':
|
||||
size = atoi(optarg);
|
||||
break;
|
||||
case 'f':
|
||||
flood = 1;
|
||||
break;
|
||||
case 'r':
|
||||
clients = atoi(optarg);
|
||||
if (clients > MAX_PING_CLIENTS || clients < 1) {
|
||||
fprintf(stderr, "Max clients supportd = %d\n",
|
||||
MAX_PING_CLIENTS);
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
case 'k':
|
||||
write_options = LWS_WRITE_CLIENT_IGNORE_XOR_MASK;
|
||||
break;
|
||||
case 'v':
|
||||
ietf_version = atoi(optarg);
|
||||
break;
|
||||
|
||||
case 'h':
|
||||
goto usage;
|
||||
}
|
||||
}
|
||||
|
||||
if (!use_mirror) {
|
||||
if (size > MAX_PING_PAYLOAD) {
|
||||
fprintf(stderr, "Max ping opcode payload size %d\n",
|
||||
MAX_PING_PAYLOAD);
|
||||
return 1;
|
||||
}
|
||||
} else {
|
||||
if (size > MAX_MIRROR_PAYLOAD) {
|
||||
fprintf(stderr, "Max mirror payload size %d\n",
|
||||
MAX_MIRROR_PAYLOAD);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef WIN32
|
||||
if (isatty(STDOUT_FILENO))
|
||||
if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &w) != -1)
|
||||
if (w.ws_col > 0)
|
||||
screen_width = w.ws_col;
|
||||
#endif
|
||||
|
||||
info.port = CONTEXT_PORT_NO_LISTEN;
|
||||
info.protocols = protocols;
|
||||
#ifndef LWS_NO_EXTENSIONS
|
||||
info.extensions = libwebsocket_get_internal_extensions();
|
||||
#endif
|
||||
info.gid = -1;
|
||||
info.uid = -1;
|
||||
|
||||
context = libwebsocket_create_context(&info);
|
||||
if (context == NULL) {
|
||||
fprintf(stderr, "Creating libwebsocket context failed\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* create client websockets using dumb increment protocol */
|
||||
|
||||
for (n = 0; n < clients; n++) {
|
||||
ping_wsi[n] = libwebsocket_client_connect(context, address,
|
||||
port, use_ssl, "/", address,
|
||||
"origin", protocols[PROTOCOL_LWS_MIRROR].name,
|
||||
ietf_version);
|
||||
if (ping_wsi[n] == NULL) {
|
||||
fprintf(stderr, "client connection %d failed to "
|
||||
"connect\n", n);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
libwebsockets_get_peer_addresses(context, ping_wsi[0],
|
||||
libwebsocket_get_socket_fd(ping_wsi[0]),
|
||||
peer_name, sizeof peer_name, ip, sizeof ip);
|
||||
|
||||
fprintf(stderr, "Websocket PING %s (%s) %d bytes of data.\n",
|
||||
peer_name, ip, size);
|
||||
|
||||
#ifndef WIN32
|
||||
/* set the ^C handler */
|
||||
sa.sa_sigaction = signal_handler;
|
||||
sa.sa_flags = SA_SIGINFO;
|
||||
sigemptyset(&sa.sa_mask);
|
||||
sigaction(SIGINT, &sa, NULL);
|
||||
#endif
|
||||
|
||||
gettimeofday(&tv, NULL);
|
||||
started = (tv.tv_sec * 1000000) + tv.tv_usec;
|
||||
|
||||
/* service loop */
|
||||
|
||||
n = 0;
|
||||
while (n >= 0) {
|
||||
|
||||
gettimeofday(&tv, NULL);
|
||||
l = (tv.tv_sec * 1000000) + tv.tv_usec;
|
||||
|
||||
/* servers can hang up on us */
|
||||
|
||||
if (clients == 0) {
|
||||
n = -1;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!interrupted_time) {
|
||||
if ((l - oldus) > interval_us) {
|
||||
for (n = 0; n < clients; n++)
|
||||
libwebsocket_callback_on_writable(
|
||||
context, ping_wsi[n]);
|
||||
oldus = l;
|
||||
}
|
||||
} else
|
||||
|
||||
/* allow time for in-flight pongs to come */
|
||||
|
||||
if ((l - interrupted_time) > 250000) {
|
||||
n = -1;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!interval_us)
|
||||
n = libwebsocket_service(context, 0);
|
||||
else
|
||||
n = libwebsocket_service(context, 1);
|
||||
}
|
||||
|
||||
/* stats */
|
||||
|
||||
fprintf(stderr, "\n--- %s websocket ping statistics "
|
||||
"using %d connections ---\n"
|
||||
"%lu packets transmitted, %lu received, "
|
||||
"%lu%% packet loss, time %ldms\n"
|
||||
"rtt min/avg/max = %0.3f/%0.3f/%0.3f ms\n"
|
||||
"payload bandwidth average %0.3f KiBytes/sec\n",
|
||||
peer_name, clients, global_tx_count, global_rx_count,
|
||||
((global_tx_count - global_rx_count) * 100) / global_tx_count,
|
||||
(l - started) / 1000,
|
||||
((double)rtt_min) / 1000.0,
|
||||
((double)rtt_avg / global_rx_count) / 1000.0,
|
||||
((double)rtt_max) / 1000.0,
|
||||
((double)global_rx_count * (double)size) /
|
||||
((double)(l - started) / 1000000.0) / 1024.0);
|
||||
|
||||
libwebsocket_context_destroy(context);
|
||||
|
||||
return 0;
|
||||
|
||||
usage:
|
||||
fprintf(stderr, "Usage: libwebsockets-test-ping "
|
||||
"<server address> [--port=<p>] "
|
||||
"[--ssl] [--interval=<float sec>] "
|
||||
"[--size=<bytes>] "
|
||||
"[--protocol=<protocolname>] "
|
||||
"[--mirror] "
|
||||
"[--replicate=clients>] "
|
||||
"[--version <version>] "
|
||||
"[-d <log bitfield> ]"
|
||||
"\n");
|
||||
return 1;
|
||||
}
|
||||
968
dependencies/libwebsockets/test-server/test-server.c
vendored
Normal file
968
dependencies/libwebsockets/test-server/test-server.c
vendored
Normal file
@ -0,0 +1,968 @@
|
||||
/*
|
||||
* libwebsockets-test-server - libwebsockets test implementation
|
||||
*
|
||||
* Copyright (C) 2010-2011 Andy Green <andy@warmcat.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation:
|
||||
* version 2.1 of the License.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
* MA 02110-1301 USA
|
||||
*/
|
||||
#ifdef CMAKE_BUILD
|
||||
#include "lws_config.h"
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <getopt.h>
|
||||
#include <signal.h>
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <assert.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <io.h>
|
||||
#ifdef EXTERNAL_POLL
|
||||
#define poll WSAPoll
|
||||
#endif
|
||||
#else
|
||||
#include <syslog.h>
|
||||
#include <sys/time.h>
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include "../lib/libwebsockets.h"
|
||||
|
||||
static int close_testing;
|
||||
int max_poll_elements;
|
||||
|
||||
struct pollfd *pollfds;
|
||||
int *fd_lookup;
|
||||
int count_pollfds;
|
||||
static volatile int force_exit = 0;
|
||||
static struct libwebsocket_context *context;
|
||||
|
||||
/*
|
||||
* This demo server shows how to use libwebsockets for one or more
|
||||
* websocket protocols in the same server
|
||||
*
|
||||
* It defines the following websocket protocols:
|
||||
*
|
||||
* dumb-increment-protocol: once the socket is opened, an incrementing
|
||||
* ascii string is sent down it every 50ms.
|
||||
* If you send "reset\n" on the websocket, then
|
||||
* the incrementing number is reset to 0.
|
||||
*
|
||||
* lws-mirror-protocol: copies any received packet to every connection also
|
||||
* using this protocol, including the sender
|
||||
*/
|
||||
|
||||
enum demo_protocols {
|
||||
/* always first */
|
||||
PROTOCOL_HTTP = 0,
|
||||
|
||||
PROTOCOL_DUMB_INCREMENT,
|
||||
PROTOCOL_LWS_MIRROR,
|
||||
|
||||
/* always last */
|
||||
DEMO_PROTOCOL_COUNT
|
||||
};
|
||||
|
||||
|
||||
#define LOCAL_RESOURCE_PATH INSTALL_DATADIR"/libwebsockets-test-server"
|
||||
char *resource_path = LOCAL_RESOURCE_PATH;
|
||||
|
||||
/*
|
||||
* We take a strict whitelist approach to stop ../ attacks
|
||||
*/
|
||||
|
||||
struct serveable {
|
||||
const char *urlpath;
|
||||
const char *mimetype;
|
||||
};
|
||||
|
||||
struct per_session_data__http {
|
||||
int fd;
|
||||
};
|
||||
|
||||
/*
|
||||
* this is just an example of parsing handshake headers, you don't need this
|
||||
* in your code unless you will filter allowing connections by the header
|
||||
* content
|
||||
*/
|
||||
|
||||
static void
|
||||
dump_handshake_info(struct libwebsocket *wsi)
|
||||
{
|
||||
int n;
|
||||
static const char *token_names[] = {
|
||||
/*[WSI_TOKEN_GET_URI] =*/ "GET URI",
|
||||
/*[WSI_TOKEN_POST_URI] =*/ "POST URI",
|
||||
/*[WSI_TOKEN_HOST] =*/ "Host",
|
||||
/*[WSI_TOKEN_CONNECTION] =*/ "Connection",
|
||||
/*[WSI_TOKEN_KEY1] =*/ "key 1",
|
||||
/*[WSI_TOKEN_KEY2] =*/ "key 2",
|
||||
/*[WSI_TOKEN_PROTOCOL] =*/ "Protocol",
|
||||
/*[WSI_TOKEN_UPGRADE] =*/ "Upgrade",
|
||||
/*[WSI_TOKEN_ORIGIN] =*/ "Origin",
|
||||
/*[WSI_TOKEN_DRAFT] =*/ "Draft",
|
||||
/*[WSI_TOKEN_CHALLENGE] =*/ "Challenge",
|
||||
|
||||
/* new for 04 */
|
||||
/*[WSI_TOKEN_KEY] =*/ "Key",
|
||||
/*[WSI_TOKEN_VERSION] =*/ "Version",
|
||||
/*[WSI_TOKEN_SWORIGIN] =*/ "Sworigin",
|
||||
|
||||
/* new for 05 */
|
||||
/*[WSI_TOKEN_EXTENSIONS] =*/ "Extensions",
|
||||
|
||||
/* client receives these */
|
||||
/*[WSI_TOKEN_ACCEPT] =*/ "Accept",
|
||||
/*[WSI_TOKEN_NONCE] =*/ "Nonce",
|
||||
/*[WSI_TOKEN_HTTP] =*/ "Http",
|
||||
|
||||
"Accept:",
|
||||
"If-Modified-Since:",
|
||||
"Accept-Encoding:",
|
||||
"Accept-Language:",
|
||||
"Pragma:",
|
||||
"Cache-Control:",
|
||||
"Authorization:",
|
||||
"Cookie:",
|
||||
"Content-Length:",
|
||||
"Content-Type:",
|
||||
"Date:",
|
||||
"Range:",
|
||||
"Referer:",
|
||||
"Uri-Args:",
|
||||
|
||||
/*[WSI_TOKEN_MUXURL] =*/ "MuxURL",
|
||||
};
|
||||
char buf[256];
|
||||
|
||||
for (n = 0; n < sizeof(token_names) / sizeof(token_names[0]); n++) {
|
||||
if (!lws_hdr_total_length(wsi, n))
|
||||
continue;
|
||||
|
||||
lws_hdr_copy(wsi, buf, sizeof buf, n);
|
||||
|
||||
fprintf(stderr, " %s = %s\n", token_names[n], buf);
|
||||
}
|
||||
}
|
||||
|
||||
const char * get_mimetype(const char *file)
|
||||
{
|
||||
int n = strlen(file);
|
||||
|
||||
if (n < 5)
|
||||
return NULL;
|
||||
|
||||
if (!strcmp(&file[n - 4], ".ico"))
|
||||
return "image/x-icon";
|
||||
|
||||
if (!strcmp(&file[n - 4], ".png"))
|
||||
return "image/png";
|
||||
|
||||
if (!strcmp(&file[n - 5], ".html"))
|
||||
return "text/html";
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* this protocol server (always the first one) just knows how to do HTTP */
|
||||
|
||||
static int callback_http(struct libwebsocket_context *context,
|
||||
struct libwebsocket *wsi,
|
||||
enum libwebsocket_callback_reasons reason, void *user,
|
||||
void *in, size_t len)
|
||||
{
|
||||
#if 0
|
||||
char client_name[128];
|
||||
char client_ip[128];
|
||||
#endif
|
||||
char buf[256];
|
||||
char leaf_path[1024];
|
||||
char b64[64];
|
||||
struct timeval tv;
|
||||
int n, m;
|
||||
unsigned char *p;
|
||||
char *other_headers;
|
||||
static unsigned char buffer[4096];
|
||||
struct stat stat_buf;
|
||||
struct per_session_data__http *pss =
|
||||
(struct per_session_data__http *)user;
|
||||
const char *mimetype;
|
||||
#ifdef EXTERNAL_POLL
|
||||
struct libwebsocket_pollargs *pa = (struct libwebsocket_pollargs *)in;
|
||||
#endif
|
||||
|
||||
switch (reason) {
|
||||
case LWS_CALLBACK_HTTP:
|
||||
|
||||
dump_handshake_info(wsi);
|
||||
|
||||
if (len < 1) {
|
||||
libwebsockets_return_http_status(context, wsi,
|
||||
HTTP_STATUS_BAD_REQUEST, NULL);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* this server has no concept of directories */
|
||||
if (strchr((const char *)in + 1, '/')) {
|
||||
libwebsockets_return_http_status(context, wsi,
|
||||
HTTP_STATUS_FORBIDDEN, NULL);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* if a legal POST URL, let it continue and accept data */
|
||||
if (lws_hdr_total_length(wsi, WSI_TOKEN_POST_URI))
|
||||
return 0;
|
||||
|
||||
/* check for the "send a big file by hand" example case */
|
||||
|
||||
if (!strcmp((const char *)in, "/leaf.jpg")) {
|
||||
if (strlen(resource_path) > sizeof(leaf_path) - 10)
|
||||
return -1;
|
||||
sprintf(leaf_path, "%s/leaf.jpg", resource_path);
|
||||
|
||||
/* well, let's demonstrate how to send the hard way */
|
||||
|
||||
p = buffer;
|
||||
|
||||
#ifdef WIN32
|
||||
pss->fd = open(leaf_path, O_RDONLY | _O_BINARY);
|
||||
#else
|
||||
pss->fd = open(leaf_path, O_RDONLY);
|
||||
#endif
|
||||
|
||||
if (pss->fd < 0)
|
||||
return -1;
|
||||
|
||||
fstat(pss->fd, &stat_buf);
|
||||
|
||||
/*
|
||||
* we will send a big jpeg file, but it could be
|
||||
* anything. Set the Content-Type: appropriately
|
||||
* so the browser knows what to do with it.
|
||||
*/
|
||||
|
||||
p += sprintf((char *)p,
|
||||
"HTTP/1.0 200 OK\x0d\x0a"
|
||||
"Server: libwebsockets\x0d\x0a"
|
||||
"Content-Type: image/jpeg\x0d\x0a"
|
||||
"Content-Length: %u\x0d\x0a\x0d\x0a",
|
||||
(unsigned int)stat_buf.st_size);
|
||||
|
||||
/*
|
||||
* send the http headers...
|
||||
* this won't block since it's the first payload sent
|
||||
* on the connection since it was established
|
||||
* (too small for partial)
|
||||
*/
|
||||
|
||||
n = libwebsocket_write(wsi, buffer,
|
||||
p - buffer, LWS_WRITE_HTTP);
|
||||
|
||||
if (n < 0) {
|
||||
close(pss->fd);
|
||||
return -1;
|
||||
}
|
||||
/*
|
||||
* book us a LWS_CALLBACK_HTTP_WRITEABLE callback
|
||||
*/
|
||||
libwebsocket_callback_on_writable(context, wsi);
|
||||
break;
|
||||
}
|
||||
|
||||
/* if not, send a file the easy way */
|
||||
strcpy(buf, resource_path);
|
||||
if (strcmp(in, "/")) {
|
||||
if (*((const char *)in) != '/')
|
||||
strcat(buf, "/");
|
||||
strncat(buf, in, sizeof(buf) - strlen(resource_path));
|
||||
} else /* default file to serve */
|
||||
strcat(buf, "/test.html");
|
||||
buf[sizeof(buf) - 1] = '\0';
|
||||
|
||||
/* refuse to serve files we don't understand */
|
||||
mimetype = get_mimetype(buf);
|
||||
if (!mimetype) {
|
||||
lwsl_err("Unknown mimetype for %s\n", buf);
|
||||
libwebsockets_return_http_status(context, wsi,
|
||||
HTTP_STATUS_UNSUPPORTED_MEDIA_TYPE, NULL);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* demostrates how to set a cookie on / */
|
||||
|
||||
other_headers = NULL;
|
||||
if (!strcmp((const char *)in, "/") &&
|
||||
!lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_COOKIE)) {
|
||||
/* this isn't very unguessable but it'll do for us */
|
||||
gettimeofday(&tv, NULL);
|
||||
sprintf(b64, "LWS_%u_%u_COOKIE",
|
||||
(unsigned int)tv.tv_sec,
|
||||
(unsigned int)tv.tv_usec);
|
||||
|
||||
sprintf(leaf_path,
|
||||
"Set-Cookie: test=LWS_%u_%u_COOKIE;Max-Age=360000\x0d\x0a",
|
||||
(unsigned int)tv.tv_sec, (unsigned int)tv.tv_usec);
|
||||
other_headers = leaf_path;
|
||||
lwsl_err(other_headers);
|
||||
}
|
||||
|
||||
if (libwebsockets_serve_http_file(context, wsi, buf,
|
||||
mimetype, other_headers))
|
||||
return -1; /* through completion or error, close the socket */
|
||||
|
||||
/*
|
||||
* notice that the sending of the file completes asynchronously,
|
||||
* we'll get a LWS_CALLBACK_HTTP_FILE_COMPLETION callback when
|
||||
* it's done
|
||||
*/
|
||||
|
||||
break;
|
||||
|
||||
case LWS_CALLBACK_HTTP_BODY:
|
||||
strncpy(buf, in, 20);
|
||||
buf[20] = '\0';
|
||||
if (len < 20)
|
||||
buf[len] = '\0';
|
||||
|
||||
lwsl_notice("LWS_CALLBACK_HTTP_BODY: %s... len %d\n",
|
||||
(const char *)buf, (int)len);
|
||||
|
||||
break;
|
||||
|
||||
case LWS_CALLBACK_HTTP_BODY_COMPLETION:
|
||||
lwsl_notice("LWS_CALLBACK_HTTP_BODY_COMPLETION\n");
|
||||
/* the whole of the sent body arried, close the connection */
|
||||
libwebsockets_return_http_status(context, wsi,
|
||||
HTTP_STATUS_OK, NULL);
|
||||
|
||||
return -1;
|
||||
|
||||
case LWS_CALLBACK_HTTP_FILE_COMPLETION:
|
||||
// lwsl_info("LWS_CALLBACK_HTTP_FILE_COMPLETION seen\n");
|
||||
/* kill the connection after we sent one file */
|
||||
return -1;
|
||||
|
||||
case LWS_CALLBACK_HTTP_WRITEABLE:
|
||||
/*
|
||||
* we can send more of whatever it is we were sending
|
||||
*/
|
||||
|
||||
do {
|
||||
n = read(pss->fd, buffer, sizeof buffer);
|
||||
/* problem reading, close conn */
|
||||
if (n < 0)
|
||||
goto bail;
|
||||
/* sent it all, close conn */
|
||||
if (n == 0)
|
||||
goto flush_bail;
|
||||
/*
|
||||
* because it's HTTP and not websocket, don't need to take
|
||||
* care about pre and postamble
|
||||
*/
|
||||
m = libwebsocket_write(wsi, buffer, n, LWS_WRITE_HTTP);
|
||||
if (m < 0)
|
||||
/* write failed, close conn */
|
||||
goto bail;
|
||||
if (m != n)
|
||||
/* partial write, adjust */
|
||||
lseek(pss->fd, m - n, SEEK_CUR);
|
||||
|
||||
if (m) /* while still active, extend timeout */
|
||||
libwebsocket_set_timeout(wsi,
|
||||
PENDING_TIMEOUT_HTTP_CONTENT, 5);
|
||||
|
||||
} while (!lws_send_pipe_choked(wsi));
|
||||
libwebsocket_callback_on_writable(context, wsi);
|
||||
break;
|
||||
flush_bail:
|
||||
/* true if still partial pending */
|
||||
if (lws_send_pipe_choked(wsi)) {
|
||||
libwebsocket_callback_on_writable(context, wsi);
|
||||
break;
|
||||
}
|
||||
|
||||
bail:
|
||||
close(pss->fd);
|
||||
return -1;
|
||||
|
||||
/*
|
||||
* callback for confirming to continue with client IP appear in
|
||||
* protocol 0 callback since no websocket protocol has been agreed
|
||||
* yet. You can just ignore this if you won't filter on client IP
|
||||
* since the default uhandled callback return is 0 meaning let the
|
||||
* connection continue.
|
||||
*/
|
||||
|
||||
case LWS_CALLBACK_FILTER_NETWORK_CONNECTION:
|
||||
#if 0
|
||||
libwebsockets_get_peer_addresses(context, wsi, (int)(long)in, client_name,
|
||||
sizeof(client_name), client_ip, sizeof(client_ip));
|
||||
|
||||
fprintf(stderr, "Received network connect from %s (%s)\n",
|
||||
client_name, client_ip);
|
||||
#endif
|
||||
/* if we returned non-zero from here, we kill the connection */
|
||||
break;
|
||||
|
||||
#ifdef EXTERNAL_POLL
|
||||
/*
|
||||
* callbacks for managing the external poll() array appear in
|
||||
* protocol 0 callback
|
||||
*/
|
||||
|
||||
case LWS_CALLBACK_LOCK_POLL:
|
||||
/*
|
||||
* lock mutex to protect pollfd state
|
||||
* called before any other POLL related callback
|
||||
*/
|
||||
break;
|
||||
|
||||
case LWS_CALLBACK_UNLOCK_POLL:
|
||||
/*
|
||||
* unlock mutex to protect pollfd state when
|
||||
* called after any other POLL related callback
|
||||
*/
|
||||
break;
|
||||
|
||||
case LWS_CALLBACK_ADD_POLL_FD:
|
||||
|
||||
if (count_pollfds >= max_poll_elements) {
|
||||
lwsl_err("LWS_CALLBACK_ADD_POLL_FD: too many sockets to track\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
fd_lookup[pa->fd] = count_pollfds;
|
||||
pollfds[count_pollfds].fd = pa->fd;
|
||||
pollfds[count_pollfds].events = pa->events;
|
||||
pollfds[count_pollfds++].revents = 0;
|
||||
break;
|
||||
|
||||
case LWS_CALLBACK_DEL_POLL_FD:
|
||||
if (!--count_pollfds)
|
||||
break;
|
||||
m = fd_lookup[pa->fd];
|
||||
/* have the last guy take up the vacant slot */
|
||||
pollfds[m] = pollfds[count_pollfds];
|
||||
fd_lookup[pollfds[count_pollfds].fd] = m;
|
||||
break;
|
||||
|
||||
case LWS_CALLBACK_CHANGE_MODE_POLL_FD:
|
||||
pollfds[fd_lookup[pa->fd]].events = pa->events;
|
||||
break;
|
||||
|
||||
#endif
|
||||
|
||||
case LWS_CALLBACK_GET_THREAD_ID:
|
||||
/*
|
||||
* if you will call "libwebsocket_callback_on_writable"
|
||||
* from a different thread, return the caller thread ID
|
||||
* here so lws can use this information to work out if it
|
||||
* should signal the poll() loop to exit and restart early
|
||||
*/
|
||||
|
||||
/* return pthread_getthreadid_np(); */
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* dumb_increment protocol */
|
||||
|
||||
/*
|
||||
* one of these is auto-created for each connection and a pointer to the
|
||||
* appropriate instance is passed to the callback in the user parameter
|
||||
*
|
||||
* for this example protocol we use it to individualize the count for each
|
||||
* connection.
|
||||
*/
|
||||
|
||||
struct per_session_data__dumb_increment {
|
||||
int number;
|
||||
};
|
||||
|
||||
static int
|
||||
callback_dumb_increment(struct libwebsocket_context *context,
|
||||
struct libwebsocket *wsi,
|
||||
enum libwebsocket_callback_reasons reason,
|
||||
void *user, void *in, size_t len)
|
||||
{
|
||||
int n, m;
|
||||
unsigned char buf[LWS_SEND_BUFFER_PRE_PADDING + 512 +
|
||||
LWS_SEND_BUFFER_POST_PADDING];
|
||||
unsigned char *p = &buf[LWS_SEND_BUFFER_PRE_PADDING];
|
||||
struct per_session_data__dumb_increment *pss = (struct per_session_data__dumb_increment *)user;
|
||||
|
||||
switch (reason) {
|
||||
|
||||
case LWS_CALLBACK_ESTABLISHED:
|
||||
lwsl_info("callback_dumb_increment: "
|
||||
"LWS_CALLBACK_ESTABLISHED\n");
|
||||
pss->number = 0;
|
||||
break;
|
||||
|
||||
case LWS_CALLBACK_SERVER_WRITEABLE:
|
||||
n = sprintf((char *)p, "%d", pss->number++);
|
||||
m = libwebsocket_write(wsi, p, n, LWS_WRITE_TEXT);
|
||||
if (m < n) {
|
||||
lwsl_err("ERROR %d writing to di socket\n", n);
|
||||
return -1;
|
||||
}
|
||||
if (close_testing && pss->number == 50) {
|
||||
lwsl_info("close tesing limit, closing\n");
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
|
||||
case LWS_CALLBACK_RECEIVE:
|
||||
// fprintf(stderr, "rx %d\n", (int)len);
|
||||
if (len < 6)
|
||||
break;
|
||||
if (strcmp((const char *)in, "reset\n") == 0)
|
||||
pss->number = 0;
|
||||
break;
|
||||
/*
|
||||
* this just demonstrates how to use the protocol filter. If you won't
|
||||
* study and reject connections based on header content, you don't need
|
||||
* to handle this callback
|
||||
*/
|
||||
|
||||
case LWS_CALLBACK_FILTER_PROTOCOL_CONNECTION:
|
||||
dump_handshake_info(wsi);
|
||||
/* you could return non-zero here and kill the connection */
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* lws-mirror_protocol */
|
||||
|
||||
#define MAX_MESSAGE_QUEUE 32
|
||||
|
||||
struct per_session_data__lws_mirror {
|
||||
struct libwebsocket *wsi;
|
||||
int ringbuffer_tail;
|
||||
};
|
||||
|
||||
struct a_message {
|
||||
void *payload;
|
||||
size_t len;
|
||||
};
|
||||
|
||||
static struct a_message ringbuffer[MAX_MESSAGE_QUEUE];
|
||||
static int ringbuffer_head;
|
||||
|
||||
static int
|
||||
callback_lws_mirror(struct libwebsocket_context *context,
|
||||
struct libwebsocket *wsi,
|
||||
enum libwebsocket_callback_reasons reason,
|
||||
void *user, void *in, size_t len)
|
||||
{
|
||||
int n;
|
||||
struct per_session_data__lws_mirror *pss = (struct per_session_data__lws_mirror *)user;
|
||||
|
||||
switch (reason) {
|
||||
|
||||
case LWS_CALLBACK_ESTABLISHED:
|
||||
lwsl_info("callback_lws_mirror: LWS_CALLBACK_ESTABLISHED\n");
|
||||
pss->ringbuffer_tail = ringbuffer_head;
|
||||
pss->wsi = wsi;
|
||||
break;
|
||||
|
||||
case LWS_CALLBACK_PROTOCOL_DESTROY:
|
||||
lwsl_notice("mirror protocol cleaning up\n");
|
||||
for (n = 0; n < sizeof ringbuffer / sizeof ringbuffer[0]; n++)
|
||||
if (ringbuffer[n].payload)
|
||||
free(ringbuffer[n].payload);
|
||||
break;
|
||||
|
||||
case LWS_CALLBACK_SERVER_WRITEABLE:
|
||||
if (close_testing)
|
||||
break;
|
||||
while (pss->ringbuffer_tail != ringbuffer_head) {
|
||||
|
||||
n = libwebsocket_write(wsi, (unsigned char *)
|
||||
ringbuffer[pss->ringbuffer_tail].payload +
|
||||
LWS_SEND_BUFFER_PRE_PADDING,
|
||||
ringbuffer[pss->ringbuffer_tail].len,
|
||||
LWS_WRITE_TEXT);
|
||||
if (n < 0) {
|
||||
lwsl_err("ERROR %d writing to mirror socket\n", n);
|
||||
return -1;
|
||||
}
|
||||
if (n < ringbuffer[pss->ringbuffer_tail].len)
|
||||
lwsl_err("mirror partial write %d vs %d\n",
|
||||
n, ringbuffer[pss->ringbuffer_tail].len);
|
||||
|
||||
if (pss->ringbuffer_tail == (MAX_MESSAGE_QUEUE - 1))
|
||||
pss->ringbuffer_tail = 0;
|
||||
else
|
||||
pss->ringbuffer_tail++;
|
||||
|
||||
if (((ringbuffer_head - pss->ringbuffer_tail) &
|
||||
(MAX_MESSAGE_QUEUE - 1)) == (MAX_MESSAGE_QUEUE - 15))
|
||||
libwebsocket_rx_flow_allow_all_protocol(
|
||||
libwebsockets_get_protocol(wsi));
|
||||
|
||||
// lwsl_debug("tx fifo %d\n", (ringbuffer_head - pss->ringbuffer_tail) & (MAX_MESSAGE_QUEUE - 1));
|
||||
|
||||
if (lws_send_pipe_choked(wsi)) {
|
||||
libwebsocket_callback_on_writable(context, wsi);
|
||||
break;
|
||||
}
|
||||
/*
|
||||
* for tests with chrome on same machine as client and
|
||||
* server, this is needed to stop chrome choking
|
||||
*/
|
||||
#ifdef _WIN32
|
||||
Sleep(1);
|
||||
#else
|
||||
usleep(1);
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
|
||||
case LWS_CALLBACK_RECEIVE:
|
||||
|
||||
if (((ringbuffer_head - pss->ringbuffer_tail) &
|
||||
(MAX_MESSAGE_QUEUE - 1)) == (MAX_MESSAGE_QUEUE - 1)) {
|
||||
lwsl_err("dropping!\n");
|
||||
goto choke;
|
||||
}
|
||||
|
||||
if (ringbuffer[ringbuffer_head].payload)
|
||||
free(ringbuffer[ringbuffer_head].payload);
|
||||
|
||||
ringbuffer[ringbuffer_head].payload =
|
||||
malloc(LWS_SEND_BUFFER_PRE_PADDING + len +
|
||||
LWS_SEND_BUFFER_POST_PADDING);
|
||||
ringbuffer[ringbuffer_head].len = len;
|
||||
memcpy((char *)ringbuffer[ringbuffer_head].payload +
|
||||
LWS_SEND_BUFFER_PRE_PADDING, in, len);
|
||||
if (ringbuffer_head == (MAX_MESSAGE_QUEUE - 1))
|
||||
ringbuffer_head = 0;
|
||||
else
|
||||
ringbuffer_head++;
|
||||
|
||||
if (((ringbuffer_head - pss->ringbuffer_tail) &
|
||||
(MAX_MESSAGE_QUEUE - 1)) != (MAX_MESSAGE_QUEUE - 2))
|
||||
goto done;
|
||||
|
||||
choke:
|
||||
lwsl_debug("LWS_CALLBACK_RECEIVE: throttling %p\n", wsi);
|
||||
libwebsocket_rx_flow_control(wsi, 0);
|
||||
|
||||
// lwsl_debug("rx fifo %d\n", (ringbuffer_head - pss->ringbuffer_tail) & (MAX_MESSAGE_QUEUE - 1));
|
||||
done:
|
||||
libwebsocket_callback_on_writable_all_protocol(
|
||||
libwebsockets_get_protocol(wsi));
|
||||
break;
|
||||
|
||||
/*
|
||||
* this just demonstrates how to use the protocol filter. If you won't
|
||||
* study and reject connections based on header content, you don't need
|
||||
* to handle this callback
|
||||
*/
|
||||
|
||||
case LWS_CALLBACK_FILTER_PROTOCOL_CONNECTION:
|
||||
dump_handshake_info(wsi);
|
||||
/* you could return non-zero here and kill the connection */
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* list of supported protocols and callbacks */
|
||||
|
||||
static struct libwebsocket_protocols protocols[] = {
|
||||
/* first protocol must always be HTTP handler */
|
||||
|
||||
{
|
||||
"http-only", /* name */
|
||||
callback_http, /* callback */
|
||||
sizeof (struct per_session_data__http), /* per_session_data_size */
|
||||
0, /* max frame size / rx buffer */
|
||||
},
|
||||
{
|
||||
"dumb-increment-protocol",
|
||||
callback_dumb_increment,
|
||||
sizeof(struct per_session_data__dumb_increment),
|
||||
10,
|
||||
},
|
||||
{
|
||||
"lws-mirror-protocol",
|
||||
callback_lws_mirror,
|
||||
sizeof(struct per_session_data__lws_mirror),
|
||||
128,
|
||||
},
|
||||
{ NULL, NULL, 0, 0 } /* terminator */
|
||||
};
|
||||
|
||||
void sighandler(int sig)
|
||||
{
|
||||
force_exit = 1;
|
||||
libwebsocket_cancel_service(context);
|
||||
}
|
||||
|
||||
static struct option options[] = {
|
||||
{ "help", no_argument, NULL, 'h' },
|
||||
{ "debug", required_argument, NULL, 'd' },
|
||||
{ "port", required_argument, NULL, 'p' },
|
||||
{ "ssl", no_argument, NULL, 's' },
|
||||
{ "allow-non-ssl", no_argument, NULL, 'a' },
|
||||
{ "interface", required_argument, NULL, 'i' },
|
||||
{ "closetest", no_argument, NULL, 'c' },
|
||||
{ "libev", no_argument, NULL, 'e' },
|
||||
#ifndef LWS_NO_DAEMONIZE
|
||||
{ "daemonize", no_argument, NULL, 'D' },
|
||||
#endif
|
||||
{ "resource_path", required_argument, NULL, 'r' },
|
||||
{ NULL, 0, 0, 0 }
|
||||
};
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
char cert_path[1024];
|
||||
char key_path[1024];
|
||||
int n = 0;
|
||||
int use_ssl = 0;
|
||||
int opts = 0;
|
||||
char interface_name[128] = "";
|
||||
const char *iface = NULL;
|
||||
#ifndef WIN32
|
||||
int syslog_options = LOG_PID | LOG_PERROR;
|
||||
#endif
|
||||
unsigned int ms, oldms = 0;
|
||||
struct lws_context_creation_info info;
|
||||
|
||||
int debug_level = 7;
|
||||
#ifndef LWS_NO_DAEMONIZE
|
||||
int daemonize = 0;
|
||||
#endif
|
||||
|
||||
memset(&info, 0, sizeof info);
|
||||
info.port = 7681;
|
||||
|
||||
while (n >= 0) {
|
||||
n = getopt_long(argc, argv, "eci:hsap:d:Dr:", options, NULL);
|
||||
if (n < 0)
|
||||
continue;
|
||||
switch (n) {
|
||||
case 'e':
|
||||
opts |= LWS_SERVER_OPTION_LIBEV;
|
||||
break;
|
||||
#ifndef LWS_NO_DAEMONIZE
|
||||
case 'D':
|
||||
daemonize = 1;
|
||||
#ifndef WIN32
|
||||
syslog_options &= ~LOG_PERROR;
|
||||
#endif
|
||||
break;
|
||||
#endif
|
||||
case 'd':
|
||||
debug_level = atoi(optarg);
|
||||
break;
|
||||
case 's':
|
||||
use_ssl = 1;
|
||||
break;
|
||||
case 'a':
|
||||
opts |= LWS_SERVER_OPTION_ALLOW_NON_SSL_ON_SSL_PORT;
|
||||
break;
|
||||
case 'p':
|
||||
info.port = atoi(optarg);
|
||||
break;
|
||||
case 'i':
|
||||
strncpy(interface_name, optarg, sizeof interface_name);
|
||||
interface_name[(sizeof interface_name) - 1] = '\0';
|
||||
iface = interface_name;
|
||||
break;
|
||||
case 'c':
|
||||
close_testing = 1;
|
||||
fprintf(stderr, " Close testing mode -- closes on "
|
||||
"client after 50 dumb increments"
|
||||
"and suppresses lws_mirror spam\n");
|
||||
break;
|
||||
case 'r':
|
||||
resource_path = optarg;
|
||||
printf("Setting resource path to \"%s\"\n", resource_path);
|
||||
break;
|
||||
case 'h':
|
||||
fprintf(stderr, "Usage: test-server "
|
||||
"[--port=<p>] [--ssl] "
|
||||
"[-d <log bitfield>] "
|
||||
"[--resource_path <path>]\n");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
#if !defined(LWS_NO_DAEMONIZE) && !defined(WIN32)
|
||||
/*
|
||||
* normally lock path would be /var/lock/lwsts or similar, to
|
||||
* simplify getting started without having to take care about
|
||||
* permissions or running as root, set to /tmp/.lwsts-lock
|
||||
*/
|
||||
if (daemonize && lws_daemonize("/tmp/.lwsts-lock")) {
|
||||
fprintf(stderr, "Failed to daemonize\n");
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
signal(SIGINT, sighandler);
|
||||
|
||||
#ifndef WIN32
|
||||
/* we will only try to log things according to our debug_level */
|
||||
setlogmask(LOG_UPTO (LOG_DEBUG));
|
||||
openlog("lwsts", syslog_options, LOG_DAEMON);
|
||||
#endif
|
||||
|
||||
/* tell the library what debug level to emit and to send it to syslog */
|
||||
lws_set_log_level(debug_level, lwsl_emit_syslog);
|
||||
|
||||
lwsl_notice("libwebsockets test server - "
|
||||
"(C) Copyright 2010-2013 Andy Green <andy@warmcat.com> - "
|
||||
"licensed under LGPL2.1\n");
|
||||
#ifdef EXTERNAL_POLL
|
||||
max_poll_elements = getdtablesize();
|
||||
pollfds = malloc(max_poll_elements * sizeof (struct pollfd));
|
||||
fd_lookup = malloc(max_poll_elements * sizeof (int));
|
||||
if (pollfds == NULL || fd_lookup == NULL) {
|
||||
lwsl_err("Out of memory pollfds=%d\n", max_poll_elements);
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
info.iface = iface;
|
||||
info.protocols = protocols;
|
||||
#ifndef LWS_NO_EXTENSIONS
|
||||
info.extensions = libwebsocket_get_internal_extensions();
|
||||
#endif
|
||||
if (!use_ssl) {
|
||||
info.ssl_cert_filepath = NULL;
|
||||
info.ssl_private_key_filepath = NULL;
|
||||
} else {
|
||||
if (strlen(resource_path) > sizeof(cert_path) - 32) {
|
||||
lwsl_err("resource path too long\n");
|
||||
return -1;
|
||||
}
|
||||
sprintf(cert_path, "%s/libwebsockets-test-server.pem",
|
||||
resource_path);
|
||||
if (strlen(resource_path) > sizeof(key_path) - 32) {
|
||||
lwsl_err("resource path too long\n");
|
||||
return -1;
|
||||
}
|
||||
sprintf(key_path, "%s/libwebsockets-test-server.key.pem",
|
||||
resource_path);
|
||||
|
||||
info.ssl_cert_filepath = cert_path;
|
||||
info.ssl_private_key_filepath = key_path;
|
||||
}
|
||||
info.gid = -1;
|
||||
info.uid = -1;
|
||||
info.options = opts;
|
||||
|
||||
context = libwebsocket_create_context(&info);
|
||||
if (context == NULL) {
|
||||
lwsl_err("libwebsocket init failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
n = 0;
|
||||
while (n >= 0 && !force_exit) {
|
||||
struct timeval tv;
|
||||
|
||||
gettimeofday(&tv, NULL);
|
||||
|
||||
/*
|
||||
* This provokes the LWS_CALLBACK_SERVER_WRITEABLE for every
|
||||
* live websocket connection using the DUMB_INCREMENT protocol,
|
||||
* as soon as it can take more packets (usually immediately)
|
||||
*/
|
||||
|
||||
ms = (tv.tv_sec * 1000) + (tv.tv_usec / 1000);
|
||||
if ((ms - oldms) > 50) {
|
||||
libwebsocket_callback_on_writable_all_protocol(&protocols[PROTOCOL_DUMB_INCREMENT]);
|
||||
oldms = ms;
|
||||
}
|
||||
|
||||
#ifdef EXTERNAL_POLL
|
||||
|
||||
/*
|
||||
* this represents an existing server's single poll action
|
||||
* which also includes libwebsocket sockets
|
||||
*/
|
||||
|
||||
n = poll(pollfds, count_pollfds, 50);
|
||||
if (n < 0)
|
||||
continue;
|
||||
|
||||
|
||||
if (n)
|
||||
for (n = 0; n < count_pollfds; n++)
|
||||
if (pollfds[n].revents)
|
||||
/*
|
||||
* returns immediately if the fd does not
|
||||
* match anything under libwebsockets
|
||||
* control
|
||||
*/
|
||||
if (libwebsocket_service_fd(context,
|
||||
&pollfds[n]) < 0)
|
||||
goto done;
|
||||
#else
|
||||
/*
|
||||
* If libwebsockets sockets are all we care about,
|
||||
* you can use this api which takes care of the poll()
|
||||
* and looping through finding who needed service.
|
||||
*
|
||||
* If no socket needs service, it'll return anyway after
|
||||
* the number of ms in the second argument.
|
||||
*/
|
||||
|
||||
n = libwebsocket_service(context, 50);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef EXTERNAL_POLL
|
||||
done:
|
||||
#endif
|
||||
|
||||
libwebsocket_context_destroy(context);
|
||||
|
||||
lwsl_notice("libwebsockets-test-server exited cleanly\n");
|
||||
|
||||
#ifndef WIN32
|
||||
closelog();
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user