buffer.c 4.8 KB
Newer Older
1 2 3 4 5 6 7
#include "tunala.h"

#ifndef NO_BUFFER

void buffer_init(buffer_t *buf)
{
	buf->used = 0;
8
	buf->total_in = buf->total_out = 0;
9 10 11 12
}

void buffer_close(buffer_t *buf)
{
13 14
	/* Our data is static - nothing needs "release", just reset it */
	buf->used = 0;
15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
}

/* 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); }
30 31 32 33 34 35 36 37 38
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. */
39
#if 0 /* To avoid "unused" warnings */
40
static unsigned int buffer_adddata(buffer_t *buf, const unsigned char *ptr,
41 42 43 44 45 46 47 48 49
		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;
50
	buf->total_in += added;
51 52 53
	return added;
}

54 55 56 57 58 59 60 61 62 63 64 65 66 67 68
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

69
static unsigned int buffer_takedata(buffer_t *buf, unsigned char *ptr,
70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89
		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)
{
90
	int toread = buffer_unused(buf);
91 92 93 94
	if(toread == 0)
		/* Shouldn't be called in this case! */
		abort();
	toread = read(fd, buf->data + buf->used, toread);
95
	if(toread > 0) {
96
		buf->used += toread;
97 98
		buf->total_in += toread;
	}
99 100 101 102 103
	return toread;
}

int buffer_to_fd(buffer_t *buf, int fd)
{
104
	int towrite = buffer_used(buf);
105 106 107 108
	if(towrite == 0)
		/* Shouldn't be called in this case! */
		abort();
	towrite = write(fd, buf->data, towrite);
109
	if(towrite > 0) {
110
		buffer_takedata(buf, NULL, towrite);
111 112
		buf->total_out += towrite;
	}
113 114 115 116 117 118 119
	return towrite;
}

#endif /* !defined(NO_IP) */

#ifndef NO_OPENSSL

120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150
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();
}

151 152 153 154 155 156
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));
157
	if(ret > 0) {
158
		buf->used += ret;
159 160
		buf->total_in += ret;
	}
161 162
	if(ret < 0)
		int_ssl_check(ssl, ret);
163 164 165 166 167 168 169 170
}

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);
171
	if(ret > 0) {
172
		buffer_takedata(buf, NULL, ret);
173 174
		buf->total_out += ret;
	}
175 176
	if(ret < 0)
		int_ssl_check(ssl, ret);
177 178 179 180 181 182 183 184
}

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));
185
	if(ret > 0) {
186
		buf->used += ret;
187 188
		buf->total_in += ret;
	}
189 190 191 192 193 194 195 196
}

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);
197
	if(ret > 0) {
198
		buffer_takedata(buf, NULL, ret);
199 200
		buf->total_out += ret;
	}
201 202 203 204 205
}

#endif /* !defined(NO_OPENSSL) */

#endif /* !defined(NO_BUFFER) */