1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
|
#include "socket.h"
#include <filesystem>
#include <iostream>
namespace fs = std::filesystem;
using namespace std::string_literals;
std::mutex& Socket::getMutex()
{
return m_mutex;
}
FCGI_ID& Socket::fcgi_id()
{
return m_fcgi_id;
}
SocketFactory::SocketFactory()
: m_io_context()
{
}
std::shared_ptr<Socket> SocketFactory::create(const std::string& app_addr)
{
size_t pos { app_addr.find(':') };
if (pos != app_addr.npos) { // tcp socket: host:port
return std::make_shared<TCPSocket>(app_addr.substr(0, pos), app_addr.substr(pos + 1), m_io_context);
} else if (fs::is_socket(fs::path{app_addr})) { // Unix domain socket
// TODO
std::cerr << "FCGI Error: Unix domain sockets not yet implemented." << std::endl;
} else if (fs::is_regular_file(fs::path{app_addr})) { // Executable to start
// TODO
std::cerr << "FCGI Error: Executable FCGI not yet implemented." << std::endl;
} else {
std::cerr << "FCGI Error: Invalid app_addr type." << std::endl;
}
return {};
}
TCPSocket::TCPSocket(const std::string& host, const std::string& port, boost::asio::io_context& io_context)
: m_io_context(io_context)
, m_host(host)
, m_port(port)
, m_socket(io_context)
{
}
TCPSocket::~TCPSocket()
{
}
void TCPSocket::open()
{
boost::asio::ip::tcp::resolver resolver(m_io_context);
auto endpoints{resolver.resolve(m_host, m_port)};
try {
boost::asio::connect(m_socket, endpoints);
} catch(const std::exception& ex) {
std::cerr << "FCGI Error: Error on connecting to " << m_host << ":" << m_port << ": " << ex.what() << std::endl;
return;
}
boost::asio::socket_base::keep_alive keepAlive(true);
m_socket.set_option(keepAlive);
struct timeval tv;
tv.tv_sec = 0; // infinite
tv.tv_usec = 0;
if (setsockopt(m_socket.native_handle(), SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)))
std::cerr << "FCGI Error: SO_RCVTIMEO" << std::endl;
if (setsockopt(m_socket.native_handle(), SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv)))
std::cerr << "FCGI Error: SO_SNDTIMEO" << std::endl;
int val{1};
if (setsockopt(m_socket.native_handle(), SOL_SOCKET, SO_KEEPALIVE, &val, sizeof(val)))
std::cerr << "FCGI Error: SO_KEEPALIVE" << std::endl;
}
bool TCPSocket::is_open()
{
return m_socket.is_open();
}
void TCPSocket::close()
{
m_socket.close();
}
size_t TCPSocket::write(const std::vector<char>& data)
{
try {
return m_socket.write_some(boost::asio::buffer(data));
} catch (const boost::system::system_error& ex) {
if (ex.code() == boost::asio::error::eof) {
throw fcgi_eof_error("EOF on write");
} else
throw std::runtime_error("FCGI Error: Unknown boost asio exception on write: "s + ex.what());
} catch (const std::exception& ex) {
throw std::runtime_error("FCGI Error: Unknown exception on write: "s + ex.what());
}
}
size_t TCPSocket::read(std::vector<char>& data)
{
try {
return m_socket.read_some(boost::asio::buffer(data));
} catch (const boost::system::system_error& ex) {
if (ex.code() == boost::asio::error::eof) {
throw fcgi_eof_error("EOF on read");
} else
throw std::runtime_error("FCGI Error: Unknown boost asio exception on read: "s + ex.what());
} catch (const std::exception& ex) {
throw std::runtime_error("FCGI Error: Unknown exception on read: "s + ex.what());
}
}
|