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: 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.
46 #include <libaura/mem.h>
47 #include <libaura/buffer.h>
50 #define NEEDS_DFUI_STRUCTURE_DEFINITIONS
52 #undef NEEDS_DFUI_STRUCTURE_DEFINITIONS
56 #include "conn_npipe.h"
59 struct dfui_connection
*
60 dfui_connection_new(int transport
, const char *rendezvous
)
62 struct dfui_connection
*c
= NULL
;
66 transport
== DFUI_TRANSPORT_NPIPE
||
69 transport
== DFUI_TRANSPORT_TCP
||
77 if (dfui_debug_file
== NULL
) {
78 dfui_debug_file
= stderr
;
80 setvbuf(dfui_debug_file
, NULL
, _IOLBF
, 0);
83 AURA_MALLOC(c
, dfui_connection
);
84 c
->rendezvous
= aura_strdup(rendezvous
);
85 c
->transport
= transport
;
86 c
->ebuf
= aura_buffer_new(16384);
92 case DFUI_TRANSPORT_NPIPE
:
93 AURA_MALLOC(c
->t_data
, dfui_conn_npipe
);
94 T_NPIPE(c
)->in_pipename
= NULL
;
95 T_NPIPE(c
)->out_pipename
= NULL
;
96 T_NPIPE(c
)->in
= NULL
;
97 T_NPIPE(c
)->out
= NULL
;
100 * Set up dispatch functions.
102 c
->be_start
= dfui_npipe_be_start
;
103 c
->be_stop
= dfui_npipe_be_stop
;
104 c
->be_ll_exchange
= dfui_npipe_be_ll_exchange
;
106 c
->fe_connect
= dfui_npipe_fe_connect
;
107 c
->fe_disconnect
= dfui_npipe_fe_disconnect
;
108 c
->fe_ll_request
= dfui_npipe_fe_ll_request
;
110 #endif /* HAS_NPIPE */
113 case DFUI_TRANSPORT_TCP
:
114 AURA_MALLOC(c
->t_data
, dfui_conn_tcp
);
115 T_TCP(c
)->listen_sd
= -1;
116 T_TCP(c
)->connected_sd
= -1;
117 T_TCP(c
)->is_connected
= 0;
120 * Set up dispatch functions.
122 c
->be_start
= dfui_tcp_be_start
;
123 c
->be_stop
= dfui_tcp_be_stop
;
124 c
->be_ll_exchange
= dfui_tcp_be_ll_exchange
;
126 c
->fe_connect
= dfui_tcp_fe_connect
;
127 c
->fe_disconnect
= dfui_tcp_fe_disconnect
;
128 c
->fe_ll_request
= dfui_tcp_fe_ll_request
;
137 dfui_connection_free(struct dfui_connection
*c
)
142 switch (c
->transport
) {
144 case DFUI_TRANSPORT_NPIPE
:
145 if (T_NPIPE(c
) != NULL
) {
146 if (T_NPIPE(c
)->in_pipename
!= NULL
)
147 aura_free(T_NPIPE(c
)->in_pipename
, "pipename");
148 if (T_NPIPE(c
)->out_pipename
!= NULL
)
149 aura_free(T_NPIPE(c
)->out_pipename
, "pipename");
150 if (T_NPIPE(c
)->in
!= NULL
)
151 fclose(T_NPIPE(c
)->in
);
152 if (T_NPIPE(c
)->out
!= NULL
)
153 fclose(T_NPIPE(c
)->out
);
154 AURA_FREE(T_NPIPE(c
), dfui_conn_npipe
);
159 case DFUI_TRANSPORT_TCP
:
160 if (T_TCP(c
) != NULL
) {
161 /* XXX close sockets/files here */
162 AURA_FREE(T_NPIPE(c
), dfui_conn_tcp
);
168 if (c
->rendezvous
!= NULL
)
170 AURA_FREE(c
, dfui_connection
);
178 * Create and present a generic `dialog box'-type form for the user
179 * and return their response. actions is a pipe-seperated list of
180 * actions to be put on the form (e.g. "OK|Cancel".) The return
181 * value is the ordinal position of the action that was selected,
182 * starting at 1 for the first action. A return value of 0 indicates
183 * that an error occurred. A return value of -1 indicates that the
184 * front end aborted the communications.
187 dfui_be_present_dialog(struct dfui_connection
*c
, const char *title
,
188 const char *actions
, const char *fmt
, ...)
191 struct dfui_response
*r
;
194 char action_id
[256], action_name
[256];
195 size_t start
, end
, counter
, i
;
198 vasprintf(&message
, fmt
, args
);
201 f
= dfui_form_create("dialog", title
, message
, "", NULL
);
206 while (actions
[end
] != '\0') {
208 while (actions
[end
] != '|' && actions
[end
] != '\0')
211 if ((end
- start
) >= 256)
213 strncpy(action_name
, &actions
[start
], end
- start
);
214 action_name
[end
- start
] = '\0';
215 strcpy(action_id
, action_name
);
216 for(i
= 0; action_id
[i
] != '\0'; i
++) {
217 if (action_id
[i
] == ' ')
220 dfui_form_action_add(f
, action_id
,
221 dfui_info_new(action_name
, "", ""));
226 if (!dfui_be_present(c
, f
, &r
)) {
228 dfui_response_free(r
);
232 strlcpy(action_name
, dfui_response_get_action_id(r
), 256);
233 for(i
= 0; action_name
[i
] != '\0'; i
++) {
234 if (action_name
[i
] == '_')
235 action_name
[i
] = ' ';
240 while (actions
[end
] != '\0') {
242 while (actions
[end
] != '|' && actions
[end
] != '\0')
245 if ((end
- start
) >= 256)
247 if (strlen(action_name
) == (end
- start
) &&
248 strncmp(action_name
, &actions
[start
], end
- start
) == 0) {
257 dfui_response_free(r
);
262 /******** BACKEND ********/
265 * Connect to the frontend.
268 dfui_be_start(struct dfui_connection
*c
)
270 if (c
->is_connected
) {
271 return(DFUI_FAILURE
);
272 } else if (c
->be_start(c
)) {
274 return(DFUI_SUCCESS
);
276 return(DFUI_FAILURE
);
281 * Tell the frontend that we're done and disconnect from it.
284 dfui_be_stop(struct dfui_connection
*c
)
286 if (!c
->is_connected
) {
287 return(DFUI_SUCCESS
);
288 } else if (c
->be_stop(c
)) {
290 return(DFUI_SUCCESS
);
292 return(DFUI_FAILURE
);
297 * Present a form to the user. This call is synchronous;
298 * it does not return until the user has selected an action.
301 dfui_be_present(struct dfui_connection
*c
,
302 struct dfui_form
*f
, struct dfui_response
**r
)
304 struct aura_buffer
*e
;
306 e
= aura_buffer_new(16384);
307 dfui_encode_form(e
, f
);
309 c
->be_ll_exchange(c
, DFUI_BE_MSG_PRESENT
, aura_buffer_buf(e
));
313 /* check for ABORT reply */
314 if (aura_buffer_buf(c
->ebuf
)[0] == DFUI_FE_MSG_ABORT
) {
315 return(DFUI_FAILURE
);
319 * Now we've got the response; so decode it.
322 e
= aura_buffer_new(16384);
323 aura_buffer_set(e
, aura_buffer_buf(c
->ebuf
) + 1, aura_buffer_len(c
->ebuf
) - 1);
324 *r
= dfui_decode_response(e
);
327 return(DFUI_SUCCESS
);
331 * Begin showing a progress bar to the user.
332 * This function is asynchronous; it returns immediately.
333 * The assumption is that the backend will make subsequent
334 * calls to dfui_be_progress_update() frequently, and in
335 * them, check to see if the user cancelled.
338 dfui_be_progress_begin(struct dfui_connection
*c
, struct dfui_progress
*pr
)
340 struct aura_buffer
*e
;
342 e
= aura_buffer_new(16384);
343 dfui_encode_progress(e
, pr
);
345 c
->be_ll_exchange(c
, DFUI_BE_MSG_PROG_BEGIN
, aura_buffer_buf(e
));
348 /* response might have been be READY or ABORT */
349 if (aura_buffer_buf(c
->ebuf
)[0] == DFUI_FE_MSG_ABORT
) {
350 return(DFUI_FAILURE
);
352 return(DFUI_SUCCESS
);
357 dfui_be_progress_update(struct dfui_connection
*c
,
358 struct dfui_progress
*pr
, int *cancelled
)
360 struct aura_buffer
*e
;
362 e
= aura_buffer_new(16384);
363 dfui_encode_progress(e
, pr
);
365 c
->be_ll_exchange(c
, DFUI_BE_MSG_PROG_UPDATE
, aura_buffer_buf(e
));
368 /* response might have been READY, CANCEL, or ABORT */
371 if (aura_buffer_buf(c
->ebuf
)[0] == DFUI_FE_MSG_CANCEL
) {
374 if (aura_buffer_buf(c
->ebuf
)[0] == DFUI_FE_MSG_ABORT
) {
375 return(DFUI_FAILURE
);
377 return(DFUI_SUCCESS
);
382 dfui_be_progress_end(struct dfui_connection
*c
)
384 c
->be_ll_exchange(c
, DFUI_BE_MSG_PROG_END
, "");
386 /* response might have been be READY or ABORT */
387 if (aura_buffer_buf(c
->ebuf
)[0] == DFUI_FE_MSG_ABORT
) {
388 return(DFUI_FAILURE
);
390 return(DFUI_SUCCESS
);
395 dfui_be_set_global_setting(struct dfui_connection
*c
,
396 const char *key
, const char *value
,
399 struct aura_buffer
*e
;
400 struct dfui_property
*p
;
402 e
= aura_buffer_new(16384);
403 p
= dfui_property_new(key
, value
);
404 dfui_encode_property(e
, p
);
405 c
->be_ll_exchange(c
, DFUI_BE_MSG_SET_GLOBAL
, aura_buffer_buf(e
));
407 dfui_property_free(p
);
409 /* response might have been READY, CANCEL, or ABORT */
412 if (aura_buffer_buf(c
->ebuf
)[0] == DFUI_FE_MSG_CANCEL
) {
415 if (aura_buffer_buf(c
->ebuf
)[0] == DFUI_FE_MSG_ABORT
) {
416 return(DFUI_FAILURE
);
418 return(DFUI_SUCCESS
);
422 /******** FRONTEND ********/
425 dfui_fe_connect(struct dfui_connection
*c
)
427 return(c
->fe_connect(c
));
431 dfui_fe_disconnect(struct dfui_connection
*c
)
433 dfui_debug("DISCONNECTING<<>>\n");
434 return(c
->fe_disconnect(c
));
438 * Receive a message from the backend. This call is synchronous;
439 * it does not return until a message comes in from the backend.
440 * After this call, the message type is available in *msgtype,
441 * and the message itself (if any) is available in *payload, ready
442 * to be casted to its real type (as per *msgtype).
445 dfui_fe_receive(struct dfui_connection
*c
, char *msgtype
, void **payload
)
447 struct aura_buffer
*e
;
449 c
->fe_ll_request(c
, DFUI_FE_MSG_READY
, "");
450 *msgtype
= aura_buffer_buf(c
->ebuf
)[0];
452 case DFUI_BE_MSG_PRESENT
:
453 e
= aura_buffer_new(16384);
454 aura_buffer_set(e
, aura_buffer_buf(c
->ebuf
) + 1, aura_buffer_len(c
->ebuf
) - 1);
455 *payload
= dfui_decode_form(e
);
457 return(DFUI_SUCCESS
);
459 case DFUI_BE_MSG_PROG_BEGIN
:
460 e
= aura_buffer_new(16384);
461 aura_buffer_set(e
, aura_buffer_buf(c
->ebuf
) + 1, aura_buffer_len(c
->ebuf
) - 1);
462 *payload
= dfui_decode_progress(e
);
464 return(DFUI_SUCCESS
);
466 case DFUI_BE_MSG_PROG_UPDATE
:
467 e
= aura_buffer_new(16384);
468 aura_buffer_set(e
, aura_buffer_buf(c
->ebuf
) + 1, aura_buffer_len(c
->ebuf
) - 1);
469 *payload
= dfui_decode_progress(e
);
471 return(DFUI_SUCCESS
);
473 case DFUI_BE_MSG_PROG_END
:
475 return(DFUI_SUCCESS
);
477 case DFUI_BE_MSG_SET_GLOBAL
:
478 e
= aura_buffer_new(16384);
479 aura_buffer_set(e
, aura_buffer_buf(c
->ebuf
) + 1, aura_buffer_len(c
->ebuf
) - 1);
480 *payload
= dfui_decode_property(e
);
482 return(DFUI_SUCCESS
);
484 case DFUI_BE_MSG_STOP
:
486 return(DFUI_SUCCESS
);
490 return(DFUI_FAILURE
);
495 * Wrapper function for dfui_fe_receive for binding generators which
496 * seem to (understandably) have problems wrapping void *'s themselves.
498 struct dfui_payload
*
499 dfui_fe_receive_payload(struct dfui_connection
*c
)
503 struct dfui_payload
*payload
;
505 if (!dfui_fe_receive(c
, &msgtype
, &v
)) {
509 AURA_MALLOC(payload
, dfui_payload
);
511 payload
->msgtype
= msgtype
;
512 payload
->form
= NULL
;
513 payload
->progress
= NULL
;
516 case DFUI_BE_MSG_PRESENT
:
520 case DFUI_BE_MSG_PROG_BEGIN
:
521 case DFUI_BE_MSG_PROG_UPDATE
:
522 payload
->progress
= v
;
525 case DFUI_BE_MSG_SET_GLOBAL
:
526 payload
->global_setting
= v
;
529 case DFUI_BE_MSG_PROG_END
:
530 case DFUI_BE_MSG_STOP
:
538 dfui_payload_get_msg_type(const struct dfui_payload
*p
)
546 dfui_payload_get_form(const struct dfui_payload
*p
)
553 struct dfui_progress
*
554 dfui_payload_get_progress(const struct dfui_payload
*p
)
562 dfui_payload_free(struct dfui_payload
*p
)
567 dfui_form_free(p
->form
);
568 if (p
->progress
!= NULL
)
569 dfui_progress_free(p
->progress
);
570 AURA_FREE(p
, dfui_payload
);
574 * Submit the result of a form to the backend.
577 dfui_fe_submit(struct dfui_connection
*c
, struct dfui_response
*r
)
579 struct aura_buffer
*e
;
580 dfui_err_t request_error
;
582 e
= aura_buffer_new(16384);
583 dfui_encode_response(e
, r
);
585 dfui_debug("ENCODE<<%s>>\n", aura_buffer_buf(e
));
586 request_error
= c
->fe_ll_request(c
, DFUI_FE_MSG_SUBMIT
,
588 /* XXX we should check for READY from the backend? */
591 return(request_error
);
595 dfui_fe_progress_continue(struct dfui_connection
*c
)
597 c
->fe_ll_request(c
, DFUI_FE_MSG_CONTINUE
, "");
598 return(DFUI_SUCCESS
);
602 dfui_fe_progress_cancel(struct dfui_connection
*c
)
604 c
->fe_ll_request(c
, DFUI_FE_MSG_CANCEL
, "");
605 return(DFUI_SUCCESS
);
609 dfui_fe_confirm_set_global(struct dfui_connection
*c
)
611 c
->fe_ll_request(c
, DFUI_FE_MSG_CONTINUE
, "");
612 return(DFUI_SUCCESS
);
616 dfui_fe_cancel_set_global(struct dfui_connection
*c
)
618 c
->fe_ll_request(c
, DFUI_FE_MSG_CANCEL
, "");
619 return(DFUI_SUCCESS
);
623 dfui_fe_confirm_stop(struct dfui_connection
*c
)
625 c
->fe_ll_request(c
, DFUI_FE_MSG_CONTINUE
, "");
626 return(DFUI_SUCCESS
);
631 * Note that you still must call dfui_fe_disconnect after this.
634 dfui_fe_abort(struct dfui_connection
*c
)
636 c
->fe_ll_request(c
, DFUI_FE_MSG_ABORT
, "");
637 return(DFUI_SUCCESS
);