Some installer cleanup.
[dragonfly.git] / contrib / bsdinstaller-1.1.6 / src / lib / libdfui / connection.c
blob9a1184c3858d46f6a2c09bb77e6a02b919af63e8
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 * connection.c
36 * $Id: connection.c,v 1.20 2005/02/07 06:39:59 cpressey Exp $
37 * This code was derived in part from:
38 * $_DragonFly: src/test/caps/client.c,v 1.3 2004/03/31 20:27:34 dillon Exp $
39 * and is therefore also subject to the license conditions on that file.
42 #include <stdarg.h>
43 #include <stdlib.h>
44 #include <string.h>
46 #include <libaura/mem.h>
47 #include <libaura/buffer.h>
49 #include "system.h"
50 #define NEEDS_DFUI_STRUCTURE_DEFINITIONS
51 #include "dfui.h"
52 #undef NEEDS_DFUI_STRUCTURE_DEFINITIONS
53 #include "encoding.h"
54 #include "dump.h"
56 #include "conn_caps.h"
57 #include "conn_npipe.h"
58 #include "conn_tcp.h"
60 struct dfui_connection *
61 dfui_connection_new(int transport, const char *rendezvous)
63 struct dfui_connection *c = NULL;
65 if (
66 #ifdef HAS_CAPS
67 transport == DFUI_TRANSPORT_CAPS ||
68 #endif
69 #ifdef HAS_NPIPE
70 transport == DFUI_TRANSPORT_NPIPE ||
71 #endif
72 #ifdef HAS_TCP
73 transport == DFUI_TRANSPORT_TCP ||
74 #endif
75 0) {
76 /* We're OK. */
77 } else {
78 return(NULL);
81 if (dfui_debug_file == NULL) {
82 dfui_debug_file = stderr;
83 } else {
84 setvbuf(dfui_debug_file, NULL, _IOLBF, 0);
87 AURA_MALLOC(c, dfui_connection);
88 c->rendezvous = aura_strdup(rendezvous);
89 c->transport = transport;
90 c->ebuf = aura_buffer_new(16384);
91 c->is_connected = 0;
92 c->t_data = NULL;
94 switch (transport) {
95 #ifdef HAS_CAPS
96 case DFUI_TRANSPORT_CAPS:
97 AURA_MALLOC(c->t_data, dfui_conn_caps);
98 T_CAPS(c)->cid = 0;
99 bzero(&T_CAPS(c)->msgid, sizeof(T_CAPS(c)->msgid));
102 * XXX Ideally, this value should grow as needed.
103 * However, CAPS currently has a size limit of
104 * 128K internally.
106 T_CAPS(c)->size = 128 * 1024;
107 if ((T_CAPS(c)->buf = aura_malloc(T_CAPS(c)->size, "CAPS buffer")) == NULL) {
108 AURA_FREE(T_CAPS(c), dfui_conn_caps);
109 aura_free(c->rendezvous, "rendezvous string");
110 AURA_FREE(c, dfui_connection);
111 return(NULL);
115 * Set up dispatch functions.
117 c->be_start = dfui_caps_be_start;
118 c->be_stop = dfui_caps_be_stop;
119 c->be_ll_exchange = dfui_caps_be_ll_exchange;
121 c->fe_connect = dfui_caps_fe_connect;
122 c->fe_disconnect = dfui_caps_fe_disconnect;
123 c->fe_ll_request = dfui_caps_fe_ll_request;
124 break;
125 #endif /* HAS_CAPS */
127 #ifdef HAS_NPIPE
128 case DFUI_TRANSPORT_NPIPE:
129 AURA_MALLOC(c->t_data, dfui_conn_npipe);
130 T_NPIPE(c)->in_pipename = NULL;
131 T_NPIPE(c)->out_pipename = NULL;
132 T_NPIPE(c)->in = NULL;
133 T_NPIPE(c)->out = NULL;
136 * Set up dispatch functions.
138 c->be_start = dfui_npipe_be_start;
139 c->be_stop = dfui_npipe_be_stop;
140 c->be_ll_exchange = dfui_npipe_be_ll_exchange;
142 c->fe_connect = dfui_npipe_fe_connect;
143 c->fe_disconnect = dfui_npipe_fe_disconnect;
144 c->fe_ll_request = dfui_npipe_fe_ll_request;
145 break;
146 #endif /* HAS_NPIPE */
148 #ifdef HAS_TCP
149 case DFUI_TRANSPORT_TCP:
150 AURA_MALLOC(c->t_data, dfui_conn_tcp);
151 T_TCP(c)->listen_sd = -1;
152 T_TCP(c)->connected_sd = -1;
153 T_TCP(c)->is_connected = 0;
156 * Set up dispatch functions.
158 c->be_start = dfui_tcp_be_start;
159 c->be_stop = dfui_tcp_be_stop;
160 c->be_ll_exchange = dfui_tcp_be_ll_exchange;
162 c->fe_connect = dfui_tcp_fe_connect;
163 c->fe_disconnect = dfui_tcp_fe_disconnect;
164 c->fe_ll_request = dfui_tcp_fe_ll_request;
165 break;
166 #endif /* HAS_TCP */
169 return(c);
172 void
173 dfui_connection_free(struct dfui_connection *c)
175 if (c == NULL)
176 return;
178 switch (c->transport) {
179 #ifdef HAS_CAPS
180 case DFUI_TRANSPORT_CAPS:
181 if (T_CAPS(c) != NULL) {
182 if (T_CAPS(c)->buf != NULL)
183 aura_free(T_CAPS(c)->buf, "CAPS buffer");
184 AURA_FREE(T_CAPS(c), dfui_conn_caps);
186 break;
187 #endif
188 #ifdef HAS_NPIPE
189 case DFUI_TRANSPORT_NPIPE:
190 if (T_NPIPE(c) != NULL) {
191 if (T_NPIPE(c)->in_pipename != NULL)
192 aura_free(T_NPIPE(c)->in_pipename, "pipename");
193 if (T_NPIPE(c)->out_pipename != NULL)
194 aura_free(T_NPIPE(c)->out_pipename, "pipename");
195 if (T_NPIPE(c)->in != NULL)
196 fclose(T_NPIPE(c)->in);
197 if (T_NPIPE(c)->out != NULL)
198 fclose(T_NPIPE(c)->out);
199 AURA_FREE(T_NPIPE(c), dfui_conn_npipe);
201 break;
202 #endif
203 #ifdef HAS_TCP
204 case DFUI_TRANSPORT_TCP:
205 if (T_TCP(c) != NULL) {
206 /* XXX close sockets/files here */
207 AURA_FREE(T_NPIPE(c), dfui_conn_tcp);
209 break;
210 #endif
213 if (c->rendezvous != NULL)
214 free(c->rendezvous);
215 AURA_FREE(c, dfui_connection);
219 * VERY HIGH LEVEL
223 * Create and present a generic `dialog box'-type form for the user
224 * and return their response. actions is a pipe-seperated list of
225 * actions to be put on the form (e.g. "OK|Cancel".) The return
226 * value is the ordinal position of the action that was selected,
227 * starting at 1 for the first action. A return value of 0 indicates
228 * that an error occurred. A return value of -1 indicates that the
229 * front end aborted the communications.
232 dfui_be_present_dialog(struct dfui_connection *c, const char *title,
233 const char *actions, const char *fmt, ...)
235 struct dfui_form *f;
236 struct dfui_response *r;
237 va_list args;
238 char *message;
239 char action_id[256], action_name[256];
240 size_t start, end, counter, i;
242 va_start(args, fmt);
243 vasprintf(&message, fmt, args);
244 va_end(args);
246 f = dfui_form_create("dialog", title, message, "", NULL);
248 free(message);
250 start = end = 0;
251 while (actions[end] != '\0') {
252 end = start;
253 while (actions[end] != '|' && actions[end] != '\0')
254 end++;
256 if ((end - start) >= 256)
257 break;
258 strncpy(action_name, &actions[start], end - start);
259 action_name[end - start] = '\0';
260 strcpy(action_id, action_name);
261 for(i = 0; action_id[i] != '\0'; i++) {
262 if (action_id[i] == ' ')
263 action_id[i] = '_';
265 dfui_form_action_add(f, action_id,
266 dfui_info_new(action_name, "", ""));
268 start = end + 1;
271 if (!dfui_be_present(c, f, &r)) {
272 dfui_form_free(f);
273 dfui_response_free(r);
274 return(-1);
277 strlcpy(action_name, dfui_response_get_action_id(r), 256);
278 for(i = 0; action_name[i] != '\0'; i++) {
279 if (action_name[i] == '_')
280 action_name[i] = ' ';
283 start = end = 0;
284 counter = 1;
285 while (actions[end] != '\0') {
286 end = start;
287 while (actions[end] != '|' && actions[end] != '\0')
288 end++;
290 if ((end - start) >= 256)
291 break;
292 if (strlen(action_name) == (end - start) &&
293 strncmp(action_name, &actions[start], end - start) == 0) {
294 break;
296 counter++;
298 start = end + 1;
301 dfui_form_free(f);
302 dfui_response_free(r);
304 return(counter);
307 /******** BACKEND ********/
310 * Connect to the frontend.
312 dfui_err_t
313 dfui_be_start(struct dfui_connection *c)
315 if (c->is_connected) {
316 return(DFUI_FAILURE);
317 } else if (c->be_start(c)) {
318 c->is_connected = 1;
319 return(DFUI_SUCCESS);
320 } else {
321 return(DFUI_FAILURE);
326 * Tell the frontend that we're done and disconnect from it.
328 dfui_err_t
329 dfui_be_stop(struct dfui_connection *c)
331 if (!c->is_connected) {
332 return(DFUI_SUCCESS);
333 } else if (c->be_stop(c)) {
334 c->is_connected = 0;
335 return(DFUI_SUCCESS);
336 } else {
337 return(DFUI_FAILURE);
342 * Present a form to the user. This call is synchronous;
343 * it does not return until the user has selected an action.
345 dfui_err_t
346 dfui_be_present(struct dfui_connection *c,
347 struct dfui_form *f, struct dfui_response **r)
349 struct aura_buffer *e;
351 e = aura_buffer_new(16384);
352 dfui_encode_form(e, f);
354 c->be_ll_exchange(c, DFUI_BE_MSG_PRESENT, aura_buffer_buf(e));
356 aura_buffer_free(e);
358 /* check for ABORT reply */
359 if (aura_buffer_buf(c->ebuf)[0] == DFUI_FE_MSG_ABORT) {
360 return(DFUI_FAILURE);
364 * Now we've got the response; so decode it.
367 e = aura_buffer_new(16384);
368 aura_buffer_set(e, aura_buffer_buf(c->ebuf) + 1, aura_buffer_len(c->ebuf) - 1);
369 *r = dfui_decode_response(e);
370 aura_buffer_free(e);
372 return(DFUI_SUCCESS);
376 * Begin showing a progress bar to the user.
377 * This function is asynchronous; it returns immediately.
378 * The assumption is that the backend will make subsequent
379 * calls to dfui_be_progress_update() frequently, and in
380 * them, check to see if the user cancelled.
382 dfui_err_t
383 dfui_be_progress_begin(struct dfui_connection *c, struct dfui_progress *pr)
385 struct aura_buffer *e;
387 e = aura_buffer_new(16384);
388 dfui_encode_progress(e, pr);
390 c->be_ll_exchange(c, DFUI_BE_MSG_PROG_BEGIN, aura_buffer_buf(e));
391 aura_buffer_free(e);
393 /* response might have been be READY or ABORT */
394 if (aura_buffer_buf(c->ebuf)[0] == DFUI_FE_MSG_ABORT) {
395 return(DFUI_FAILURE);
396 } else {
397 return(DFUI_SUCCESS);
401 dfui_err_t
402 dfui_be_progress_update(struct dfui_connection *c,
403 struct dfui_progress *pr, int *cancelled)
405 struct aura_buffer *e;
407 e = aura_buffer_new(16384);
408 dfui_encode_progress(e, pr);
410 c->be_ll_exchange(c, DFUI_BE_MSG_PROG_UPDATE, aura_buffer_buf(e));
411 aura_buffer_free(e);
413 /* response might have been READY, CANCEL, or ABORT */
415 *cancelled = 0;
416 if (aura_buffer_buf(c->ebuf)[0] == DFUI_FE_MSG_CANCEL) {
417 *cancelled = 1;
419 if (aura_buffer_buf(c->ebuf)[0] == DFUI_FE_MSG_ABORT) {
420 return(DFUI_FAILURE);
421 } else {
422 return(DFUI_SUCCESS);
426 dfui_err_t
427 dfui_be_progress_end(struct dfui_connection *c)
429 c->be_ll_exchange(c, DFUI_BE_MSG_PROG_END, "");
431 /* response might have been be READY or ABORT */
432 if (aura_buffer_buf(c->ebuf)[0] == DFUI_FE_MSG_ABORT) {
433 return(DFUI_FAILURE);
434 } else {
435 return(DFUI_SUCCESS);
439 dfui_err_t
440 dfui_be_set_global_setting(struct dfui_connection *c,
441 const char *key, const char *value,
442 int *cancelled)
444 struct aura_buffer *e;
445 struct dfui_property *p;
447 e = aura_buffer_new(16384);
448 p = dfui_property_new(key, value);
449 dfui_encode_property(e, p);
450 c->be_ll_exchange(c, DFUI_BE_MSG_SET_GLOBAL, aura_buffer_buf(e));
451 aura_buffer_free(e);
452 dfui_property_free(p);
454 /* response might have been READY, CANCEL, or ABORT */
456 *cancelled = 0;
457 if (aura_buffer_buf(c->ebuf)[0] == DFUI_FE_MSG_CANCEL) {
458 *cancelled = 1;
460 if (aura_buffer_buf(c->ebuf)[0] == DFUI_FE_MSG_ABORT) {
461 return(DFUI_FAILURE);
462 } else {
463 return(DFUI_SUCCESS);
467 /******** FRONTEND ********/
469 dfui_err_t
470 dfui_fe_connect(struct dfui_connection *c)
472 return(c->fe_connect(c));
475 dfui_err_t
476 dfui_fe_disconnect(struct dfui_connection *c)
478 dfui_debug("DISCONNECTING<<>>\n");
479 return(c->fe_disconnect(c));
483 * Receive a message from the backend. This call is synchronous;
484 * it does not return until a message comes in from the backend.
485 * After this call, the message type is available in *msgtype,
486 * and the message itself (if any) is available in *payload, ready
487 * to be casted to its real type (as per *msgtype).
489 dfui_err_t
490 dfui_fe_receive(struct dfui_connection *c, char *msgtype, void **payload)
492 struct aura_buffer *e;
494 c->fe_ll_request(c, DFUI_FE_MSG_READY, "");
495 *msgtype = aura_buffer_buf(c->ebuf)[0];
496 switch (*msgtype) {
497 case DFUI_BE_MSG_PRESENT:
498 e = aura_buffer_new(16384);
499 aura_buffer_set(e, aura_buffer_buf(c->ebuf) + 1, aura_buffer_len(c->ebuf) - 1);
500 *payload = dfui_decode_form(e);
501 aura_buffer_free(e);
502 return(DFUI_SUCCESS);
504 case DFUI_BE_MSG_PROG_BEGIN:
505 e = aura_buffer_new(16384);
506 aura_buffer_set(e, aura_buffer_buf(c->ebuf) + 1, aura_buffer_len(c->ebuf) - 1);
507 *payload = dfui_decode_progress(e);
508 aura_buffer_free(e);
509 return(DFUI_SUCCESS);
511 case DFUI_BE_MSG_PROG_UPDATE:
512 e = aura_buffer_new(16384);
513 aura_buffer_set(e, aura_buffer_buf(c->ebuf) + 1, aura_buffer_len(c->ebuf) - 1);
514 *payload = dfui_decode_progress(e);
515 aura_buffer_free(e);
516 return(DFUI_SUCCESS);
518 case DFUI_BE_MSG_PROG_END:
519 *payload = NULL;
520 return(DFUI_SUCCESS);
522 case DFUI_BE_MSG_SET_GLOBAL:
523 e = aura_buffer_new(16384);
524 aura_buffer_set(e, aura_buffer_buf(c->ebuf) + 1, aura_buffer_len(c->ebuf) - 1);
525 *payload = dfui_decode_property(e);
526 aura_buffer_free(e);
527 return(DFUI_SUCCESS);
529 case DFUI_BE_MSG_STOP:
530 *payload = NULL;
531 return(DFUI_SUCCESS);
533 default:
534 /* XXX ??? */
535 return(DFUI_FAILURE);
540 * Wrapper function for dfui_fe_receive for binding generators which
541 * seem to (understandably) have problems wrapping void *'s themselves.
543 struct dfui_payload *
544 dfui_fe_receive_payload(struct dfui_connection *c)
546 char msgtype;
547 void *v;
548 struct dfui_payload *payload;
550 if (!dfui_fe_receive(c, &msgtype, &v)) {
551 return(NULL);
554 AURA_MALLOC(payload, dfui_payload);
556 payload->msgtype = msgtype;
557 payload->form = NULL;
558 payload->progress = NULL;
560 switch (msgtype) {
561 case DFUI_BE_MSG_PRESENT:
562 payload->form = v;
563 break;
565 case DFUI_BE_MSG_PROG_BEGIN:
566 case DFUI_BE_MSG_PROG_UPDATE:
567 payload->progress = v;
568 break;
570 case DFUI_BE_MSG_SET_GLOBAL:
571 payload->global_setting = v;
572 break;
574 case DFUI_BE_MSG_PROG_END:
575 case DFUI_BE_MSG_STOP:
576 break;
579 return(payload);
582 char
583 dfui_payload_get_msg_type(const struct dfui_payload *p)
585 if (p == NULL)
586 return(' ');
587 return(p->msgtype);
590 struct dfui_form *
591 dfui_payload_get_form(const struct dfui_payload *p)
593 if (p == NULL)
594 return(NULL);
595 return(p->form);
598 struct dfui_progress *
599 dfui_payload_get_progress(const struct dfui_payload *p)
601 if (p == NULL)
602 return(NULL);
603 return(p->progress);
606 void
607 dfui_payload_free(struct dfui_payload *p)
609 if (p == NULL)
610 return;
611 if (p->form != NULL)
612 dfui_form_free(p->form);
613 if (p->progress != NULL)
614 dfui_progress_free(p->progress);
615 AURA_FREE(p, dfui_payload);
619 * Submit the result of a form to the backend.
621 dfui_err_t
622 dfui_fe_submit(struct dfui_connection *c, struct dfui_response *r)
624 struct aura_buffer *e;
625 dfui_err_t request_error;
627 e = aura_buffer_new(16384);
628 dfui_encode_response(e, r);
630 dfui_debug("ENCODE<<%s>>\n", aura_buffer_buf(e));
631 request_error = c->fe_ll_request(c, DFUI_FE_MSG_SUBMIT,
632 aura_buffer_buf(e));
633 /* XXX we should check for READY from the backend? */
634 aura_buffer_free(e);
636 return(request_error);
639 dfui_err_t
640 dfui_fe_progress_continue(struct dfui_connection *c)
642 c->fe_ll_request(c, DFUI_FE_MSG_CONTINUE, "");
643 return(DFUI_SUCCESS);
646 dfui_err_t
647 dfui_fe_progress_cancel(struct dfui_connection *c)
649 c->fe_ll_request(c, DFUI_FE_MSG_CANCEL, "");
650 return(DFUI_SUCCESS);
653 dfui_err_t
654 dfui_fe_confirm_set_global(struct dfui_connection *c)
656 c->fe_ll_request(c, DFUI_FE_MSG_CONTINUE, "");
657 return(DFUI_SUCCESS);
660 dfui_err_t
661 dfui_fe_cancel_set_global(struct dfui_connection *c)
663 c->fe_ll_request(c, DFUI_FE_MSG_CANCEL, "");
664 return(DFUI_SUCCESS);
667 dfui_err_t
668 dfui_fe_confirm_stop(struct dfui_connection *c)
670 c->fe_ll_request(c, DFUI_FE_MSG_CONTINUE, "");
671 return(DFUI_SUCCESS);
675 * Abort the backend.
676 * Note that you still must call dfui_fe_disconnect after this.
678 dfui_err_t
679 dfui_fe_abort(struct dfui_connection *c)
681 c->fe_ll_request(c, DFUI_FE_MSG_ABORT, "");
682 return(DFUI_SUCCESS);