1/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
2 * All rights reserved.
3 *
4 * This package is an SSL implementation written
5 * by Eric Young (eay@cryptsoft.com).
6 * The implementation was written so as to conform with Netscapes SSL.
7 *
8 * This library is free for commercial and non-commercial use as long as
9 * the following conditions are aheared to.  The following conditions
10 * apply to all code found in this distribution, be it the RC4, RSA,
11 * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
12 * included with this distribution is covered by the same copyright terms
13 * except that the holder is Tim Hudson (tjh@cryptsoft.com).
14 *
15 * Copyright remains Eric Young's, and as such any Copyright notices in
16 * the code are not to be removed.
17 * If this package is used in a product, Eric Young should be given attribution
18 * as the author of the parts of the library used.
19 * This can be in the form of a textual message at program startup or
20 * in documentation (online or textual) provided with the package.
21 *
22 * Redistribution and use in source and binary forms, with or without
23 * modification, are permitted provided that the following conditions
24 * are met:
25 * 1. Redistributions of source code must retain the copyright
26 *    notice, this list of conditions and the following disclaimer.
27 * 2. Redistributions in binary form must reproduce the above copyright
28 *    notice, this list of conditions and the following disclaimer in the
29 *    documentation and/or other materials provided with the distribution.
30 * 3. All advertising materials mentioning features or use of this software
31 *    must display the following acknowledgement:
32 *    "This product includes cryptographic software written by
33 *     Eric Young (eay@cryptsoft.com)"
34 *    The word 'cryptographic' can be left out if the rouines from the library
35 *    being used are not cryptographic related :-).
36 * 4. If you include any Windows specific code (or a derivative thereof) from
37 *    the apps directory (application code) you must include an acknowledgement:
38 *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
39 *
40 * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
41 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
42 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
43 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
44 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
45 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
46 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
47 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
48 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
49 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
50 * SUCH DAMAGE.
51 *
52 * The licence and distribution terms for any publically available version or
53 * derivative of this code cannot be changed.  i.e. this code cannot simply be
54 * copied and put under another distribution licence
55 * [including the GNU Public Licence.] */
56
57#include <openssl/bio.h>
58
59#include <errno.h>
60#include <string.h>
61
62#if !defined(OPENSSL_WINDOWS)
63#include <unistd.h>
64#else
65#include <io.h>
66#pragma warning(push, 3)
67#include <windows.h>
68#pragma warning(pop)
69#endif
70
71#include <openssl/buf.h>
72#include <openssl/err.h>
73#include <openssl/mem.h>
74
75
76static int bio_fd_non_fatal_error(int err) {
77  if (
78#ifdef EWOULDBLOCK
79    err == EWOULDBLOCK ||
80#endif
81#ifdef WSAEWOULDBLOCK
82    err == WSAEWOULDBLOCK ||
83#endif
84#ifdef ENOTCONN
85    err == ENOTCONN ||
86#endif
87#ifdef EINTR
88    err == EINTR ||
89#endif
90#ifdef EAGAIN
91    err == EAGAIN ||
92#endif
93#ifdef EPROTO
94    err == EPROTO ||
95#endif
96#ifdef EINPROGRESS
97    err == EINPROGRESS ||
98#endif
99#ifdef EALREADY
100    err == EALREADY ||
101#endif
102    0) {
103    return 1;
104  }
105  return 0;
106}
107
108#if defined(OPENSSL_WINDOWS)
109int bio_fd_should_retry(int i) {
110  if (i == -1) {
111    return bio_fd_non_fatal_error((int)GetLastError());
112  }
113  return 0;
114}
115#else
116int bio_fd_should_retry(int i) {
117  if (i == -1) {
118    return bio_fd_non_fatal_error(errno);
119  }
120  return 0;
121}
122#endif
123
124BIO *BIO_new_fd(int fd, int close_flag) {
125  BIO *ret = BIO_new(BIO_s_fd());
126  if (ret == NULL) {
127    return NULL;
128  }
129  BIO_set_fd(ret, fd, close_flag);
130  return ret;
131}
132
133static int fd_new(BIO *bio) {
134  /* num is used to store the file descriptor. */
135  bio->num = -1;
136  return 1;
137}
138
139static int fd_free(BIO *bio) {
140  if (bio == NULL) {
141    return 0;
142  }
143
144  if (bio->shutdown) {
145    if (bio->init) {
146      close(bio->num);
147    }
148    bio->init = 0;
149  }
150  return 1;
151}
152
153static int fd_read(BIO *b, char *out, int outl) {
154  int ret = 0;
155
156  ret = read(b->num, out, outl);
157  BIO_clear_retry_flags(b);
158  if (ret <= 0) {
159    if (bio_fd_should_retry(ret)) {
160      BIO_set_retry_read(b);
161    }
162  }
163
164  return ret;
165}
166
167static int fd_write(BIO *b, const char *in, int inl) {
168  int ret = write(b->num, in, inl);
169  BIO_clear_retry_flags(b);
170  if (ret <= 0) {
171    if (bio_fd_should_retry(ret)) {
172      BIO_set_retry_write(b);
173    }
174  }
175
176  return ret;
177}
178
179static long fd_ctrl(BIO *b, int cmd, long num, void *ptr) {
180  long ret = 1;
181  int *ip;
182
183  switch (cmd) {
184    case BIO_CTRL_RESET:
185      num = 0;
186    case BIO_C_FILE_SEEK:
187      ret = 0;
188      if (b->init) {
189        ret = (long)lseek(b->num, num, SEEK_SET);
190      }
191      break;
192    case BIO_C_FILE_TELL:
193    case BIO_CTRL_INFO:
194      ret = 0;
195      if (b->init) {
196        ret = (long)lseek(b->num, 0, SEEK_CUR);
197      }
198      break;
199    case BIO_C_SET_FD:
200      fd_free(b);
201      b->num = *((int *)ptr);
202      b->shutdown = (int)num;
203      b->init = 1;
204      break;
205    case BIO_C_GET_FD:
206      if (b->init) {
207        ip = (int *)ptr;
208        if (ip != NULL) {
209          *ip = b->num;
210        }
211        return b->num;
212      } else {
213        ret = -1;
214      }
215      break;
216    case BIO_CTRL_GET_CLOSE:
217      ret = b->shutdown;
218      break;
219    case BIO_CTRL_SET_CLOSE:
220      b->shutdown = (int)num;
221      break;
222    case BIO_CTRL_PENDING:
223    case BIO_CTRL_WPENDING:
224      ret = 0;
225      break;
226    case BIO_CTRL_FLUSH:
227      ret = 1;
228      break;
229    default:
230      ret = 0;
231      break;
232  }
233
234  return ret;
235}
236
237static int fd_puts(BIO *bp, const char *str) {
238  return fd_write(bp, str, strlen(str));
239}
240
241static int fd_gets(BIO *bp, char *buf, int size) {
242  char *ptr = buf;
243  char *end = buf + size - 1;
244
245  if (size <= 0) {
246    return 0;
247  }
248
249  while (ptr < end && fd_read(bp, ptr, 1) > 0 && ptr[0] != '\n') {
250    ptr++;
251  }
252
253  ptr[0] = '\0';
254
255  return ptr - buf;
256}
257
258static const BIO_METHOD methods_fdp = {
259    BIO_TYPE_FD, "file descriptor", fd_write, fd_read, fd_puts,
260    fd_gets,     fd_ctrl,           fd_new,   fd_free, NULL, };
261
262const BIO_METHOD *BIO_s_fd(void) { return &methods_fdp; }
263
264int BIO_set_fd(BIO *bio, int fd, int close_flag) {
265  return BIO_int_ctrl(bio, BIO_C_SET_FD, close_flag, fd);
266}
267
268int BIO_get_fd(BIO *bio, int *out_fd) {
269  return BIO_ctrl(bio, BIO_C_GET_FD, 0, (char *) out_fd);
270}
271