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