summaryrefslogtreecommitdiffhomepage
path: root/plugins/fcgi/socket.cpp
blob: 0a2a381717d43cc136d7f37c1ebad96a0b179339 (plain)
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());
 }
}