Imported Upstream version 1.51.0
[platform/upstream/boost.git] / libs / asio / example / fork / process_per_connection.cpp
1 //
2 // process_per_connection.cpp
3 // ~~~~~~~~~~~~~~~~~~~~~~~~~~
4 //
5 // Copyright (c) 2003-2012 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 }