#include "tunala.h" #ifndef NO_BUFFER void buffer_init(buffer_t * buf) { buf->used = 0; buf->total_in = buf->total_out = 0; } void buffer_close(buffer_t * buf) { /* Our data is static - nothing needs "release", just reset it */ buf->used = 0; } /* Code these simple ones in compact form */ unsigned int buffer_used(buffer_t * buf) { return buf->used; } unsigned int buffer_unused(buffer_t * buf) { return (MAX_DATA_SIZE - buf->used); } int buffer_full(buffer_t * buf) { return (buf->used == MAX_DATA_SIZE ? 1 : 0); } int buffer_notfull(buffer_t * buf) { return (buf->used < MAX_DATA_SIZE ? 1 : 0); } int buffer_empty(buffer_t * buf) { return (buf->used == 0 ? 1 : 0); } int buffer_notempty(buffer_t * buf) { return (buf->used > 0 ? 1 : 0); } unsigned long buffer_total_in(buffer_t * buf) { return buf->total_in; } unsigned long buffer_total_out(buffer_t * buf) { return buf->total_out; } /* * These 3 static (internal) functions don't adjust the "total" variables as * it's not sure when they're called how it should be interpreted. Only the * higher-level "buffer_[to|from]_[fd|SSL|BIO]" functions should alter these * values. */ # if 0 /* To avoid "unused" warnings */ static unsigned int buffer_adddata(buffer_t * buf, const unsigned char *ptr, unsigned int size) { unsigned int added = MAX_DATA_SIZE - buf->used; if (added > size) added = size; if (added == 0) return 0; memcpy(buf->data + buf->used, ptr, added); buf->used += added; buf->total_in += added; return added; } static unsigned int buffer_tobuffer(buffer_t * to, buffer_t * from, int cap) { unsigned int moved, tomove = from->used; if ((int)tomove > cap) tomove = cap; if (tomove == 0) return 0; moved = buffer_adddata(to, from->data, tomove); if (moved == 0) return 0; buffer_takedata(from, NULL, moved); return moved; } # endif static unsigned int buffer_takedata(buffer_t * buf, unsigned char *ptr, unsigned int size) { unsigned int taken = buf->used; if (taken > size) taken = size; if (taken == 0) return 0; if (ptr) memcpy(ptr, buf->data, taken); buf->used -= taken; /* Do we have to scroll? */ if (buf->used > 0) memmove(buf->data, buf->data + taken, buf->used); return taken; } # ifndef NO_IP int buffer_from_fd(buffer_t * buf, int fd) { int toread = buffer_unused(buf); if (toread == 0) /* Shouldn't be called in this case! */ abort(); toread = read(fd, buf->data + buf->used, toread); if (toread > 0) { buf->used += toread; buf->total_in += toread; } return toread; } int buffer_to_fd(buffer_t * buf, int fd) { int towrite = buffer_used(buf); if (towrite == 0) /* Shouldn't be called in this case! */ abort(); towrite = write(fd, buf->data, towrite); if (towrite > 0) { buffer_takedata(buf, NULL, towrite); buf->total_out += towrite; } return towrite; } # endif /* !defined(NO_IP) */ # ifndef NO_OPENSSL static void int_ssl_check(SSL *s, int ret) { int e = SSL_get_error(s, ret); switch (e) { /* * These seem to be harmless and already "dealt with" by our * non-blocking environment. NB: "ZERO_RETURN" is the clean "error" * indicating a successfully closed SSL tunnel. We let this happen * because our IO loop should not appear to have broken on this * condition - and outside the IO loop, the "shutdown" state is * checked. */ case SSL_ERROR_NONE: case SSL_ERROR_WANT_READ: case SSL_ERROR_WANT_WRITE: case SSL_ERROR_WANT_X509_LOOKUP: case SSL_ERROR_ZERO_RETURN: return; /* * These seem to be indications of a genuine error that should result * in the SSL tunnel being regarded as "dead". */ case SSL_ERROR_SYSCALL: case SSL_ERROR_SSL: SSL_set_app_data(s, (char *)1); return; default: break; } /* * For any other errors that (a) exist, and (b) crop up - we need to * interpret what to do with them - so "politely inform" the caller that * the code needs updating here. */ abort(); } void buffer_from_SSL(buffer_t * buf, SSL *ssl) { int ret; if (!ssl || buffer_full(buf)) return; ret = SSL_read(ssl, buf->data + buf->used, buffer_unused(buf)); if (ret > 0) { buf->used += ret; buf->total_in += ret; } if (ret < 0) int_ssl_check(ssl, ret); } void buffer_to_SSL(buffer_t * buf, SSL *ssl) { int ret; if (!ssl || buffer_empty(buf)) return; ret = SSL_write(ssl, buf->data, buf->used); if (ret > 0) { buffer_takedata(buf, NULL, ret); buf->total_out += ret; } if (ret < 0) int_ssl_check(ssl, ret); } void buffer_from_BIO(buffer_t * buf, BIO *bio) { int ret; if (!bio || buffer_full(buf)) return; ret = BIO_read(bio, buf->data + buf->used, buffer_unused(buf)); if (ret > 0) { buf->used += ret; buf->total_in += ret; } } void buffer_to_BIO(buffer_t * buf, BIO *bio) { int ret; if (!bio || buffer_empty(buf)) return; ret = BIO_write(bio, buf->data, buf->used); if (ret > 0) { buffer_takedata(buf, NULL, ret); buf->total_out += ret; } } # endif /* !defined(NO_OPENSSL) */ #endif /* !defined(NO_BUFFER) */