static unsigned int get_from_filesource(isc_entropysource_t *source, isc_uint32_t desired) { isc_entropy_t *ent = source->ent; unsigned char buf[128]; HCRYPTPROV hcryptprov = source->sources.file.handle; ssize_t ndesired; unsigned int added; if (source->bad) return (0); desired = desired / 8 + (((desired & 0x07) > 0) ? 1 : 0); added = 0; while (desired > 0) { ndesired = ISC_MIN(desired, sizeof(buf)); if (!CryptGenRandom(hcryptprov, ndesired, buf)) { CryptReleaseContext(hcryptprov, 0); source->bad = ISC_TRUE; goto out; } entropypool_adddata(ent, buf, ndesired, ndesired * 8); added += ndesired * 8; desired -= ndesired; } out: return (added); }
static unsigned int get_from_filesource (isc_entropysource_t * source, isc_uint32_t desired) { isc_entropy_t *ent = source->ent; unsigned char buf[128]; int fd = source->sources.file.handle; ssize_t n, ndesired; unsigned int added; if (source->bad) return (0); desired = desired / 8 + (((desired & 0x07) > 0) ? 1 : 0); added = 0; while (desired > 0) { ndesired = ISC_MIN (desired, sizeof (buf)); n = read (fd, buf, ndesired); if (n < 0) { if (errno == EAGAIN || errno == EINTR) goto out; goto err; } if (n == 0) goto err; entropypool_adddata (ent, buf, n, n * 8); added += n * 8; desired -= n; } goto out; err: (void) close (fd); source->sources.file.handle = -1; source->bad = ISC_TRUE; out: return (added); }
static unsigned int get_from_usocketsource (isc_entropysource_t * source, isc_uint32_t desired) { isc_entropy_t *ent = source->ent; unsigned char buf[128]; int fd = source->sources.usocket.handle; ssize_t n = 0, ndesired; unsigned int added; size_t sz_to_recv = source->sources.usocket.sz_to_recv; if (source->bad) return (0); desired = desired / 8 + (((desired & 0x07) > 0) ? 1 : 0); added = 0; while (desired > 0) { ndesired = ISC_MIN (desired, sizeof (buf)); eagain_loop: switch (source->sources.usocket.status) { case isc_usocketsource_ndesired: buf[0] = ndesired; if ((n = sendto (fd, buf, 1, 0, NULL, 0)) < 0) { if (errno == EWOULDBLOCK || errno == EINTR || errno == ECONNRESET) goto out; goto err; } INSIST (n == 1); source->sources.usocket.status = isc_usocketsource_wrote; goto eagain_loop; case isc_usocketsource_connecting: case isc_usocketsource_connected: buf[0] = 1; buf[1] = ndesired; if ((n = sendto (fd, buf, 2, 0, NULL, 0)) < 0) { if (errno == EWOULDBLOCK || errno == EINTR || errno == ECONNRESET) goto out; goto err; } if (n == 1) { source->sources.usocket.status = isc_usocketsource_ndesired; goto eagain_loop; } INSIST (n == 2); source->sources.usocket.status = isc_usocketsource_wrote; /*FALLTHROUGH*/ case isc_usocketsource_wrote: if (recvfrom (fd, buf, 1, 0, NULL, NULL) != 1) { if (errno == EAGAIN) { /* * The problem of EAGAIN (try again * later) is a major issue on HP-UX. * Solaris actually tries the recvfrom * call again, while HP-UX just dies. * This code is an attempt to let the * entropy pool fill back up (at least * that's what I think the problem is.) * We go to eagain_loop because if we * just "break", then the "desired" * amount gets borked. */ #ifdef HAVE_NANOSLEEP struct timespec ts; ts.tv_sec = 0; ts.tv_nsec = 1000000; nanosleep (&ts, NULL); #else usleep (1000); #endif goto eagain_loop; } if (errno == EWOULDBLOCK || errno == EINTR) goto out; goto err; } source->sources.usocket.status = isc_usocketsource_reading; sz_to_recv = buf[0]; source->sources.usocket.sz_to_recv = sz_to_recv; if (sz_to_recv > sizeof (buf)) goto err; /*FALLTHROUGH*/ case isc_usocketsource_reading: if (sz_to_recv != 0U) { n = recv (fd, buf, sz_to_recv, 0); if (n < 0) { if (errno == EWOULDBLOCK || errno == EINTR) goto out; goto err; } } else n = 0; break; default: goto err; } if ((size_t) n != sz_to_recv) source->sources.usocket.sz_to_recv -= n; else source->sources.usocket.status = isc_usocketsource_connected; if (n == 0) goto out; entropypool_adddata (ent, buf, n, n * 8); added += n * 8; desired -= n; } goto out; err: close (fd); source->bad = ISC_TRUE; source->sources.usocket.status = isc_usocketsource_disconnected; source->sources.usocket.handle = -1; out: return (added); }