core: Add public function gpgme_get_ctx_flag.
[gpgme.git] / src / assuan-support.c
1 #if HAVE_CONFIG_H
2 #include <config.h>
3 #endif
4
5 #include <assert.h>
6 #include <stdlib.h>
7 #include <errno.h>
8
9 #include "assuan.h"
10
11 #include "gpgme.h"
12 #include "ath.h"
13 #include "priv-io.h"
14 #include "debug.h"
15
16 \f
17 struct assuan_malloc_hooks _gpgme_assuan_malloc_hooks =
18   {
19     malloc,
20     realloc,
21     free
22   };
23
24 \f
25 int
26 _gpgme_assuan_log_cb (assuan_context_t ctx, void *hook,
27                       unsigned int cat, const char *msg)
28 {
29   (void)ctx;
30   (void)hook;
31   (void)cat;
32
33   if (msg == NULL)
34     return 1;
35
36   _gpgme_debug (DEBUG_ASSUAN, "%s", msg);
37   return 0;
38 }
39
40 \f
41 static void
42 my_usleep (assuan_context_t ctx, unsigned int usec)
43 {
44   /* FIXME: Add to ath.  */
45   __assuan_usleep (ctx, usec);
46 }
47
48
49 /* Create a pipe with an inheritable end.  */
50 static int
51 my_pipe (assuan_context_t ctx, assuan_fd_t fds[2], int inherit_idx)
52 {
53   int res;
54   int gfds[2];
55
56   (void)ctx;
57
58   res = _gpgme_io_pipe (gfds, inherit_idx);
59
60   /* For now... */
61   fds[0] = (assuan_fd_t) gfds[0];
62   fds[1] = (assuan_fd_t) gfds[1];
63
64   return res;
65 }
66
67
68 /* Close the given file descriptor, created with _assuan_pipe or one
69    of the socket functions.  */
70 static int
71 my_close (assuan_context_t ctx, assuan_fd_t fd)
72 {
73   (void)ctx;
74   return _gpgme_io_close ((int) fd);
75 }
76
77
78 static gpgme_ssize_t
79 my_read (assuan_context_t ctx, assuan_fd_t fd, void *buffer, size_t size)
80 {
81   (void)ctx;
82   return _gpgme_io_read ((int) fd, buffer, size);
83 }
84
85
86 static gpgme_ssize_t
87 my_write (assuan_context_t ctx, assuan_fd_t fd, const void *buffer, size_t size)
88 {
89   (void)ctx;
90   return _gpgme_io_write ((int) fd, buffer, size);
91 }
92
93
94 static int
95 my_recvmsg (assuan_context_t ctx, assuan_fd_t fd, assuan_msghdr_t msg,
96             int flags)
97 {
98   (void)ctx;
99 #ifdef HAVE_W32_SYSTEM
100   (void)fd;
101   (void)msg;
102   (void)flags;
103   gpg_err_set_errno (ENOSYS);
104   return -1;
105 #else
106   return _gpgme_io_recvmsg ((int) fd, msg, flags);
107 #endif
108 }
109
110
111
112 static int
113 my_sendmsg (assuan_context_t ctx, assuan_fd_t fd, const assuan_msghdr_t msg,
114             int flags)
115 {
116   (void)ctx;
117 #ifdef HAVE_W32_SYSTEM
118   (void)fd;
119   (void)msg;
120   (void)flags;
121   gpg_err_set_errno (ENOSYS);
122   return -1;
123 #else
124   return _gpgme_io_sendmsg ((int) fd, msg, flags);
125 #endif
126 }
127
128
129 /* If NAME is NULL, don't exec, just fork.  FD_CHILD_LIST is modified
130    to reflect the value of the FD in the peer process (on
131    Windows).  */
132 static int
133 my_spawn (assuan_context_t ctx, pid_t *r_pid, const char *name,
134           const char **argv,
135           assuan_fd_t fd_in, assuan_fd_t fd_out,
136           assuan_fd_t *fd_child_list,
137           void (*atfork) (void *opaque, int reserved),
138           void *atforkvalue, unsigned int flags)
139 {
140   int err;
141   struct spawn_fd_item_s *fd_items;
142   int i;
143
144   (void)ctx;
145   (void)flags;
146
147   assert (name);
148
149   if (! name)
150     {
151       gpg_err_set_errno (ENOSYS);
152       return -1;
153     }
154
155   i = 0;
156   if (fd_child_list)
157     {
158       while (fd_child_list[i] != ASSUAN_INVALID_FD)
159         i++;
160     }
161   /* fd_in, fd_out, terminator */
162   i += 3;
163   fd_items = calloc (i, sizeof (struct spawn_fd_item_s));
164   if (! fd_items)
165     return -1;
166   i = 0;
167   if (fd_child_list)
168     {
169       while (fd_child_list[i] != ASSUAN_INVALID_FD)
170         {
171           fd_items[i].fd = (int) fd_child_list[i];
172           fd_items[i].dup_to = -1;
173           i++;
174         }
175     }
176   if (fd_in != ASSUAN_INVALID_FD)
177     {
178       fd_items[i].fd = (int) fd_in;
179       fd_items[i].dup_to = 0;
180       i++;
181     }
182   if (fd_out != ASSUAN_INVALID_FD)
183     {
184       fd_items[i].fd = (int) fd_out;
185       fd_items[i].dup_to = 1;
186       i++;
187     }
188   fd_items[i].fd = -1;
189   fd_items[i].dup_to = -1;
190
191   err = _gpgme_io_spawn (name, (char*const*)argv,
192                          (IOSPAWN_FLAG_NOCLOSE | IOSPAWN_FLAG_DETACHED),
193                          fd_items, atfork, atforkvalue, r_pid);
194   if (! err)
195     {
196       i = 0;
197
198       if (fd_child_list)
199         {
200           while (fd_child_list[i] != ASSUAN_INVALID_FD)
201             {
202               fd_child_list[i] = (assuan_fd_t) fd_items[i].peer_name;
203               i++;
204             }
205         }
206     }
207   free (fd_items);
208   return err;
209 }
210
211
212 /* If action is 0, like waitpid.  If action is 1, just release the PID?  */
213 static pid_t
214 my_waitpid (assuan_context_t ctx, pid_t pid,
215             int nowait, int *status, int options)
216 {
217   (void)ctx;
218 #ifdef HAVE_W32_SYSTEM
219   (void)nowait;
220   (void)status;
221   (void)options;
222   CloseHandle ((HANDLE) pid);
223 #else
224   /* We can't just release the PID, a waitpid is mandatory.  But
225      NOWAIT in POSIX systems just means the caller already did the
226      waitpid for this child.  */
227   if (! nowait)
228     return _gpgme_ath_waitpid (pid, status, options);
229 #endif
230   return 0;
231 }
232
233
234
235
236 static int
237 my_socketpair (assuan_context_t ctx, int namespace, int style,
238                int protocol, assuan_fd_t filedes[2])
239 {
240 #ifdef HAVE_W32_SYSTEM
241   (void)ctx;
242   (void)namespace;
243   (void)style;
244   (void)protocol;
245   (void)filedes;
246   gpg_err_set_errno (ENOSYS);
247   return -1;
248 #else
249   /* FIXME: Debug output missing.  */
250   return __assuan_socketpair (ctx, namespace, style, protocol, filedes);
251 #endif
252 }
253
254
255 static int
256 my_socket (assuan_context_t ctx, int namespace, int style, int protocol)
257 {
258   (void)ctx;
259   return _gpgme_io_socket (namespace, style, protocol);
260 }
261
262
263 static int
264 my_connect (assuan_context_t ctx, int sock, struct sockaddr *addr,
265             socklen_t length)
266 {
267   (void)ctx;
268   return _gpgme_io_connect (sock, addr, length);
269 }
270
271
272 /* Note for Windows: Ignore the incompatible pointer type warning for
273    my_read and my_write.  Mingw has been changed to use int for
274    ssize_t on 32 bit systems while we use long.  For 64 bit we use
275    int64_t while mingw uses __int64_t.  It doe not matter at all
276    because under Windows long and int are both 32 bit even on 64
277    bit.  */
278 struct assuan_system_hooks _gpgme_assuan_system_hooks =
279   {
280     ASSUAN_SYSTEM_HOOKS_VERSION,
281     my_usleep,
282     my_pipe,
283     my_close,
284     my_read,
285     my_write,
286     my_recvmsg,
287     my_sendmsg,
288     my_spawn,
289     my_waitpid,
290     my_socketpair,
291     my_socket,
292     my_connect
293   };
294