mirror of https://github.com/openssl/openssl.git
				
				
				
			
		
			
				
	
	
		
			206 lines
		
	
	
		
			4.8 KiB
		
	
	
	
		
			C
		
	
	
	
			
		
		
	
	
			206 lines
		
	
	
		
			4.8 KiB
		
	
	
	
		
			C
		
	
	
	
#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) */
 |