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_caps.h"
57 #include "conn_npipe.h"
60 struct dfui_connection
*
61 dfui_connection_new(int transport
, const char *rendezvous
)
63 struct dfui_connection
*c
= NULL
;
67 transport
== DFUI_TRANSPORT_CAPS
||
70 transport
== DFUI_TRANSPORT_NPIPE
||
73 transport
== DFUI_TRANSPORT_TCP
||
81 if (dfui_debug_file
== NULL
) {
82 dfui_debug_file
= stderr
;
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);
96 case DFUI_TRANSPORT_CAPS
:
97 AURA_MALLOC(c
->t_data
, dfui_conn_caps
);
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
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
);
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
;
125 #endif /* HAS_CAPS */
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
;
146 #endif /* HAS_NPIPE */
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
;
173 dfui_connection_free(struct dfui_connection
*c
)
178 switch (c
->transport
) {
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
);
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
);
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
);
213 if (c
->rendezvous
!= NULL
)
215 AURA_FREE(c
, dfui_connection
);
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
, ...)
236 struct dfui_response
*r
;
239 char action_id
[256], action_name
[256];
240 size_t start
, end
, counter
, i
;
243 vasprintf(&message
, fmt
, args
);
246 f
= dfui_form_create("dialog", title
, message
, "", NULL
);
251 while (actions
[end
] != '\0') {
253 while (actions
[end
] != '|' && actions
[end
] != '\0')
256 if ((end
- start
) >= 256)
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
] == ' ')
265 dfui_form_action_add(f
, action_id
,
266 dfui_info_new(action_name
, "", ""));
271 if (!dfui_be_present(c
, f
, &r
)) {
273 dfui_response_free(r
);
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
] = ' ';
285 while (actions
[end
] != '\0') {
287 while (actions
[end
] != '|' && actions
[end
] != '\0')
290 if ((end
- start
) >= 256)
292 if (strlen(action_name
) == (end
- start
) &&
293 strncmp(action_name
, &actions
[start
], end
- start
) == 0) {
302 dfui_response_free(r
);
307 /******** BACKEND ********/
310 * Connect to the frontend.
313 dfui_be_start(struct dfui_connection
*c
)
315 if (c
->is_connected
) {
316 return(DFUI_FAILURE
);
317 } else if (c
->be_start(c
)) {
319 return(DFUI_SUCCESS
);
321 return(DFUI_FAILURE
);
326 * Tell the frontend that we're done and disconnect from it.
329 dfui_be_stop(struct dfui_connection
*c
)
331 if (!c
->is_connected
) {
332 return(DFUI_SUCCESS
);
333 } else if (c
->be_stop(c
)) {
335 return(DFUI_SUCCESS
);
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.
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
));
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
);
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.
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
));
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
);
397 return(DFUI_SUCCESS
);
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
));
413 /* response might have been READY, CANCEL, or ABORT */
416 if (aura_buffer_buf(c
->ebuf
)[0] == DFUI_FE_MSG_CANCEL
) {
419 if (aura_buffer_buf(c
->ebuf
)[0] == DFUI_FE_MSG_ABORT
) {
420 return(DFUI_FAILURE
);
422 return(DFUI_SUCCESS
);
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
);
435 return(DFUI_SUCCESS
);
440 dfui_be_set_global_setting(struct dfui_connection
*c
,
441 const char *key
, const char *value
,
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
));
452 dfui_property_free(p
);
454 /* response might have been READY, CANCEL, or ABORT */
457 if (aura_buffer_buf(c
->ebuf
)[0] == DFUI_FE_MSG_CANCEL
) {
460 if (aura_buffer_buf(c
->ebuf
)[0] == DFUI_FE_MSG_ABORT
) {
461 return(DFUI_FAILURE
);
463 return(DFUI_SUCCESS
);
467 /******** FRONTEND ********/
470 dfui_fe_connect(struct dfui_connection
*c
)
472 return(c
->fe_connect(c
));
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).
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];
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
);
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
);
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
);
516 return(DFUI_SUCCESS
);
518 case DFUI_BE_MSG_PROG_END
:
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
);
527 return(DFUI_SUCCESS
);
529 case DFUI_BE_MSG_STOP
:
531 return(DFUI_SUCCESS
);
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
)
548 struct dfui_payload
*payload
;
550 if (!dfui_fe_receive(c
, &msgtype
, &v
)) {
554 AURA_MALLOC(payload
, dfui_payload
);
556 payload
->msgtype
= msgtype
;
557 payload
->form
= NULL
;
558 payload
->progress
= NULL
;
561 case DFUI_BE_MSG_PRESENT
:
565 case DFUI_BE_MSG_PROG_BEGIN
:
566 case DFUI_BE_MSG_PROG_UPDATE
:
567 payload
->progress
= v
;
570 case DFUI_BE_MSG_SET_GLOBAL
:
571 payload
->global_setting
= v
;
574 case DFUI_BE_MSG_PROG_END
:
575 case DFUI_BE_MSG_STOP
:
583 dfui_payload_get_msg_type(const struct dfui_payload
*p
)
591 dfui_payload_get_form(const struct dfui_payload
*p
)
598 struct dfui_progress
*
599 dfui_payload_get_progress(const struct dfui_payload
*p
)
607 dfui_payload_free(struct dfui_payload
*p
)
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.
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
,
633 /* XXX we should check for READY from the backend? */
636 return(request_error
);
640 dfui_fe_progress_continue(struct dfui_connection
*c
)
642 c
->fe_ll_request(c
, DFUI_FE_MSG_CONTINUE
, "");
643 return(DFUI_SUCCESS
);
647 dfui_fe_progress_cancel(struct dfui_connection
*c
)
649 c
->fe_ll_request(c
, DFUI_FE_MSG_CANCEL
, "");
650 return(DFUI_SUCCESS
);
654 dfui_fe_confirm_set_global(struct dfui_connection
*c
)
656 c
->fe_ll_request(c
, DFUI_FE_MSG_CONTINUE
, "");
657 return(DFUI_SUCCESS
);
661 dfui_fe_cancel_set_global(struct dfui_connection
*c
)
663 c
->fe_ll_request(c
, DFUI_FE_MSG_CANCEL
, "");
664 return(DFUI_SUCCESS
);
668 dfui_fe_confirm_stop(struct dfui_connection
*c
)
670 c
->fe_ll_request(c
, DFUI_FE_MSG_CONTINUE
, "");
671 return(DFUI_SUCCESS
);
676 * Note that you still must call dfui_fe_disconnect after this.
679 dfui_fe_abort(struct dfui_connection
*c
)
681 c
->fe_ll_request(c
, DFUI_FE_MSG_ABORT
, "");
682 return(DFUI_SUCCESS
);