MFC: An off-by-one malloc size was corrupting the installer's memory,
[dragonfly.git] / contrib / bsdinstaller-1.1.6 / src / lib / libdfui / conn_npipe.c
bloba62fa6984b3afce39f01641e550d285d4952d9f0
1 /*
2 * Copyright (c)2004 Cat's Eye Technologies. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 *
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 <errno.h>
49 #include <stdarg.h>
50 #include <stdio.h>
51 #include <stdlib.h>
52 #include <string.h>
53 #include <unistd.h>
55 #include <aura/buffer.h>
56 #include <aura/fspred.h>
58 #define NEEDS_DFUI_STRUCTURE_DEFINITIONS
59 #include "dfui.h"
60 #undef NEEDS_DFUI_STRUCTURE_DEFINITIONS
61 #include "encoding.h"
62 #include "dump.h"
63 #include "conn_npipe.h"
65 /***** BACKEND ******/
67 /** High Level **/
70 * Connect to the frontend.
72 dfui_err_t
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.
81 errno = 0;
82 if (mkfifo(T_NPIPE(c)->in_pipename, 0600) < 0) {
83 if (errno != EEXIST) {
84 warn("mkfifo (to_be)");
85 return(DFUI_FAILURE);
88 errno = 0;
89 if (mkfifo(T_NPIPE(c)->out_pipename, 0600) < 0) {
90 if (errno != EEXIST) {
91 warn("mkfifo (to_fe)");
92 return(DFUI_FAILURE);
95 dfui_debug("opening pipes...\n");
96 if ((T_NPIPE(c)->out = fopen(T_NPIPE(c)->out_pipename, "w")) == NULL) {
97 return(DFUI_FAILURE);
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.
112 dfui_err_t
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);
119 } else
120 return(DFUI_FAILURE);
123 /** Low Level **/
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 * ------------------+------------------
140 * [stage 1]
141 * READY --> ll_receive()
142 * <-- PRESENT(form) ll_reply()
144 * [stage 2]
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
156 * in stage 2.
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.
166 dfui_err_t
167 dfui_npipe_be_ll_exchange(struct dfui_connection *c, char msgtype, const char *msg)
169 char *fmsg;
172 * Construct our message to send.
175 fmsg = malloc(strlen(msg) + 2);
176 fmsg[0] = msgtype;
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) {
191 free(fmsg);
192 return(DFUI_FAILURE);
195 /* XXX if (!READY) ??? */
197 do {
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?
209 * If so, loop!
212 } while (aura_buffer_buf(c->ebuf)[0] == DFUI_FE_MSG_READY);
214 fmsg[0] = DFUI_BE_MSG_READY;
215 fmsg[1] = '\0';
216 dfui_npipe_be_ll_reply(c, fmsg);
218 free(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
226 * c->ebuf.
228 dfui_err_t
229 dfui_npipe_be_ll_receive(struct dfui_connection *c)
231 int length;
232 char *buf;
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);
243 free(buf);
245 dfui_debug("RECEIVED<<%s>>\n", aura_buffer_buf(c->ebuf));
247 return(DFUI_SUCCESS);
251 * Send a NUL-terminated reply to the frontend.
253 dfui_err_t
254 dfui_npipe_be_ll_reply(struct dfui_connection *c, const char *fmsg)
256 int length;
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 ********/
270 /** High Level **/
272 dfui_err_t
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)) {
285 sleep(1);
287 sleep(1);
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);
309 dfui_err_t
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);
317 /** Low Level **/
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.
326 dfui_err_t
327 dfui_npipe_fe_ll_request(struct dfui_connection *c, char msgtype, const char *msg)
329 char *fmsg, *buf;
330 int length;
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);
344 fmsg[0] = msgtype;
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);
369 free(buf);
371 dfui_debug("RECV<<%s>>\n", aura_buffer_buf(c->ebuf));
373 free(fmsg);
375 return(DFUI_SUCCESS);
378 #endif /* HAS_NPIPE */