src/​examples/​cpp03/​fork/​daemon.​cppsrc/​examples/​cpp11/​fork/​daemon.​cpp
1 /​/​1 /​/​
2 /​/​·​daemon.​cpp2 /​/​·​daemon.​cpp
3 /​/​·​~~~~~~~~~~3 /​/​·​~~~~~~~~~~
4 /​/​4 /​/​
5 /​/​·​Copyright·​(c)​·​2003-​2023·​Christopher·​M.​·​Kohlhoff·​(chris·​at·​kohlhoff·​dot·​com)​5 /​/​·​Copyright·​(c)​·​2003-​2023·​Christopher·​M.​·​Kohlhoff·​(chris·​at·​kohlhoff·​dot·​com)​
6 /​/​6 /​/​
7 /​/​·​Distributed·​under·​the·​Boost·​Software·​License,​·​Version·​1.​0.​·​(See·​accompanying7 /​/​·​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)​8 /​/​·​file·​LICENSE_1_0.​txt·​or·​copy·​at·​http:​/​/​www.​boost.​org/​LICENSE_1_0.​txt)​
9 /​/​9 /​/​
10 10
11 #include·​<asio/​io_context.​hpp>11 #include·​<asio/​io_context.​hpp>
12 #include·​<asio/​ip/​udp.​hpp>12 #include·​<asio/​ip/​udp.​hpp>
13 #include·​<asio/​signal_set.​hpp>13 #include·​<asio/​signal_set.​hpp>
14 #include·​<boost/​array.​hpp>14 #include·​<array>
15 #include·<boost/​bind/​bind.​hpp>
16 #include·​<ctime>15 #include·​<ctime>
17 #include·​<iostream>16 #include·​<iostream>
18 #include·​<syslog.​h>17 #include·​<syslog.​h>
19 #include·​<unistd.​h>18 #include·​<unistd.​h>
20 19
21 using·​asio:​:​ip:​:​udp;​20 using·​asio:​:​ip:​:​udp;​
22 21
23 class·​udp_daytime_server22 class·​udp_daytime_server
24 {23 {
25 public:​24 public:​
26 ··​udp_daytime_server(as​io:​:​io_context&·​io_context)​25 ··​udp_daytime_server(as​io:​:​io_context&·​io_context)​
27 ····​:​·​local_socket(io_context,​·udp:​:​endpoint(udp:​:​v4()​,​·​13)​)​26 ····​:​·​local_socket(io_context,​·{udp:​:​v4()​,​·​13})​
28 ··​{27 ··​{
29 ····start_receive()​;​28 ····​receive()​;​
30 ··​}29 ··​}
31 30
32 private:​31 private:​
33 ··​void·start_receive()​32 ··​void·​receive()​
34 ··​{33 ··​{
35 ····​local_socket.​async_receive_from(34 ····​local_socket.​async_receive_from(
36 ········​asio:​:​buffer(recv_buffer_)​,​·​remote_connection,​35 ········​asio:​:​buffer(recv_buffer_)​,​·​remote_connection,​
37 ········boost:​:​bind(&udp_daytime_ser​ver:​:​handle_receive,​36 ········[this](std:​:​error_code·ec,​·std:​:​size_t·/​*n*/​)​
38 ··········this,​·boost:​:​placeholders:​:​_1)​)​;​37 ········{
39 ··}38 ··········if·(!ec)​
39 ··········​{
40 ············​using·​namespace·​std;​·​/​/​·​For·​time_t,​·​time·​and·​ctime;​
41 ············​time_t·​now·​=·​time(0)​;​
42 ············​std:​:​string·​message·​=·​ctime(&now)​;​
40 43
41 ··void·handle_receive(const·asio:​:​error_code&·ec)​44 ············std:​:​error_code·​ignored_ec;​
42 ··{45 ············socket_.​send_to(asio:​:​buffer(message)​,​
43 ····​if·(!ec)​46 ················remote_endpoint_,​·0,​·ignored_ec)​;​
44 ····{47 ··········}
45 ······using·namespace·std;​·/​/​·For·time_t,​·time·and·ctime;​
46 ······time_t·now·=·time(0)​;​
47 ······std:​:​string·message·=·ctime(&now)​;​
48 48
49 ······asio:​:​error_code·ignored_ec;​49 ··········receive()​;​
50 ······socket_.​send_to(asio:​:​buffer(message)​,​50 ········})​;​
51 ··········remote_endpoint_,​·0,​·ignored_ec)​;​
52 ····}
53
54 ····start_receive()​;​
55 ··​}51 ··​}
56 52
57 ··​udp:​:​socket·​local_socket;​53 ··​udp:​:​socket·​local_socket;​
58 ··​udp:​:​endpoint·​remote_connection;​54 ··​udp:​:​endpoint·​remote_connection;​
59 ··boost:​:​array<char,​·​1>·​recv_buffer_;​55 ··​std:​:​array<char,​·​1>·​recv_buffer_;​
60 };​56 };​
61 57
62 int·​main()​58 int·​main()​
63 {59 {
64 ··​try60 ··​try
65 ··​{61 ··​{
66 ····​asio:​:​io_context·​io_context;​62 ····​asio:​:​io_context·​io_context;​
67 63
68 ····​/​/​·​Initialise·​the·​server·​before·​becoming·​a·​daemon.​·​If·​the·​process·​is64 ····​/​/​·​Initialise·​the·​server·​before·​becoming·​a·​daemon.​·​If·​the·​process·​is
69 ····​/​/​·​started·​from·​a·​shell,​·​this·​means·​any·​errors·​will·​be·​reported·​back·​to·​the65 ····​/​/​·​started·​from·​a·​shell,​·​this·​means·​any·​errors·​will·​be·​reported·​back·​to·​the
70 ····​/​/​·​user.​66 ····​/​/​·​user.​
71 ····​udp_daytime_server·​server(io_context)​;​67 ····​udp_daytime_server·​server(io_context)​;​
72 68
73 ····​/​/​·​Register·​signal·​handlers·​so·​that·​the·​daemon·​may·​be·​shut·​down.​·​You·​may69 ····​/​/​·​Register·​signal·​handlers·​so·​that·​the·​daemon·​may·​be·​shut·​down.​·​You·​may
74 ····​/​/​·​also·​want·​to·​register·​for·​other·​signals,​·​such·​as·​SIGHUP·​to·​trigger·​a70 ····​/​/​·​also·​want·​to·​register·​for·​other·​signals,​·​such·​as·​SIGHUP·​to·​trigger·​a
75 ····​/​/​·​re-​read·​of·​a·​configuration·​file.​71 ····​/​/​·​re-​read·​of·​a·​configuration·​file.​
76 ····​asio:​:​signal_set·​signals(io_context,​·​SIGINT,​·​SIGTERM)​;​72 ····​asio:​:​signal_set·​signals(io_context,​·​SIGINT,​·​SIGTERM)​;​
77 ····​signals.​async_wait(73 ····​signals.​async_wait(
78 ········boost:​:​bind(&asio:​:​io_context:​:​stop,​·&io_context)​)​;​74 ········[&](std:​:​error_code·/​*ec*/​,​·int·/​*signo*/​)​
75 ········​{
76 ··········​io_context.​stop()​;​
77 ········​})​;​
79 78
80 ····​/​/​·​Inform·​the·​io_context·​that·​we·​are·​about·​to·​become·​a·​daemon.​·​The79 ····​/​/​·​Inform·​the·​io_context·​that·​we·​are·​about·​to·​become·​a·​daemon.​·​The
81 ····​/​/​·​io_context·​cleans·​up·​any·​internal·​resources,​·​such·​as·​threads,​·​that·​may80 ····​/​/​·​io_context·​cleans·​up·​any·​internal·​resources,​·​such·​as·​threads,​·​that·​may
82 ····​/​/​·​interfere·​with·​forking.​81 ····​/​/​·​interfere·​with·​forking.​
83 ····​io_context.​notify_fork(asio:​:​io_context:​:​fork_prepare)​;​82 ····​io_context.​notify_fork(asio:​:​io_context:​:​fork_prepare)​;​
84 83
85 ····​/​/​·​Fork·​the·​process·​and·​have·​the·​parent·​exit.​·​If·​the·​process·​was·​started84 ····​/​/​·​Fork·​the·​process·​and·​have·​the·​parent·​exit.​·​If·​the·​process·​was·​started
86 ····​/​/​·​from·​a·​shell,​·​this·​returns·​control·​to·​the·​user.​·​Forking·​a·​new·​process·​is85 ····​/​/​·​from·​a·​shell,​·​this·​returns·​control·​to·​the·​user.​·​Forking·​a·​new·​process·​is
87 ····​/​/​·​also·​a·​prerequisite·​for·​the·​subsequent·​call·​to·​setsid()​.​86 ····​/​/​·​also·​a·​prerequisite·​for·​the·​subsequent·​call·​to·​setsid()​.​
88 ····​if·​(pid_t·​pid·​=·​fork()​)​87 ····​if·​(pid_t·​pid·​=·​fork()​)​
89 ····​{88 ····​{
90 ······​if·​(pid·​>·​0)​89 ······​if·​(pid·​>·​0)​
91 ······​{90 ······​{
92 ········​/​/​·​We're·​in·​the·​parent·​process·​and·​need·​to·​exit.​91 ········​/​/​·​We're·​in·​the·​parent·​process·​and·​need·​to·​exit.​
93 ········​/​/​92 ········​/​/​
94 ········​/​/​·​When·​the·​exit()​·​function·​is·​used,​·​the·​program·​terminates·​without93 ········​/​/​·​When·​the·​exit()​·​function·​is·​used,​·​the·​program·​terminates·​without
95 ········​/​/​·​invoking·​local·​variables'·​destructors.​·​Only·​global·​variables·​are94 ········​/​/​·​invoking·​local·​variables'·​destructors.​·​Only·​global·​variables·​are
96 ········​/​/​·​destroyed.​·​As·​the·​io_context·​object·​is·​a·​local·​variable,​·​this·​means95 ········​/​/​·​destroyed.​·​As·​the·​io_context·​object·​is·​a·​local·​variable,​·​this·​means
97 ········​/​/​·​we·​do·​not·​have·​to·​call:​96 ········​/​/​·​we·​do·​not·​have·​to·​call:​
98 ········​/​/​97 ········​/​/​
99 ········​/​/​···​io_context.​notify_fork(asio:​:​io_context:​:​fork_parent)​;​98 ········​/​/​···​io_context.​notify_fork(asio:​:​io_context:​:​fork_parent)​;​
100 ········​/​/​99 ········​/​/​
101 ········​/​/​·​However,​·​this·​line·​should·​be·​added·​before·​each·​call·​to·​exit()​·​if100 ········​/​/​·​However,​·​this·​line·​should·​be·​added·​before·​each·​call·​to·​exit()​·​if
102 ········​/​/​·​using·​a·​global·​io_context·​object.​·​An·​additional·​call:​101 ········​/​/​·​using·​a·​global·​io_context·​object.​·​An·​additional·​call:​
103 ········​/​/​102 ········​/​/​
104 ········​/​/​···​io_context.​notify_fork(asio:​:​io_context:​:​fork_prepare)​;​103 ········​/​/​···​io_context.​notify_fork(asio:​:​io_context:​:​fork_prepare)​;​
105 ········​/​/​104 ········​/​/​
106 ········​/​/​·​should·​also·​precede·​the·​second·​fork()​.​105 ········​/​/​·​should·​also·​precede·​the·​second·​fork()​.​
107 ········​exit(0)​;​106 ········​exit(0)​;​
108 ······​}107 ······​}
109 ······​else108 ······​else
110 ······​{109 ······​{
111 ········​syslog(LOG_ERR·​|·​LOG_USER,​·​"First·​fork·​failed:​·​%m")​;​110 ········​syslog(LOG_ERR·​|·​LOG_USER,​·​"First·​fork·​failed:​·​%m")​;​
112 ········​return·​1;​111 ········​return·​1;​
113 ······​}112 ······​}
114 ····​}113 ····​}
115 114
116 ····​/​/​·​Make·​the·​process·​a·​new·​session·​leader.​·​This·​detaches·​it·​from·​the115 ····​/​/​·​Make·​the·​process·​a·​new·​session·​leader.​·​This·​detaches·​it·​from·​the
117 ····​/​/​·​terminal.​116 ····​/​/​·​terminal.​
118 ····​setsid()​;​117 ····​setsid()​;​
119 118
120 ····​/​/​·​A·​process·​inherits·​its·​working·​directory·​from·​its·​parent.​·​This·​could·​be119 ····​/​/​·​A·​process·​inherits·​its·​working·​directory·​from·​its·​parent.​·​This·​could·​be
121 ····​/​/​·​on·​a·​mounted·​filesystem,​·​which·​means·​that·​the·​running·​daemon·​would120 ····​/​/​·​on·​a·​mounted·​filesystem,​·​which·​means·​that·​the·​running·​daemon·​would
122 ····​/​/​·​prevent·​this·​filesystem·​from·​being·​unmounted.​·​Changing·​to·​the·​root121 ····​/​/​·​prevent·​this·​filesystem·​from·​being·​unmounted.​·​Changing·​to·​the·​root
123 ····​/​/​·​directory·​avoids·​this·​problem.​122 ····​/​/​·​directory·​avoids·​this·​problem.​
124 ····​chdir("/​")​;​123 ····​chdir("/​")​;​
125 124
126 ····​/​/​·​The·​file·​mode·​creation·​mask·​is·​also·​inherited·​from·​the·​parent·​process.​125 ····​/​/​·​The·​file·​mode·​creation·​mask·​is·​also·​inherited·​from·​the·​parent·​process.​
127 ····​/​/​·​We·​don't·​want·​to·​restrict·​the·​permissions·​on·​files·​created·​by·​the126 ····​/​/​·​We·​don't·​want·​to·​restrict·​the·​permissions·​on·​files·​created·​by·​the
128 ····​/​/​·​daemon,​·​so·​the·​mask·​is·​cleared.​127 ····​/​/​·​daemon,​·​so·​the·​mask·​is·​cleared.​
129 ····​umask(0)​;​128 ····​umask(0)​;​
130 129
131 ····​/​/​·​A·​second·​fork·​ensures·​the·​process·​cannot·​acquire·​a·​controlling·​terminal.​130 ····​/​/​·​A·​second·​fork·​ensures·​the·​process·​cannot·​acquire·​a·​controlling·​terminal.​
132 ····​if·​(pid_t·​pid·​=·​fork()​)​131 ····​if·​(pid_t·​pid·​=·​fork()​)​
133 ····​{132 ····​{
134 ······​if·​(pid·​>·​0)​133 ······​if·​(pid·​>·​0)​
135 ······​{134 ······​{
136 ········​exit(0)​;​135 ········​exit(0)​;​
137 ······​}136 ······​}
138 ······​else137 ······​else
139 ······​{138 ······​{
140 ········​syslog(LOG_ERR·​|·​LOG_USER,​·​"Second·​fork·​failed:​·​%m")​;​139 ········​syslog(LOG_ERR·​|·​LOG_USER,​·​"Second·​fork·​failed:​·​%m")​;​
141 ········​return·​1;​140 ········​return·​1;​
142 ······​}141 ······​}
143 ····​}142 ····​}
144 143
145 ····​/​/​·​Close·​the·​standard·​streams.​·​This·​decouples·​the·​daemon·​from·​the·​terminal144 ····​/​/​·​Close·​the·​standard·​streams.​·​This·​decouples·​the·​daemon·​from·​the·​terminal
146 ····​/​/​·​that·​started·​it.​145 ····​/​/​·​that·​started·​it.​
147 ····​close(0)​;​146 ····​close(0)​;​
148 ····​close(1)​;​147 ····​close(1)​;​
149 ····​close(2)​;​148 ····​close(2)​;​
150 149
151 ····​/​/​·​We·​don't·​want·​the·​daemon·​to·​have·​any·​standard·​input.​150 ····​/​/​·​We·​don't·​want·​the·​daemon·​to·​have·​any·​standard·​input.​
152 ····​if·​(open("/​dev/​null",​·​O_RDONLY)​·​<·​0)​151 ····​if·​(open("/​dev/​null",​·​O_RDONLY)​·​<·​0)​
153 ····​{152 ····​{
154 ······​syslog(LOG_ERR·​|·​LOG_USER,​·​"Unable·​to·​open·​/​dev/​null:​·​%m")​;​153 ······​syslog(LOG_ERR·​|·​LOG_USER,​·​"Unable·​to·​open·​/​dev/​null:​·​%m")​;​
155 ······​return·​1;​154 ······​return·​1;​
156 ····​}155 ····​}
157 156
158 ····​/​/​·​Send·​standard·​output·​to·​a·​log·​file.​157 ····​/​/​·​Send·​standard·​output·​to·​a·​log·​file.​
159 ····​const·​char*·​output·​=·​"/​tmp/​asio.​daemon.​out";​158 ····​const·​char*·​output·​=·​"/​tmp/​asio.​daemon.​out";​
160 ····​const·​int·​flags·​=·​O_WRONLY·​|·​O_CREAT·​|·​O_APPEND;​159 ····​const·​int·​flags·​=·​O_WRONLY·​|·​O_CREAT·​|·​O_APPEND;​
161 ····​const·​mode_t·​mode·​=·​S_IRUSR·​|·​S_IWUSR·​|·​S_IRGRP·​|·​S_IROTH;​160 ····​const·​mode_t·​mode·​=·​S_IRUSR·​|·​S_IWUSR·​|·​S_IRGRP·​|·​S_IROTH;​
162 ····​if·​(open(output,​·​flags,​·​mode)​·​<·​0)​161 ····​if·​(open(output,​·​flags,​·​mode)​·​<·​0)​
163 ····​{162 ····​{
164 ······​syslog(LOG_ERR·​|·​LOG_USER,​·​"Unable·​to·​open·​output·​file·​%s:​·​%m",​·​output)​;​163 ······​syslog(LOG_ERR·​|·​LOG_USER,​·​"Unable·​to·​open·​output·​file·​%s:​·​%m",​·​output)​;​
165 ······​return·​1;​164 ······​return·​1;​
166 ····​}165 ····​}
167 166
168 ····​/​/​·​Also·​send·​standard·​error·​to·​the·​same·​log·​file.​167 ····​/​/​·​Also·​send·​standard·​error·​to·​the·​same·​log·​file.​
169 ····​if·​(dup(1)​·​<·​0)​168 ····​if·​(dup(1)​·​<·​0)​
170 ····​{169 ····​{
171 ······​syslog(LOG_ERR·​|·​LOG_USER,​·​"Unable·​to·​dup·​output·​descriptor:​·​%m")​;​170 ······​syslog(LOG_ERR·​|·​LOG_USER,​·​"Unable·​to·​dup·​output·​descriptor:​·​%m")​;​
172 ······​return·​1;​171 ······​return·​1;​
173 ····​}172 ····​}
174 173
175 ····​/​/​·​Inform·​the·​io_context·​that·​we·​have·​finished·​becoming·​a·​daemon.​·​The174 ····​/​/​·​Inform·​the·​io_context·​that·​we·​have·​finished·​becoming·​a·​daemon.​·​The
176 ····​/​/​·​io_context·​uses·​this·​opportunity·​to·​create·​any·​internal·​file·​descriptors175 ····​/​/​·​io_context·​uses·​this·​opportunity·​to·​create·​any·​internal·​file·​descriptors
177 ····​/​/​·​that·​need·​to·​be·​private·​to·​the·​new·​process.​176 ····​/​/​·​that·​need·​to·​be·​private·​to·​the·​new·​process.​
178 ····​io_context.​notify_fork(asio:​:​io_context:​:​fork_child)​;​177 ····​io_context.​notify_fork(asio:​:​io_context:​:​fork_child)​;​
179 178
180 ····​/​/​·​The·​io_context·​can·​now·​be·​used·​normally.​179 ····​/​/​·​The·​io_context·​can·​now·​be·​used·​normally.​
181 ····​syslog(LOG_INFO·​|·​LOG_USER,​·​"Daemon·​started")​;​180 ····​syslog(LOG_INFO·​|·​LOG_USER,​·​"Daemon·​started")​;​
182 ····​io_context.​run()​;​181 ····​io_context.​run()​;​
183 ····​syslog(LOG_INFO·​|·​LOG_USER,​·​"Daemon·​stopped")​;​182 ····​syslog(LOG_INFO·​|·​LOG_USER,​·​"Daemon·​stopped")​;​
184 ··​}183 ··​}
185 ··​catch·​(std:​:​exception&·​e)​184 ··​catch·​(std:​:​exception&·​e)​
186 ··​{185 ··​{
187 ····​syslog(LOG_ERR·​|·​LOG_USER,​·​"Exception:​·​%s",​·​e.​what()​)​;​186 ····​syslog(LOG_ERR·​|·​LOG_USER,​·​"Exception:​·​%s",​·​e.​what()​)​;​
188 ····​std:​:​cerr·​<<·​"Exception:​·​"·​<<·​e.​what()​·​<<·​std:​:​endl;​187 ····​std:​:​cerr·​<<·​"Exception:​·​"·​<<·​e.​what()​·​<<·​std:​:​endl;​
189 ··​}188 ··​}
190 }189 }