/*
* newio.c: This is some handy stuff to deal with file descriptors in a way
* much like stdio's FILE pointers
*
* IMPORTANT NOTE: If you use the routines here-in, you shouldn't switch to
* using normal reads() on the descriptors cause that will cause bad things
* to happen. If using any of these routines, use them all
*
* Written By Michael Sandrof
*
* Copyright(c) 1990
*
* See the COPYRIGHT file, or do a HELP IRCII COPYRIGHT
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "irc.h"
#include "ircaux.h"
#include "newio.h"
#ifdef ISC22
#include <sys/bsdtypes.h>
#endif /* ISC22 */
#include "irc_std.h"
#define IO_BUFFER_SIZE 512
#ifdef HAVE_SYSCONF
#define IO_ARRAYLEN sysconf(_SC_OPEN_MAX)
#else
#ifdef FD_SETSIZE
#define IO_ARRAYLEN FDSETSIZE
#else
#define IO_ARRAYLEN NFDBITS
#endif
#endif
typedef struct myio_struct {
char buffer[IO_BUFFER_SIZE + 1];
unsigned int read_pos, write_pos;
unsigned misc_flags;
} MyIO;
#define IO_SOCKET 1
static struct timeval right_away = { 0L, 0L };
static MyIO **io_rec = NULL;
static struct timeval dgets_timer = { 0, 0 };
static struct timeval *timer = NULL;
int dgets_errno = 0;
static void init_io(void);
/*
* dgets_timeout: does what you'd expect. Sets a timeout in seconds for
* dgets to read a line. if second is -1, then make it a poll.
*/
extern time_t dgets_timeout(int sec)
{
time_t old_timeout = dgets_timer.tv_sec;
if (sec) {
dgets_timer.tv_sec = (sec == -1) ? 0 : sec;
dgets_timer.tv_usec = 0;
timer = &dgets_timer;
} else
timer = NULL;
return old_timeout;
}
static void init_io(void)
{
static int first = 1;
if (first) {
int c, max_fd = IO_ARRAYLEN;
io_rec = (MyIO **) new_malloc(sizeof(MyIO *) * max_fd);
for (c = 0; c < max_fd; c++)
io_rec[c] = NULL;
(void) dgets_timeout(-1);
first = 0;
}
}
/*
* dgets: works much like fgets except on descriptor rather than file
* pointers. Returns the number of character read in. Returns 0 on EOF and
* -1 on a timeout (see dgets_timeout())
*/
int dgets(char *str, int len, int des, char *specials)
{
#if 1
int cnt = 0, c;
fd_set rd;
int BufferEmpty;
init_io();
if (io_rec[des] == NULL) {
io_rec[des] = (MyIO *) new_malloc(sizeof(MyIO));
io_rec[des]->read_pos = 0;
io_rec[des]->write_pos = 0;
io_rec[des]->misc_flags = 0;
}
while (1) {
if ((BufferEmpty = (io_rec[des]->read_pos == io_rec[des]->write_pos))) {
if (BufferEmpty) {
io_rec[des]->read_pos = 0;
io_rec[des]->write_pos = 0;
}
FD_ZERO(&rd);
FD_SET(des, &rd);
switch (select(des + 1, &rd, NULL, NULL, timer)) {
case 0:
{
str[cnt] = (char) 0;
dgets_errno = 0;
return (-1);
}
default:
{
c = read(des, io_rec[des]->buffer + io_rec[des]->write_pos, IO_BUFFER_SIZE - io_rec[des]->write_pos);
if (c <= 0) {
if (c == 0)
dgets_errno = -1;
else
dgets_errno = errno;
return 0;
}
io_rec[des]->write_pos += c;
break;
}
}
}
while (io_rec[des]->read_pos < io_rec[des]->write_pos) {
if (((str[cnt++] = io_rec[des]->buffer[(io_rec[des]->read_pos)++])
== '\n') || (cnt == len)) {
dgets_errno = 0;
str[cnt] = (char) 0;
return (cnt);
}
}
}
#else
int cnt = 0, c, s;
fd_set rd;
int BufferEmpty;
init_io();
if (io_rec[des] == NULL) {
io_rec[des] = (MyIO *) new_malloc(sizeof(MyIO));
io_rec[des]->read_pos = 0;
io_rec[des]->write_pos = 0;
io_rec[des]->misc_flags = 0;
}
if (io_rec[des]->read_pos == io_rec[des]->write_pos) {
io_rec[des]->read_pos = 0;
io_rec[des]->write_pos = 0;
FD_ZERO(&rd);
FD_SET(des, &rd);
s = select(des + 1, &rd, 0, 0, timer);
if (s <= 0) {
strcpy(str, empty_str);
dgets_errno = (s == 0) ? -1 : errno;
return 0;
} else {
c = read(des, io_rec[des]->buffer + io_rec[des]->write_pos, IO_BUFFER_SIZE - io_rec[des]->write_pos);
if (c <= 0) {
dgets_errno = (s == 0) ? -1 : errno;
return 0;
}
io_rec[des]->write_pos += c;
}
}
while (io_rec[des]->read_pos < io_rec[des]->write_pos) {
str[cnt] = io_rec[des]->buffer[io_rec[des]->read_pos];
io_rec[des]->read_pos++;
if (str[cnt] == '\n')
break;
cnt++;
}
/* Add on newline if its not there. */
if (str[cnt] != '\n')
str[++cnt] = '\n';
dgets_errno = 0;
str[++cnt] = 0;
return cnt - 1;
#endif
}
/*
* new_select: works just like select(), execpt I trimmed out the excess
* parameters I didn't need.
*/
int new_select(fd_set * rd, fd_set * wd, struct timeval *timeout)
{
int i, set = 0;
fd_set new;
struct timeval thetimeout, *newtimeout = &thetimeout;
int max_fd = -1;
static int num_fd = 0;
if (!num_fd) {
num_fd = IO_ARRAYLEN; /* why do it a zillion times? */
if (num_fd > FD_SETSIZE)
num_fd = FD_SETSIZE;
}
if (timeout)
memcpy(newtimeout, timeout, sizeof(struct timeval));
else
newtimeout = NULL;
init_io();
FD_ZERO(&new);
for (i = 0; i < num_fd; i++) {
if (i > max_fd && ((rd && FD_ISSET(i, rd)) || (wd && FD_ISSET(i, wd))))
max_fd = i;
if (io_rec[i]) {
if (io_rec[i]->read_pos < io_rec[i]->write_pos) {
FD_SET(i, &new);
set = 1;
}
}
}
if (set) {
set = 0;
if (select(max_fd + 1, rd, wd, NULL, &right_away) <= 0)
FD_ZERO(rd);
for (i = 0; i < num_fd; i++) {
if ((FD_ISSET(i, rd)) || (FD_ISSET(i, &new))) {
set++;
FD_SET(i, rd);
} else
FD_CLR(i, rd);
}
return (set);
}
return (select(max_fd + 1, rd, wd, NULL, newtimeout));
}
/* new_close: works just like close */
void new_close(int des)
{
if (des < 0 || !io_rec)
return;
new_free((char **) &(io_rec[des]));
close(des);
}
/* set's socket options */
extern void set_socket_options(int s)
{
int opt = 1;
int optlen = sizeof(opt);
#ifndef NO_STRUCT_LINGER
struct linger lin = { 0 };
lin.l_onoff = lin.l_linger = 0;
(void) setsockopt(s, SOL_SOCKET, SO_LINGER, (void *) &lin, optlen);
opt = 1;
#endif /* NO_STRUCT_LINGER */
(void) setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (void *) &opt, optlen);
opt = 1;
(void) setsockopt(s, SOL_SOCKET, SO_KEEPALIVE, (void *) &opt, optlen);
}
syntax highlighted by Code2HTML, v. 0.9.1