Line data Source code
1 : /* wait-private.c
2 : Copyright (C) 2000 Werner Koch (dd9jn)
3 : Copyright (C) 2001, 2002, 2003, 2004, 2005 g10 Code GmbH
4 :
5 : This file is part of GPGME.
6 :
7 : GPGME is free software; you can redistribute it and/or modify it
8 : under the terms of the GNU Lesser General Public License as
9 : published by the Free Software Foundation; either version 2.1 of
10 : the License, or (at your option) any later version.
11 :
12 : GPGME is distributed in the hope that it will be useful, but
13 : WITHOUT ANY WARRANTY; without even the implied warranty of
14 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 : Lesser General Public License for more details.
16 :
17 : You should have received a copy of the GNU Lesser General Public
18 : License along with this program; if not, write to the Free Software
19 : Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
20 : 02111-1307, USA. */
21 :
22 : #if HAVE_CONFIG_H
23 : #include <config.h>
24 : #endif
25 : #include <assert.h>
26 : #include <errno.h>
27 :
28 : #include "gpgme.h"
29 : #include "context.h"
30 : #include "wait.h"
31 : #include "ops.h"
32 : #include "priv-io.h"
33 : #include "util.h"
34 : #include "debug.h"
35 :
36 :
37 : /* The private event loops are used for all blocking operations, and
38 : for the key and trust item listing operations. They are completely
39 : separated from each other. */
40 :
41 :
42 : /* Internal I/O callback functions. */
43 :
44 : /* The add_io_cb and remove_io_cb handlers are shared with the global
45 : event loops. */
46 :
47 : void
48 6391 : _gpgme_wait_private_event_cb (void *data, gpgme_event_io_t type,
49 : void *type_data)
50 : {
51 6391 : switch (type)
52 : {
53 : case GPGME_EVENT_START:
54 : /* Nothing to do here, as the wait routine is called after the
55 : initialization is finished. */
56 696 : break;
57 :
58 : case GPGME_EVENT_DONE:
59 980 : break;
60 :
61 : case GPGME_EVENT_NEXT_KEY:
62 4718 : _gpgme_op_keylist_event_cb (data, type, type_data);
63 4709 : break;
64 :
65 : case GPGME_EVENT_NEXT_TRUSTITEM:
66 0 : _gpgme_op_trustlist_event_cb (data, type, type_data);
67 0 : break;
68 : }
69 6382 : }
70 :
71 :
72 : /* If COND is a null pointer, wait until the blocking operation in CTX
73 : finished and return its error value. Otherwise, wait until COND is
74 : satisfied or the operation finished. */
75 : gpgme_error_t
76 2682 : _gpgme_wait_on_condition (gpgme_ctx_t ctx, volatile int *cond,
77 : gpgme_error_t *op_err_p)
78 : {
79 2682 : gpgme_error_t err = 0;
80 2682 : int hang = 1;
81 :
82 2682 : if (op_err_p)
83 16 : *op_err_p = 0;
84 :
85 : do
86 : {
87 7503 : int nr = _gpgme_io_select (ctx->fdt.fds, ctx->fdt.size, 0);
88 : unsigned int i;
89 :
90 7560 : if (nr < 0)
91 : {
92 : /* An error occurred. Close all fds in this context, and
93 : signal it. */
94 0 : err = gpg_error_from_syserror ();
95 0 : _gpgme_cancel_with_err (ctx, err, 0);
96 :
97 0 : return err;
98 : }
99 :
100 19363 : for (i = 0; i < ctx->fdt.size && nr; i++)
101 : {
102 11895 : if (ctx->fdt.fds[i].fd != -1 && ctx->fdt.fds[i].signaled)
103 : {
104 7919 : gpgme_error_t op_err = 0;
105 :
106 7919 : ctx->fdt.fds[i].signaled = 0;
107 7919 : assert (nr);
108 7925 : nr--;
109 :
110 7925 : LOCK (ctx->lock);
111 7924 : if (ctx->canceled)
112 0 : err = gpg_error (GPG_ERR_CANCELED);
113 7924 : UNLOCK (ctx->lock);
114 :
115 7924 : if (!err)
116 7924 : err = _gpgme_run_io_cb (&ctx->fdt.fds[i], 0, &op_err);
117 7852 : if (err)
118 : {
119 : /* An error occurred. Close all fds in this context,
120 : and signal it. */
121 21 : _gpgme_cancel_with_err (ctx, err, 0);
122 :
123 46 : return err;
124 : }
125 7831 : else if (op_err)
126 : {
127 : /* An operational error occurred. Cancel the current
128 : operation but not the session, and signal it. */
129 4 : _gpgme_cancel_with_err (ctx, 0, op_err);
130 :
131 : /* NOTE: This relies on the operational error being
132 : generated after the operation really has
133 : completed, for example after no further status
134 : line output is generated. Otherwise the
135 : following I/O will spill over into the next
136 : operation. */
137 4 : if (op_err_p)
138 4 : *op_err_p = op_err;
139 4 : return 0;
140 : }
141 : }
142 : }
143 :
144 17457 : for (i = 0; i < ctx->fdt.size; i++)
145 16501 : if (ctx->fdt.fds[i].fd != -1)
146 6512 : break;
147 7468 : if (i == ctx->fdt.size)
148 : {
149 : struct gpgme_io_event_done_data data;
150 955 : data.err = 0;
151 955 : data.op_err = 0;
152 955 : _gpgme_engine_io_event (ctx->engine, GPGME_EVENT_DONE, &data);
153 955 : hang = 0;
154 : }
155 7468 : if (cond && *cond)
156 1993 : hang = 0;
157 : }
158 7468 : while (hang);
159 :
160 2647 : return 0;
161 : }
162 :
163 :
164 : /* Wait until the blocking operation in context CTX has finished and
165 : return the error value. This variant can not be used for
166 : session-based protocols. */
167 : gpgme_error_t
168 342 : _gpgme_wait_one (gpgme_ctx_t ctx)
169 : {
170 342 : return _gpgme_wait_on_condition (ctx, NULL, NULL);
171 : }
172 :
173 : /* Wait until the blocking operation in context CTX has finished and
174 : return the error value. This is the right variant to use for
175 : sesion-based protocols. */
176 : gpgme_error_t
177 16 : _gpgme_wait_one_ext (gpgme_ctx_t ctx, gpgme_error_t *op_err)
178 : {
179 16 : return _gpgme_wait_on_condition (ctx, NULL, op_err);
180 : }
|