/* Copyright (C) 1999 Beau Kuiper
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#include "ftpd.h"
/* Note that i may one day replace all this with the poll funcutions */
#define MAXFDNUM 16 /* Set startup maximum file descriptor number */
/* Creates a new select structure */
extern int signumber;
SELECTER *select_new(void)
{
SELECTER *new = mallocwrapper(sizeof(SELECTER));
debuglog("select_new - starting new select structure");
new->fdtable = mallocwrapper(sizeof(struct selectorobj *) * (MAXFDNUM + 1));
memset(new->fdtable, 0, sizeof(struct selectorobj *) * (MAXFDNUM + 1));
new->maxfds = MAXFDNUM;
new->firstfd = -1;
new->smax = 0;
return(new);
}
/* The following adds a FD to the fdtable. If the table is too small,
then increase it. Favours long running times */
void select_addfd(SELECTER *sel, int newport)
{
debuglog("select_addfd - adding fd %d", newport);
if (newport > sel->maxfds)
{
int temp = newport + 32; /* give some breathing space */
reallocwrapper(sizeof(struct selectorobj *) * (temp + 1), (void *)&(sel->fdtable));
memset(&(sel->fdtable[sel->maxfds + 1]), 0, sizeof(struct selectorobj *) * (temp - sel->maxfds));
sel->maxfds = temp;
}
if (sel->fdtable[newport] != NULL)
errormsg("select.c: select_addfd - trying to add a file descriptor already in table.", __FILE__, __LINE__);
else
{
struct selectorobj *temp = mallocwrapper(sizeof(struct selectorobj));
temp->readsockopt = NULL;
temp->writesockopt = NULL;
temp->readdata = NULL;
temp->writedata = NULL;
temp->last = -1;
temp->next = sel->firstfd;
if (sel->firstfd != -1)
sel->fdtable[sel->firstfd]->last = newport;
sel->firstfd = newport;
sel->fdtable[newport] = temp;
}
}
void select_delfd(SELECTER *sel, int deadport)
{
int result;
struct selectorobj *temp = sel->fdtable[deadport];
debuglog("select_delfd - removing fd %d", deadport);
result = close(deadport); /* make sure the port is closed :) */
/* if (result == -1)
errormsg(strerror(errno), __FILE__, __LINE__);
*/
select_takeread(sel, deadport);
select_takewrite(sel, deadport);
if (sel->firstfd == deadport)
{
sel->firstfd = temp->next;
if (sel->firstfd != -1)
sel->fdtable[sel->firstfd]->last = -1;
}
else
{
sel->fdtable[temp->last]->next = temp->next;
if (temp->next != -1)
sel->fdtable[temp->next]->last = temp->last;
}
freewrapper(temp);
sel->fdtable[deadport] = NULL;
}
void select_addread(SELECTER *sel, int port, int (* proc)(SELECTER *, int, void *), void *dat)
{
debuglog("select_addread - fd %d", port);
sel->fdtable[port]->readsockopt = proc;
sel->fdtable[port]->readdata = dat;
sel->smax = MAXIMUM(sel->smax, port);
}
void select_addwrite(SELECTER *sel, int port, int (* proc)(SELECTER *, int, void *), void *dat)
{
debuglog("select_addwrite - fd %d", port);
sel->fdtable[port]->writesockopt = proc;
sel->fdtable[port]->writedata = dat;
sel->smax = MAXIMUM(sel->smax, port);
}
void select_takeread(SELECTER *sel, int port)
{
debuglog("select_takeread - fd %d", port);
sel->fdtable[port]->readsockopt = NULL;
sel->fdtable[port]->readdata = NULL;
/* FD_CLR(port, &(sel->readset)); */
}
void select_takewrite(SELECTER *sel, int port)
{
debuglog("select_takewrite - fd %d", port);
sel->fdtable[port]->writesockopt = NULL;
sel->fdtable[port]->writedata = NULL;
/* FD_CLR(port, &(sel->writeset)); */
}
int select_do(SELECTER *sel, int *signum, int timeout)
{
fd_set readset, writeset;
struct timeval tv, *tv2;
int result = 0;
FD_ZERO(&readset);
FD_ZERO(&writeset);
debuglog("do_select - waiting on fd's");
*signum = 0; signumber = 0;
while (result == 0)
{
int pos = sel->firstfd;
while(pos != -1)
{
struct selectorobj *temp = sel->fdtable[pos];
if (temp->readsockopt)
FD_SET(pos, &readset);
if (temp->writesockopt)
FD_SET(pos, &writeset);
pos = temp->next;
}
if (timeout != -1)
{
tv.tv_sec = timeout;
tv.tv_usec = 0;
tv2 = &tv;
}
else
tv2 = NULL;
if (signumber != 0)
{
*signum = signumber;
return(-1);
}
result = select(sel->smax + 1, &readset, &writeset, NULL, tv2);
if (result == 0)
return(0);
else if (result == -1)
{
if (errno == EINTR)
{
*signum = signumber;
return(-1);
}
else
{
errormsg(strerror(errno), __FILE__, __LINE__);
return(-1);
}
}
else
{
pos = sel->firstfd;
result = 0;
while((pos != -1) && (result == 0))
{
struct selectorobj *temp = sel->fdtable[pos];
if (temp->readsockopt)
if (FD_ISSET(pos, &readset))
result = temp->readsockopt(sel, pos, temp->readdata);
if ((temp->writesockopt) && (result == 0))
if (FD_ISSET(pos, &writeset))
result = temp->writesockopt(sel, pos, temp->writedata);
FD_CLR(pos, &writeset);
FD_CLR(pos, &readset);
if (result == 2)
{
int pos2 = temp->next;
select_delfd(sel, pos);
result = 0;
pos = pos2;
}
else
pos = temp->next;
}
}
}
return(result);
}
void select_shutdown(SELECTER *sel)
{
int count;
for (count = 0; count < sel->maxfds; count++)
if (sel->fdtable[count])
select_delfd(sel, count);
freewrapper(sel->fdtable);
freewrapper(sel);
}
syntax highlighted by Code2HTML, v. 0.9.1