work on buffer handling
diff --git a/libtelnet.c b/libtelnet.c
index badffaf..20941b7 100644
--- a/libtelnet.c
+++ b/libtelnet.c
@@ -9,28 +9,68 @@
#include "libtelnet.h"
/* initialize a telnet state tracker */
-libtelnet_error_t libtelnet_init(struct libtelnet_t *telnet) {
+void libtelnet_init(struct libtelnet_t *telnet) {
telnet->state = LIBTELNET_TEXT;
telnet->buffer = 0;
telnet->size = 0;
telnet->length = 0;
-
- /* attempt to allocate default buffer */
- telnet->buffer = (unsigned char *)malloc(LIBTELNET_BUFFER_SIZE);
- if (telnet->buffer == 0)
- return LIBTELNET_ERROR_NOMEM;
-
- return LIBTELNET_ERROR_OK;
}
/* free up any memory allocated by a state tracker */
-void libtelnet_close(struct libtelnet_t *telnet) {
- if (telnet->buffer) {
+void libtelnet_free(struct libtelnet_t *telnet) {
+ if (telnet->buffer != 0) {
free(telnet->buffer);
telnet->buffer = 0;
+ telnet->size = 0;
+ telnet->length = 0;
}
}
+/* push a byte into the telnet buffer */
+static enum libtelnet_error_t _libtelnet_buffer_byte(
+ struct libtelnet_t *telnet, unsigned char byte, void *user_data) {
+ /* check if we're out of room */
+ if (telnet->length == telnet->size) {
+ /* if we already have a large buffer, we're out of space, give up */
+ if (telnet->size == LIBTELNET_BUFFER_SIZE_LARGE) {
+ libtelnet_error_cb(telnet, LIBTELNET_ERROR_OVERFLOW, user_data);
+ libtelnet_free(telnet);
+ return LIBTELNET_ERROR_OVERFLOW;
+
+ /* if we have a small buffer, try to resize to a larger one */
+ } else if (telnet->size == LIBTELNET_BUFFER_SIZE_SMALL) {
+ unsigned char *new_buffer = (unsigned char *)realloc(
+ telnet->buffer, LIBTELNET_BUFFER_SIZE_LARGE);
+ if (new_buffer == 0) {
+ libtelnet_error_cb(telnet, LIBTELNET_ERROR_NOMEM,
+ user_data);
+ libtelnet_free(telnet);
+ return LIBTELNET_ERROR_NOMEM;
+ }
+
+ telnet->buffer = new_buffer;
+ telnet->size = LIBTELNET_BUFFER_SIZE_LARGE;
+
+ /* we have no buffer at all, so allocate one */
+ } else {
+ telnet->buffer = (unsigned char *)realloc(
+ telnet->buffer, LIBTELNET_BUFFER_SIZE_SMALL);
+ if (telnet->buffer == 0) {
+ libtelnet_error_cb(telnet, LIBTELNET_ERROR_NOMEM,
+ user_data);
+ libtelnet_free(telnet);
+ return LIBTELNET_ERROR_NOMEM;
+ }
+
+ telnet->size = LIBTELNET_BUFFER_SIZE_SMALL;
+ }
+ }
+
+ /* push the byte, all set */
+ telnet->buffer[telnet->length++] = byte;
+ return LIBTELNET_ERROR_OK;
+}
+
/* push a single byte into the state tracker */
void libtelnet_push_byte(struct libtelnet_t *telnet, unsigned char byte,
void *user_data) {
@@ -94,11 +134,14 @@
/* subrequest -- buffer bytes until end request */
case LIBTELNET_STATE_SB:
/* IAC command in subrequest -- either IAC SE or IAC IAC */
- if (byte == LIBTELNET_IAC) {
+ if (byte == LIBTELNET_IAC)
telnet->state = LIBTELNET_STATE_SB_IAC;
- } else {
- /* FIXME: buffer byte */
- }
+ /* buffer the byte, or bail if we can't */
+ else if (_libtelnet_buffer_byte(telnet, LIBTELNET_IAC, user_data) !=
+ LIBTELNET_ERROR_OK)
+ telnet->state = LIBTELNET_STATE_TEXT;
+ else
+ telnet->state = LIBTELNET_STATE_SB;
break;
/* IAC escaping inside a subrequest */
case LIBTELNET_STATE_SB_IAC:
@@ -113,10 +156,6 @@
} else {
libtelnet_subrequest_cb(telnet, telnet->buffer[0],
telnet->buffer + 1, telnet->length - 1, user_data);
-
- /* unallocate free buffer */
- free(telnet->buffer);
- telnet->size = 0;
telnet->length = 0;
}
@@ -125,8 +164,12 @@
break;
/* escaped IAC byte */
case LIBTELNET_IAC:
- /* FIXME: buffer byte */
- telnet->state = LIBTELNET_STATE_SB;
+ /* push IAC into buffer */
+ if (_libtelnet_buffer_byte(telnet, LIBTELNET_IAC, user_data) !=
+ LIBTELNET_ERROR_OK)
+ telnet->state = LIBTELNET_STATE_TEXT;
+ else
+ telnet->state = LIBTELNET_STATE_SB;
break;
/* something else -- protocol error */
default: