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 2904 : _gpgme_wait_private_event_cb (void *data, gpgme_event_io_t type,
49 : void *type_data)
50 : {
51 2904 : 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 760 : break;
57 :
58 : case GPGME_EVENT_DONE:
59 1093 : break;
60 :
61 : case GPGME_EVENT_NEXT_KEY:
62 1052 : _gpgme_op_keylist_event_cb (data, type, type_data);
63 1052 : break;
64 :
65 : case GPGME_EVENT_NEXT_TRUSTITEM:
66 0 : _gpgme_op_trustlist_event_cb (data, type, type_data);
67 0 : break;
68 : }
69 2904 : }
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 1410 : _gpgme_wait_on_condition (gpgme_ctx_t ctx, volatile int *cond,
77 : gpgme_error_t *op_err_p)
78 : {
79 1410 : gpgme_error_t err = 0;
80 1410 : int hang = 1;
81 :
82 1410 : if (op_err_p)
83 16 : *op_err_p = 0;
84 :
85 : do
86 : {
87 7919 : int nr = _gpgme_io_select (ctx->fdt.fds, ctx->fdt.size, 0);
88 : unsigned int i;
89 :
90 7914 : 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 22027 : for (i = 0; i < ctx->fdt.size && nr; i++)
101 : {
102 14141 : if (ctx->fdt.fds[i].fd != -1 && ctx->fdt.fds[i].signaled)
103 : {
104 9271 : gpgme_error_t op_err = 0;
105 :
106 9271 : ctx->fdt.fds[i].signaled = 0;
107 9271 : assert (nr);
108 9271 : nr--;
109 :
110 9271 : LOCK (ctx->lock);
111 9273 : if (ctx->canceled)
112 0 : err = gpg_error (GPG_ERR_CANCELED);
113 9273 : UNLOCK (ctx->lock);
114 :
115 9273 : if (!err)
116 9273 : err = _gpgme_run_io_cb (&ctx->fdt.fds[i], 0, &op_err);
117 9272 : if (err)
118 : {
119 : /* An error occurred. Close all fds in this context,
120 : and signal it. */
121 27 : _gpgme_cancel_with_err (ctx, err, 0);
122 :
123 56 : return err;
124 : }
125 9245 : else if (op_err)
126 : {
127 : /* An operational error occurred. Cancel the current
128 : operation but not the session, and signal it. */
129 2 : _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 2 : if (op_err_p)
138 2 : *op_err_p = op_err;
139 2 : return 0;
140 : }
141 : }
142 : }
143 :
144 18665 : for (i = 0; i < ctx->fdt.size; i++)
145 17601 : if (ctx->fdt.fds[i].fd != -1)
146 6822 : break;
147 7886 : if (i == ctx->fdt.size)
148 : {
149 : struct gpgme_io_event_done_data data;
150 1064 : data.err = 0;
151 1064 : data.op_err = 0;
152 1064 : _gpgme_engine_io_event (ctx->engine, GPGME_EVENT_DONE, &data);
153 1064 : hang = 0;
154 : }
155 7886 : if (cond && *cond)
156 629 : hang = 0;
157 : }
158 7886 : while (hang);
159 :
160 1377 : 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 433 : _gpgme_wait_one (gpgme_ctx_t ctx)
169 : {
170 433 : 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 : }
|