Merge branch 'master' of git+ssh://playfair.gnupg.org/git/gpgme
[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   if (msg == NULL)
30     return 1;
31
32   _gpgme_debug (DEBUG_ASSUAN, "%s", msg);
33   return 0;
34 }
35
36 \f
37 static void
38 my_usleep (assuan_context_t ctx, unsigned int usec)
39 {
40   /* FIXME: Add to ath.  */
41   __assuan_usleep (ctx, usec);
42 }
43
44
45 /* Create a pipe with an inheritable end.  */
46 static int
47 my_pipe (assuan_context_t ctx, assuan_fd_t fds[2], int inherit_idx)
48 {
49   int res;
50   int gfds[2];
51
52   res = _gpgme_io_pipe (gfds, inherit_idx);
53
54   /* For now... */
55   fds[0] = (assuan_fd_t) gfds[0];
56   fds[1] = (assuan_fd_t) gfds[1];
57
58   return res;
59 }
60
61
62 /* Close the given file descriptor, created with _assuan_pipe or one
63    of the socket functions.  */
64 static int
65 my_close (assuan_context_t ctx, assuan_fd_t fd)
66 {
67   return _gpgme_io_close ((int) fd);
68 }
69
70
71 static ssize_t
72 my_read (assuan_context_t ctx, assuan_fd_t fd, void *buffer, size_t size)
73 {
74   return _gpgme_io_read ((int) fd, buffer, size);
75 }
76
77
78 static ssize_t
79 my_write (assuan_context_t ctx, assuan_fd_t fd, const void *buffer, size_t size)
80 {
81   return _gpgme_io_write ((int) fd, buffer, size);
82 }
83
84
85 static int
86 my_recvmsg (assuan_context_t ctx, assuan_fd_t fd, assuan_msghdr_t msg,
87             int flags)
88 {
89 #ifdef HAVE_W32_SYSTEM
90   gpg_err_set_errno (ENOSYS);
91   return -1;
92 #else
93   return _gpgme_io_recvmsg ((int) fd, msg, flags);
94 #endif
95 }
96
97
98
99 static int
100 my_sendmsg (assuan_context_t ctx, assuan_fd_t fd, const assuan_msghdr_t msg,
101             int flags)
102 {
103 #ifdef HAVE_W32_SYSTEM
104   gpg_err_set_errno (ENOSYS);
105   return -1;
106 #else
107   return _gpgme_io_sendmsg ((int) fd, msg, flags);
108 #endif
109 }
110
111
112 /* If NAME is NULL, don't exec, just fork.  FD_CHILD_LIST is modified
113    to reflect the value of the FD in the peer process (on
114    Windows).  */
115 static int
116 my_spawn (assuan_context_t ctx, pid_t *r_pid, const char *name,
117           const char **argv,
118           assuan_fd_t fd_in, assuan_fd_t fd_out,
119           assuan_fd_t *fd_child_list,
120           void (*atfork) (void *opaque, int reserved),
121           void *atforkvalue, unsigned int flags)
122 {
123   int err;
124   struct spawn_fd_item_s *fd_items;
125   int i;
126
127   assert (name);
128
129   if (! name)
130     {
131       gpg_err_set_errno (ENOSYS);
132       return -1;
133     }
134
135   i = 0;
136   if (fd_child_list)
137     {
138       while (fd_child_list[i] != ASSUAN_INVALID_FD)
139         i++;
140     }
141   /* fd_in, fd_out, terminator */
142   i += 3;
143   fd_items = calloc (i, sizeof (struct spawn_fd_item_s));
144   if (! fd_items)
145     return -1;
146   i = 0;
147   if (fd_child_list)
148     {
149       while (fd_child_list[i] != ASSUAN_INVALID_FD)
150         {
151           fd_items[i].fd = (int) fd_child_list[i];
152           fd_items[i].dup_to = -1;
153           i++;
154         }
155     }
156   if (fd_in != ASSUAN_INVALID_FD)
157     {
158       fd_items[i].fd = (int) fd_in;
159       fd_items[i].dup_to = 0;
160       i++;
161     }
162   if (fd_out != ASSUAN_INVALID_FD)
163     {
164       fd_items[i].fd = (int) fd_out;
165       fd_items[i].dup_to = 1;
166       i++;
167     }
168   fd_items[i].fd = -1;
169   fd_items[i].dup_to = -1;
170
171   err = _gpgme_io_spawn (name, (char*const*)argv, IOSPAWN_FLAG_NOCLOSE,
172                          fd_items, atfork, atforkvalue, r_pid);
173   if (! err)
174     {
175       i = 0;
176
177       if (fd_child_list)
178         {
179           while (fd_child_list[i] != ASSUAN_INVALID_FD)
180             {
181               fd_child_list[i] = (assuan_fd_t) fd_items[i].peer_name;
182               i++;
183             }
184         }
185     }
186   free (fd_items);
187   return err;
188 }
189
190
191 /* If action is 0, like waitpid.  If action is 1, just release the PID?  */
192 static pid_t
193 my_waitpid (assuan_context_t ctx, pid_t pid,
194             int nowait, int *status, int options)
195 {
196 #ifdef HAVE_W32_SYSTEM
197   CloseHandle ((HANDLE) pid);
198 #else
199   /* We can't just release the PID, a waitpid is mandatory.  But
200      NOWAIT in POSIX systems just means the caller already did the
201      waitpid for this child.  */
202   if (! nowait)
203     return _gpgme_ath_waitpid (pid, status, options); 
204 #endif
205   return 0;
206 }
207
208
209
210
211 static int
212 my_socketpair (assuan_context_t ctx, int namespace, int style,
213                int protocol, assuan_fd_t filedes[2])
214 {
215 #ifdef HAVE_W32_SYSTEM
216   gpg_err_set_errno (ENOSYS);
217   return -1;
218 #else
219   /* FIXME: Debug output missing.  */
220   return __assuan_socketpair (ctx, namespace, style, protocol, filedes);
221 #endif
222 }
223
224
225 static int
226 my_socket (assuan_context_t ctx, int namespace, int style, int protocol)
227 {
228   return _gpgme_io_socket (namespace, style, protocol);
229 }
230
231
232 static int
233 my_connect (assuan_context_t ctx, int sock, struct sockaddr *addr,
234             socklen_t length)
235 {
236   return _gpgme_io_connect (sock, addr, length);
237 }
238
239
240 struct assuan_system_hooks _gpgme_assuan_system_hooks =
241   {
242     ASSUAN_SYSTEM_HOOKS_VERSION,
243     my_usleep,
244     my_pipe,
245     my_close,
246     my_read,
247     my_write,
248     my_recvmsg,
249     my_sendmsg,
250     my_spawn,
251     my_waitpid,
252     my_socketpair,
253     my_socket,
254     my_connect
255   };
256