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>
54 #include <libaura/buffer.h>
55 #include <libaura/fspred.h>
57 #define NEEDS_DFUI_STRUCTURE_DEFINITIONS
59 #undef NEEDS_DFUI_STRUCTURE_DEFINITIONS
62 #include "conn_npipe.h"
64 /***** BACKEND ******/
69 * Connect to the frontend.
72 dfui_npipe_be_start(struct dfui_connection
*c
)
74 asprintf(&T_NPIPE(c
)->out_pipename
, "/tmp/dfui.%s.to_fe", c
->rendezvous
);
75 asprintf(&T_NPIPE(c
)->in_pipename
, "/tmp/dfui.%s.from_fe", c
->rendezvous
);
78 * Create the named pipes.
81 if (mkfifo(T_NPIPE(c
)->in_pipename
, 0600) < 0) {
82 if (errno
!= EEXIST
) {
83 warn("mkfifo (to_be)");
88 if (mkfifo(T_NPIPE(c
)->out_pipename
, 0600) < 0) {
89 if (errno
!= EEXIST
) {
90 warn("mkfifo (to_fe)");
94 dfui_debug("opening pipes...\n");
95 if ((T_NPIPE(c
)->out
= fopen(T_NPIPE(c
)->out_pipename
, "w")) == NULL
) {
98 dfui_debug("opened to_fe pipe\n");
99 setvbuf(T_NPIPE(c
)->out
, NULL
, _IONBF
, 0);
100 if ((T_NPIPE(c
)->in
= fopen(T_NPIPE(c
)->in_pipename
, "r")) == NULL
) {
101 fclose(T_NPIPE(c
)->out
);
102 return(DFUI_FAILURE
);
104 dfui_debug("opened to_be pipe\n");
105 return(DFUI_SUCCESS
);
109 * Tell the frontend that we're done and disconnect from it.
112 dfui_npipe_be_stop(struct dfui_connection
*c
)
114 if (dfui_npipe_be_ll_exchange(c
, DFUI_BE_MSG_STOP
, "")) {
115 fclose(T_NPIPE(c
)->in
);
116 fclose(T_NPIPE(c
)->out
);
117 return(DFUI_SUCCESS
);
119 return(DFUI_FAILURE
);
125 * Exchange a message with the frontend. This involves two receive()/reply()
126 * cycles: one to provide our message, one to get a reply from the frontend.
128 * Note that this does not immediately send the message to the frontend -
129 * it can't, because we're a service and it's a client. What it does is
130 * keep the message handy and wait for a frontend request to come in. It
131 * then replies to that request with our message.
133 * The protocol looks something like the following, using the PRESENT and
134 * SUBMIT exchange as an example:
136 * frontend (client) | backend (service)
137 * ------------------+------------------
140 * READY --> ll_receive()
141 * <-- PRESENT(form) ll_reply()
144 * SUBMIT(form) --> ll_receive()
145 * <-- READY ll_reply()
147 * Each of those exchanges is a pair of calls, on our end, to
148 * dfui_npipe_be_ll_receive() and dfui_npipe_be_ll_reply().
150 * The set of messages that the client can pass us is determined by
151 * the conversation state:
153 * o In stage 1, only READY and ABORT are meaningful.
154 * o After a PRESENT, the messages SUBMIT and ABORT are meaningul
156 * o During a PROG_*, the messages CONTINUE, CANCEL, and ABORT
157 * are meaningful in stage 2.
159 * If the frontend sends us with READY in stage 2, we assume it has
160 * fallen out of sync, so we send the same initial reply again, going
161 * back to stage 1 as it were.
163 * After this call, the message is available in c->ebuf.
166 dfui_npipe_be_ll_exchange(struct dfui_connection
*c
, char msgtype
, const char *msg
)
171 * Construct our message to send.
174 fmsg
= malloc(strlen(msg
) + 2);
176 strcpy(fmsg
+ 1, msg
);
179 * Get the frontend's message.
182 dfui_npipe_be_ll_receive(c
);
185 * Frontend message should have been either READY or ABORT.
186 * If ABORT, we get out of here pronto.
189 if (aura_buffer_buf(c
->ebuf
)[0] == DFUI_FE_MSG_ABORT
) {
191 return(DFUI_FAILURE
);
194 /* XXX if (!READY) ??? */
197 dfui_npipe_be_ll_reply(c
, fmsg
);
200 * Here, the frontend has picked up our request and is
201 * processing it. We have to wait for the response.
204 dfui_npipe_be_ll_receive(c
);
207 * Did we get READY from this?
211 } while (aura_buffer_buf(c
->ebuf
)[0] == DFUI_FE_MSG_READY
);
213 fmsg
[0] = DFUI_BE_MSG_READY
;
215 dfui_npipe_be_ll_reply(c
, fmsg
);
218 return(DFUI_SUCCESS
);
222 * Receive a message from the frontend.
223 * This call is synchronous.
224 * After this call, the NUL-terminated message is available in
228 dfui_npipe_be_ll_receive(struct dfui_connection
*c
)
233 dfui_debug("WAITING<<>>\n");
235 fread(&length
, 4, 1, T_NPIPE(c
)->in
);
237 dfui_debug("LENGTH<<%d>>\n", length
);
239 buf
= malloc(length
+ 1);
240 fread(buf
, length
, 1, T_NPIPE(c
)->in
);
241 aura_buffer_set(c
->ebuf
, buf
, length
);
244 dfui_debug("RECEIVED<<%s>>\n", aura_buffer_buf(c
->ebuf
));
246 return(DFUI_SUCCESS
);
250 * Send a NUL-terminated reply to the frontend.
253 dfui_npipe_be_ll_reply(struct dfui_connection
*c
, const char *fmsg
)
257 dfui_debug("SEND<<%s>>\n", fmsg
);
259 length
= strlen(fmsg
);
261 fwrite(&length
, 4, 1, T_NPIPE(c
)->out
);
262 fwrite(fmsg
, length
, 1, T_NPIPE(c
)->out
);
264 return(DFUI_SUCCESS
);
267 /******** FRONTEND ********/
272 dfui_npipe_fe_connect(struct dfui_connection
*c
)
274 asprintf(&T_NPIPE(c
)->in_pipename
, "/tmp/dfui.%s.to_fe", c
->rendezvous
);
275 asprintf(&T_NPIPE(c
)->out_pipename
, "/tmp/dfui.%s.from_fe", c
->rendezvous
);
277 dfui_debug("waiting for named pipes...\n");
280 * Wait for named pipes to be created.
282 if (!is_named_pipe("%s", T_NPIPE(c
)->in_pipename
)) {
283 while (!is_named_pipe("%s", T_NPIPE(c
)->in_pipename
)) {
289 dfui_debug("opening inflow pipe...\n");
291 if ((T_NPIPE(c
)->in
= fopen(T_NPIPE(c
)->in_pipename
, "r")) == NULL
) {
292 return(DFUI_FAILURE
);
295 dfui_debug("opening outflow pipe...\n");
297 if ((T_NPIPE(c
)->out
= fopen(T_NPIPE(c
)->out_pipename
, "w")) == NULL
) {
298 fclose(T_NPIPE(c
)->in
);
299 return(DFUI_FAILURE
);
302 dfui_debug("making outflow pipe raw...\n");
304 setvbuf(T_NPIPE(c
)->out
, NULL
, _IONBF
, 0);
305 return(DFUI_SUCCESS
);
309 dfui_npipe_fe_disconnect(struct dfui_connection
*c
)
311 fclose(T_NPIPE(c
)->in
);
312 fclose(T_NPIPE(c
)->out
);
313 return(DFUI_SUCCESS
);
319 * Ask for, and subsequently receieve, a message from the backend.
320 * msgtype should be one of the DFUI_FE_MSG_* constants.
321 * This call is synchronous.
322 * After this call, the null-terminated, encoded message is
323 * available in T_NPIPE(c)->buf.
326 dfui_npipe_fe_ll_request(struct dfui_connection
*c
, char msgtype
, const char *msg
)
332 * First, assert that the connection is open.
335 if (c
== NULL
|| T_NPIPE(c
)->in
== NULL
|| T_NPIPE(c
)->out
== NULL
)
336 return(DFUI_FAILURE
);
339 * Construct a message.
342 fmsg
= malloc(strlen(msg
) + 2);
344 strcpy(fmsg
+ 1, msg
);
346 dfui_debug("SEND<<%s>>\n", fmsg
);
349 * Send a NUL-terminated message to the backend.
352 length
= strlen(fmsg
);
353 fwrite(&length
, 4, 1, T_NPIPE(c
)->out
);
354 fwrite(fmsg
, length
, 1, T_NPIPE(c
)->out
);
357 * Receive a reply from the backend.
358 * If our message was a READY, this should be a message like PRESENT.
359 * Otherwise it should simply be a READY.
362 dfui_debug("WAITING<<>>\n");
364 fread(&length
, 4, 1, T_NPIPE(c
)->in
);
365 buf
= malloc(length
+ 1);
366 fread(buf
, length
, 1, T_NPIPE(c
)->in
);
367 aura_buffer_set(c
->ebuf
, buf
, length
);
370 dfui_debug("RECV<<%s>>\n", aura_buffer_buf(c
->ebuf
));
374 return(DFUI_SUCCESS
);
377 #endif /* HAS_NPIPE */