2 * Copyright (c)2004 Cat's Eye Technologies. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
8 * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
11 * Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in
13 * the documentation and/or other materials provided with the
16 * Neither the name of Cat's Eye Technologies nor the names of its
17 * contributors may be used to endorse or promote products derived
18 * from this software without specific prior written permission.
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
25 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
26 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
27 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
29 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
31 * OF THE POSSIBILITY OF SUCH DAMAGE.
36 * $Id: conn_npipe.c,v 1.13 2005/02/06 19:53:19 cpressey Exp $
42 #include <sys/types.h>
45 #include <sys/errno.h>
55 #include <aura/buffer.h>
56 #include <aura/fspred.h>
58 #define NEEDS_DFUI_STRUCTURE_DEFINITIONS
60 #undef NEEDS_DFUI_STRUCTURE_DEFINITIONS
63 #include "conn_npipe.h"
65 /***** BACKEND ******/
70 * Connect to the frontend.
73 dfui_npipe_be_start(struct dfui_connection
*c
)
75 asprintf(&T_NPIPE(c
)->out_pipename
, "/tmp/dfui.%s.to_fe", c
->rendezvous
);
76 asprintf(&T_NPIPE(c
)->in_pipename
, "/tmp/dfui.%s.from_fe", c
->rendezvous
);
79 * Create the named pipes.
82 if (mkfifo(T_NPIPE(c
)->in_pipename
, 0600) < 0) {
83 if (errno
!= EEXIST
) {
84 warn("mkfifo (to_be)");
89 if (mkfifo(T_NPIPE(c
)->out_pipename
, 0600) < 0) {
90 if (errno
!= EEXIST
) {
91 warn("mkfifo (to_fe)");
95 dfui_debug("opening pipes...\n");
96 if ((T_NPIPE(c
)->out
= fopen(T_NPIPE(c
)->out_pipename
, "w")) == NULL
) {
99 dfui_debug("opened to_fe pipe\n");
100 setvbuf(T_NPIPE(c
)->out
, NULL
, _IONBF
, 0);
101 if ((T_NPIPE(c
)->in
= fopen(T_NPIPE(c
)->in_pipename
, "r")) == NULL
) {
102 fclose(T_NPIPE(c
)->out
);
103 return(DFUI_FAILURE
);
105 dfui_debug("opened to_be pipe\n");
106 return(DFUI_SUCCESS
);
110 * Tell the frontend that we're done and disconnect from it.
113 dfui_npipe_be_stop(struct dfui_connection
*c
)
115 if (dfui_npipe_be_ll_exchange(c
, DFUI_BE_MSG_STOP
, "")) {
116 fclose(T_NPIPE(c
)->in
);
117 fclose(T_NPIPE(c
)->out
);
118 return(DFUI_SUCCESS
);
120 return(DFUI_FAILURE
);
126 * Exchange a message with the frontend. This involves two receive()/reply()
127 * cycles: one to provide our message, one to get a reply from the frontend.
129 * Note that this does not immediately send the message to the frontend -
130 * it can't, because we're a service and it's a client. What it does is
131 * keep the message handy and wait for a frontend request to come in. It
132 * then replies to that request with our message.
134 * The protocol looks something like the following, using the PRESENT and
135 * SUBMIT exchange as an example:
137 * frontend (client) | backend (service)
138 * ------------------+------------------
141 * READY --> ll_receive()
142 * <-- PRESENT(form) ll_reply()
145 * SUBMIT(form) --> ll_receive()
146 * <-- READY ll_reply()
148 * Each of those exchanges is a pair of calls, on our end, to
149 * dfui_npipe_be_ll_receive() and dfui_npipe_be_ll_reply().
151 * The set of messages that the client can pass us is determined by
152 * the conversation state:
154 * o In stage 1, only READY and ABORT are meaningful.
155 * o After a PRESENT, the messages SUBMIT and ABORT are meaningul
157 * o During a PROG_*, the messages CONTINUE, CANCEL, and ABORT
158 * are meaningful in stage 2.
160 * If the frontend sends us with READY in stage 2, we assume it has
161 * fallen out of sync, so we send the same initial reply again, going
162 * back to stage 1 as it were.
164 * After this call, the message is available in c->ebuf.
167 dfui_npipe_be_ll_exchange(struct dfui_connection
*c
, char msgtype
, const char *msg
)
172 * Construct our message to send.
175 fmsg
= malloc(strlen(msg
) + 2);
177 strcpy(fmsg
+ 1, msg
);
180 * Get the frontend's message.
183 dfui_npipe_be_ll_receive(c
);
186 * Frontend message should have been either READY or ABORT.
187 * If ABORT, we get out of here pronto.
190 if (aura_buffer_buf(c
->ebuf
)[0] == DFUI_FE_MSG_ABORT
) {
192 return(DFUI_FAILURE
);
195 /* XXX if (!READY) ??? */
198 dfui_npipe_be_ll_reply(c
, fmsg
);
201 * Here, the frontend has picked up our request and is
202 * processing it. We have to wait for the response.
205 dfui_npipe_be_ll_receive(c
);
208 * Did we get READY from this?
212 } while (aura_buffer_buf(c
->ebuf
)[0] == DFUI_FE_MSG_READY
);
214 fmsg
[0] = DFUI_BE_MSG_READY
;
216 dfui_npipe_be_ll_reply(c
, fmsg
);
219 return(DFUI_SUCCESS
);
223 * Receive a message from the frontend.
224 * This call is synchronous.
225 * After this call, the NUL-terminated message is available in
229 dfui_npipe_be_ll_receive(struct dfui_connection
*c
)
234 dfui_debug("WAITING<<>>\n");
236 fread(&length
, 4, 1, T_NPIPE(c
)->in
);
238 dfui_debug("LENGTH<<%d>>\n", length
);
240 buf
= malloc(length
+ 1);
241 fread(buf
, length
, 1, T_NPIPE(c
)->in
);
242 aura_buffer_set(c
->ebuf
, buf
, length
);
245 dfui_debug("RECEIVED<<%s>>\n", aura_buffer_buf(c
->ebuf
));
247 return(DFUI_SUCCESS
);
251 * Send a NUL-terminated reply to the frontend.
254 dfui_npipe_be_ll_reply(struct dfui_connection
*c
, const char *fmsg
)
258 dfui_debug("SEND<<%s>>\n", fmsg
);
260 length
= strlen(fmsg
);
262 fwrite(&length
, 4, 1, T_NPIPE(c
)->out
);
263 fwrite(fmsg
, length
, 1, T_NPIPE(c
)->out
);
265 return(DFUI_SUCCESS
);
268 /******** FRONTEND ********/
273 dfui_npipe_fe_connect(struct dfui_connection
*c
)
275 asprintf(&T_NPIPE(c
)->in_pipename
, "/tmp/dfui.%s.to_fe", c
->rendezvous
);
276 asprintf(&T_NPIPE(c
)->out_pipename
, "/tmp/dfui.%s.from_fe", c
->rendezvous
);
278 dfui_debug("waiting for named pipes...\n");
281 * Wait for named pipes to be created.
283 if (!is_named_pipe(T_NPIPE(c
)->in_pipename
)) {
284 while (!is_named_pipe(T_NPIPE(c
)->in_pipename
)) {
290 dfui_debug("opening inflow pipe...\n");
292 if ((T_NPIPE(c
)->in
= fopen(T_NPIPE(c
)->in_pipename
, "r")) == NULL
) {
293 return(DFUI_FAILURE
);
296 dfui_debug("opening outflow pipe...\n");
298 if ((T_NPIPE(c
)->out
= fopen(T_NPIPE(c
)->out_pipename
, "w")) == NULL
) {
299 fclose(T_NPIPE(c
)->in
);
300 return(DFUI_FAILURE
);
303 dfui_debug("making outflow pipe raw...\n");
305 setvbuf(T_NPIPE(c
)->out
, NULL
, _IONBF
, 0);
306 return(DFUI_SUCCESS
);
310 dfui_npipe_fe_disconnect(struct dfui_connection
*c
)
312 fclose(T_NPIPE(c
)->in
);
313 fclose(T_NPIPE(c
)->out
);
314 return(DFUI_SUCCESS
);
320 * Ask for, and subsequently receieve, a message from the backend.
321 * msgtype should be one of the DFUI_FE_MSG_* constants.
322 * This call is synchronous.
323 * After this call, the null-terminated, encoded message is
324 * available in T_NPIPE(c)->buf.
327 dfui_npipe_fe_ll_request(struct dfui_connection
*c
, char msgtype
, const char *msg
)
333 * First, assert that the connection is open.
336 if (c
== NULL
|| T_NPIPE(c
)->in
== NULL
|| T_NPIPE(c
)->out
== NULL
)
337 return(DFUI_FAILURE
);
340 * Construct a message.
343 fmsg
= malloc(strlen(msg
) + 2);
345 strcpy(fmsg
+ 1, msg
);
347 dfui_debug("SEND<<%s>>\n", fmsg
);
350 * Send a NUL-terminated message to the backend.
353 length
= strlen(fmsg
);
354 fwrite(&length
, 4, 1, T_NPIPE(c
)->out
);
355 fwrite(fmsg
, length
, 1, T_NPIPE(c
)->out
);
358 * Receive a reply from the backend.
359 * If our message was a READY, this should be a message like PRESENT.
360 * Otherwise it should simply be a READY.
363 dfui_debug("WAITING<<>>\n");
365 fread(&length
, 4, 1, T_NPIPE(c
)->in
);
366 buf
= malloc(length
+ 1);
367 fread(buf
, length
, 1, T_NPIPE(c
)->in
);
368 aura_buffer_set(c
->ebuf
, buf
, length
);
371 dfui_debug("RECV<<%s>>\n", aura_buffer_buf(c
->ebuf
));
375 return(DFUI_SUCCESS
);
378 #endif /* HAS_NPIPE */