mirror of https://gerrit.osmocom.org/libtelnet
make libtelnet_t private; libtelnet_init now returns a pointer instead of taking one, and libtelnet_free frees the pointer passed in
This commit is contained in:
parent
d08d812c30
commit
d2466a01b6
44
libtelnet.c
44
libtelnet.c
|
@ -35,6 +35,36 @@
|
||||||
# define INLINE
|
# define INLINE
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* telnet state */
|
||||||
|
struct telnet_t {
|
||||||
|
/* user data */
|
||||||
|
void *ud;
|
||||||
|
/* telopt support table */
|
||||||
|
const telnet_telopt_t *telopts;
|
||||||
|
/* event handler */
|
||||||
|
telnet_event_handler_t eh;
|
||||||
|
#ifdef HAVE_ZLIB
|
||||||
|
/* zlib (mccp2) compression */
|
||||||
|
z_stream *z;
|
||||||
|
#endif
|
||||||
|
/* RFC1143 option negotiation states */
|
||||||
|
struct telnet_rfc1143_t *q;
|
||||||
|
/* sub-request buffer */
|
||||||
|
char *buffer;
|
||||||
|
/* current size of the buffer */
|
||||||
|
size_t buffer_size;
|
||||||
|
/* current buffer write position (also length of buffer data) */
|
||||||
|
size_t buffer_pos;
|
||||||
|
/* current state */
|
||||||
|
enum telnet_state_t state;
|
||||||
|
/* option flags */
|
||||||
|
unsigned char flags;
|
||||||
|
/* current subnegotiation telopt */
|
||||||
|
unsigned char sb_telopt;
|
||||||
|
/* length of RFC1143 queue */
|
||||||
|
unsigned char q_size;
|
||||||
|
};
|
||||||
|
|
||||||
/* RFC1143 option negotiation state */
|
/* RFC1143 option negotiation state */
|
||||||
typedef struct telnet_rfc1143_t {
|
typedef struct telnet_rfc1143_t {
|
||||||
unsigned char telopt;
|
unsigned char telopt;
|
||||||
|
@ -559,13 +589,20 @@ static int _subnegotiate(telnet_t *telnet) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/* initialize a telnet state tracker */
|
/* initialize a telnet state tracker */
|
||||||
void telnet_init(telnet_t *telnet, const telnet_telopt_t *telopts,
|
telnet_t *telnet_init(const telnet_telopt_t *telopts,
|
||||||
telnet_event_handler_t eh, unsigned char flags, void *user_data) {
|
telnet_event_handler_t eh, unsigned char flags, void *user_data) {
|
||||||
memset(telnet, 0, sizeof(telnet_t));
|
/* allocate structure */
|
||||||
|
struct telnet_t *telnet = (telnet_t*)calloc(1, sizeof(telnet_t));
|
||||||
|
if (telnet == 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/* initialize data */
|
||||||
telnet->ud = user_data;
|
telnet->ud = user_data;
|
||||||
telnet->telopts = telopts;
|
telnet->telopts = telopts;
|
||||||
telnet->eh = eh;
|
telnet->eh = eh;
|
||||||
telnet->flags = flags;
|
telnet->flags = flags;
|
||||||
|
|
||||||
|
return telnet;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* free up any memory allocated by a state tracker */
|
/* free up any memory allocated by a state tracker */
|
||||||
|
@ -596,6 +633,9 @@ void telnet_free(telnet_t *telnet) {
|
||||||
telnet->q = 0;
|
telnet->q = 0;
|
||||||
telnet->q_size = 0;
|
telnet->q_size = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* free the telnet structure itself */
|
||||||
|
free(telnet);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* push a byte into the telnet buffer */
|
/* push a byte into the telnet buffer */
|
||||||
|
|
33
libtelnet.h
33
libtelnet.h
|
@ -186,38 +186,11 @@ struct telnet_telopt_t {
|
||||||
unsigned char him; /* TELNET_DO or TELNET_DONT */
|
unsigned char him; /* TELNET_DO or TELNET_DONT */
|
||||||
};
|
};
|
||||||
|
|
||||||
/* state tracker */
|
/* state tracker -- private data structure */
|
||||||
struct telnet_t {
|
struct telnet_t;
|
||||||
/* user data */
|
|
||||||
void *ud;
|
|
||||||
/* telopt support table */
|
|
||||||
const telnet_telopt_t *telopts;
|
|
||||||
/* event handler */
|
|
||||||
telnet_event_handler_t eh;
|
|
||||||
#ifdef HAVE_ZLIB
|
|
||||||
/* zlib (mccp2) compression */
|
|
||||||
z_stream *z;
|
|
||||||
#endif
|
|
||||||
/* RFC1143 option negotiation states */
|
|
||||||
struct telnet_rfc1143_t *q;
|
|
||||||
/* sub-request buffer */
|
|
||||||
char *buffer;
|
|
||||||
/* current size of the buffer */
|
|
||||||
size_t buffer_size;
|
|
||||||
/* current buffer write position (also length of buffer data) */
|
|
||||||
size_t buffer_pos;
|
|
||||||
/* current state */
|
|
||||||
enum telnet_state_t state;
|
|
||||||
/* option flags */
|
|
||||||
unsigned char flags;
|
|
||||||
/* current subnegotiation telopt */
|
|
||||||
unsigned char sb_telopt;
|
|
||||||
/* length of RFC1143 queue */
|
|
||||||
unsigned char q_size;
|
|
||||||
};
|
|
||||||
|
|
||||||
/* initialize a telnet state tracker */
|
/* initialize a telnet state tracker */
|
||||||
extern void telnet_init(telnet_t *telnet, const telnet_telopt_t *telopts,
|
extern telnet_t* telnet_init(const telnet_telopt_t *telopts,
|
||||||
telnet_event_handler_t eh, unsigned char flags, void *user_data);
|
telnet_event_handler_t eh, unsigned char flags, void *user_data);
|
||||||
|
|
||||||
/* free up any memory allocated by a state tracker */
|
/* free up any memory allocated by a state tracker */
|
||||||
|
|
|
@ -37,7 +37,7 @@ const telnet_telopt_t telopts[] = {
|
||||||
struct user_t {
|
struct user_t {
|
||||||
char *name;
|
char *name;
|
||||||
int sock;
|
int sock;
|
||||||
telnet_t telnet;
|
telnet_t *telnet;
|
||||||
char linebuf[256];
|
char linebuf[256];
|
||||||
int linepos;
|
int linepos;
|
||||||
};
|
};
|
||||||
|
@ -79,7 +79,7 @@ static void _message(const char *from, const char *msg) {
|
||||||
int i;
|
int i;
|
||||||
for (i = 0; i != MAX_USERS; ++i) {
|
for (i = 0; i != MAX_USERS; ++i) {
|
||||||
if (users[i].sock != -1) {
|
if (users[i].sock != -1) {
|
||||||
telnet_printf(&users[i].telnet, "%s: %s\n", from, msg);
|
telnet_printf(users[i].telnet, "%s: %s\n", from, msg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -120,21 +120,21 @@ static void _online(const char *line, int overflow, void *ud) {
|
||||||
if (user->name == 0) {
|
if (user->name == 0) {
|
||||||
/* must not be empty, must be at least 32 chars */
|
/* must not be empty, must be at least 32 chars */
|
||||||
if (strlen(line) == 0 || strlen(line) > 32) {
|
if (strlen(line) == 0 || strlen(line) > 32) {
|
||||||
telnet_printf(&user->telnet, "Invalid name.\nEnter name: ");
|
telnet_printf(user->telnet, "Invalid name.\nEnter name: ");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* must not already be in use */
|
/* must not already be in use */
|
||||||
for (i = 0; i != MAX_USERS; ++i) {
|
for (i = 0; i != MAX_USERS; ++i) {
|
||||||
if (users[i].name != 0 && strcmp(users[i].name, line) == 0) {
|
if (users[i].name != 0 && strcmp(users[i].name, line) == 0) {
|
||||||
telnet_printf(&user->telnet, "Name in use.\nEnter name: ");
|
telnet_printf(user->telnet, "Name in use.\nEnter name: ");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* keep name */
|
/* keep name */
|
||||||
user->name = strdup(line);
|
user->name = strdup(line);
|
||||||
telnet_printf(&user->telnet, "Welcome, %s!\n", line);
|
telnet_printf(user->telnet, "Welcome, %s!\n", line);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -187,7 +187,7 @@ static void _event_handler(telnet_t *telnet, telnet_event_t *ev,
|
||||||
free(user->name);
|
free(user->name);
|
||||||
user->name = 0;
|
user->name = 0;
|
||||||
}
|
}
|
||||||
telnet_free(&user->telnet);
|
telnet_free(user->telnet);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
/* ignore */
|
/* ignore */
|
||||||
|
@ -296,11 +296,11 @@ int main(int argc, char **argv) {
|
||||||
|
|
||||||
/* init, welcome */
|
/* init, welcome */
|
||||||
users[i].sock = rs;
|
users[i].sock = rs;
|
||||||
telnet_init(&users[i].telnet, telopts, _event_handler, 0,
|
users[i].telnet = telnet_init(telopts, _event_handler, 0,
|
||||||
&users[i]);
|
&users[i]);
|
||||||
telnet_negotiate(&users[i].telnet, TELNET_WILL,
|
telnet_negotiate(users[i].telnet, TELNET_WILL,
|
||||||
TELNET_TELOPT_COMPRESS2);
|
TELNET_TELOPT_COMPRESS2);
|
||||||
telnet_printf(&users[i].telnet, "Enter name: ");
|
telnet_printf(users[i].telnet, "Enter name: ");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* read from client */
|
/* read from client */
|
||||||
|
@ -311,7 +311,7 @@ int main(int argc, char **argv) {
|
||||||
|
|
||||||
if (pfd[i].revents & POLLIN) {
|
if (pfd[i].revents & POLLIN) {
|
||||||
if ((rs = recv(users[i].sock, buffer, sizeof(buffer), 0)) > 0) {
|
if ((rs = recv(users[i].sock, buffer, sizeof(buffer), 0)) > 0) {
|
||||||
telnet_recv(&users[i].telnet, buffer, rs);
|
telnet_recv(users[i].telnet, buffer, rs);
|
||||||
} else if (rs == 0) {
|
} else if (rs == 0) {
|
||||||
printf("Connection closed.\n");
|
printf("Connection closed.\n");
|
||||||
close(users[i].sock);
|
close(users[i].sock);
|
||||||
|
@ -320,7 +320,7 @@ int main(int argc, char **argv) {
|
||||||
free(users[i].name);
|
free(users[i].name);
|
||||||
users[i].name = 0;
|
users[i].name = 0;
|
||||||
}
|
}
|
||||||
telnet_free(&users[i].telnet);
|
telnet_free(users[i].telnet);
|
||||||
users[i].sock = -1;
|
users[i].sock = -1;
|
||||||
break;
|
break;
|
||||||
} else if (errno != EINTR) {
|
} else if (errno != EINTR) {
|
||||||
|
|
|
@ -29,7 +29,7 @@
|
||||||
#include "libtelnet.h"
|
#include "libtelnet.h"
|
||||||
|
|
||||||
static struct termios orig_tios;
|
static struct termios orig_tios;
|
||||||
static telnet_t telnet;
|
static telnet_t *telnet;
|
||||||
static int do_echo;
|
static int do_echo;
|
||||||
|
|
||||||
static const telnet_telopt_t telopts[] = {
|
static const telnet_telopt_t telopts[] = {
|
||||||
|
@ -56,11 +56,11 @@ static void _input(char *buffer, int size) {
|
||||||
if (buffer[i] == '\r' || buffer[i] == '\n') {
|
if (buffer[i] == '\r' || buffer[i] == '\n') {
|
||||||
if (do_echo)
|
if (do_echo)
|
||||||
printf("\r\n");
|
printf("\r\n");
|
||||||
telnet_send(&telnet, crlf, 2);
|
telnet_send(telnet, crlf, 2);
|
||||||
} else {
|
} else {
|
||||||
if (do_echo)
|
if (do_echo)
|
||||||
putchar(buffer[i]);
|
putchar(buffer[i]);
|
||||||
telnet_send(&telnet, buffer + i, 1);
|
telnet_send(telnet, buffer + i, 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fflush(stdout);
|
fflush(stdout);
|
||||||
|
@ -197,7 +197,7 @@ int main(int argc, char **argv) {
|
||||||
do_echo = 1;
|
do_echo = 1;
|
||||||
|
|
||||||
/* initialize telnet box */
|
/* initialize telnet box */
|
||||||
telnet_init(&telnet, telopts, _event_handler, 0, &sock);
|
telnet = telnet_init(telopts, _event_handler, 0, &sock);
|
||||||
|
|
||||||
/* initialize poll descriptors */
|
/* initialize poll descriptors */
|
||||||
memset(pfd, 0, sizeof(pfd));
|
memset(pfd, 0, sizeof(pfd));
|
||||||
|
@ -224,7 +224,7 @@ int main(int argc, char **argv) {
|
||||||
/* read from client */
|
/* read from client */
|
||||||
if (pfd[1].revents & POLLIN) {
|
if (pfd[1].revents & POLLIN) {
|
||||||
if ((rs = recv(sock, buffer, sizeof(buffer), 0)) > 0) {
|
if ((rs = recv(sock, buffer, sizeof(buffer), 0)) > 0) {
|
||||||
telnet_recv(&telnet, buffer, rs);
|
telnet_recv(telnet, buffer, rs);
|
||||||
} else if (rs == 0) {
|
} else if (rs == 0) {
|
||||||
break;
|
break;
|
||||||
} else {
|
} else {
|
||||||
|
@ -236,7 +236,7 @@ int main(int argc, char **argv) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/* clean up */
|
/* clean up */
|
||||||
telnet_free(&telnet);
|
telnet_free(telnet);
|
||||||
close(sock);
|
close(sock);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -44,7 +44,7 @@
|
||||||
struct conn_t {
|
struct conn_t {
|
||||||
const char *name;
|
const char *name;
|
||||||
int sock;
|
int sock;
|
||||||
telnet_t telnet;
|
telnet_t *telnet;
|
||||||
struct conn_t *remote;
|
struct conn_t *remote;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -176,7 +176,7 @@ static void _event_handler(telnet_t *telnet, telnet_event_t *ev,
|
||||||
print_buffer(ev->buffer, ev->size);
|
print_buffer(ev->buffer, ev->size);
|
||||||
printf(COLOR_NORMAL "\n");
|
printf(COLOR_NORMAL "\n");
|
||||||
|
|
||||||
telnet_send(&conn->remote->telnet, ev->buffer, ev->size);
|
telnet_send(conn->remote->telnet, ev->buffer, ev->size);
|
||||||
break;
|
break;
|
||||||
/* data must be sent */
|
/* data must be sent */
|
||||||
case TELNET_EV_SEND:
|
case TELNET_EV_SEND:
|
||||||
|
@ -193,33 +193,33 @@ static void _event_handler(telnet_t *telnet, telnet_event_t *ev,
|
||||||
printf("%s IAC %s" COLOR_NORMAL "\n", conn->name,
|
printf("%s IAC %s" COLOR_NORMAL "\n", conn->name,
|
||||||
get_cmd(ev->command));
|
get_cmd(ev->command));
|
||||||
|
|
||||||
telnet_iac(&conn->remote->telnet, ev->command);
|
telnet_iac(conn->remote->telnet, ev->command);
|
||||||
break;
|
break;
|
||||||
/* negotiation, WILL */
|
/* negotiation, WILL */
|
||||||
case TELNET_EV_WILL:
|
case TELNET_EV_WILL:
|
||||||
printf("%s IAC WILL %d (%s)" COLOR_NORMAL "\n", conn->name,
|
printf("%s IAC WILL %d (%s)" COLOR_NORMAL "\n", conn->name,
|
||||||
(int)ev->telopt, get_opt(ev->telopt));
|
(int)ev->telopt, get_opt(ev->telopt));
|
||||||
telnet_negotiate(&conn->remote->telnet, TELNET_WILL,
|
telnet_negotiate(conn->remote->telnet, TELNET_WILL,
|
||||||
ev->telopt);
|
ev->telopt);
|
||||||
break;
|
break;
|
||||||
/* negotiation, WONT */
|
/* negotiation, WONT */
|
||||||
case TELNET_EV_WONT:
|
case TELNET_EV_WONT:
|
||||||
printf("%s IAC WONT %d (%s)" COLOR_NORMAL "\n", conn->name,
|
printf("%s IAC WONT %d (%s)" COLOR_NORMAL "\n", conn->name,
|
||||||
(int)ev->telopt, get_opt(ev->telopt));
|
(int)ev->telopt, get_opt(ev->telopt));
|
||||||
telnet_negotiate(&conn->remote->telnet, TELNET_WONT,
|
telnet_negotiate(conn->remote->telnet, TELNET_WONT,
|
||||||
ev->telopt);
|
ev->telopt);
|
||||||
break;
|
break;
|
||||||
/* negotiation, DO */
|
/* negotiation, DO */
|
||||||
case TELNET_EV_DO:
|
case TELNET_EV_DO:
|
||||||
printf("%s IAC DO %d (%s)" COLOR_NORMAL "\n", conn->name,
|
printf("%s IAC DO %d (%s)" COLOR_NORMAL "\n", conn->name,
|
||||||
(int)ev->telopt, get_opt(ev->telopt));
|
(int)ev->telopt, get_opt(ev->telopt));
|
||||||
telnet_negotiate(&conn->remote->telnet, TELNET_DO,
|
telnet_negotiate(conn->remote->telnet, TELNET_DO,
|
||||||
ev->telopt);
|
ev->telopt);
|
||||||
break;
|
break;
|
||||||
case TELNET_EV_DONT:
|
case TELNET_EV_DONT:
|
||||||
printf("%s IAC DONT %d (%s)" COLOR_NORMAL "\n", conn->name,
|
printf("%s IAC DONT %d (%s)" COLOR_NORMAL "\n", conn->name,
|
||||||
(int)ev->telopt, get_opt(ev->telopt));
|
(int)ev->telopt, get_opt(ev->telopt));
|
||||||
telnet_negotiate(&conn->remote->telnet, TELNET_DONT,
|
telnet_negotiate(conn->remote->telnet, TELNET_DONT,
|
||||||
ev->telopt);
|
ev->telopt);
|
||||||
break;
|
break;
|
||||||
/* subnegotiation */
|
/* subnegotiation */
|
||||||
|
@ -264,7 +264,7 @@ static void _event_handler(telnet_t *telnet, telnet_event_t *ev,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* forward */
|
/* forward */
|
||||||
telnet_subnegotiation(&conn->remote->telnet, ev->telopt,
|
telnet_subnegotiation(conn->remote->telnet, ev->telopt,
|
||||||
ev->buffer, ev->size);
|
ev->buffer, ev->size);
|
||||||
break;
|
break;
|
||||||
/* compression notification */
|
/* compression notification */
|
||||||
|
@ -389,9 +389,9 @@ int main(int argc, char **argv) {
|
||||||
client.remote = &server;
|
client.remote = &server;
|
||||||
|
|
||||||
/* initialize telnet boxes */
|
/* initialize telnet boxes */
|
||||||
telnet_init(&server.telnet, 0, _event_handler, TELNET_FLAG_PROXY,
|
server.telnet = telnet_init(0, _event_handler, TELNET_FLAG_PROXY,
|
||||||
&server);
|
&server);
|
||||||
telnet_init(&client.telnet, 0, _event_handler, TELNET_FLAG_PROXY,
|
client.telnet = telnet_init(0, _event_handler, TELNET_FLAG_PROXY,
|
||||||
&client);
|
&client);
|
||||||
|
|
||||||
/* initialize poll descriptors */
|
/* initialize poll descriptors */
|
||||||
|
@ -406,7 +406,7 @@ int main(int argc, char **argv) {
|
||||||
/* read from server */
|
/* read from server */
|
||||||
if (pfd[0].revents & POLLIN) {
|
if (pfd[0].revents & POLLIN) {
|
||||||
if ((rs = recv(server.sock, buffer, sizeof(buffer), 0)) > 0) {
|
if ((rs = recv(server.sock, buffer, sizeof(buffer), 0)) > 0) {
|
||||||
telnet_recv(&server.telnet, buffer, rs);
|
telnet_recv(server.telnet, buffer, rs);
|
||||||
} else if (rs == 0) {
|
} else if (rs == 0) {
|
||||||
printf("%s DISCONNECTED" COLOR_NORMAL "\n", server.name);
|
printf("%s DISCONNECTED" COLOR_NORMAL "\n", server.name);
|
||||||
break;
|
break;
|
||||||
|
@ -422,7 +422,7 @@ int main(int argc, char **argv) {
|
||||||
/* read from client */
|
/* read from client */
|
||||||
if (pfd[1].revents & POLLIN) {
|
if (pfd[1].revents & POLLIN) {
|
||||||
if ((rs = recv(client.sock, buffer, sizeof(buffer), 0)) > 0) {
|
if ((rs = recv(client.sock, buffer, sizeof(buffer), 0)) > 0) {
|
||||||
telnet_recv(&client.telnet, buffer, rs);
|
telnet_recv(client.telnet, buffer, rs);
|
||||||
} else if (rs == 0) {
|
} else if (rs == 0) {
|
||||||
printf("%s DISCONNECTED" COLOR_NORMAL "\n", client.name);
|
printf("%s DISCONNECTED" COLOR_NORMAL "\n", client.name);
|
||||||
break;
|
break;
|
||||||
|
@ -437,8 +437,8 @@ int main(int argc, char **argv) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/* clean up */
|
/* clean up */
|
||||||
telnet_free(&server.telnet);
|
telnet_free(server.telnet);
|
||||||
telnet_free(&client.telnet);
|
telnet_free(client.telnet);
|
||||||
close(server.sock);
|
close(server.sock);
|
||||||
close(client.sock);
|
close(client.sock);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue