| #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) */ |