~singpolyma/biboumi

ref: 6804f315464b592eeece8c8837b21c9cd1db074d biboumi/src/main.cpp -rw-r--r-- 3.6 KiB
6804f315 — Florent Le Coz Set sigaction.sa_flags to 0 10 years ago
                                                                                
ccebe901 Florent Le Coz
f0d9273d Florent Le Coz
3afb63a6 Florent Le Coz
bf7b05ef Florent Le Coz
f0d9273d Florent Le Coz
bf7b05ef Florent Le Coz
3afb63a6 Florent Le Coz
8fd27466 Florent Le Coz
3afb63a6 Florent Le Coz
bf7b05ef Florent Le Coz
b60cbda4 Florent Le Coz
3afb63a6 Florent Le Coz
8fd27466 Florent Le Coz
f0d9273d Florent Le Coz
64c1b28c Florent Le Coz
f0d9273d Florent Le Coz
b60cbda4 Florent Le Coz
f0d9273d Florent Le Coz
b60cbda4 Florent Le Coz
f0d9273d Florent Le Coz
b60cbda4 Florent Le Coz
f0d9273d Florent Le Coz
b60cbda4 Florent Le Coz
df59a091 Florent Le Coz
ccebe901 Florent Le Coz
b60cbda4 Florent Le Coz
f0d9273d Florent Le Coz
ccebe901 Florent Le Coz
3afb63a6 Florent Le Coz
8fd27466 Florent Le Coz
3afb63a6 Florent Le Coz
8fd27466 Florent Le Coz
6804f315 Florent Le Coz
8fd27466 Florent Le Coz
3afb63a6 Florent Le Coz
e8e592d1 Florent Le Coz
3afb63a6 Florent Le Coz
8fd27466 Florent Le Coz
3afb63a6 Florent Le Coz
64c1b28c Florent Le Coz
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
122
123
124
125
126
127
#include <xmpp/xmpp_component.hpp>
#include <network/poller.hpp>
#include <config/config.hpp>
#include <logger/logger.hpp>

#include <iostream>
#include <memory>
#include <atomic>

#include <signal.h>

// A flag set by the SIGINT signal handler.
static volatile std::atomic<bool> stop(false);
// Flag set by the SIGUSR1/2 signal handler.
static volatile std::atomic<bool> reload(false);
// A flag indicating that we are wanting to exit the process. i.e: if this
// flag is set and all connections are closed, we can exit properly.
static bool exiting = false;

/**
 * Provide an helpful message to help the user write a minimal working
 * configuration file.
 */
int config_help(const std::string& missing_option)
{
  if (!missing_option.empty())
    std::cerr << "Error: empty value for option " << missing_option << "." << std::endl;
  std::cerr <<
    "Please provide a configuration file filled like this:\n\n"
    "hostname=irc.example.com\npassword=S3CR3T"
            << std::endl;
  return 1;
}

static void sigint_handler(int, siginfo_t*, void*)
{
  stop = true;
}

static void sigusr_handler(int, siginfo_t*, void*)
{
  reload = true;
}

int main(int ac, char** av)
{
  if (ac > 1)
    Config::filename = av[1];
  Config::file_must_exist = true;
  std::cerr << "Using configuration file: " << Config::filename << std::endl;

  std::string password;
  try { // The file must exist
    password = Config::get("password", "");
  }
  catch (const std::ios::failure& e) {
    return config_help("");
  }
  const std::string hostname = Config::get("hostname", "");
  if (password.empty())
    return config_help("password");
  if (hostname.empty())
    return config_help("hostname");
  std::shared_ptr<XmppComponent> xmpp_component =
    std::make_shared<XmppComponent>(hostname, password);

  Poller p;
  p.add_socket_handler(xmpp_component);
  if (!xmpp_component->start())
  {
    log_info("Exiting");
    return -1;
  }

  // Install the signals used to exit the process cleanly, or reload the
  // config
  sigset_t mask;
  sigemptyset(&mask);
  struct sigaction on_sigint;
  on_sigint.sa_sigaction = &sigint_handler;
  on_sigint.sa_mask = mask;
  // we want to catch that signal only once.
  // Sending SIGINT again will "force" an exit
  on_sigint.sa_flags = SA_RESETHAND;
  sigaction(SIGINT, &on_sigint, nullptr);
  sigaction(SIGTERM, &on_sigint, nullptr);

  // Install a signal to reload the config on SIGUSR1/2
  struct sigaction on_sigusr;
  on_sigusr.sa_sigaction = &sigusr_handler;
  on_sigusr.sa_mask = mask;
  on_sigusr.sa_flags = 0;
  sigaction(SIGUSR1, &on_sigusr, nullptr);
  sigaction(SIGUSR2, &on_sigusr, nullptr);

  const std::chrono::milliseconds timeout(-1);
  while (p.poll(timeout) != -1 || !exiting)
  {
    // Check for empty irc_clients (not connected, or with no joined
    // channel) and remove them
    xmpp_component->clean();
    if (stop)
    {
      log_info("Signal received, exiting...");
      exiting = true;
      stop = false;
      xmpp_component->shutdown();
    }
    if (reload)
    {
      // Closing the config will just force it to be reopened the next time
      // a configuration option is needed
      log_info("Signal received, reloading the config...");
      Config::close();
      // Destroy the logger instance, to be recreated the next time a log
      // line needs to be written
      Logger::instance().reset();
      reload = false;
    }
    // If the only existing connection is the one to the XMPP component:
    // close the XMPP stream.
    if (exiting && p.size() == 1 && xmpp_component->is_document_open())
      xmpp_component->close_document();
  }
  log_info("All connection cleanely closed, have a nice day.");
  return 0;
}