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 */
- buffer_init(buf);
+ /* Our data is static - nothing needs "release", just reset it */
+ buf->used = 0;
}
/* Code these simple ones in compact form */
return (buf->used == 0 ? 1 : 0); }
int buffer_notempty(buffer_t *buf) {
return (buf->used > 0 ? 1 : 0); }
-
-unsigned int buffer_adddata(buffer_t *buf, const unsigned char *ptr,
+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;
return 0;
memcpy(buf->data + buf->used, ptr, added);
buf->used += added;
+ buf->total_in += added;
return added;
}
-unsigned int buffer_takedata(buffer_t *buf, unsigned char *ptr,
+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;
return taken;
}
-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;
-}
-
#ifndef NO_IP
int buffer_from_fd(buffer_t *buf, int fd)
/* Shouldn't be called in this case! */
abort();
toread = read(fd, buf->data + buf->used, toread);
- if(toread > 0)
+ if(toread > 0) {
buf->used += toread;
+ buf->total_in += toread;
+ }
return toread;
}
/* Shouldn't be called in this case! */
abort();
towrite = write(fd, buf->data, towrite);
- if(towrite > 0)
+ if(towrite > 0) {
buffer_takedata(buf, NULL, towrite);
+ buf->total_out += towrite;
+ }
return towrite;
}
#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)
+ 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)
if(!ssl || buffer_empty(buf))
return;
ret = SSL_write(ssl, buf->data, buf->used);
- if(ret > 0)
+ 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)
if(!bio || buffer_full(buf))
return;
ret = BIO_read(bio, buf->data + buf->used, buffer_unused(buf));
- if(ret > 0)
+ if(ret > 0) {
buf->used += ret;
+ buf->total_in += ret;
+ }
}
void buffer_to_BIO(buffer_t *buf, BIO *bio)
if(!bio || buffer_empty(buf))
return;
ret = BIO_write(bio, buf->data, buf->used);
- if(ret > 0)
+ if(ret > 0) {
buffer_takedata(buf, NULL, ret);
+ buf->total_out += ret;
+ }
}
#endif /* !defined(NO_OPENSSL) */