2003-07-31 Marcus Brinkmann <marcus@g10code.de>
[gpgme.git] / gpgme / wait.c
1 /* wait.c 
2    Copyright (C) 2000 Werner Koch (dd9jn)
3    Copyright (C) 2001, 2002, 2003 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 General Public License as published by
9    the Free Software Foundation; either version 2 of the License, or
10    (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    General Public License for more details.
16  
17    You should have received a copy of the GNU General Public License
18    along with GPGME; if not, write to the Free Software Foundation,
19    Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
20
21 #if HAVE_CONFIG_H
22 #include <config.h>
23 #endif
24 #include <stdlib.h>
25 #include <string.h>
26 #include <assert.h>
27 #include <errno.h>
28 #include <sys/types.h>
29
30 #include "util.h"
31 #include "context.h"
32 #include "ops.h"
33 #include "wait.h"
34 #include "sema.h"
35 #include "io.h"
36 #include "engine.h"
37 #include "debug.h"
38
39 \f
40 void
41 _gpgme_fd_table_init (fd_table_t fdt)
42 {
43   fdt->fds = NULL;
44   fdt->size = 0;
45 }
46
47 void
48 _gpgme_fd_table_deinit (fd_table_t fdt)
49 {
50   if (fdt->fds)
51     free (fdt->fds);
52 }
53
54
55 /* XXX We should keep a marker and roll over for speed.  */
56 static gpgme_error_t
57 fd_table_put (fd_table_t fdt, int fd, int dir, void *opaque, int *idx)
58 {
59   unsigned int i, j;
60   struct io_select_fd_s *new_fds;
61
62   for (i = 0; i < fdt->size; i++)
63     {
64       if (fdt->fds[i].fd == -1)
65         break;
66     }
67   if (i == fdt->size)
68     {
69 #define FDT_ALLOCSIZE 10
70       new_fds = realloc (fdt->fds, (fdt->size + FDT_ALLOCSIZE)
71                          * sizeof (*new_fds));
72       if (!new_fds)
73         return gpg_error_from_errno (errno);
74       
75       fdt->fds = new_fds;
76       fdt->size += FDT_ALLOCSIZE;
77       for (j = 0; j < FDT_ALLOCSIZE; j++)
78         fdt->fds[i + j].fd = -1;
79     }
80
81   fdt->fds[i].fd = fd;
82   fdt->fds[i].for_read = (dir == 1);
83   fdt->fds[i].for_write = (dir == 0);
84   fdt->fds[i].frozen = 0;
85   fdt->fds[i].signaled = 0;
86   fdt->fds[i].opaque = opaque;
87   *idx = i;
88   return 0;
89 }
90
91 \f
92 /* Register the file descriptor FD with the handler FNC (which gets
93    FNC_DATA as its first argument) for the direction DIR.  DATA should
94    be the context for which the fd is added.  R_TAG will hold the tag
95    that can be used to remove the fd.  */
96 gpgme_error_t
97 _gpgme_add_io_cb (void *data, int fd, int dir, gpgme_io_cb_t fnc,
98                   void *fnc_data, void **r_tag)
99 {
100   gpgme_error_t err;
101   gpgme_ctx_t ctx = (gpgme_ctx_t) data;
102   fd_table_t fdt;
103   struct wait_item_s *item;
104   struct tag *tag;
105
106   assert (fnc);
107   assert (ctx);
108
109   fdt = &ctx->fdt;
110   assert (fdt);
111
112   tag = malloc (sizeof *tag);
113   if (!tag)
114     return gpg_error_from_errno (errno);
115   tag->ctx = ctx;
116
117   /* Allocate a structure to hold information about the handler.  */
118   item = calloc (1, sizeof *item);
119   if (!item)
120     {
121       int saved_errno = errno;
122       free (tag);
123       return gpg_error_from_errno (saved_errno);
124     }
125   item->ctx = ctx;
126   item->dir = dir;
127   item->handler = fnc;
128   item->handler_value = fnc_data;
129
130   err = fd_table_put (fdt, fd, dir, item, &tag->idx);
131   if (err)
132     {
133       free (tag);
134       free (item);
135       return err;
136     }
137
138   *r_tag = tag;
139   return 0;
140 }
141
142
143 void
144 _gpgme_remove_io_cb (void *data)
145 {
146   struct tag *tag = data;
147   gpgme_ctx_t ctx;
148   fd_table_t fdt;
149   int idx;
150
151   assert (tag);
152   ctx = tag->ctx;
153   assert (ctx);
154   fdt = &ctx->fdt;
155   assert (fdt);
156   idx = tag->idx;
157
158   DEBUG2 ("setting fd %d (item=%p) done", fdt->fds[idx].fd,
159           fdt->fds[idx].opaque);
160   free (fdt->fds[idx].opaque);
161   free (tag);
162
163   /* Free the table entry.  */
164   fdt->fds[idx].fd = -1;
165   fdt->fds[idx].for_read = 0;
166   fdt->fds[idx].for_write = 0;
167   fdt->fds[idx].opaque = NULL;
168 }