make API const-safe

This commit is contained in:
Sean Middleditch 2009-03-16 16:51:41 -04:00
parent c337ba6bca
commit 97a8cb25b9
6 changed files with 26 additions and 352 deletions

11
README
View File

@ -95,7 +95,7 @@ IIa. Initialization
IIb. Receiving Data IIb. Receiving Data
void libtelnet_push(libtelnet_t *telnet, void libtelnet_push(libtelnet_t *telnet,
unsigned char *buffer, unsigned int size, void *user_data); const unsigned char *buffer, unsigned int size, void *user_data);
When your application receives data over the socket from the When your application receives data over the socket from the
remote end, it must pass the received bytes into this function. remote end, it must pass the received bytes into this function.
@ -132,13 +132,14 @@ IIc. Sending Data
LIBTELNET_DONT. The opt parameter is the option to LIBTELNET_DONT. The opt parameter is the option to
negotiate. negotiate.
void libtelnet_send_data(libtelnet_t *telnet, unsigned char *buffer, void libtelnet_send_data(libtelnet_t *telnet,
unsigned int size); const unsigned char *buffer, unsigned int size);
Sends raw data, which would be either the process output from Sends raw data, which would be either the process output from
a server or the user input from a client. a server or the user input from a client.
void libtelnet_send_subnegotiation(libtelnet_t *telnet, void libtelnet_send_subnegotiation(libtelnet_t *telnet,
unsigned char telopt, unsigned char *buffer, unsigned int size); unsigned char telopt, const unsigned char *buffer,
unsigned int size);
Sends a TELNET sub-negotiation command. The telopt parameter Sends a TELNET sub-negotiation command. The telopt parameter
is the sub-negotiation option. is the sub-negotiation option.
@ -172,7 +173,7 @@ IId. Event Handling
pointer passed to libtelnet_init(). pointer passed to libtelnet_init().
struct libtelnet_event_t { struct libtelnet_event_t {
unsigned char *buffer; const unsigned char *buffer;
unsigned int size; unsigned int size;
libtelnet_event_type_t type; libtelnet_event_type_t type;
unsigned char command; unsigned char command;

View File

@ -48,8 +48,8 @@ static const unsigned int _buffer_sizes_count = sizeof(_buffer_sizes) /
/* event dispatch helper; return value is value of the accept field of the /* event dispatch helper; return value is value of the accept field of the
* event struct after dispatch; used for the funky REQUEST event */ * event struct after dispatch; used for the funky REQUEST event */
static int _event(libtelnet_t *telnet, libtelnet_event_type_t type, static int _event(libtelnet_t *telnet, libtelnet_event_type_t type,
unsigned char command, unsigned char telopt, unsigned char *buffer, unsigned char command, unsigned char telopt,
unsigned int size) { const unsigned char *buffer, unsigned int size) {
libtelnet_event_t ev; libtelnet_event_t ev;
ev.buffer = buffer; ev.buffer = buffer;
ev.size = size; ev.size = size;
@ -126,7 +126,7 @@ libtelnet_error_t _init_zlib(libtelnet_t *telnet, int deflate, int err_fatal) {
} }
/* push bytes out, compressing them first if need be */ /* push bytes out, compressing them first if need be */
static void _send(libtelnet_t *telnet, unsigned char *buffer, static void _send(libtelnet_t *telnet, const unsigned char *buffer,
unsigned int size) { unsigned int size) {
#ifdef HAVE_ZLIB #ifdef HAVE_ZLIB
/* if we have a deflate (compression) zlib box, use it */ /* if we have a deflate (compression) zlib box, use it */
@ -135,7 +135,7 @@ static void _send(libtelnet_t *telnet, unsigned char *buffer,
int rs; int rs;
/* initialize z state */ /* initialize z state */
telnet->z->next_in = buffer; telnet->z->next_in = (unsigned char *)buffer;
telnet->z->avail_in = size; telnet->z->avail_in = size;
telnet->z->next_out = deflate_buffer; telnet->z->next_out = deflate_buffer;
telnet->z->avail_out = sizeof(deflate_buffer); telnet->z->avail_out = sizeof(deflate_buffer);
@ -450,7 +450,7 @@ static libtelnet_error_t _buffer_byte(libtelnet_t *telnet,
return LIBTELNET_EOK; return LIBTELNET_EOK;
} }
static void _process(libtelnet_t *telnet, unsigned char *buffer, static void _process(libtelnet_t *telnet, const unsigned char *buffer,
unsigned int size) { unsigned int size) {
unsigned char byte; unsigned char byte;
unsigned int i, start; unsigned int i, start;
@ -610,7 +610,7 @@ static void _process(libtelnet_t *telnet, unsigned char *buffer,
} }
/* push a bytes into the state tracker */ /* push a bytes into the state tracker */
void libtelnet_push(libtelnet_t *telnet, unsigned char *buffer, void libtelnet_push(libtelnet_t *telnet, const unsigned char *buffer,
unsigned int size) { unsigned int size) {
#ifdef HAVE_ZLIB #ifdef HAVE_ZLIB
/* if we have an inflate (decompression) zlib stream, use it */ /* if we have an inflate (decompression) zlib stream, use it */
@ -619,7 +619,7 @@ void libtelnet_push(libtelnet_t *telnet, unsigned char *buffer,
int rs; int rs;
/* initialize zlib state */ /* initialize zlib state */
telnet->z->next_in = buffer; telnet->z->next_in = (unsigned char *)buffer;
telnet->z->avail_in = size; telnet->z->avail_in = size;
telnet->z->next_out = inflate_buffer; telnet->z->next_out = inflate_buffer;
telnet->z->avail_out = sizeof(inflate_buffer); telnet->z->avail_out = sizeof(inflate_buffer);
@ -792,10 +792,10 @@ void libtelnet_send_negotiate(libtelnet_t *telnet, unsigned char cmd,
} }
/* send non-command data (escapes IAC bytes) */ /* send non-command data (escapes IAC bytes) */
void libtelnet_send_data(libtelnet_t *telnet, unsigned char *buffer, void libtelnet_send_data(libtelnet_t *telnet, const unsigned char *buffer,
unsigned int size) { unsigned int size) {
static unsigned char CRLF[] = { '\r', '\n' }; static const unsigned char CRLF[] = { '\r', '\n' };
static unsigned char CRNUL[] = { '\r', '\0' }; static const unsigned char CRNUL[] = { '\r', '\0' };
unsigned int i, l; unsigned int i, l;
for (l = i = 0; i != size; ++i) { for (l = i = 0; i != size; ++i) {
@ -832,7 +832,7 @@ void libtelnet_send_data(libtelnet_t *telnet, unsigned char *buffer,
/* send sub-request */ /* send sub-request */
void libtelnet_send_subnegotiation(libtelnet_t *telnet, unsigned char telopt, void libtelnet_send_subnegotiation(libtelnet_t *telnet, unsigned char telopt,
unsigned char *buffer, unsigned int size) { const unsigned char *buffer, unsigned int size) {
libtelnet_send_telopt(telnet, LIBTELNET_SB, telopt); libtelnet_send_telopt(telnet, LIBTELNET_SB, telopt);
libtelnet_send_data(telnet, buffer, size); libtelnet_send_data(telnet, buffer, size);
libtelnet_send_command(telnet, LIBTELNET_SE); libtelnet_send_command(telnet, LIBTELNET_SE);
@ -855,7 +855,7 @@ void libtelnet_send_subnegotiation(libtelnet_t *telnet, unsigned char telopt,
void libtelnet_begin_compress2(libtelnet_t *telnet) { void libtelnet_begin_compress2(libtelnet_t *telnet) {
#ifdef HAVE_ZLIB #ifdef HAVE_ZLIB
unsigned char compress2[] = { LIBTELNET_IAC, LIBTELNET_SB, static const unsigned char compress2[] = { LIBTELNET_IAC, LIBTELNET_SB,
LIBTELNET_TELOPT_COMPRESS2, LIBTELNET_IAC, LIBTELNET_SE }; LIBTELNET_TELOPT_COMPRESS2, LIBTELNET_IAC, LIBTELNET_SE };
/* attempt to create output stream first, bail if we can't */ /* attempt to create output stream first, bail if we can't */

View File

@ -137,7 +137,7 @@ enum libtelnet_event_type_t {
/* event information */ /* event information */
struct libtelnet_event_t { struct libtelnet_event_t {
/* data buffer: for DATA, SEND, SUBNEGOTIATION, and ERROR events */ /* data buffer: for DATA, SEND, SUBNEGOTIATION, and ERROR events */
unsigned char *buffer; const unsigned char *buffer;
unsigned int size; unsigned int size;
/* type of event */ /* type of event */
enum libtelnet_event_type_t type; enum libtelnet_event_type_t type;
@ -195,7 +195,7 @@ extern void libtelnet_init(libtelnet_t *telnet, libtelnet_event_handler_t eh,
extern void libtelnet_free(libtelnet_t *telnet); extern void libtelnet_free(libtelnet_t *telnet);
/* push a byte buffer into the state tracker */ /* push a byte buffer into the state tracker */
extern void libtelnet_push(libtelnet_t *telnet, unsigned char *buffer, extern void libtelnet_push(libtelnet_t *telnet, const unsigned char *buffer,
unsigned int size); unsigned int size);
/* send an iac command */ /* send an iac command */
@ -213,8 +213,8 @@ extern void libtelnet_send_negotiate(libtelnet_t *telnet, unsigned char cmd,
unsigned char opt); unsigned char opt);
/* send non-command data (escapes IAC bytes) */ /* send non-command data (escapes IAC bytes) */
extern void libtelnet_send_data(libtelnet_t *telnet, unsigned char *buffer, extern void libtelnet_send_data(libtelnet_t *telnet,
unsigned int size); const unsigned char *buffer, unsigned int size);
/* send sub-request, equivalent to: /* send sub-request, equivalent to:
* libtelnet_send_telopt(telnet, LIBTELNET_SB, telopt) * libtelnet_send_telopt(telnet, LIBTELNET_SB, telopt)
@ -224,7 +224,7 @@ extern void libtelnet_send_data(libtelnet_t *telnet, unsigned char *buffer,
* thare are most easily implemented with a series of send_data calls. * thare are most easily implemented with a series of send_data calls.
*/ */
extern void libtelnet_send_subnegotiation(libtelnet_t *telnet, extern void libtelnet_send_subnegotiation(libtelnet_t *telnet,
unsigned char telopt, unsigned char *buffer, unsigned int size); unsigned char telopt, const unsigned char *buffer, unsigned int size);
/* begin sending compressed data (server only) */ /* begin sending compressed data (server only) */
extern void libtelnet_begin_compress2(libtelnet_t *telnet); extern void libtelnet_begin_compress2(libtelnet_t *telnet);

View File

@ -1,327 +0,0 @@
/*
* Sean Middleditch
* sean@sourcemud.org
*
* The author or authors of this code dedicate any and all copyright interest
* in this code to the public domain. We make this dedication for the benefit
* of the public at large and to the detriment of our heirs and successors. We
* intend this dedication to be an overt act of relinquishment in perpetuity of
* all present and future rights to this code under copyright law.
*/
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <poll.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#include <unistd.h>
#ifdef HAVE_ZLIB
#include "zlib.h"
#endif
#include "libtelnet.h"
#define MAX_USERS 64
#define LINEBUFFER_SIZE 256
struct user_t {
char *name;
int sock;
libtelnet_t telnet;
char linebuf[256];
int linepos;
};
static struct user_t users[MAX_USERS];
static void linebuffer_push(char *buffer, size_t size, int *linepos,
char ch, void (*cb)(const char *line, int overflow, void *ud),
void *ud) {
/* CRLF -- line terminator */
if (ch == '\n' && *linepos > 0 && buffer[*linepos - 1] == '\r') {
/* NUL terminate (replaces \r in buffer), notify app, clear */
buffer[*linepos - 1] = 0;
cb(buffer, 0, ud);
*linepos = 0;
/* CRNUL -- just a CR */
} else if (ch == 0 && *linepos > 0 && buffer[*linepos - 1] == '\r') {
/* do nothing, the CR is already in the buffer */
/* anything else (including technically invalid CR followed by
* anything besides LF or NUL -- just buffer if we have room
* \r
*/
} else if (*linepos != size) {
buffer[(*linepos)++] = ch;
/* buffer overflow */
} else {
/* terminate (NOTE: eats a byte), notify app, clear buffer */
buffer[size - 1] = 0;
cb(buffer, size - 1, ud);
*linepos = 0;
}
}
static void _message(const char *from, const char *msg) {
int i;
for (i = 0; i != MAX_USERS; ++i) {
if (users[i].sock != -1) {
libtelnet_send_printf(&users[i].telnet, "%s: %s\r\n",
from, msg);
}
}
}
static void _send(int sock, unsigned char *buffer, unsigned int size) {
int rs;
/* ignore on invalid socket */
if (sock == -1)
return;
/* send data */
while (size > 0) {
if ((rs = send(sock, buffer, size, 0)) == -1) {
if (errno != EINTR && errno != ECONNRESET) {
fprintf(stderr, "send() failed: %s\n", strerror(errno));
exit(1);
} else {
return;
}
} else if (rs == 0) {
fprintf(stderr, "send() unexpectedly returned 0\n");
exit(1);
}
/* update pointer and size to see if we've got more to send */
buffer += rs;
size -= rs;
}
}
/* process input line */
static void _online(const char *line, int overflow, void *ud) {
struct user_t *user = (struct user_t*)ud;
int i;
/* if the user has no name, this is his "login" */
if (user->name == 0) {
/* must not be empty, must be at least 32 chars */
if (strlen(line) == 0 || strlen(line) > 32) {
libtelnet_send_printf(&user->telnet,
"Invalid name.\r\nEnter name: ");
return;
}
/* must not already be in use */
for (i = 0; i != MAX_USERS; ++i) {
if (users[i].name != 0 && strcmp(users[i].name, line) == 0) {
libtelnet_send_printf(&user->telnet,
"Name in use.\r\nEnter name: ");
return;
}
}
/* keep name */
user->name = strdup(line);
libtelnet_send_printf(&user->telnet, "Welcome, %s!\r\n", line);
return;
}
/* if line is "quit" then, well, quit */
if (strcmp(line, "quit") == 0) {
close(user->sock);
user->sock = -1;
_message(user->name, "** HAS QUIT **");
free(user->name);
user->name = 0;
return;
}
/* just a message -- send to all users */
_message(user->name, line);
}
static void _input(struct user_t *user, unsigned char *buffer,
unsigned int size) {
unsigned int i;
for (i = 0; i != size; ++i)
linebuffer_push(user->linebuf, sizeof(user->linebuf), &user->linepos,
(char)buffer[i], _online, user);
}
static void _event_handler(libtelnet_t *telnet, libtelnet_event_t *ev,
void *user_data) {
struct user_t *user = (struct user_t*)user_data;
switch (ev->type) {
/* data received */
case LIBTELNET_EV_DATA:
_input(user, ev->buffer, ev->size);
break;
/* data must be sent */
case LIBTELNET_EV_SEND:
_send(user->sock, ev->buffer, ev->size);
break;
/* error */
case LIBTELNET_EV_ERROR:
close(user->sock);
user->sock = -1;
if (user->name != 0) {
_message(user->name, "** HAS HAD AN ERROR **");
free(user->name);
user->name = 0;
}
libtelnet_free(&user->telnet);
break;
default:
/* ignore */
break;
}
}
int main(int argc, char **argv) {
unsigned char buffer[512];
short listen_port;
int listen_sock;
int rs;
int i;
struct sockaddr_in addr;
socklen_t addrlen;
struct pollfd pfd[MAX_USERS + 1];
/* check usage */
if (argc != 2) {
fprintf(stderr, "Usage:\n ./telnet-chatd <port>\n");
return 1;
}
/* initialize data structures */
memset(&pfd, 0, sizeof(pfd));
memset(users, 0, sizeof(users));
for (i = 0; i != MAX_USERS; ++i)
users[i].sock = -1;
/* parse listening port */
listen_port = strtol(argv[1], 0, 10);
/* create listening socket */
if ((listen_sock = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
fprintf(stderr, "socket() failed: %s\n", strerror(errno));
return 1;
}
/* reuse address option */
rs = 1;
setsockopt(listen_sock, SOL_SOCKET, SO_REUSEADDR, &rs, sizeof(rs));
/* bind to listening addr/port */
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = INADDR_ANY;
addr.sin_port = htons(listen_port);
if (bind(listen_sock, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
fprintf(stderr, "bind() failed: %s\n", strerror(errno));
return 1;
}
/* listen for clients */
if (listen(listen_sock, 5) == -1) {
fprintf(stderr, "listen() failed: %s\n", strerror(errno));
return 1;
}
printf("LISTENING ON PORT %d\n", listen_port);
/* initialize listening descriptors */
pfd[MAX_USERS].fd = listen_sock;
pfd[MAX_USERS].events = POLLIN;
/* loop for ever */
for (;;) {
/* prepare for poll */
for (i = 0; i != MAX_USERS; ++i) {
if (users[i].sock != -1) {
pfd[i].fd = users[i].sock;
pfd[i].events = POLLIN;
} else {
pfd[i].fd = -1;
pfd[i].events = 0;
}
}
/* poll */
rs = poll(pfd, MAX_USERS + 1, -1);
if (rs == -1 && errno != EINTR) {
fprintf(stderr, "poll() failed: %s\n", strerror(errno));
return 1;
}
/* new connection */
if (pfd[MAX_USERS].revents & POLLIN) {
/* acept the sock */
addrlen = sizeof(addr);
if ((rs = accept(listen_sock, (struct sockaddr *)&addr,
&addrlen)) == -1) {
fprintf(stderr, "accept() failed: %s\n", strerror(errno));
return 1;
}
printf("Connection received.\n");
/* find a free user */
for (i = 0; i != MAX_USERS; ++i)
if (users[i].sock == -1)
break;
if (i == MAX_USERS) {
printf(" rejected (too many users)\n");
_send(rs, (unsigned char *)"Too many users.\r\n", 14);
close(rs);
}
/* init, welcome */
users[i].sock = rs;
libtelnet_init(&users[i].telnet, _event_handler, 0, &users[i]);
libtelnet_send_printf(&users[i].telnet, "Enter name: ");
}
/* read from client */
for (i = 0; i != MAX_USERS; ++i) {
/* skip users that aren't actually connected */
if (users[i].sock == -1)
continue;
if (pfd[i].revents & POLLIN) {
if ((rs = recv(users[i].sock, buffer, sizeof(buffer), 0)) > 0) {
libtelnet_push(&users[i].telnet, buffer, rs);
} else if (rs == 0) {
printf("Connection closed.\n");
close(users[i].sock);
if (users[i].name != 0) {
_message(users[i].name, "** HAS DISCONNECTED **");
free(users[i].name);
users[i].name = 0;
}
libtelnet_free(&users[i].telnet);
users[i].sock = -1;
break;
} else if (errno != EINTR) {
fprintf(stderr, "recv(client) failed: %s\n",
strerror(errno));
exit(1);
}
}
}
}
/* not that we can reach this, but GCC will cry if it's not here */
return 0;
}

View File

@ -57,7 +57,7 @@ static void _input(unsigned char *buffer, int size) {
} }
} }
static void _send(int sock, unsigned char *buffer, unsigned int size) { static void _send(int sock, const unsigned char *buffer, unsigned int size) {
int rs; int rs;
/* send data */ /* send data */

View File

@ -129,7 +129,7 @@ static const char *get_opt(unsigned char opt) {
} }
} }
static void print_buffer(unsigned char *buffer, unsigned int size) { static void print_buffer(const unsigned char *buffer, unsigned int size) {
unsigned int i; unsigned int i;
for (i = 0; i != size; ++i) { for (i = 0; i != size; ++i) {
if (buffer[i] == ' ' || (isprint(buffer[i]) && !isspace(buffer[i]))) if (buffer[i] == ' ' || (isprint(buffer[i]) && !isspace(buffer[i])))
@ -142,7 +142,7 @@ static void print_buffer(unsigned char *buffer, unsigned int size) {
} }
} }
static void _send(int sock, unsigned char *buffer, unsigned int size) { static void _send(int sock, const unsigned char *buffer, unsigned int size) {
int rs; int rs;
/* send data */ /* send data */