1 /*
2 Copyright (c) 2012-2013 Martin Sustrik All rights reserved.
3 Copyright 2016 Garrett D'Amore <garrett@damore.org>
4
5 Permission is hereby granted, free of charge, to any person obtaining a copy
6 of this software and associated documentation files (the "Software"),
7 to deal in the Software without restriction, including without limitation
8 the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 and/or sell copies of the Software, and to permit persons to whom
10 the Software is furnished to do so, subject to the following conditions:
11
12 The above copyright notice and this permission notice shall be included
13 in all copies or substantial portions of the Software.
14
15 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21 IN THE SOFTWARE.
22 */
23
24 #include "aipc.h"
25
26 #include "../../utils/err.h"
27 #include "../../utils/cont.h"
28 #include "../../utils/attr.h"
29
30 #define NN_AIPC_STATE_IDLE 1
31 #define NN_AIPC_STATE_ACCEPTING 2
32 #define NN_AIPC_STATE_ACTIVE 3
33 #define NN_AIPC_STATE_STOPPING_SIPC 4
34 #define NN_AIPC_STATE_STOPPING_USOCK 5
35 #define NN_AIPC_STATE_DONE 6
36 #define NN_AIPC_STATE_STOPPING_SIPC_FINAL 7
37 #define NN_AIPC_STATE_STOPPING 8
38
39 #define NN_AIPC_SRC_USOCK 1
40 #define NN_AIPC_SRC_SIPC 2
41 #define NN_AIPC_SRC_LISTENER 3
42
43 /* Private functions. */
44 static void nn_aipc_handler (struct nn_fsm *self, int src, int type,
45 void *srcptr);
46 static void nn_aipc_shutdown (struct nn_fsm *self, int src, int type,
47 void *srcptr);
48
nn_aipc_init(struct nn_aipc * self,int src,struct nn_ep * ep,struct nn_fsm * owner)49 void nn_aipc_init (struct nn_aipc *self, int src,
50 struct nn_ep *ep, struct nn_fsm *owner)
51 {
52 nn_fsm_init (&self->fsm, nn_aipc_handler, nn_aipc_shutdown,
53 src, self, owner);
54 self->state = NN_AIPC_STATE_IDLE;
55 self->ep = ep;
56 nn_usock_init (&self->usock, NN_AIPC_SRC_USOCK, &self->fsm);
57 self->listener = NULL;
58 self->listener_owner.src = -1;
59 self->listener_owner.fsm = NULL;
60 nn_sipc_init (&self->sipc, NN_AIPC_SRC_SIPC, ep, &self->fsm);
61 nn_fsm_event_init (&self->accepted);
62 nn_fsm_event_init (&self->done);
63 nn_list_item_init (&self->item);
64 }
65
nn_aipc_term(struct nn_aipc * self)66 void nn_aipc_term (struct nn_aipc *self)
67 {
68 nn_assert_state (self, NN_AIPC_STATE_IDLE);
69
70 nn_list_item_term (&self->item);
71 nn_fsm_event_term (&self->done);
72 nn_fsm_event_term (&self->accepted);
73 nn_sipc_term (&self->sipc);
74 nn_usock_term (&self->usock);
75 nn_fsm_term (&self->fsm);
76 }
77
nn_aipc_isidle(struct nn_aipc * self)78 int nn_aipc_isidle (struct nn_aipc *self)
79 {
80 return nn_fsm_isidle (&self->fsm);
81 }
82
nn_aipc_start(struct nn_aipc * self,struct nn_usock * listener)83 void nn_aipc_start (struct nn_aipc *self, struct nn_usock *listener)
84 {
85 #if defined NN_HAVE_WINDOWS
86 size_t sz;
87 #endif
88 nn_assert_state (self, NN_AIPC_STATE_IDLE);
89
90 /* Take ownership of the listener socket. */
91 self->listener = listener;
92 self->listener_owner.src = NN_AIPC_SRC_LISTENER;
93 self->listener_owner.fsm = &self->fsm;
94 nn_usock_swap_owner (listener, &self->listener_owner);
95
96 #if defined NN_HAVE_WINDOWS
97 /* Get/Set security attribute pointer*/
98 nn_ep_getopt (self->ep, NN_IPC, NN_IPC_SEC_ATTR, &self->usock.sec_attr, &sz);
99 nn_ep_getopt (self->ep, NN_IPC, NN_IPC_OUTBUFSZ, &self->usock.outbuffersz, &sz);
100 nn_ep_getopt (self->ep, NN_IPC, NN_IPC_INBUFSZ, &self->usock.inbuffersz, &sz);
101 #endif
102
103 /* Start the state machine. */
104 nn_fsm_start (&self->fsm);
105 }
106
nn_aipc_stop(struct nn_aipc * self)107 void nn_aipc_stop (struct nn_aipc *self)
108 {
109 nn_fsm_stop (&self->fsm);
110 }
111
nn_aipc_shutdown(struct nn_fsm * self,int src,int type,NN_UNUSED void * srcptr)112 static void nn_aipc_shutdown (struct nn_fsm *self, int src, int type,
113 NN_UNUSED void *srcptr)
114 {
115 struct nn_aipc *aipc;
116
117 aipc = nn_cont (self, struct nn_aipc, fsm);
118
119 if (nn_slow (src == NN_FSM_ACTION && type == NN_FSM_STOP)) {
120 if (!nn_sipc_isidle (&aipc->sipc)) {
121 nn_ep_stat_increment (aipc->ep, NN_STAT_DROPPED_CONNECTIONS, 1);
122 nn_sipc_stop (&aipc->sipc);
123 }
124 aipc->state = NN_AIPC_STATE_STOPPING_SIPC_FINAL;
125 }
126 if (nn_slow (aipc->state == NN_AIPC_STATE_STOPPING_SIPC_FINAL)) {
127 if (!nn_sipc_isidle (&aipc->sipc))
128 return;
129 nn_usock_stop (&aipc->usock);
130 aipc->state = NN_AIPC_STATE_STOPPING;
131 }
132 if (nn_slow (aipc->state == NN_AIPC_STATE_STOPPING)) {
133 if (!nn_usock_isidle (&aipc->usock))
134 return;
135 if (aipc->listener) {
136 nn_assert (aipc->listener_owner.fsm);
137 nn_usock_swap_owner (aipc->listener, &aipc->listener_owner);
138 aipc->listener = NULL;
139 aipc->listener_owner.src = -1;
140 aipc->listener_owner.fsm = NULL;
141 }
142 aipc->state = NN_AIPC_STATE_IDLE;
143 nn_fsm_stopped (&aipc->fsm, NN_AIPC_STOPPED);
144 return;
145 }
146
147 nn_fsm_bad_state(aipc->state, src, type);
148 }
149
nn_aipc_handler(struct nn_fsm * self,int src,int type,NN_UNUSED void * srcptr)150 static void nn_aipc_handler (struct nn_fsm *self, int src, int type,
151 NN_UNUSED void *srcptr)
152 {
153 struct nn_aipc *aipc;
154 int val;
155 size_t sz;
156
157 aipc = nn_cont (self, struct nn_aipc, fsm);
158
159 switch (aipc->state) {
160
161 /******************************************************************************/
162 /* IDLE state. */
163 /* The state machine wasn't yet started. */
164 /******************************************************************************/
165 case NN_AIPC_STATE_IDLE:
166 switch (src) {
167
168 case NN_FSM_ACTION:
169 switch (type) {
170 case NN_FSM_START:
171 nn_usock_accept (&aipc->usock, aipc->listener);
172 aipc->state = NN_AIPC_STATE_ACCEPTING;
173 return;
174 default:
175 nn_fsm_bad_action (aipc->state, src, type);
176 }
177
178 default:
179 nn_fsm_bad_source (aipc->state, src, type);
180 }
181
182 /******************************************************************************/
183 /* ACCEPTING state. */
184 /* Waiting for incoming connection. */
185 /******************************************************************************/
186 case NN_AIPC_STATE_ACCEPTING:
187 switch (src) {
188
189 case NN_AIPC_SRC_USOCK:
190 switch (type) {
191 case NN_USOCK_ACCEPTED:
192 nn_ep_clear_error (aipc->ep);
193
194 /* Set the relevant socket options. */
195 sz = sizeof (val);
196 nn_ep_getopt (aipc->ep, NN_SOL_SOCKET, NN_SNDBUF, &val, &sz);
197 nn_assert (sz == sizeof (val));
198 nn_usock_setsockopt (&aipc->usock, SOL_SOCKET, SO_SNDBUF,
199 &val, sizeof (val));
200 sz = sizeof (val);
201 nn_ep_getopt (aipc->ep, NN_SOL_SOCKET, NN_RCVBUF, &val, &sz);
202 nn_assert (sz == sizeof (val));
203 nn_usock_setsockopt (&aipc->usock, SOL_SOCKET, SO_RCVBUF,
204 &val, sizeof (val));
205
206 /* Return ownership of the listening socket to the parent. */
207 nn_usock_swap_owner (aipc->listener, &aipc->listener_owner);
208 aipc->listener = NULL;
209 aipc->listener_owner.src = -1;
210 aipc->listener_owner.fsm = NULL;
211 nn_fsm_raise (&aipc->fsm, &aipc->accepted, NN_AIPC_ACCEPTED);
212
213 /* Start the sipc state machine. */
214 nn_usock_activate (&aipc->usock);
215 nn_sipc_start (&aipc->sipc, &aipc->usock);
216 aipc->state = NN_AIPC_STATE_ACTIVE;
217
218 nn_ep_stat_increment (aipc->ep,
219 NN_STAT_ACCEPTED_CONNECTIONS, 1);
220
221 return;
222
223 default:
224 nn_fsm_bad_action (aipc->state, src, type);
225 }
226
227 case NN_AIPC_SRC_LISTENER:
228 switch (type) {
229 case NN_USOCK_ACCEPT_ERROR:
230 nn_ep_set_error (aipc->ep, nn_usock_geterrno (aipc->listener));
231 nn_ep_stat_increment (aipc->ep, NN_STAT_ACCEPT_ERRORS, 1);
232 nn_usock_accept (&aipc->usock, aipc->listener);
233
234 return;
235
236 default:
237 nn_fsm_bad_action (aipc->state, src, type);
238 }
239
240 default:
241 nn_fsm_bad_source (aipc->state, src, type);
242 }
243
244 /******************************************************************************/
245 /* ACTIVE state. */
246 /******************************************************************************/
247 case NN_AIPC_STATE_ACTIVE:
248 switch (src) {
249
250 case NN_AIPC_SRC_SIPC:
251 switch (type) {
252 case NN_SIPC_ERROR:
253 nn_sipc_stop (&aipc->sipc);
254 aipc->state = NN_AIPC_STATE_STOPPING_SIPC;
255 nn_ep_stat_increment (aipc->ep, NN_STAT_BROKEN_CONNECTIONS, 1);
256 return;
257 default:
258 nn_fsm_bad_action (aipc->state, src, type);
259 }
260
261 default:
262 nn_fsm_bad_source (aipc->state, src, type);
263 }
264
265 /******************************************************************************/
266 /* STOPPING_SIPC state. */
267 /******************************************************************************/
268 case NN_AIPC_STATE_STOPPING_SIPC:
269 switch (src) {
270
271 case NN_AIPC_SRC_SIPC:
272 switch (type) {
273 case NN_USOCK_SHUTDOWN:
274 return;
275 case NN_SIPC_STOPPED:
276 nn_usock_stop (&aipc->usock);
277 aipc->state = NN_AIPC_STATE_STOPPING_USOCK;
278 return;
279 default:
280 nn_fsm_bad_action (aipc->state, src, type);
281 }
282
283 default:
284 nn_fsm_bad_source (aipc->state, src, type);
285 }
286
287 /******************************************************************************/
288 /* STOPPING_USOCK state. */
289 /******************************************************************************/
290 case NN_AIPC_STATE_STOPPING_USOCK:
291 switch (src) {
292
293 case NN_AIPC_SRC_USOCK:
294 switch (type) {
295 case NN_USOCK_SHUTDOWN:
296 return;
297 case NN_USOCK_STOPPED:
298 nn_fsm_raise (&aipc->fsm, &aipc->done, NN_AIPC_ERROR);
299 aipc->state = NN_AIPC_STATE_DONE;
300 return;
301 default:
302 nn_fsm_bad_action (aipc->state, src, type);
303 }
304
305 default:
306 nn_fsm_bad_source (aipc->state, src, type);
307 }
308
309 /******************************************************************************/
310 /* Invalid state. */
311 /******************************************************************************/
312 default:
313 nn_fsm_bad_state (aipc->state, src, type);
314 }
315 }
316