]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/libs/asio/example/cpp03/fork/process_per_connection.cpp
add subtree-ish sources for 12.0.3
[ceph.git] / ceph / src / boost / libs / asio / example / cpp03 / fork / process_per_connection.cpp
1 //
2 // process_per_connection.cpp
3 // ~~~~~~~~~~~~~~~~~~~~~~~~~~
4 //
5 // Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com)
6 //
7 // Distributed under the Boost Software License, Version 1.0. (See accompanying
8 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
9 //
10
11 #include <boost/asio/io_service.hpp>
12 #include <boost/asio/ip/tcp.hpp>
13 #include <boost/asio/signal_set.hpp>
14 #include <boost/asio/write.hpp>
15 #include <boost/array.hpp>
16 #include <boost/bind.hpp>
17 #include <cstdlib>
18 #include <iostream>
19 #include <sys/types.h>
20 #include <sys/wait.h>
21 #include <unistd.h>
22
23 using boost::asio::ip::tcp;
24
25 class server
26 {
27 public:
28 server(boost::asio::io_service& io_service, unsigned short port)
29 : io_service_(io_service),
30 signal_(io_service, SIGCHLD),
31 acceptor_(io_service, tcp::endpoint(tcp::v4(), port)),
32 socket_(io_service)
33 {
34 start_signal_wait();
35 start_accept();
36 }
37
38 private:
39 void start_signal_wait()
40 {
41 signal_.async_wait(boost::bind(&server::handle_signal_wait, this));
42 }
43
44 void handle_signal_wait()
45 {
46 // Only the parent process should check for this signal. We can determine
47 // whether we are in the parent by checking if the acceptor is still open.
48 if (acceptor_.is_open())
49 {
50 // Reap completed child processes so that we don't end up with zombies.
51 int status = 0;
52 while (waitpid(-1, &status, WNOHANG) > 0) {}
53
54 start_signal_wait();
55 }
56 }
57
58 void start_accept()
59 {
60 acceptor_.async_accept(socket_,
61 boost::bind(&server::handle_accept, this, _1));
62 }
63
64 void handle_accept(const boost::system::error_code& ec)
65 {
66 if (!ec)
67 {
68 // Inform the io_service that we are about to fork. The io_service cleans
69 // up any internal resources, such as threads, that may interfere with
70 // forking.
71 io_service_.notify_fork(boost::asio::io_service::fork_prepare);
72
73 if (fork() == 0)
74 {
75 // Inform the io_service that the fork is finished and that this is the
76 // child process. The io_service uses this opportunity to create any
77 // internal file descriptors that must be private to the new process.
78 io_service_.notify_fork(boost::asio::io_service::fork_child);
79
80 // The child won't be accepting new connections, so we can close the
81 // acceptor. It remains open in the parent.
82 acceptor_.close();
83
84 // The child process is not interested in processing the SIGCHLD signal.
85 signal_.cancel();
86
87 start_read();
88 }
89 else
90 {
91 // Inform the io_service that the fork is finished (or failed) and that
92 // this is the parent process. The io_service uses this opportunity to
93 // recreate any internal resources that were cleaned up during
94 // preparation for the fork.
95 io_service_.notify_fork(boost::asio::io_service::fork_parent);
96
97 socket_.close();
98 start_accept();
99 }
100 }
101 else
102 {
103 std::cerr << "Accept error: " << ec.message() << std::endl;
104 start_accept();
105 }
106 }
107
108 void start_read()
109 {
110 socket_.async_read_some(boost::asio::buffer(data_),
111 boost::bind(&server::handle_read, this, _1, _2));
112 }
113
114 void handle_read(const boost::system::error_code& ec, std::size_t length)
115 {
116 if (!ec)
117 start_write(length);
118 }
119
120 void start_write(std::size_t length)
121 {
122 boost::asio::async_write(socket_, boost::asio::buffer(data_, length),
123 boost::bind(&server::handle_write, this, _1));
124 }
125
126 void handle_write(const boost::system::error_code& ec)
127 {
128 if (!ec)
129 start_read();
130 }
131
132 boost::asio::io_service& io_service_;
133 boost::asio::signal_set signal_;
134 tcp::acceptor acceptor_;
135 tcp::socket socket_;
136 boost::array<char, 1024> data_;
137 };
138
139 int main(int argc, char* argv[])
140 {
141 try
142 {
143 if (argc != 2)
144 {
145 std::cerr << "Usage: process_per_connection <port>\n";
146 return 1;
147 }
148
149 boost::asio::io_service io_service;
150
151 using namespace std; // For atoi.
152 server s(io_service, atoi(argv[1]));
153
154 io_service.run();
155 }
156 catch (std::exception& e)
157 {
158 std::cerr << "Exception: " << e.what() << std::endl;
159 }
160 }