assuan/
[gpgme.git] / assuan / assuan-io.c
1 /* assuan-io.c - Wraps the read and write functions.
2  * Copyright (C) 2002, 2004, 2006, 2007, 2008 Free Software Foundation, Inc.
3  *
4  * This file is part of Assuan.
5  *
6  * Assuan 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  * Assuan 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 <http://www.gnu.org/licenses/>.
18  */
19
20 #ifdef HAVE_CONFIG_H
21 #include <config.h>
22 #endif
23
24 #include <time.h>
25 #include <sys/time.h>
26 #include <sys/types.h>
27 #ifdef HAVE_SYS_SOCKET_H
28 # include <sys/socket.h>
29 #endif
30 #include <unistd.h>
31 #include <errno.h>
32 #ifdef HAVE_W32_SYSTEM
33 # include <windows.h>
34 #else
35 # include <sys/wait.h>
36 #endif
37
38 #include "assuan-defs.h"
39
40
41 #ifndef HAVE_W32_SYSTEM
42 pid_t 
43 _assuan_waitpid (pid_t pid, int *status, int options)
44 {
45   return waitpid (pid, status, options);
46 }
47 #endif
48
49
50 static ssize_t
51 do_io_read (assuan_fd_t fd, void *buffer, size_t size)
52 {
53 #if defined(HAVE_W32_SYSTEM) && !defined(_ASSUAN_IN_GPGME_BUILD_ASSUAN)
54   /* Due to the peculiarities of the W32 API we can't use read for a
55      network socket and thus we try to use recv first and fallback to
56      read if recv detects that it is not a network socket.  */
57   int n;
58
59   n = recv (HANDLE2SOCKET(fd), buffer, size, 0);
60   if (n == -1)
61     {
62       switch (WSAGetLastError ())
63         {
64         case WSAENOTSOCK:
65           {
66             DWORD nread = 0;
67             
68             n = ReadFile (fd, buffer, size, &nread, NULL);
69             if (!n)
70               {
71                 switch (GetLastError())
72                   {
73                   case ERROR_BROKEN_PIPE: errno = EPIPE; break;
74                   default: errno = EIO; 
75                   }
76                 n = -1;
77               }
78             else
79               n = (int)nread;
80           }
81           break;
82           
83         case WSAEWOULDBLOCK: errno = EAGAIN; break;
84         case ERROR_BROKEN_PIPE: errno = EPIPE; break;
85         default: errno = EIO; break;
86         }
87     }
88   return n;
89 #else /*!HAVE_W32_SYSTEM*/
90   return read (fd, buffer, size);
91 #endif /*!HAVE_W32_SYSTEM*/
92 }
93
94
95 ssize_t
96 _assuan_io_read (assuan_fd_t fd, void *buffer, size_t size)
97 {
98   ssize_t retval;
99   
100   if (_assuan_io_hooks.read_hook
101       && _assuan_io_hooks.read_hook (NULL, fd, buffer, size, &retval) == 1)
102     return retval;
103
104   return do_io_read (fd, buffer, size);
105 }
106
107 ssize_t
108 _assuan_simple_read (assuan_context_t ctx, void *buffer, size_t size)
109 {
110   ssize_t retval;
111   
112   if (_assuan_io_hooks.read_hook
113       && _assuan_io_hooks.read_hook (ctx, ctx->inbound.fd, 
114                                      buffer, size, &retval) == 1)
115     return retval;
116
117   return do_io_read (ctx->inbound.fd, buffer, size);
118 }
119
120
121
122 static ssize_t
123 do_io_write (assuan_fd_t fd, const void *buffer, size_t size)
124 {
125 #if defined(HAVE_W32_SYSTEM) && !defined(_ASSUAN_IN_GPGME_BUILD_ASSUAN)
126   /* Due to the peculiarities of the W32 API we can't use write for a
127      network socket and thus we try to use send first and fallback to
128      write if send detects that it is not a network socket.  */
129   int n;
130
131   n = send (HANDLE2SOCKET(fd), buffer, size, 0);
132   if (n == -1 && WSAGetLastError () == WSAENOTSOCK)
133     {
134       DWORD nwrite;
135
136       n = WriteFile (fd, buffer, size, &nwrite, NULL);
137       if (!n)
138         {
139           switch (GetLastError ())
140             {
141             case ERROR_BROKEN_PIPE: 
142             case ERROR_NO_DATA: errno = EPIPE; break;
143             default:            errno = EIO;   break;
144             }
145           n = -1;
146         }
147       else
148         n = (int)nwrite;
149     }
150   return n;
151 #else /*!HAVE_W32_SYSTEM*/
152   return write (fd, buffer, size);
153 #endif /*!HAVE_W32_SYSTEM*/
154 }
155
156 ssize_t
157 _assuan_io_write (assuan_fd_t fd, const void *buffer, size_t size)
158 {
159   ssize_t retval;
160   
161   if (_assuan_io_hooks.write_hook
162       && _assuan_io_hooks.write_hook (NULL, fd, buffer, size, &retval) == 1)
163     return retval;
164   return do_io_write (fd, buffer, size);
165 }
166
167 ssize_t
168 _assuan_simple_write (assuan_context_t ctx, const void *buffer, size_t size)
169 {
170   ssize_t retval;
171   
172   if (_assuan_io_hooks.write_hook
173       && _assuan_io_hooks.write_hook (ctx, ctx->outbound.fd, 
174                                       buffer, size, &retval) == 1)
175     return retval;
176
177   return do_io_write (ctx->outbound.fd, buffer, size);
178 }
179
180
181 #ifdef HAVE_W32_SYSTEM
182 int
183 _assuan_simple_sendmsg (assuan_context_t ctx, void *msg)
184 #else
185 ssize_t
186 _assuan_simple_sendmsg (assuan_context_t ctx, struct msghdr *msg)
187 #endif
188 {
189 #ifdef HAVE_W32_SYSTEM
190   return _assuan_error (ASSUAN_Not_Implemented);
191 #else
192   int ret;
193   while ( (ret = sendmsg (ctx->outbound.fd, msg, 0)) == -1 && errno == EINTR)
194     ;
195   return ret;
196 #endif
197 }
198
199
200 #ifdef HAVE_W32_SYSTEM
201 int
202 _assuan_simple_recvmsg (assuan_context_t ctx, void *msg)
203 #else
204 ssize_t
205 _assuan_simple_recvmsg (assuan_context_t ctx, struct msghdr *msg)
206 #endif
207 {
208 #ifdef HAVE_W32_SYSTEM
209   return _assuan_error (ASSUAN_Not_Implemented);
210 #else
211   int ret;
212   while ( (ret = recvmsg (ctx->inbound.fd, msg, 0)) == -1 && errno == EINTR)
213     ;
214   return ret;
215 #endif
216 }
217
218
219 void
220 _assuan_usleep (unsigned int usec)
221 {
222   if (usec)
223     {
224 #ifdef HAVE_NANOSLEEP
225       struct timespec req;
226       struct timespec rem;
227       
228       req.tv_sec = 0;
229       req.tv_nsec = usec * 1000;
230       
231       while (nanosleep (&req, &rem) < 0 && errno == EINTR)
232         req = rem;
233
234 #elif defined(HAVE_W32_SYSTEM)
235       Sleep (usec / 1000);
236 #else
237       struct timeval tv;
238
239       tv.tv_sec  = usec / 1000000;
240       tv.tv_usec = usec % 1000000;
241       select (0, NULL, NULL, NULL, &tv);
242 #endif
243     }
244 }
245