select interrupt cleanup
This commit is contained in:
parent
b462b5a5c8
commit
b91dc77d6f
@ -16,7 +16,6 @@ if (NOT WIN32)
|
|||||||
endif()
|
endif()
|
||||||
|
|
||||||
set( IXWEBSOCKET_SOURCES
|
set( IXWEBSOCKET_SOURCES
|
||||||
ixwebsocket/IXEventFd.cpp
|
|
||||||
ixwebsocket/IXSocket.cpp
|
ixwebsocket/IXSocket.cpp
|
||||||
ixwebsocket/IXSocketServer.cpp
|
ixwebsocket/IXSocketServer.cpp
|
||||||
ixwebsocket/IXSocketConnect.cpp
|
ixwebsocket/IXSocketConnect.cpp
|
||||||
@ -33,10 +32,11 @@ set( IXWEBSOCKET_SOURCES
|
|||||||
ixwebsocket/IXWebSocketHttpHeaders.cpp
|
ixwebsocket/IXWebSocketHttpHeaders.cpp
|
||||||
ixwebsocket/IXHttpClient.cpp
|
ixwebsocket/IXHttpClient.cpp
|
||||||
ixwebsocket/IXUrlParser.cpp
|
ixwebsocket/IXUrlParser.cpp
|
||||||
|
ixwebsocket/IXSelectInterrupt.cpp
|
||||||
|
ixwebsocket/IXSelectInterruptFactory.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
set( IXWEBSOCKET_HEADERS
|
set( IXWEBSOCKET_HEADERS
|
||||||
ixwebsocket/IXEventFd.h
|
|
||||||
ixwebsocket/IXSocket.h
|
ixwebsocket/IXSocket.h
|
||||||
ixwebsocket/IXSocketServer.h
|
ixwebsocket/IXSocketServer.h
|
||||||
ixwebsocket/IXSocketConnect.h
|
ixwebsocket/IXSocketConnect.h
|
||||||
@ -58,15 +58,21 @@ set( IXWEBSOCKET_HEADERS
|
|||||||
ixwebsocket/libwshandshake.hpp
|
ixwebsocket/libwshandshake.hpp
|
||||||
ixwebsocket/IXHttpClient.h
|
ixwebsocket/IXHttpClient.h
|
||||||
ixwebsocket/IXUrlParser.h
|
ixwebsocket/IXUrlParser.h
|
||||||
|
ixwebsocket/IXSelectInterrupt.h
|
||||||
|
ixwebsocket/IXSelectInterruptFactory.h
|
||||||
)
|
)
|
||||||
|
|
||||||
# Platform specific code
|
# Platform specific code
|
||||||
if (APPLE)
|
if (APPLE)
|
||||||
list( APPEND IXWEBSOCKET_SOURCES ixwebsocket/apple/IXSetThreadName_apple.cpp)
|
list( APPEND IXWEBSOCKET_SOURCES ixwebsocket/apple/IXSetThreadName_apple.cpp)
|
||||||
|
list( APPEND IXWEBSOCKET_SOURCES ixwebsocket/IXSelectInterruptPipe.cpp)
|
||||||
|
list( APPEND IXWEBSOCKET_HEADERS ixwebsocket/IXSelectInterruptPipe.h)
|
||||||
elseif (WIN32)
|
elseif (WIN32)
|
||||||
list( APPEND IXWEBSOCKET_SOURCES ixwebsocket/windows/IXSetThreadName_windows.cpp)
|
list( APPEND IXWEBSOCKET_SOURCES ixwebsocket/windows/IXSetThreadName_windows.cpp)
|
||||||
else()
|
else()
|
||||||
list( APPEND IXWEBSOCKET_SOURCES ixwebsocket/linux/IXSetThreadName_linux.cpp)
|
list( APPEND IXWEBSOCKET_SOURCES ixwebsocket/linux/IXSetThreadName_linux.cpp)
|
||||||
|
list( APPEND IXWEBSOCKET_SOURCES ixwebsocket/IXSelectInterruptEventFd.cpp)
|
||||||
|
list( APPEND IXWEBSOCKET_HEADERS ixwebsocket/IXSelectInterruptEventFd.h)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (USE_TLS)
|
if (USE_TLS)
|
||||||
|
46
ixwebsocket/IXSelectInterrupt.cpp
Normal file
46
ixwebsocket/IXSelectInterrupt.cpp
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
/*
|
||||||
|
* IXSelectInterrupt.cpp
|
||||||
|
* Author: Benjamin Sergeant
|
||||||
|
* Copyright (c) 2019 Machine Zone, Inc. All rights reserved.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "IXSelectInterrupt.h"
|
||||||
|
|
||||||
|
namespace ix
|
||||||
|
{
|
||||||
|
SelectInterrupt::SelectInterrupt()
|
||||||
|
{
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
SelectInterrupt::~SelectInterrupt()
|
||||||
|
{
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SelectInterrupt::init(std::string& /*errorMsg*/)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SelectInterrupt::notify(uint64_t /*value*/)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t SelectInterrupt::read()
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SelectInterrupt::clear()
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
int SelectInterrupt::getFd()
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
28
ixwebsocket/IXSelectInterrupt.h
Normal file
28
ixwebsocket/IXSelectInterrupt.h
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
/*
|
||||||
|
* IXSelectInterrupt.h
|
||||||
|
* Author: Benjamin Sergeant
|
||||||
|
* Copyright (c) 2019 Machine Zone, Inc. All rights reserved.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace ix
|
||||||
|
{
|
||||||
|
class SelectInterrupt {
|
||||||
|
public:
|
||||||
|
SelectInterrupt();
|
||||||
|
virtual ~SelectInterrupt();
|
||||||
|
|
||||||
|
virtual bool init(std::string& errorMsg);
|
||||||
|
|
||||||
|
virtual bool notify(uint64_t value);
|
||||||
|
virtual bool clear();
|
||||||
|
virtual uint64_t read();
|
||||||
|
virtual int getFd();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -1,9 +1,13 @@
|
|||||||
/*
|
/*
|
||||||
* IXEventFd.cpp
|
* IXSelectInterruptEventFd.cpp
|
||||||
* Author: Benjamin Sergeant
|
* Author: Benjamin Sergeant
|
||||||
* Copyright (c) 2018 Machine Zone, Inc. All rights reserved.
|
* Copyright (c) 2018-2019 Machine Zone, Inc. All rights reserved.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
//
|
||||||
|
// On Linux we use eventd to wake up select.
|
||||||
|
//
|
||||||
|
|
||||||
//
|
//
|
||||||
// Linux/Android has a special type of virtual files. select(2) will react
|
// Linux/Android has a special type of virtual files. select(2) will react
|
||||||
// when reading/writing to those files, unlike closing sockets.
|
// when reading/writing to those files, unlike closing sockets.
|
||||||
@ -22,57 +26,59 @@
|
|||||||
|
|
||||||
#include "IXEventFd.h"
|
#include "IXEventFd.h"
|
||||||
|
|
||||||
#ifdef __linux__
|
#include <sys/eventfd.h>
|
||||||
# include <sys/eventfd.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <unistd.h> // for write
|
#include <unistd.h> // for write
|
||||||
|
#include <string.h> // for strerror
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
namespace ix
|
namespace ix
|
||||||
{
|
{
|
||||||
// File descriptor at index 0 in _fildes is the read end of the pipe
|
SelectInterruptEventFd::SelectInterruptEventFd()
|
||||||
// File descriptor at index 1 in _fildes is the write end of the pipe
|
|
||||||
const int EventFd::kPipeReadIndex = 0;
|
|
||||||
const int EventFd::kPipeWriteIndex = 1;
|
|
||||||
|
|
||||||
EventFd::EventFd()
|
|
||||||
{
|
{
|
||||||
#ifdef __linux__
|
;
|
||||||
_eventfd = -1;
|
|
||||||
_eventfd = eventfd(0, 0);
|
|
||||||
fcntl(_eventfd, F_SETFL, O_NONBLOCK);
|
|
||||||
#else
|
|
||||||
_fildes[kPipeReadIndex] = -1;
|
|
||||||
_fildes[kPipeWriteIndex] = -1;
|
|
||||||
|
|
||||||
pipe(_fildes);
|
|
||||||
fcntl(_fildes[kPipeReadIndex], F_SETFL, O_NONBLOCK);
|
|
||||||
fcntl(_fildes[kPipeWriteIndex], F_SETFL, O_NONBLOCK);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
EventFd::~EventFd()
|
SelectInterruptEventFd::~SelectInterruptEventFd()
|
||||||
{
|
{
|
||||||
#ifdef __linux__
|
|
||||||
::close(_eventfd);
|
::close(_eventfd);
|
||||||
#else
|
|
||||||
::close(_fildes[kPipeReadIndex]);
|
|
||||||
::close(_fildes[kPipeWriteIndex]);
|
|
||||||
_fildes[kPipeReadIndex] = -1;
|
|
||||||
_fildes[kPipeWriteIndex] = -1;
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool EventFd::notify(uint64_t value)
|
bool SelectInterruptEventFd::init(std::string& errorMsg)
|
||||||
{
|
{
|
||||||
int fd;
|
_eventfd = -1;
|
||||||
|
|
||||||
#if defined(__linux__)
|
_eventfd = eventfd(0, 0);
|
||||||
fd = _eventfd;
|
if (_eventfd < 0)
|
||||||
#else
|
{
|
||||||
fd = _fildes[kPipeWriteIndex];
|
std::stringstream ss;
|
||||||
#endif
|
ss << "SelectInterruptEventFd::init() failed in eventfd()"
|
||||||
|
<< " : " << strerror(errno);
|
||||||
|
errorMsg = ss.str();
|
||||||
|
|
||||||
|
_eventfd = -1;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fcntl(_eventfd, F_SETFL, O_NONBLOCK) == -1)
|
||||||
|
{
|
||||||
|
std::stringstream ss;
|
||||||
|
ss << "SelectInterruptEventFd::init() failed in fcntl() call"
|
||||||
|
<< " : " << strerror(errno);
|
||||||
|
errorMsg = ss.str();
|
||||||
|
|
||||||
|
_eventfd = -1;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SelectInterruptEventFd::notify(uint64_t value)
|
||||||
|
{
|
||||||
|
int fd = _eventfd;
|
||||||
|
|
||||||
if (fd == -1) return false;
|
if (fd == -1) return false;
|
||||||
|
|
||||||
@ -81,23 +87,17 @@ namespace ix
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TODO: return max uint64_t for errors ?
|
// TODO: return max uint64_t for errors ?
|
||||||
uint64_t EventFd::read()
|
uint64_t SelectInterruptEventFd::read()
|
||||||
{
|
{
|
||||||
int fd;
|
int fd = _eventfd;
|
||||||
|
|
||||||
#if defined(__linux__)
|
|
||||||
fd = _eventfd;
|
|
||||||
#else
|
|
||||||
fd = _fildes[kPipeReadIndex];
|
|
||||||
#endif
|
|
||||||
uint64_t value = 0;
|
uint64_t value = 0;
|
||||||
::read(fd, &value, sizeof(value));
|
::read(fd, &value, sizeof(value));
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool EventFd::clear()
|
bool SelectInterruptEventFd::clear()
|
||||||
{
|
{
|
||||||
#if defined(__linux__)
|
|
||||||
if (_eventfd == -1) return false;
|
if (_eventfd == -1) return false;
|
||||||
|
|
||||||
// 0 is a special value ; select will not wake up
|
// 0 is a special value ; select will not wake up
|
||||||
@ -105,17 +105,10 @@ namespace ix
|
|||||||
|
|
||||||
// we should write 8 bytes for an uint64_t
|
// we should write 8 bytes for an uint64_t
|
||||||
return write(_eventfd, &value, sizeof(value)) == 8;
|
return write(_eventfd, &value, sizeof(value)) == 8;
|
||||||
#else
|
|
||||||
return true;
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int EventFd::getFd()
|
int SelectInterruptEventFd::getFd()
|
||||||
{
|
{
|
||||||
#if defined(__linux__)
|
|
||||||
return _eventfd;
|
return _eventfd;
|
||||||
#else
|
|
||||||
return _fildes[kPipeReadIndex];
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
}
|
}
|
32
ixwebsocket/IXSelectInterruptEventFd.h
Normal file
32
ixwebsocket/IXSelectInterruptEventFd.h
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
/*
|
||||||
|
* IXSelectInterruptEventFd.h
|
||||||
|
* Author: Benjamin Sergeant
|
||||||
|
* Copyright (c) 2018-2019 Machine Zone, Inc. All rights reserved.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "IXSelectInterrupt.h"
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace ix
|
||||||
|
{
|
||||||
|
class SelectInterruptEventFd : public SelectInterrupt {
|
||||||
|
public:
|
||||||
|
SelectInterruptEventFd();
|
||||||
|
virtual ~SelectInterruptEventFd();
|
||||||
|
|
||||||
|
bool init(std::string& errorMsg) final;
|
||||||
|
|
||||||
|
bool notify(uint64_t value) final;
|
||||||
|
bool clear() final;
|
||||||
|
uint64_t read() final;
|
||||||
|
int getFd() final;
|
||||||
|
|
||||||
|
private:
|
||||||
|
int _eventfd;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
25
ixwebsocket/IXSelectInterruptFactory.cpp
Normal file
25
ixwebsocket/IXSelectInterruptFactory.cpp
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
/*
|
||||||
|
* IXSelectInterruptFactory.cpp
|
||||||
|
* Author: Benjamin Sergeant
|
||||||
|
* Copyright (c) 2019 Machine Zone, Inc. All rights reserved.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "IXSelectInterruptFactory.h"
|
||||||
|
|
||||||
|
#if defined(__linux__)
|
||||||
|
# include <ixwebsocket/IXSelectInterruptEventFd.h>
|
||||||
|
#else
|
||||||
|
# include <ixwebsocket/IXSelectInterruptPipe.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace ix
|
||||||
|
{
|
||||||
|
std::shared_ptr<SelectInterrupt> createSelectInterrupt()
|
||||||
|
{
|
||||||
|
#if defined(__linux__)
|
||||||
|
return std::make_shared<SelectInterruptEventFd>();
|
||||||
|
#else
|
||||||
|
return std::make_shared<SelectInterruptPipe>();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
15
ixwebsocket/IXSelectInterruptFactory.h
Normal file
15
ixwebsocket/IXSelectInterruptFactory.h
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
/*
|
||||||
|
* IXSelectInterruptFactory.h
|
||||||
|
* Author: Benjamin Sergeant
|
||||||
|
* Copyright (c) 2019 Machine Zone, Inc. All rights reserved.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
namespace ix
|
||||||
|
{
|
||||||
|
class SelectInterrupt;
|
||||||
|
std::shared_ptr<SelectInterrupt> createSelectInterrupt();
|
||||||
|
}
|
108
ixwebsocket/IXSelectInterruptPipe.cpp
Normal file
108
ixwebsocket/IXSelectInterruptPipe.cpp
Normal file
@ -0,0 +1,108 @@
|
|||||||
|
/*
|
||||||
|
* IXEventFd.cpp
|
||||||
|
* Author: Benjamin Sergeant
|
||||||
|
* Copyright (c) 2018-2019 Machine Zone, Inc. All rights reserved.
|
||||||
|
*/
|
||||||
|
|
||||||
|
//
|
||||||
|
// On macOS we use UNIX pipes to wake up select.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "IXSelectInterruptPipe.h"
|
||||||
|
|
||||||
|
#include <unistd.h> // for write
|
||||||
|
#include <string.h> // for strerror
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
|
namespace ix
|
||||||
|
{
|
||||||
|
// File descriptor at index 0 in _fildes is the read end of the pipe
|
||||||
|
// File descriptor at index 1 in _fildes is the write end of the pipe
|
||||||
|
const int SelectInterruptPipe::kPipeReadIndex = 0;
|
||||||
|
const int SelectInterruptPipe::kPipeWriteIndex = 1;
|
||||||
|
|
||||||
|
SelectInterruptPipe::SelectInterruptPipe()
|
||||||
|
{
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
SelectInterruptPipe::~SelectInterruptPipe()
|
||||||
|
{
|
||||||
|
::close(_fildes[kPipeReadIndex]);
|
||||||
|
::close(_fildes[kPipeWriteIndex]);
|
||||||
|
_fildes[kPipeReadIndex] = -1;
|
||||||
|
_fildes[kPipeWriteIndex] = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SelectInterruptPipe::init(std::string& errorMsg)
|
||||||
|
{
|
||||||
|
_fildes[kPipeReadIndex] = -1;
|
||||||
|
_fildes[kPipeWriteIndex] = -1;
|
||||||
|
|
||||||
|
if (pipe(_fildes) < 0)
|
||||||
|
{
|
||||||
|
std::stringstream ss;
|
||||||
|
ss << "SelectInterruptPipe::init() failed in pipe() call"
|
||||||
|
<< " : " << strerror(errno);
|
||||||
|
errorMsg = ss.str();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fcntl(_fildes[kPipeReadIndex], F_SETFL, O_NONBLOCK) == -1)
|
||||||
|
{
|
||||||
|
std::stringstream ss;
|
||||||
|
ss << "SelectInterruptPipe::init() failed in fcntl() call"
|
||||||
|
<< " : " << strerror(errno);
|
||||||
|
errorMsg = ss.str();
|
||||||
|
|
||||||
|
_fildes[kPipeReadIndex] = -1;
|
||||||
|
_fildes[kPipeWriteIndex] = -1;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fcntl(_fildes[kPipeWriteIndex], F_SETFL, O_NONBLOCK) == -1)
|
||||||
|
{
|
||||||
|
std::stringstream ss;
|
||||||
|
ss << "SelectInterruptPipe::init() failed in fcntl() call"
|
||||||
|
<< " : " << strerror(errno);
|
||||||
|
errorMsg = ss.str();
|
||||||
|
|
||||||
|
_fildes[kPipeReadIndex] = -1;
|
||||||
|
_fildes[kPipeWriteIndex] = -1;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SelectInterruptPipe::notify(uint64_t value)
|
||||||
|
{
|
||||||
|
int fd = _fildes[kPipeWriteIndex];
|
||||||
|
if (fd == -1) return false;
|
||||||
|
|
||||||
|
// we should write 8 bytes for an uint64_t
|
||||||
|
return write(fd, &value, sizeof(value)) == 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: return max uint64_t for errors ?
|
||||||
|
uint64_t SelectInterruptPipe::read()
|
||||||
|
{
|
||||||
|
int fd = _fildes[kPipeReadIndex];
|
||||||
|
|
||||||
|
uint64_t value = 0;
|
||||||
|
::read(fd, &value, sizeof(value));
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SelectInterruptPipe::clear()
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
int SelectInterruptPipe::getFd()
|
||||||
|
{
|
||||||
|
return _fildes[kPipeReadIndex];
|
||||||
|
}
|
||||||
|
}
|
@ -1,37 +1,39 @@
|
|||||||
/*
|
/*
|
||||||
* IXEventFd.h
|
* IXSelectInterruptPipe.h
|
||||||
* Author: Benjamin Sergeant
|
* Author: Benjamin Sergeant
|
||||||
* Copyright (c) 2018 Machine Zone, Inc. All rights reserved.
|
* Copyright (c) 2018-2019 Machine Zone, Inc. All rights reserved.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "IXSelectInterrupt.h"
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
namespace ix
|
namespace ix
|
||||||
{
|
{
|
||||||
class EventFd {
|
class SelectInterruptPipe : public SelectInterrupt {
|
||||||
public:
|
public:
|
||||||
EventFd();
|
SelectInterruptPipe();
|
||||||
virtual ~EventFd();
|
virtual ~SelectInterruptPipe();
|
||||||
|
|
||||||
bool notify(uint64_t value);
|
bool init(std::string& errorMsg) final;
|
||||||
bool clear();
|
|
||||||
uint64_t read();
|
bool notify(uint64_t value) final;
|
||||||
int getFd();
|
bool clear() final;
|
||||||
|
uint64_t read() final;
|
||||||
|
int getFd() final;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
#if defined(__linux__)
|
|
||||||
int _eventfd;
|
|
||||||
#else
|
|
||||||
// Store file descriptors used by the communication pipe. Communication
|
// Store file descriptors used by the communication pipe. Communication
|
||||||
// happens between a control thread and a background thread, which is
|
// happens between a control thread and a background thread, which is
|
||||||
// blocked on select.
|
// blocked on select.
|
||||||
int _fildes[2];
|
int _fildes[2];
|
||||||
#endif
|
|
||||||
|
|
||||||
// Used to identify the read/write idx
|
// Used to identify the read/write idx
|
||||||
static const int kPipeReadIndex;
|
static const int kPipeReadIndex;
|
||||||
static const int kPipeWriteIndex;
|
static const int kPipeWriteIndex;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
@ -7,6 +7,8 @@
|
|||||||
#include "IXSocket.h"
|
#include "IXSocket.h"
|
||||||
#include "IXSocketConnect.h"
|
#include "IXSocketConnect.h"
|
||||||
#include "IXNetSystem.h"
|
#include "IXNetSystem.h"
|
||||||
|
#include "IXSelectInterrupt.h"
|
||||||
|
#include "IXSelectInterruptFactory.h"
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
@ -28,7 +30,8 @@ namespace ix
|
|||||||
constexpr size_t Socket::kChunkSize;
|
constexpr size_t Socket::kChunkSize;
|
||||||
|
|
||||||
Socket::Socket(int fd) :
|
Socket::Socket(int fd) :
|
||||||
_sockfd(fd)
|
_sockfd(fd),
|
||||||
|
_selectInterrupt(createSelectInterrupt())
|
||||||
{
|
{
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
@ -57,11 +60,11 @@ namespace ix
|
|||||||
FD_ZERO(&rfds);
|
FD_ZERO(&rfds);
|
||||||
FD_SET(_sockfd, &rfds);
|
FD_SET(_sockfd, &rfds);
|
||||||
|
|
||||||
// File descriptor at index 0 in _fildes is the read end of the pipe
|
// File descriptor used to interrupt select when needed
|
||||||
int eventfd = _eventfd.getFd();
|
int interruptFd = _selectInterrupt->getFd();
|
||||||
if (eventfd != -1)
|
if (interruptFd != -1)
|
||||||
{
|
{
|
||||||
FD_SET(eventfd, &rfds);
|
FD_SET(interruptFd, &rfds);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct timeval timeout;
|
struct timeval timeout;
|
||||||
@ -70,7 +73,7 @@ namespace ix
|
|||||||
|
|
||||||
// Compute the highest fd.
|
// Compute the highest fd.
|
||||||
int sockfd = _sockfd;
|
int sockfd = _sockfd;
|
||||||
int nfds = (std::max)(sockfd, eventfd);
|
int nfds = (std::max)(sockfd, interruptFd);
|
||||||
|
|
||||||
int ret = ::select(nfds + 1, &rfds, nullptr, nullptr,
|
int ret = ::select(nfds + 1, &rfds, nullptr, nullptr,
|
||||||
(timeoutSecs < 0) ? nullptr : &timeout);
|
(timeoutSecs < 0) ? nullptr : &timeout);
|
||||||
@ -84,9 +87,9 @@ namespace ix
|
|||||||
{
|
{
|
||||||
pollResult = PollResultType_Timeout;
|
pollResult = PollResultType_Timeout;
|
||||||
}
|
}
|
||||||
else if (eventfd != -1 && FD_ISSET(eventfd, &rfds))
|
else if (interruptFd != -1 && FD_ISSET(interruptFd, &rfds))
|
||||||
{
|
{
|
||||||
uint64_t value = _eventfd.read();
|
uint64_t value = _selectInterrupt->read();
|
||||||
|
|
||||||
if (value == kSendRequest)
|
if (value == kSendRequest)
|
||||||
{
|
{
|
||||||
@ -104,7 +107,7 @@ namespace ix
|
|||||||
// Wake up from poll/select by writing to the pipe which is watched by select
|
// Wake up from poll/select by writing to the pipe which is watched by select
|
||||||
bool Socket::wakeUpFromPoll(uint8_t wakeUpCode)
|
bool Socket::wakeUpFromPoll(uint8_t wakeUpCode)
|
||||||
{
|
{
|
||||||
return _eventfd.notify(wakeUpCode);
|
return _selectInterrupt->notify(wakeUpCode);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Socket::connect(const std::string& host,
|
bool Socket::connect(const std::string& host,
|
||||||
@ -114,7 +117,7 @@ namespace ix
|
|||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> lock(_socketMutex);
|
std::lock_guard<std::mutex> lock(_socketMutex);
|
||||||
|
|
||||||
if (!_eventfd.clear()) return false;
|
if (!_selectInterrupt->clear()) return false;
|
||||||
|
|
||||||
_sockfd = SocketConnect::connect(host, port, errMsg, isCancellationRequested);
|
_sockfd = SocketConnect::connect(host, port, errMsg, isCancellationRequested);
|
||||||
return _sockfd != -1;
|
return _sockfd != -1;
|
||||||
@ -173,24 +176,9 @@ namespace ix
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Socket::init()
|
bool Socket::init(std::string& errorMsg)
|
||||||
{
|
{
|
||||||
#ifdef _WIN32
|
return _selectInterrupt->init(errorMsg);
|
||||||
INT rc;
|
|
||||||
WSADATA wsaData;
|
|
||||||
|
|
||||||
rc = WSAStartup(MAKEWORD(2, 2), &wsaData);
|
|
||||||
return rc != 0;
|
|
||||||
#else
|
|
||||||
return true;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
void Socket::cleanup()
|
|
||||||
{
|
|
||||||
#ifdef _WIN32
|
|
||||||
WSACleanup();
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Socket::writeBytes(const std::string& str,
|
bool Socket::writeBytes(const std::string& str,
|
||||||
|
@ -23,6 +23,8 @@ typedef SSIZE_T ssize_t;
|
|||||||
|
|
||||||
namespace ix
|
namespace ix
|
||||||
{
|
{
|
||||||
|
class SelectInterrupt;
|
||||||
|
|
||||||
enum PollResultType
|
enum PollResultType
|
||||||
{
|
{
|
||||||
PollResultType_ReadyForRead = 0,
|
PollResultType_ReadyForRead = 0,
|
||||||
@ -38,6 +40,7 @@ namespace ix
|
|||||||
|
|
||||||
Socket(int fd = -1);
|
Socket(int fd = -1);
|
||||||
virtual ~Socket();
|
virtual ~Socket();
|
||||||
|
bool init(std::string& errorMsg);
|
||||||
|
|
||||||
void configure();
|
void configure();
|
||||||
|
|
||||||
@ -72,8 +75,6 @@ namespace ix
|
|||||||
const CancellationRequest& isCancellationRequested);
|
const CancellationRequest& isCancellationRequested);
|
||||||
|
|
||||||
static int getErrno();
|
static int getErrno();
|
||||||
static bool init(); // Required on Windows to initialize WinSocket
|
|
||||||
static void cleanup(); // Required on Windows to cleanup WinSocket
|
|
||||||
|
|
||||||
// Used as special codes for pipe communication
|
// Used as special codes for pipe communication
|
||||||
static const uint64_t kSendRequest;
|
static const uint64_t kSendRequest;
|
||||||
@ -93,6 +94,6 @@ namespace ix
|
|||||||
std::vector<uint8_t> _readBuffer;
|
std::vector<uint8_t> _readBuffer;
|
||||||
static constexpr size_t kChunkSize = 1 << 15;
|
static constexpr size_t kChunkSize = 1 << 15;
|
||||||
|
|
||||||
EventFd _eventfd;
|
std::shared_ptr<SelectInterrupt> _selectInterrupt;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -20,23 +20,45 @@ namespace ix
|
|||||||
std::string& errorMsg)
|
std::string& errorMsg)
|
||||||
{
|
{
|
||||||
errorMsg.clear();
|
errorMsg.clear();
|
||||||
|
std::shared_ptr<Socket> socket;
|
||||||
|
|
||||||
if (!tls)
|
if (!tls)
|
||||||
{
|
{
|
||||||
return std::make_shared<Socket>();
|
socket = std::make_shared<Socket>();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
#ifdef IXWEBSOCKET_USE_TLS
|
#ifdef IXWEBSOCKET_USE_TLS
|
||||||
# ifdef __APPLE__
|
# ifdef __APPLE__
|
||||||
return std::make_shared<SocketAppleSSL>();
|
socket = std::make_shared<SocketAppleSSL>();
|
||||||
# else
|
# else
|
||||||
return std::make_shared<SocketOpenSSL>();
|
socket = std::make_shared<SocketOpenSSL>();
|
||||||
# endif
|
# endif
|
||||||
#else
|
#else
|
||||||
errorMsg = "TLS support is not enabled on this platform.";
|
errorMsg = "TLS support is not enabled on this platform.";
|
||||||
return nullptr;
|
return nullptr;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!socket->init(errorMsg))
|
||||||
|
{
|
||||||
|
socket.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
return socket;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<Socket> createSocket(int fd,
|
||||||
|
std::string& errorMsg)
|
||||||
|
{
|
||||||
|
errorMsg.clear();
|
||||||
|
|
||||||
|
std::shared_ptr<Socket> socket = std::make_shared<Socket>(fd);
|
||||||
|
if (!socket->init(errorMsg))
|
||||||
|
{
|
||||||
|
socket.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
return socket;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,4 +14,7 @@ namespace ix
|
|||||||
class Socket;
|
class Socket;
|
||||||
std::shared_ptr<Socket> createSocket(bool tls,
|
std::shared_ptr<Socket> createSocket(bool tls,
|
||||||
std::string& errorMsg);
|
std::string& errorMsg);
|
||||||
|
|
||||||
|
std::shared_ptr<Socket> createSocket(int fd,
|
||||||
|
std::string& errorMsg);
|
||||||
}
|
}
|
||||||
|
@ -123,8 +123,13 @@ namespace ix
|
|||||||
// Server
|
// Server
|
||||||
WebSocketInitResult WebSocketTransport::connectToSocket(int fd, int timeoutSecs)
|
WebSocketInitResult WebSocketTransport::connectToSocket(int fd, int timeoutSecs)
|
||||||
{
|
{
|
||||||
_socket.reset();
|
std::string errorMsg;
|
||||||
_socket = std::make_shared<Socket>(fd);
|
_socket = createSocket(fd, errorMsg);
|
||||||
|
|
||||||
|
if (!_socket)
|
||||||
|
{
|
||||||
|
return WebSocketInitResult(false, 0, errorMsg);
|
||||||
|
}
|
||||||
|
|
||||||
WebSocketHandshake webSocketHandshake(_requestInitCancellation,
|
WebSocketHandshake webSocketHandshake(_requestInitCancellation,
|
||||||
_socket,
|
_socket,
|
||||||
|
@ -5,17 +5,10 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
#include <ixwebsocket/IXSocketFactory.h>
|
||||||
#include <ixwebsocket/IXSocket.h>
|
#include <ixwebsocket/IXSocket.h>
|
||||||
#include <ixwebsocket/IXCancellationRequest.h>
|
#include <ixwebsocket/IXCancellationRequest.h>
|
||||||
|
|
||||||
#if defined(__APPLE__) or defined(__linux__)
|
|
||||||
# ifdef __APPLE__
|
|
||||||
# include <ixwebsocket/IXSocketAppleSSL.h>
|
|
||||||
# else
|
|
||||||
# include <ixwebsocket/IXSocketOpenSSL.h>
|
|
||||||
# endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "IXTest.h"
|
#include "IXTest.h"
|
||||||
#include "catch.hpp"
|
#include "catch.hpp"
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
@ -63,7 +56,9 @@ TEST_CASE("socket", "[socket]")
|
|||||||
{
|
{
|
||||||
SECTION("Connect to google HTTP server. Send GET request without header. Should return 200")
|
SECTION("Connect to google HTTP server. Send GET request without header. Should return 200")
|
||||||
{
|
{
|
||||||
std::shared_ptr<Socket> socket(new Socket);
|
std::string errMsg;
|
||||||
|
bool tls = false;
|
||||||
|
std::shared_ptr<Socket> socket = createSocket(tls, errMsg);
|
||||||
std::string host("www.google.com");
|
std::string host("www.google.com");
|
||||||
int port = 80;
|
int port = 80;
|
||||||
|
|
||||||
@ -82,11 +77,9 @@ TEST_CASE("socket", "[socket]")
|
|||||||
#if defined(__APPLE__) or defined(__linux__)
|
#if defined(__APPLE__) or defined(__linux__)
|
||||||
SECTION("Connect to google HTTPS server. Send GET request without header. Should return 200")
|
SECTION("Connect to google HTTPS server. Send GET request without header. Should return 200")
|
||||||
{
|
{
|
||||||
# ifdef __APPLE__
|
std::string errMsg;
|
||||||
std::shared_ptr<Socket> socket = std::make_shared<SocketAppleSSL>();
|
bool tls = true;
|
||||||
# else
|
std::shared_ptr<Socket> socket = createSocket(tls, errMsg);
|
||||||
std::shared_ptr<Socket> socket = std::make_shared<SocketOpenSSL>();
|
|
||||||
# endif
|
|
||||||
std::string host("www.google.com");
|
std::string host("www.google.com");
|
||||||
int port = 443;
|
int port = 443;
|
||||||
std::string request("GET / HTTP/1.1\r\n\r\n");
|
std::string request("GET / HTTP/1.1\r\n\r\n");
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
#include <ixwebsocket/IXSocket.h>
|
#include <ixwebsocket/IXSocket.h>
|
||||||
#include <ixwebsocket/IXWebSocket.h>
|
#include <ixwebsocket/IXWebSocket.h>
|
||||||
#include <ixwebsocket/IXWebSocketServer.h>
|
#include <ixwebsocket/IXWebSocketServer.h>
|
||||||
|
#include <ixwebsocket/IXSocketFactory.h>
|
||||||
|
|
||||||
#include "IXTest.h"
|
#include "IXTest.h"
|
||||||
|
|
||||||
@ -79,17 +80,18 @@ TEST_CASE("Websocket_server", "[websocket_server]")
|
|||||||
ix::WebSocketServer server(port);
|
ix::WebSocketServer server(port);
|
||||||
REQUIRE(startServer(server));
|
REQUIRE(startServer(server));
|
||||||
|
|
||||||
Socket socket;
|
|
||||||
std::string host("localhost");
|
|
||||||
std::string errMsg;
|
std::string errMsg;
|
||||||
|
bool tls = false;
|
||||||
|
std::shared_ptr<Socket> socket = createSocket(tls, errMsg);
|
||||||
|
std::string host("localhost");
|
||||||
auto isCancellationRequested = []() -> bool
|
auto isCancellationRequested = []() -> bool
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
bool success = socket.connect(host, port, errMsg, isCancellationRequested);
|
bool success = socket->connect(host, port, errMsg, isCancellationRequested);
|
||||||
REQUIRE(success);
|
REQUIRE(success);
|
||||||
|
|
||||||
auto lineResult = socket.readLine(isCancellationRequested);
|
auto lineResult = socket->readLine(isCancellationRequested);
|
||||||
auto lineValid = lineResult.first;
|
auto lineValid = lineResult.first;
|
||||||
auto line = lineResult.second;
|
auto line = lineResult.second;
|
||||||
|
|
||||||
@ -111,20 +113,21 @@ TEST_CASE("Websocket_server", "[websocket_server]")
|
|||||||
ix::WebSocketServer server(port);
|
ix::WebSocketServer server(port);
|
||||||
REQUIRE(startServer(server));
|
REQUIRE(startServer(server));
|
||||||
|
|
||||||
Socket socket;
|
|
||||||
std::string host("localhost");
|
|
||||||
std::string errMsg;
|
std::string errMsg;
|
||||||
|
bool tls = false;
|
||||||
|
std::shared_ptr<Socket> socket = createSocket(tls, errMsg);
|
||||||
|
std::string host("localhost");
|
||||||
auto isCancellationRequested = []() -> bool
|
auto isCancellationRequested = []() -> bool
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
bool success = socket.connect(host, port, errMsg, isCancellationRequested);
|
bool success = socket->connect(host, port, errMsg, isCancellationRequested);
|
||||||
REQUIRE(success);
|
REQUIRE(success);
|
||||||
|
|
||||||
Logger() << "writeBytes";
|
Logger() << "writeBytes";
|
||||||
socket.writeBytes("GET /\r\n", isCancellationRequested);
|
socket->writeBytes("GET /\r\n", isCancellationRequested);
|
||||||
|
|
||||||
auto lineResult = socket.readLine(isCancellationRequested);
|
auto lineResult = socket->readLine(isCancellationRequested);
|
||||||
auto lineValid = lineResult.first;
|
auto lineValid = lineResult.first;
|
||||||
auto line = lineResult.second;
|
auto line = lineResult.second;
|
||||||
|
|
||||||
@ -146,24 +149,25 @@ TEST_CASE("Websocket_server", "[websocket_server]")
|
|||||||
ix::WebSocketServer server(port);
|
ix::WebSocketServer server(port);
|
||||||
REQUIRE(startServer(server));
|
REQUIRE(startServer(server));
|
||||||
|
|
||||||
Socket socket;
|
|
||||||
std::string host("localhost");
|
|
||||||
std::string errMsg;
|
std::string errMsg;
|
||||||
|
bool tls = false;
|
||||||
|
std::shared_ptr<Socket> socket = createSocket(tls, errMsg);
|
||||||
|
std::string host("localhost");
|
||||||
auto isCancellationRequested = []() -> bool
|
auto isCancellationRequested = []() -> bool
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
bool success = socket.connect(host, port, errMsg, isCancellationRequested);
|
bool success = socket->connect(host, port, errMsg, isCancellationRequested);
|
||||||
REQUIRE(success);
|
REQUIRE(success);
|
||||||
|
|
||||||
socket.writeBytes("GET / HTTP/1.1\r\n"
|
socket->writeBytes("GET / HTTP/1.1\r\n"
|
||||||
"Upgrade: websocket\r\n"
|
"Upgrade: websocket\r\n"
|
||||||
"Sec-WebSocket-Version: 13\r\n"
|
"Sec-WebSocket-Version: 13\r\n"
|
||||||
"Sec-WebSocket-Key: foobar\r\n"
|
"Sec-WebSocket-Key: foobar\r\n"
|
||||||
"\r\n",
|
"\r\n",
|
||||||
isCancellationRequested);
|
isCancellationRequested);
|
||||||
|
|
||||||
auto lineResult = socket.readLine(isCancellationRequested);
|
auto lineResult = socket->readLine(isCancellationRequested);
|
||||||
auto lineValid = lineResult.first;
|
auto lineValid = lineResult.first;
|
||||||
auto line = lineResult.second;
|
auto line = lineResult.second;
|
||||||
|
|
||||||
|
@ -78,7 +78,7 @@ shutil.copy(os.path.join(
|
|||||||
'bin',
|
'bin',
|
||||||
'zlib.dll'), '.')
|
'zlib.dll'), '.')
|
||||||
|
|
||||||
lldb = "lldb --batch -o 'run' -k 'thread backtrace all' -k 'quit 1'"
|
# lldb = "lldb --batch -o 'run' -k 'thread backtrace all' -k 'quit 1'"
|
||||||
lldb = "" # Disabled for now
|
lldb = "" # Disabled for now
|
||||||
testCommand = '{} {} {}'.format(lldb, testBinary, os.getenv('TEST', ''))
|
testCommand = '{} {} {}'.format(lldb, testBinary, os.getenv('TEST', ''))
|
||||||
ret = os.system(testCommand)
|
ret = os.system(testCommand)
|
||||||
|
@ -11,10 +11,6 @@
|
|||||||
|
|
||||||
int main(int argc, char* argv[])
|
int main(int argc, char* argv[])
|
||||||
{
|
{
|
||||||
ix::Socket::init(); // for Windows
|
|
||||||
|
|
||||||
int result = Catch::Session().run(argc, argv);
|
int result = Catch::Session().run(argc, argv);
|
||||||
|
|
||||||
ix::Socket::cleanup(); // for Windows
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -92,12 +92,9 @@ int main(int argc, char** argv)
|
|||||||
|
|
||||||
CLI11_PARSE(app, argc, argv);
|
CLI11_PARSE(app, argc, argv);
|
||||||
|
|
||||||
ix::Socket::init();
|
|
||||||
|
|
||||||
// pid file handling
|
|
||||||
|
|
||||||
if (app.got_subcommand("transfer"))
|
if (app.got_subcommand("transfer"))
|
||||||
{
|
{
|
||||||
|
// pid file handling
|
||||||
if (!pidfile.empty())
|
if (!pidfile.empty())
|
||||||
{
|
{
|
||||||
unlink(pidfile.c_str());
|
unlink(pidfile.c_str());
|
||||||
|
@ -153,7 +153,6 @@ namespace ix
|
|||||||
|
|
||||||
int ws_connect_main(const std::string& url)
|
int ws_connect_main(const std::string& url)
|
||||||
{
|
{
|
||||||
Socket::init();
|
|
||||||
interactiveMain(url);
|
interactiveMain(url);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -254,7 +254,6 @@ namespace ix
|
|||||||
int ws_receive_main(const std::string& url,
|
int ws_receive_main(const std::string& url,
|
||||||
bool enablePerMessageDeflate)
|
bool enablePerMessageDeflate)
|
||||||
{
|
{
|
||||||
Socket::init();
|
|
||||||
wsReceive(url, enablePerMessageDeflate);
|
wsReceive(url, enablePerMessageDeflate);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -298,7 +298,6 @@ namespace ix
|
|||||||
bool throttle = false;
|
bool throttle = false;
|
||||||
bool enablePerMessageDeflate = false;
|
bool enablePerMessageDeflate = false;
|
||||||
|
|
||||||
Socket::init();
|
|
||||||
wsSend(url, path, enablePerMessageDeflate, throttle);
|
wsSend(url, path, enablePerMessageDeflate, throttle);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user