/* * 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 */ #ifndef lint static char rcsid[] = "@(#)$Id: newio.c,v 1.21 1994/07/03 09:41:00 mrg Stab $"; #endif #include "irc.h" #include "ircaux.h" #ifdef ISC22 # include #endif /* ISC22 */ #ifdef ESIX # include #endif /* ESIX */ #include "irc_std.h" #define IO_BUFFER_SIZE 512 #define WAIT_NL ((unsigned) 0x0001) #ifdef FDSETSIZE # define IO_ARRAYLEN FDSETSIZE #else # ifdef FD_SETSIZE # define IO_ARRAYLEN FD_SETSIZE # 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; #if defined(ESIX) || defined(_Windows) unsigned flags; #endif /* ESIX */ #ifdef _Windows int fd; #endif } MyIO; #define IO_SOCKET 1 static struct timeval right_away = { 0L, 0L }; static MyIO *io_rec[IO_ARRAYLEN]; #ifdef _Windows #define get_ior(x) (*get_io_rec(x)) MyIO **get_io_rec(int fd) { int i; for (i = 0; i < IO_ARRAYLEN; i++) { if (io_rec[i] && io_rec[i]->fd == fd) return &io_rec[i]; } for (i = 0; i < IO_ARRAYLEN; i++) { if (!io_rec[i]) return &io_rec[i]; } } #else #define get_ior(x) io_rec[x] #endif static struct timeval dgets_timer; static struct timeval *timer; int dgets_errno = 0; MyIO * new_io_rec(int fd) { MyIO *rec; rec = (MyIO *) new_malloc(sizeof(MyIO)); rec->read_pos = 0; rec->write_pos = 0; rec->flags = 0; #ifdef _Windows rec->fd = fd; #endif return rec; } #if defined(ESIX) || defined(_Windows) static void init_io(); /* Esix must know if it is a socket or not. */ void mark_socket(int des) { MyIO **rec; init_io(); rec = & get_ior(des); if (*rec == (MyIO *) 0) *rec = new_io_rec(des); (*rec)->flags |= IO_SOCKET; } void unmark_socket(int des) { MyIO **rec; init_io(); rec = & get_ior(des); if (*rec == (MyIO *) 0) *rec = new_io_rec(des); (*rec)->flags &= ~IO_SOCKET; } #endif /* ESIX || _Windows */ /* * 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(sec) 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 = (struct timeval *) 0; return old_timeout; } static void init_io() { static int first = 1; if (first) { int c; for (c = 0; c < IO_ARRAYLEN; c++) io_rec[c] = (MyIO *) 0; (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(str, len, des, specials) char *str; int len; int des; char *specials; { char *ptr, ch; int cnt = 0, c; fd_set rd; int WantNewLine = 0; int BufferEmpty; int i, j; MyIO **rec; init_io(); rec = & get_ior(des); if (*rec == (MyIO *) 0) *rec = new_io_rec(des); if (len < 0) { WantNewLine = 1; len = (-len); (*rec)->misc_flags |= WAIT_NL; } while (1) { if ((BufferEmpty = ((*rec)->read_pos == (*rec)->write_pos)) || WantNewLine) { if(BufferEmpty) { (*rec)->read_pos = 0; (*rec)->write_pos = 0; } FD_ZERO(&rd); FD_SET(des, &rd); switch (select(des + 1, &rd, 0, 0, timer)) { case 0: str[cnt] = (char) 0; dgets_errno = 0; return (-1); default: #if defined(ESIX) || defined(_Windows) if ((*rec)->flags & IO_SOCKET) { #ifdef _Windows WSASetLastError(0); #endif c = recv(des, (*rec)->buffer + (*rec)->write_pos, IO_BUFFER_SIZE-(*rec)->write_pos, 0); } else #endif /* ESIX */ c = read(des, (*rec)->buffer + (*rec)->write_pos, IO_BUFFER_SIZE-(*rec)->write_pos); if (c <= 0) { #ifdef _Windows if ((*rec)->flags & IO_SOCKET) { dgets_errno == WSAGetLastError(); if (dgets_errno == WSAEWOULDBLOCK || dgets_errno == WSAEINTR) { return -1; } return 0; } else { dgets_errno = errno; return 0; } #else dgets_errno = errno; return 0; #endif } if (WantNewLine && specials) { ptr = (*rec)->buffer; for (i = (*rec)->write_pos; i < (*rec)->write_pos+c;i++) /* This section re-indented - phone, jan 1993 */ { if((ch = ptr[i]) == specials[0]) { if (i > 0) { bcopy(ptr + i - 1, ptr + i + 1, (*rec)->write_pos + c - i - 1); i -= 2; c -= 2; } else { bcopy(ptr, ptr + 1, (*rec)->write_pos + c - 1); i--; c--; } } else if (ch == specials[2]) { for (j = i - 1; j >= 0 && isspace(ptr[j]); j--) ; for (;j >= 0 && !isspace(ptr[j]); j--) ; bcopy(ptr + j + 1, ptr + i + 1, (*rec)->write_pos + c - i - 1); c -= (i - j); i = j; } else if (ch == specials[1]) { for (j = i - 1; j >= 0 && ptr[j] != '\n'; j--); bcopy(ptr + j + 1, ptr + i + 1, (*rec)->write_pos + c - i - 1); c -= (i-j); i = j; } } } (*rec)->write_pos += c; break; } } ptr = (*rec)->buffer; if (WantNewLine) { for (cnt = (*rec)->write_pos; cnt > 0;cnt--,ptr++) { if (*ptr == '\n' || cnt == len-1) { *ptr = '\0'; (void) strcpy(str, (*rec)->buffer); (*rec)->write_pos=cnt-1; bcopy((*rec)->buffer, ptr, cnt); dgets_errno = 0; return 1; } } return -2; } while ((*rec)->read_pos < (*rec)->write_pos) { if (((str[cnt++] = ptr[((*rec)->read_pos)++]) == '\n') || (cnt == len)) { dgets_errno = 0; str[cnt] = (char) 0; return (cnt); } } } } /* * new_select: works just like select(), execpt I trimmed out the excess * parameters I didn't need. */ int new_select(rd, wd, timeout) fd_set *rd, *wd; struct timeval *timeout; { int i, set = 0; fd_set new; struct timeval *newtimeout, thetimeout; if (timeout) { newtimeout = &thetimeout; bcopy(timeout, newtimeout, sizeof(struct timeval)); } else newtimeout = NULL; init_io(); FD_ZERO(&new); for (i = 0; i < IO_ARRAYLEN; i++) { if (io_rec[i] && !(io_rec[i]->misc_flags&WAIT_NL)) { if (io_rec[i]->read_pos < io_rec[i]->write_pos) { #ifdef _Windows FD_SET(io_rec[i]->fd, &new); #else FD_SET(i, &new); #endif set = 1; } } } if (set) { set = 0; if (!(select(IO_ARRAYLEN, rd, wd, NULL, &right_away) > 0)) FD_ZERO(rd); for (i = 0; i < IO_ARRAYLEN; i++) { if ((FD_ISSET(i, rd)) || (FD_ISSET(i, &new))) { set++; FD_SET(i, rd); } else FD_CLR(i, rd); } return (set); } return (select(IO_ARRAYLEN, rd, wd, NULL, newtimeout)); } /* new_close: works just like close */ void new_close(des) int des; { #ifdef ESIX if (get_ior(des)->flags & IO_SOCKET) t_close(des); #endif /* ESIX */ #ifdef _Windows if (get_ior(des)->flags & IO_SOCKET) closesocket(des); #else close(des) #endif new_free(&(get_ior(des))); #ifndef _Windows close(des); #endif } /* set's socket options */ extern void set_socket_options(s) int s; { #if defined(ESIX) || defined(_Windows) mark_socket(s); #else #ifndef NO_STRUCT_LINGER struct linger lin; #endif int opt = 1; int optlen = sizeof(opt); (void) setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &opt, optlen); opt = 1; (void) setsockopt(s, SOL_SOCKET, SO_KEEPALIVE, &opt, optlen); #ifndef NO_STRUCT_LINGER lin.l_onoff = lin.l_linger = 0; (void) setsockopt(s, SOL_SOCKET, SO_LINGER, &lin, optlen); #endif /* NO_STRUCT_LINGER */ #endif /* ESIX */ }