#include <boost/asio/io_context.hpp>
#include <boost/asio/ip/udp.hpp>
#include <boost/asio/signal_set.hpp>
#include <array>
#include <ctime>
#include <iostream>
#include <syslog.h>
#include <unistd.h>
using boost::asio::ip::udp;
class udp_daytime_server
{
public:
udp_daytime_server(boost::asio::io_context& io_context)
: socket_(io_context, {udp::v4(), 13})
{
receive();
}
private:
void receive()
{
socket_.async_receive_from(
boost::asio::buffer(recv_buffer_), remote_endpoint_,
[this](boost::system::error_code ec, std::size_t )
{
if (!ec)
{
using namespace std; time_t now = time(0);
std::string message = ctime(&now);
boost::system::error_code ignored_ec;
socket_.send_to(boost::asio::buffer(message),
remote_endpoint_, 0, ignored_ec);
}
receive();
});
}
udp::socket socket_;
udp::endpoint remote_endpoint_;
std::array<char, 1> recv_buffer_;
};
int main()
{
try
{
boost::asio::io_context io_context;
udp_daytime_server server(io_context);
boost::asio::signal_set signals(io_context, SIGINT, SIGTERM);
signals.async_wait(
[&](boost::system::error_code , int )
{
io_context.stop();
});
io_context.notify_fork(boost::asio::io_context::fork_prepare);
if (pid_t pid = fork())
{
if (pid > 0)
{
exit(0);
}
else
{
syslog(LOG_ERR | LOG_USER, "First fork failed: %m");
return 1;
}
}
setsid();
chdir("/");
umask(0);
if (pid_t pid = fork())
{
if (pid > 0)
{
exit(0);
}
else
{
syslog(LOG_ERR | LOG_USER, "Second fork failed: %m");
return 1;
}
}
close(0);
close(1);
close(2);
if (open("/dev/null", O_RDONLY) < 0)
{
syslog(LOG_ERR | LOG_USER, "Unable to open /dev/null: %m");
return 1;
}
const char* output = "/tmp/asio.daemon.out";
const int flags = O_WRONLY | O_CREAT | O_APPEND;
const mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
if (open(output, flags, mode) < 0)
{
syslog(LOG_ERR | LOG_USER, "Unable to open output file %s: %m", output);
return 1;
}
if (dup(1) < 0)
{
syslog(LOG_ERR | LOG_USER, "Unable to dup output descriptor: %m");
return 1;
}
io_context.notify_fork(boost::asio::io_context::fork_child);
syslog(LOG_INFO | LOG_USER, "Daemon started");
io_context.run();
syslog(LOG_INFO | LOG_USER, "Daemon stopped");
}
catch (std::exception& e)
{
syslog(LOG_ERR | LOG_USER, "Exception: %s", e.what());
std::cerr << "Exception: " << e.what() << std::endl;
}
}