Clean up a bit for symlinked headers.
[dragonfly.git] / usr.sbin / installer / libdfui / conn_npipe.c
bloba9150f1a0808447071dc7bc4a305cc2015c8536c
1 /*
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
6 * are met:
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
14 * distribution.
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.
35 * conn_npipe.c
36 * $Id: conn_npipe.c,v 1.13 2005/02/06 19:53:19 cpressey Exp $
39 #include "system.h"
40 #ifdef HAS_NPIPE
42 #include <sys/types.h>
43 #include <sys/stat.h>
44 #include <sys/time.h>
45 #include <sys/errno.h>
47 #include <err.h>
48 #include <stdarg.h>
49 #include <stdio.h>
50 #include <stdlib.h>
51 #include <string.h>
52 #include <unistd.h>
54 #include <libaura/buffer.h>
55 #include <libaura/fspred.h>
57 #define NEEDS_DFUI_STRUCTURE_DEFINITIONS
58 #include "dfui.h"
59 #undef NEEDS_DFUI_STRUCTURE_DEFINITIONS
60 #include "encoding.h"
61 #include "dump.h"
62 #include "conn_npipe.h"
64 /***** BACKEND ******/
66 /** High Level **/
69 * Connect to the frontend.
71 dfui_err_t
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.
80 errno = 0;
81 if (mkfifo(T_NPIPE(c)->in_pipename, 0600) < 0) {
82 if (errno != EEXIST) {
83 warn("mkfifo (to_be)");
84 return(DFUI_FAILURE);
87 errno = 0;
88 if (mkfifo(T_NPIPE(c)->out_pipename, 0600) < 0) {
89 if (errno != EEXIST) {
90 warn("mkfifo (to_fe)");
91 return(DFUI_FAILURE);
94 dfui_debug("opening pipes...\n");
95 if ((T_NPIPE(c)->out = fopen(T_NPIPE(c)->out_pipename, "w")) == NULL) {
96 return(DFUI_FAILURE);
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.
111 dfui_err_t
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);
118 } else
119 return(DFUI_FAILURE);
122 /** Low Level **/
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 * ------------------+------------------
139 * [stage 1]
140 * READY --> ll_receive()
141 * <-- PRESENT(form) ll_reply()
143 * [stage 2]
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
155 * in stage 2.
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.
165 dfui_err_t
166 dfui_npipe_be_ll_exchange(struct dfui_connection *c, char msgtype, const char *msg)
168 char *fmsg;
171 * Construct our message to send.
174 fmsg = malloc(strlen(msg) + 2);
175 fmsg[0] = msgtype;
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) {
190 free(fmsg);
191 return(DFUI_FAILURE);
194 /* XXX if (!READY) ??? */
196 do {
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?
208 * If so, loop!
211 } while (aura_buffer_buf(c->ebuf)[0] == DFUI_FE_MSG_READY);
213 fmsg[0] = DFUI_BE_MSG_READY;
214 fmsg[1] = '\0';
215 dfui_npipe_be_ll_reply(c, fmsg);
217 free(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
225 * c->ebuf.
227 dfui_err_t
228 dfui_npipe_be_ll_receive(struct dfui_connection *c)
230 int length;
231 char *buf;
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);
242 free(buf);
244 dfui_debug("RECEIVED<<%s>>\n", aura_buffer_buf(c->ebuf));
246 return(DFUI_SUCCESS);
250 * Send a NUL-terminated reply to the frontend.
252 dfui_err_t
253 dfui_npipe_be_ll_reply(struct dfui_connection *c, const char *fmsg)
255 int length;
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 ********/
269 /** High Level **/
271 dfui_err_t
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)) {
284 sleep(1);
286 sleep(1);
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);
308 dfui_err_t
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);
316 /** Low Level **/
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.
325 dfui_err_t
326 dfui_npipe_fe_ll_request(struct dfui_connection *c, char msgtype, const char *msg)
328 char *fmsg, *buf;
329 int length;
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);
343 fmsg[0] = msgtype;
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);
368 free(buf);
370 dfui_debug("RECV<<%s>>\n", aura_buffer_buf(c->ebuf));
372 free(fmsg);
374 return(DFUI_SUCCESS);
377 #endif /* HAS_NPIPE */