Commit edd5bb42 authored by Poul-Henning Kamp's avatar Poul-Henning Kamp

CLI reworking in the manager process.

Use the new cli_serve stuff, as ammended.

Give cli's an "auth level" and only allow the commands with lower
auth levels than what the cli has collected.  Use this to implement
the -S handling.  In the future, we can also use it to do "R/O" vs. "R/W"
command separation.

Add a param (syslog_cli_traffic) to control if all CLI traffic is syslog'ed.

Everything should work the same, as far as I know.



git-svn-id: http://www.varnish-cache.org/svn/trunk/varnish-cache@4473 d4fa192b-c00b-0410-8231-f00ffab90ce4
parent eaa021b6
......@@ -94,11 +94,9 @@ CLI_AddFuncs(enum cli_set_e which, struct cli_proto *p)
}
static void
cli_cb_before(void *priv)
cli_cb_before(struct cli *cli)
{
struct cli *cli;
cli = priv;
VSL(SLT_CLI, 0, "Rd %s", cli->cmd);
VCL_Poll();
VBE_Poll();
......@@ -106,12 +104,9 @@ cli_cb_before(void *priv)
}
static void
cli_cb_after(void *priv)
cli_cb_after(struct cli *cli)
{
struct cli *cli;
Lck_Unlock(&cli_mtx);
cli = priv;
VSL(SLT_CLI, 0, "Wr %03u %s", cli->result, vsb_data(cli->sb));
}
......@@ -123,11 +118,12 @@ CLI_Run(void)
add_check = 1;
cls = CLS_New(cli_cb_before, cli_cb_after, NULL, params->cli_buffer);
AZ(CLS_AddFd(cls, heritage.cli_in, heritage.cli_out, NULL, NULL));
AZ(CLS_AddFunc(cls, ccf_master_cli));
AZ(CLS_AddFunc(cls, ccf_public_cli));
AZ(CLS_AddFunc(cls, ccf_debug_cli));
cls = CLS_New(cli_cb_before, cli_cb_after, params->cli_buffer);
AN(cls);
AN(CLS_AddFd(cls, heritage.cli_in, heritage.cli_out, NULL, NULL));
AZ(CLS_AddFunc(cls, 0, ccf_master_cli));
AZ(CLS_AddFunc(cls, 0, ccf_public_cli));
AZ(CLS_AddFunc(cls, 0, ccf_debug_cli));
do {
i = CLS_Poll(cls, -1);
......
......@@ -193,14 +193,13 @@ struct params {
/* Get rid of duplicate purges */
unsigned purge_dups;
/* CLI banner */
unsigned cli_banner;
/* How long time does the ban lurker sleep */
double ban_lurker_sleep;
/* Max size of the saintmode list. 0 == no saint mode. */
unsigned saintmode_threshold;
unsigned syslog_cli_traffic;
};
extern volatile struct params *params;
......
......@@ -38,7 +38,6 @@ SVNID("$Id$")
#include <stdarg.h>
#include <stdio.h>
#include <ctype.h>
#include <fcntl.h>
#include <stdlib.h>
#include <syslog.h>
......@@ -54,6 +53,7 @@ SVNID("$Id$")
#include "cli.h"
#include "vsb.h"
#include "cli_common.h"
#include "cli_serve.h"
#include "vev.h"
#include "vsha256.h"
#include "shmlog.h"
......@@ -66,32 +66,14 @@ SVNID("$Id$")
#include "mgt_cli.h"
static int cli_i = -1, cli_o = -1;
static struct cls *cls;
static const char *secret_file;
struct telnet {
unsigned magic;
#define TELNET_MAGIC 0x53ec3ac0
int fd;
struct vev *ev;
};
#define MCF_NOAUTH 0
#define MCF_AUTH 16
struct cli_port {
unsigned magic;
#define CLI_PORT_MAGIC 0x5791079f
VTAILQ_ENTRY(cli_port) list;
struct vev *ev;
int fdi;
int fdo;
int verbose;
struct vlu *vlu;
struct cli cli[1];
char *name;
char challenge[34];
mgt_cli_close_f *closefunc;
void *priv;
};
static void mcf_help(struct cli *cli, const char * const *av, void *priv);
static VTAILQ_HEAD(,cli_port) clilist = VTAILQ_HEAD_INITIALIZER(clilist);
/*--------------------------------------------------------------------*/
......@@ -110,25 +92,6 @@ mcf_stats(struct cli *cli, const char * const *av, void *priv)
#undef MAC_STAT
}
/*--------------------------------------------------------------------*/
static void
mcf_help(struct cli *cli, const char * const *av, void *priv)
{
unsigned u;
char *p;
cli_func_help(cli, av, priv);
if (cli_o >= 0 && (av[2] == NULL || *av[2] == '-')) {
p = NULL;
if (!mgt_cli_askchild(&u, &p,
"help %s\n", av[2] != NULL ? av[2] : "")) {
cli_out(cli, "%s", p);
cli_result(cli, u);
}
free(p);
}
}
/*--------------------------------------------------------------------*/
......@@ -164,7 +127,6 @@ mcf_banner(struct cli *cli, const char *const *av, void *priv)
/* XXX: what order should this list be in ? */
static struct cli_proto cli_proto[] = {
{ CLI_HELP, mcf_help, cli_proto },
{ CLI_BANNER, mcf_banner, NULL },
{ CLI_PING, cli_func_ping },
{ CLI_SERVER_STATUS, mcf_server_status, NULL },
......@@ -308,6 +270,24 @@ mgt_cli_stop_child(void)
/* XXX: kick any users */
}
/*--------------------------------------------------------------------
* Generate a random challenge
*/
static void
mgt_cli_challenge(struct cli *cli)
{
int i;
for (i = 0; i + 2L < sizeof cli->challenge; i++)
cli->challenge[i] = (random() % 26) + 'a';
cli->challenge[i++] = '\n';
cli->challenge[i] = '\0';
cli_out(cli, "%s", cli->challenge);
cli_out(cli, "\nAuthentication required.\n");
cli_result(cli, CLIS_AUTH);
}
/*--------------------------------------------------------------------
* Validate the authentication
*/
......@@ -319,10 +299,8 @@ mcf_auth(struct cli *cli, const char *const *av, void *priv)
int i, fd;
struct SHA256Context sha256ctx;
unsigned char digest[SHA256_LEN];
struct cli_port *cp;
AN(av[2]);
CAST_OBJ_NOTNULL(cp, cli->priv, CLI_PORT_MAGIC);
(void)priv;
AN(secret_file);
fd = open(secret_file, O_RDONLY);
......@@ -353,20 +331,20 @@ mcf_auth(struct cli *cli, const char *const *av, void *priv)
buf[i] = '\0';
AZ(close(fd));
SHA256_Init(&sha256ctx);
SHA256_Update(&sha256ctx, cp->challenge, strlen(cp->challenge));
SHA256_Update(&sha256ctx, cli->challenge, strlen(cli->challenge));
SHA256_Update(&sha256ctx, buf, i);
SHA256_Update(&sha256ctx, cp->challenge, strlen(cp->challenge));
SHA256_Update(&sha256ctx, cli->challenge, strlen(cli->challenge));
SHA256_Final(digest, &sha256ctx);
for (i = 0; i < SHA256_LEN; i++)
sprintf(buf + i + i, "%02x", digest[i]);
if (strcasecmp(buf, av[2])) {
cli_result(cli, CLIS_UNKNOWN);
mgt_cli_challenge(cli);
return;
}
cp->challenge[0] = '\0';
cli->auth = MCF_AUTH;
memset(cli->challenge, 0, sizeof cli->challenge);
cli_result(cli, CLIS_OK);
if (params->cli_banner)
mcf_banner(cli, av, priv);
mcf_banner(cli, av, priv);
}
static struct cli_proto cli_auth[] = {
......@@ -376,101 +354,61 @@ static struct cli_proto cli_auth[] = {
{ NULL }
};
/*--------------------------------------------------------------------
* Generate a random challenge
*/
/*--------------------------------------------------------------------*/
static void
mgt_cli_challenge(struct cli_port *cp)
mcf_help(struct cli *cli, const char * const *av, void *priv)
{
int i;
unsigned u;
char *p;
for (i = 0; i + 2L < sizeof cp->challenge; i++)
cp->challenge[i] = (random() % 26) + 'a';
cp->challenge[i++] = '\n';
cp->challenge[i] = '\0';
cli_out(cp->cli, "%s", cp->challenge);
cli_out(cp->cli, "\nAuthentication required.\n");
cli_result(cp->cli, CLIS_AUTH);
(void)priv;
cli_func_help(cli, av, cli_auth);
if (cli->auth == MCF_NOAUTH)
return;
cli_func_help(cli, av, cli_proto);
if (cli_o >= 0 && (av[2] == NULL || *av[2] == '-')) {
p = NULL;
if (!mgt_cli_askchild(&u, &p,
"help %s\n", av[2] != NULL ? av[2] : "")) {
cli_out(cli, "%s", p);
cli_result(cli, u);
}
free(p);
}
}
/*--------------------------------------------------------------------*/
static int
mgt_cli_vlu(void *priv, const char *p)
/*--------------------------------------------------------------------*/
static void
mgt_cli_cb_before(struct cli *cli)
{
struct cli_port *cp;
CAST_OBJ_NOTNULL(cp, priv, CLI_PORT_MAGIC);
vsb_clear(cp->cli->sb);
/* Skip whitespace */
for (; isspace(*p); p++)
continue;
/* Ignore empty lines */
if (*p == '\0')
return (0);
cp->cli->cmd = p;
if (secret_file != NULL && cp->challenge[0] != '\0') {
/* Authentication not yet passed */
cli_dispatch(cp->cli, cli_auth, p);
if (cp->cli->result == CLIS_UNKNOWN)
mgt_cli_challenge(cp);
} else {
cli_dispatch(cp->cli, cli_proto, p);
if (cp->cli->result == CLIS_UNKNOWN) {
vsb_clear(cp->cli->sb);
cli_dispatch(cp->cli, cli_debug, p);
}
if (cp->cli->result == CLIS_UNKNOWN) {
vsb_clear(cp->cli->sb);
cli_dispatch(cp->cli, cli_askchild, p);
}
}
vsb_finish(cp->cli->sb);
AZ(vsb_overflowed(cp->cli->sb));
if (params->syslog_cli_traffic)
syslog(LOG_NOTICE, "CLI %s Rd %s", cli->ident, cli->cmd);
}
cp->cli->cmd = NULL;
static void
mgt_cli_cb_after(struct cli *cli)
{
/* send the result back */
syslog(LOG_INFO, "CLI %d result %d \"%s\"",
cp->fdi, cp->cli->result, p);
if (cli_writeres(cp->fdo, cp->cli) || cp->cli->result == CLIS_CLOSE)
return (1);
return (0);
if (params->syslog_cli_traffic)
syslog(LOG_NOTICE, "CLI %s Wr %03u %s",
cli->ident, cli->result, vsb_data(cli->sb));
}
/*--------------------------------------------------------------------
* Get rid of a CLI session.
*
* Always and only called from mgt_cli_callback().
*
* We must get rid of everything but the event, which gets GC'ed by
* ev_schdule_one() when mgt_cli_callback, through our return value
* returns non-zero.
*/
/*--------------------------------------------------------------------*/
static int
mgt_cli_close(struct cli_port *cp)
static void
mgt_cli_init_cls(void)
{
CHECK_OBJ_NOTNULL(cp, CLI_PORT_MAGIC);
syslog(LOG_NOTICE, "CLI %d closed", cp->fdi);
/*
* Remove from list, so that if closefunc calls mgt_cli_close_all
* it will not try to remove this one too.
*/
VTAILQ_REMOVE(&clilist, cp, list);
free(cp->name);
vsb_delete(cp->cli->sb);
VLU_Destroy(cp->vlu);
cp->closefunc(cp->priv);
FREE_OBJ(cp);
return (1);
cls = CLS_New(mgt_cli_cb_before, mgt_cli_cb_after, params->cli_buffer);
AN(cls);
AZ(CLS_AddFunc(cls, MCF_NOAUTH, cli_auth));
AZ(CLS_AddFunc(cls, MCF_AUTH, cli_proto));
AZ(CLS_AddFunc(cls, MCF_AUTH, cli_debug));
AZ(CLS_AddFunc(cls, MCF_AUTH, cli_askchild));
}
/*--------------------------------------------------------------------
......@@ -480,13 +418,8 @@ mgt_cli_close(struct cli_port *cp)
void
mgt_cli_close_all(void)
{
struct cli_port *cp;
while (!VTAILQ_EMPTY(&clilist)) {
cp = VTAILQ_FIRST(&clilist);
vev_del(mgt_evb, cp->ev);
(void)mgt_cli_close(cp);
}
CLS_Destroy(&cls);
}
/*--------------------------------------------------------------------
......@@ -494,18 +427,14 @@ mgt_cli_close_all(void)
*/
static int
mgt_cli_callback(const struct vev *e, int what)
mgt_cli_callback2(const struct vev *e, int what)
{
struct cli_port *cp;
CAST_OBJ_NOTNULL(cp, e->priv, CLI_PORT_MAGIC);
if (what & (EV_ERR | EV_HUP | EV_GONE))
return (mgt_cli_close(cp));
int i;
if (VLU_Fd(cp->fdi, cp->vlu))
return (mgt_cli_close(cp));
return (0);
(void)e;
(void)what;
i = CLS_PollFd(cls, e->fd, 0);
return (i);
}
/*--------------------------------------------------------------------*/
......@@ -513,50 +442,41 @@ mgt_cli_callback(const struct vev *e, int what)
void
mgt_cli_setup(int fdi, int fdo, int verbose, const char *ident, mgt_cli_close_f *closefunc, void *priv)
{
struct cli_port *cp;
struct cli *cli;
struct vev *ev;
cp = calloc(sizeof *cp, 1);
XXXAN(cp);
cp->vlu = VLU_New(cp, mgt_cli_vlu, params->cli_buffer);
(void)ident;
(void)verbose;
if (cls == NULL)
mgt_cli_init_cls();
cp->name = strdup(ident);
XXXAN(cp->name);
syslog(LOG_NOTICE, "CLI %d open %s", fdi, cp->name);
cp->magic = CLI_PORT_MAGIC;
cli = CLS_AddFd(cls, fdi, fdo, closefunc, priv);
cp->fdi = fdi;
cp->fdo = fdo;
cp->verbose = verbose;
cp->closefunc = closefunc;
cp->priv = priv;
cp->cli->sb = vsb_newauto();
XXXAN(cp->cli->sb);
cp->cli->priv = cp;
cli->ident = strdup(ident);
/* Deal with TELNET options */
if (cp->fdi != 0)
VLU_SetTelnet(cp->vlu, cp->fdo);
if (fdi != 0)
VLU_SetTelnet(cli->vlu, fdo);
/*
* If we have a secret file authenticate all CLI connections
* except the stdin/stdout debug port.
*/
if (cp->fdi != 0 && secret_file != NULL) {
mgt_cli_challenge(cp);
(void)VLU_Data("auth -\n", -1, cp->vlu);
} else if (params->cli_banner)
(void)VLU_Data("banner\n", -1, cp->vlu);
cp->ev = vev_new();
cp->ev->name = cp->name;
cp->ev->fd = fdi;
cp->ev->fd_flags = EV_RD;
cp->ev->callback = mgt_cli_callback;
cp->ev->priv = cp;
VTAILQ_INSERT_TAIL(&clilist, cp, list);
AZ(vev_add(mgt_evb, cp->ev));
if (fdi != 0 && secret_file != NULL) {
cli->auth = MCF_NOAUTH;
mgt_cli_challenge(cli);
} else {
cli->auth = MCF_AUTH;
mcf_banner(cli, NULL, NULL);
}
vsb_finish(cli->sb);
(void)cli_writeres(fdo, cli);
ev = vev_new();
AN(ev);
ev->name = cli->ident;
ev->fd = fdi;
ev->fd_flags = EV_RD;
ev->callback = mgt_cli_callback2;
ev->priv = cli;
AZ(vev_add(mgt_evb, ev));
}
/*--------------------------------------------------------------------*/
......@@ -581,6 +501,13 @@ sock_id(const char *pfx, int fd)
/*--------------------------------------------------------------------*/
struct telnet {
unsigned magic;
#define TELNET_MAGIC 0x53ec3ac0
int fd;
struct vev *ev;
};
static void
telnet_close(void *priv)
{
......
......@@ -756,9 +756,8 @@ static const struct parspec input_parspec[] = {
"Detect and eliminate duplicate purges.\n",
0,
"on", "bool" },
{ "cli_banner", tweak_bool, &master.cli_banner, 0, 0,
"Emit CLI banner on connect.\n"
"Set to off for compatibility with pre 2.1 versions.\n",
{ "syslog_cli_traffic", tweak_bool, &master.syslog_cli_traffic, 0, 0,
"Log all CLI traffic to syslog(LOG_INFO).\n",
0,
"on", "bool" },
{ "ban_lurker_sleep", tweak_timeout_double,
......
......@@ -247,6 +247,8 @@ varnish_launch(struct varnish *v)
struct vss_addr **ap;
char abuf[128],pbuf[128];
struct pollfd fd;
unsigned retval;
char *r;
/* Create listener socket */
nap = VSS_resolve("127.0.0.1", "0", &ap);
......@@ -261,8 +263,8 @@ varnish_launch(struct varnish *v)
AN(vsb);
vsb_printf(vsb, "cd ../varnishd &&");
vsb_printf(vsb, " ./varnishd -d -d -n %s", v->workdir);
vsb_printf(vsb, " -p cli_banner=off");
vsb_printf(vsb, " -p auto_restart=off");
vsb_printf(vsb, " -p syslog_cli_traffic=off");
vsb_printf(vsb, " -a '%s'", "127.0.0.1:0");
vsb_printf(vsb, " -M %s:%s", abuf, pbuf);
vsb_printf(vsb, " -P %s/varnishd.pid", v->workdir);
......@@ -317,6 +319,13 @@ varnish_launch(struct varnish *v)
vtc_log(v->vl, 3, "CLI connection fd = %d", v->cli_fd);
assert(v->cli_fd >= 0);
i = cli_readres(v->cli_fd, &retval, &r, 20.0);
if (i != 0 || retval != CLIS_OK)
vtc_log(v->vl, 0, "CLI banner fail", v->cli_fd);
vtc_log(v->vl, 4, "CLI banner %03u", retval);
free(r);
if (v->stats != NULL)
VSL_Close();
v->stats = VSL_OpenStats(v->workdir);
......
......@@ -29,12 +29,17 @@
* $Id$
*/
struct vlu;
struct cli {
/* XXX: should be MINI_OBJ */
struct vsb *sb;
enum cli_status_e result;
void *priv;
const char *cmd;
unsigned auth;
char challenge[34];
char *ident;
struct vlu *vlu;
};
int cli_writeres(int fd, const struct cli *cli);
......
......@@ -31,8 +31,12 @@
struct cls;
typedef void cls_cb_f(void *priv);
struct cls *CLS_New(cls_cb_f *before, cls_cb_f *after, void *priv, unsigned maxlen);
int CLS_AddFd(struct cls *cs, int fdi, int fdo, cls_cb_f *closefunc,
typedef void cls_cbc_f(struct cli*);
struct cls *CLS_New(cls_cbc_f *before, cls_cbc_f *after, unsigned maxlen);
struct cli *CLS_AddFd(struct cls *cs, int fdi, int fdo, cls_cb_f *closefunc,
void *priv);
int CLS_AddFunc(struct cls *cs, struct cli_proto *clp);
int CLS_AddFunc(struct cls *cs, unsigned auth, struct cli_proto *clp);
int CLS_Poll(struct cls *cs, int timeout);
int CLS_PollFd(struct cls *cs, int fd, int timeout);
void CLS_Destroy(struct cls **);
......@@ -55,6 +55,7 @@ struct cls_func {
unsigned magic;
#define CLS_FUNC_MAGIC 0x7d280c9b
VTAILQ_ENTRY(cls_func) list;
unsigned auth;
struct cli_proto *clp;
};
......@@ -63,7 +64,6 @@ struct cls_fd {
#define CLS_FD_MAGIC 0x010dbd1e
VTAILQ_ENTRY(cls_fd) list;
int fdi, fdo;
struct vlu *vlu;
struct cls *cls;
struct cli *cli, clis;
cls_cb_f *closefunc;
......@@ -76,8 +76,7 @@ struct cls {
VTAILQ_HEAD(,cls_fd) fds;
unsigned nfd;
VTAILQ_HEAD(,cls_func) funcs;
cls_cb_f *before, *after;
void *priv;
cls_cbc_f *before, *after;
unsigned maxlen;
};
......@@ -92,10 +91,22 @@ cls_vlu(void *priv, const char *p)
cs = cfd->cls;
CHECK_OBJ_NOTNULL(cs, CLS_MAGIC);
/* Skip whitespace */
for (; isspace(*p); p++)
continue;
/* Ignore empty lines */
if (*p == '\0')
return (0);
cfd->cli->cmd = p;
if (cs->before != NULL)
cs->before(cs->priv != NULL ? cs->priv : cfd->cli);
cs->before(cfd->cli);
vsb_clear(cfd->cli->sb);
cfd->cli->result = CLIS_UNKNOWN;
VTAILQ_FOREACH(cfn, &cs->funcs, list) {
if (cfn->auth > cfd->cli->auth)
continue;
vsb_clear(cfd->cli->sb);
cfd->cli->result = CLIS_OK;
cli_dispatch(cfd->cli, cfn->clp, p);
......@@ -105,7 +116,7 @@ cls_vlu(void *priv, const char *p)
vsb_finish(cfd->cli->sb);
AZ(vsb_overflowed(cfd->cli->sb));
if (cs->after != NULL)
cs->after(cs->priv != NULL ? cs->priv : cfd->cli);
cs->after(cfd->cli);
if (cli_writeres(cfd->fdo, cfd->cli) || cfd->cli->result == CLIS_CLOSE)
return (1);
cfd->cli->cmd = NULL;
......@@ -113,7 +124,7 @@ cls_vlu(void *priv, const char *p)
}
struct cls *
CLS_New(cls_cb_f *before, cls_cb_f *after, void *priv, unsigned maxlen)
CLS_New(cls_cbc_f *before, cls_cbc_f *after, unsigned maxlen)
{
struct cls *cs;
......@@ -123,12 +134,11 @@ CLS_New(cls_cb_f *before, cls_cb_f *after, void *priv, unsigned maxlen)
VTAILQ_INIT(&cs->funcs);
cs->before = before;
cs->after = after;
cs->priv = priv;
cs->maxlen = maxlen;
return (cs);
}
int
struct cli *
CLS_AddFd(struct cls *cs, int fdi, int fdo, cls_cb_f *closefunc, void *priv)
{
struct cls_fd *cfd;
......@@ -141,15 +151,15 @@ CLS_AddFd(struct cls *cs, int fdi, int fdo, cls_cb_f *closefunc, void *priv)
cfd->cls = cs;
cfd->fdi = fdi;
cfd->fdo = fdo;
cfd->vlu = VLU_New(cfd, cls_vlu, cs->maxlen);
cfd->cli = &cfd->clis;
cfd->cli->vlu = VLU_New(cfd, cls_vlu, cs->maxlen);
cfd->cli->sb = vsb_newauto();
cfd->closefunc = closefunc;
cfd->priv = priv;
AN(cfd->cli->sb);
VTAILQ_INSERT_TAIL(&cs->fds, cfd, list);
cs->nfd++;
return (0);
return (cfd->cli);
}
static void
......@@ -161,7 +171,7 @@ cls_close_fd(struct cls *cs, struct cls_fd *cfd)
VTAILQ_REMOVE(&cs->fds, cfd, list);
cs->nfd--;
VLU_Destroy(cfd->vlu);
VLU_Destroy(cfd->cli->vlu);
vsb_delete(cfd->cli->sb);
if (cfd->closefunc == NULL) {
(void)close(cfd->fdi);
......@@ -170,12 +180,14 @@ cls_close_fd(struct cls *cs, struct cls_fd *cfd)
} else {
cfd->closefunc(cfd->priv);
}
if (cfd->cli->ident != NULL)
free(cfd->cli->ident);
FREE_OBJ(cfd);
}
int
CLS_AddFunc(struct cls *cs, struct cli_proto *clp)
CLS_AddFunc(struct cls *cs, unsigned auth, struct cli_proto *clp)
{
struct cls_func *cfn;
......@@ -183,10 +195,50 @@ CLS_AddFunc(struct cls *cs, struct cli_proto *clp)
ALLOC_OBJ(cfn, CLS_FUNC_MAGIC);
AN(cfn);
cfn->clp = clp;
cfn->auth = auth;
VTAILQ_INSERT_TAIL(&cs->funcs, cfn, list);
return (0);
}
int
CLS_PollFd(struct cls *cs, int fd, int timeout)
{
struct cls_fd *cfd;
struct pollfd pfd[1];
int i, j, k;
CHECK_OBJ_NOTNULL(cs, CLS_MAGIC);
if (cs->nfd == 0) {
errno = 0;
return (-1);
}
assert(cs->nfd > 0);
i = 0;
VTAILQ_FOREACH(cfd, &cs->fds, list) {
if (cfd->fdi != fd)
continue;
pfd[i].fd = cfd->fdi;
pfd[i].events = POLLIN;
pfd[i].revents = 0;
i++;
break;
}
assert(i == 1);
CHECK_OBJ_NOTNULL(cfd, CLS_FD_MAGIC);
j = poll(pfd, 1, timeout);
if (j <= 0)
return (j);
if (pfd[0].revents & POLLHUP)
k = 1;
else
k = VLU_Fd(cfd->fdi, cfd->cli->vlu);
if (k)
cls_close_fd(cs, cfd);
return (k);
}
int
CLS_Poll(struct cls *cs, int timeout)
{
......@@ -220,7 +272,7 @@ CLS_Poll(struct cls *cs, int timeout)
if (pfd[i].revents & POLLHUP)
k = 1;
else
k = VLU_Fd(cfd->fdi, cfd->vlu);
k = VLU_Fd(cfd->fdi, cfd->cli->vlu);
if (k)
cls_close_fd(cs, cfd);
i++;
......@@ -229,3 +281,25 @@ CLS_Poll(struct cls *cs, int timeout)
}
return (j);
}
void
CLS_Destroy(struct cls **csp)
{
struct cls *cs;
struct cls_fd *cfd, *cfd2;
struct cls_func *cfn;
cs = *csp;
*csp = NULL;
CHECK_OBJ_NOTNULL(cs, CLS_MAGIC);
VTAILQ_FOREACH_SAFE(cfd, &cs->fds, list, cfd2)
cls_close_fd(cs, cfd);
while (!VTAILQ_EMPTY(&cs->funcs)) {
cfn = VTAILQ_FIRST(&cs->funcs);
VTAILQ_REMOVE(&cs->funcs, cfn, list);
FREE_OBJ(cfn);
}
FREE_OBJ(cs);
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment