head 1.41;
access;
symbols
L2_0_9_13:1.41
FSL_1_7_0:1.41
L2_0_9_12:1.41
LMTP2NNTP_1_4_1:1.41
LMTP2NNTP_1_4_0:1.41
FSL_1_6_1:1.41
L2_0_9_11:1.41
FSL_1_6_0:1.40
FSL_1_6b2:1.40
L2_0_9_10:1.40
FSL_1_6b1:1.39
L2_0_9_9:1.39
LMTP2NNTP_1_3_0:1.38
LMTP2NNTP_1_3b2:1.38
LMTP2NNTP_1_3b1:1.38
LMTP2NNTP_1_3a3:1.38
FSL_1_5_0:1.38
LMTP2NNTP_1_3a2:1.38
FSL_1_5a3:1.38
LMTP2NNTP_1_3a1:1.38
FSL_1_5a2:1.38
L2_0_9_8:1.38
FSL_1_5a1:1.38
L2_0_9_7:1.38
L2_0_9_6:1.38
FSL_1_4_0:1.38
FSL_1_4b1:1.38
L2_0_9_5:1.38
FSL_1_4a1:1.38
FSL_1_3_0:1.38
FSL_1_3b1:1.38
L2_0_9_4:1.38
FSL_1_2_1:1.38
L2_0_9_3:1.38
FSL_1_2_0:1.38
L2_0_9_2:1.38
FSL_1_1_0:1.38
FSL_1_1b1:1.38
WORKOFF:1.38.0.2
WORKOFF_BP:1.38
FSL_1_0_8:1.38
LMTP2NNTP_1_2_0:1.38
LMTP2NNTP_1_2b4:1.38
LMTP2NNTP_1_2b3:1.38
LMTP2NNTP_1_2b2:1.38
LMTP2NNTP_1_2b1:1.38
LMTP2NNTP_1_2a8:1.38
LMTP2NNTP_1_2a7:1.38
FSL_1_0_7:1.38
FSL_1_0_6:1.37
FSL_1_0_5:1.37
FSL_1_0_4:1.37
L2_0_9_1:1.37
FSL_1_0_3:1.37
LMTP2NNTP_1_2a6:1.37
FSL_1_0_2:1.37
FSL_1_0_1:1.37
FSL_1_0_0:1.37
FSL_0_9_0:1.37
L2_0_9_0:1.37
FSL_0_1_12:1.36
FSL_0_1_11:1.36
FSL_0_1_10:1.36
FSL_0_1_9:1.36
FSL_0_1_8:1.36
FSL_0_1_7:1.36
FSL_0_1_6:1.36
FSL_0_1_5:1.36
FSL_0_1_1:1.36
LMTP2NNTP_1_2a5:1.36
LMTP2NNTP_1_2a4:1.36
LMTP2NNTP_1_2a3:1.36
LMTP2NNTP_1_2a1:1.35
LMTP2NNTP_1_1_1:1.30
LMTP2NNTP_1_1_0:1.30
LMTP2NNTP_1_1b4:1.30
LMTP2NNTP_1_1b3:1.30
L2_CHANNEL_ONLY_REVAMPING_BEFORE:1.30
LMTP2NNTP_1_1b2:1.24
LMTP2NNTP_1_1b1:1.23
L2_0_1_0:1.20
L2NGATE:1.9.0.2
START_MICHAEL:1.5
L2_INITIAL:1.1.1.1
OSSP:1.1.1;
locks; strict;
comment @ * @;
1.41
date 2005.10.03.08.08.11; author rse; state Exp;
branches;
next 1.40;
1.40
date 2005.02.03.09.41.38; author rse; state Exp;
branches;
next 1.39;
1.39
date 2005.01.24.15.03.17; author rse; state Exp;
branches;
next 1.38;
1.38
date 2003.01.06.11.41.51; author rse; state Exp;
branches;
next 1.37;
1.37
date 2002.07.30.19.08.24; author rse; state Exp;
branches;
next 1.36;
1.36
date 2002.01.02.17.07.38; author rse; state Exp;
branches;
next 1.35;
1.35
date 2001.11.16.20.07.54; author ms; state Exp;
branches;
next 1.34;
1.34
date 2001.11.07.13.05.20; author rse; state Exp;
branches;
next 1.33;
1.33
date 2001.11.07.11.37.18; author rse; state Exp;
branches;
next 1.32;
1.32
date 2001.11.04.14.11.04; author rse; state Exp;
branches;
next 1.31;
1.31
date 2001.11.03.22.51.36; author rse; state Exp;
branches;
next 1.30;
1.30
date 2001.10.31.16.47.05; author ms; state Exp;
branches;
next 1.29;
1.29
date 2001.10.30.18.55.27; author ms; state Exp;
branches;
next 1.28;
1.28
date 2001.10.30.08.12.28; author thl; state Exp;
branches;
next 1.27;
1.27
date 2001.10.26.11.02.01; author rse; state Exp;
branches;
next 1.26;
1.26
date 2001.10.23.10.05.53; author ms; state Exp;
branches;
next 1.25;
1.25
date 2001.10.22.16.32.29; author ms; state Exp;
branches;
next 1.24;
1.24
date 2001.10.12.14.46.17; author ms; state Exp;
branches;
next 1.23;
1.23
date 2001.10.05.14.25.57; author ms; state Exp;
branches;
next 1.22;
1.22
date 2001.10.05.10.40.17; author ms; state Exp;
branches;
next 1.21;
1.21
date 2001.09.14.07.41.49; author rse; state Exp;
branches;
next 1.20;
1.20
date 2001.09.12.16.07.23; author ms; state Exp;
branches;
next 1.19;
1.19
date 2001.09.12.09.39.16; author ms; state Exp;
branches;
next 1.18;
1.18
date 2001.09.11.11.59.59; author rse; state Exp;
branches;
next 1.17;
1.17
date 2001.09.06.16.10.05; author rse; state Exp;
branches;
next 1.16;
1.16
date 2001.09.06.14.37.53; author rse; state Exp;
branches;
next 1.15;
1.15
date 2001.09.06.11.47.51; author rse; state Exp;
branches;
next 1.14;
1.14
date 2001.09.05.07.47.12; author rse; state Exp;
branches;
next 1.13;
1.13
date 2001.09.04.19.18.49; author rse; state Exp;
branches;
next 1.12;
1.12
date 2001.09.04.15.41.17; author rse; state Exp;
branches;
next 1.11;
1.11
date 2001.09.04.14.54.03; author rse; state Exp;
branches;
next 1.10;
1.10
date 2001.09.04.13.52.59; author rse; state Exp;
branches;
next 1.9;
1.9
date 2001.09.02.15.37.48; author ms; state Exp;
branches;
next 1.8;
1.8
date 2001.08.24.15.16.43; author ms; state Exp;
branches;
next 1.7;
1.7
date 2001.08.23.05.30.58; author ms; state Exp;
branches;
next 1.6;
1.6
date 2001.08.22.18.12.16; author ms; state Exp;
branches;
next 1.5;
1.5
date 2001.08.15.10.36.03; author rse; state Exp;
branches;
next 1.4;
1.4
date 2001.05.24.09.40.28; author rse; state Exp;
branches;
next 1.3;
1.3
date 2001.05.22.20.00.12; author rse; state Exp;
branches;
next 1.2;
1.2
date 2001.05.11.17.07.52; author rse; state Exp;
branches;
next 1.1;
1.1
date 2001.05.10.19.46.01; author rse; state Exp;
branches
1.1.1.1;
next ;
1.1.1.1
date 2001.05.10.19.46.01; author rse; state Exp;
branches;
next ;
desc
@@
1.41
log
@Adjust copyright messages for new year 2005.
@
text
@/*
** OSSP l2 - Flexible Logging
** Copyright (c) 2001-2005 Cable & Wireless
** Copyright (c) 2001-2005 The OSSP Project
** Copyright (c) 2001-2005 Ralf S. Engelschall
**
** This file is part of OSSP l2, a flexible logging library which
** can be found at http://www.ossp.org/pkg/lib/l2/.
**
** Permission to use, copy, modify, and distribute this software for
** any purpose with or without fee is hereby granted, provided that
** the above copyright notice and this permission notice appear in all
** copies.
**
** THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
** WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
** MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
** IN NO EVENT SHALL THE AUTHORS AND COPYRIGHT HOLDERS AND THEIR
** CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
** USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
** ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
** OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
** OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
** SUCH DAMAGE.
**
** l2_ch_buffer.c: buffering channel implementation
*/
#include "l2.h"
#include "l2_p.h" /* for TRACE macro */
#include
#include /* for alarm(3) */
#include /* for sigaction(2) and SIGALRM */
#ifdef HAVE_SYS_TIME_H
#include /* for setitimer(2) */
#endif
#define L2_BUFFER_TIMER ITIMER_REAL /* calls to [s|g]etitimer() and alarm() */
/* declare private channel configuration */
typedef struct {
char *buf;
int bufpos;
int bufsize;
long bufinterval;
struct sigaction sigalrm;
#if defined(HAVE_SETITIMER) && defined(HAVE_SYS_TIME_H)
struct itimerval valprev;
#endif
int levelflush;
l2_level_t level;
} l2_ch_buffer_t;
/* Sets the VIRTUAL timer to preconfigured value in cfg */
static int set_alarm(l2_ch_buffer_t *cfg)
{
#if defined(HAVE_SETITIMER) && defined(HAVE_SYS_TIME_H)
struct itimerval valtest, valnew;
/* initialize auto vars before using them */
memset(&valnew, 0, sizeof(valnew));
valnew.it_interval.tv_sec = cfg->bufinterval;
valnew.it_interval.tv_usec = 0;
valnew.it_value.tv_sec = cfg->bufinterval;
valnew.it_value.tv_usec = 0;
if ((getitimer(L2_BUFFER_TIMER, &valtest) == 0) &&
((valtest.it_value.tv_sec | valtest.it_value.tv_usec |
valtest.it_interval.tv_sec | valtest.it_interval.tv_usec) == 0))
return setitimer(L2_BUFFER_TIMER, &valnew, &cfg->valprev);
else {
cfg->bufinterval = -1L; /* mark this timer as broken */
assert(FALSE);
return 1; /* to make the compiler happy */
}
#else
unsigned int uiAlarmed = 0;
assert(uiAlarmed = alarm(cfg->bufinterval));
if (uiAlarmed) { /* check if SIGALRM is occupied */
alarm(uiAlarmed); /* ...if so, then hack in the old value */
cfg->bufinterval = -1L; /* ...mark this timer as broken */
}
return 0;
#endif
}
/* Resets the VIRTUAL timer to preconfigured value in cfg */
static int reset_alarm(l2_ch_buffer_t *cfg)
{
#if defined(HAVE_SETITIMER) && defined(HAVE_SYS_TIME_H)
struct itimerval valnew;
/* initialize auto vars before using them */
memset(&valnew, 0, sizeof(valnew));
valnew.it_interval.tv_sec = cfg->bufinterval;
valnew.it_interval.tv_usec = 0;
valnew.it_value.tv_sec = cfg->bufinterval;
valnew.it_value.tv_usec = 0;
return setitimer(L2_BUFFER_TIMER, &valnew, 0);
#else
alarm(cfg->bufinterval);
return 0;
#endif
}
static void catchsignal(int sig, ...)
{
va_list ap;
static l2_channel_t *ch = NULL;
static l2_ch_buffer_t *cfg = NULL;
if (sig == 0) {
va_start(ap, sig);
ch = va_arg(ap, l2_channel_t *); /* init the handler just like */
cfg = va_arg(ap, l2_ch_buffer_t *); /* Thomas Lotterer does */
va_end(ap);
}
else if (sig == SIGALRM) {
TRACE("SIGALRM caught");
l2_channel_flush(ch);
reset_alarm(cfg); /* alarm(3) doesn't auto-reset like setitime(2) */
}
}
/* create channel */
static l2_result_t hook_create(l2_context_t *ctx, l2_channel_t *ch)
{
l2_ch_buffer_t *cfg;
/* allocate private channel configuration */
if ((cfg = (l2_ch_buffer_t *)malloc(sizeof(l2_ch_buffer_t))) == NULL)
return L2_ERR_MEM;
/* initialize configuration with reasonable defaults */
cfg->buf = NULL;
cfg->bufpos = 0;
cfg->bufsize = 4096;
cfg->bufinterval = 0;
cfg->levelflush = 0;
cfg->level = L2_LEVEL_NONE;
memset(&cfg->sigalrm, 0, sizeof(cfg->sigalrm));
#if defined(HAVE_SETITIMER) && defined(HAVE_SYS_TIME_H)
memset(&cfg->valprev, 0, sizeof(cfg->valprev));
#endif
/* link private channel configuration into channel context */
ctx->vp = cfg;
return L2_OK;
}
/* configure channel */
static l2_result_t hook_configure(l2_context_t *ctx, l2_channel_t *ch, const char *fmt, va_list ap)
{
l2_ch_buffer_t *cfg = (l2_ch_buffer_t *)ctx->vp;
l2_param_t pa[4];
l2_result_t rv;
l2_env_t *env;
/* feed and call generic parameter parsing engine */
L2_PARAM_SET(pa[0], size, INT, &cfg->bufsize);
L2_PARAM_SET(pa[1], interval, INT, &cfg->bufinterval);
L2_PARAM_SET(pa[2], levelflush, INT, &cfg->levelflush);
L2_PARAM_END(pa[3]);
l2_channel_env(ch, &env);
rv = l2_util_setparams(env, pa, fmt, ap);
if (cfg->bufinterval == -1L) /* -1 is reserved by L2 */
return L2_ERR_ARG; /* set_alarm() uses it */
if (cfg->bufsize < 0)
return L2_ERR_ARG;
return rv;
}
/* open channel */
static l2_result_t hook_open(l2_context_t *ctx, l2_channel_t *ch)
{
l2_ch_buffer_t *cfg = (l2_ch_buffer_t *)ctx->vp;
struct sigaction locact;
if ((cfg->bufinterval != 0) && (cfg->bufinterval != -1L)) {
/* initialize auto vars before using them */
memset(&locact, 0, sizeof(locact));
locact.sa_handler = (void(*)(int))catchsignal;
sigemptyset(&locact.sa_mask);
locact.sa_flags = 0;
catchsignal(0, ch, (l2_ch_buffer_t *)ctx->vp);
/* save old signal context before replacing with our own */
if (sigaction(SIGALRM, &locact, &cfg->sigalrm) < 0)
return L2_ERR_SYS;
if (set_alarm(cfg)) /* this is our own L2 set_alarm */
return L2_ERR_SYS;
}
/* open channel buffer */
if (cfg->bufsize > 0) {
if ((cfg->buf = malloc(cfg->bufsize)) == NULL)
return L2_ERR_MEM;
cfg->bufpos = 0;
}
return L2_OK_PASS;
}
/* write to channel */
static l2_result_t hook_write(l2_context_t *ctx, l2_channel_t *ch,
l2_level_t level, const char *buf, size_t buf_size)
{
l2_ch_buffer_t *cfg = (l2_ch_buffer_t *)ctx->vp;
l2_channel_t *downstream;
l2_result_t rv;
if (buf_size > (cfg->bufsize - cfg->bufpos)) {
/* flush buffer if necessary */
if (cfg->bufpos > 0) {
downstream = NULL;
while ((rv = l2_channel_downstream(ch, &downstream)) == L2_OK)
if ((rv = l2_channel_write(downstream, cfg->level, cfg->buf, cfg->bufpos)) != L2_OK)
return rv;
cfg->bufpos = 0;
cfg->level = L2_LEVEL_NONE;
}
/* pass through immediately to downstream if still too large */
if (buf_size > cfg->bufsize) {
downstream = NULL;
while ((rv = l2_channel_downstream(ch, &downstream)) == L2_OK)
if ((rv = l2_channel_write(downstream, level, buf, buf_size)) != L2_OK)
return rv;
return L2_OK;
}
}
/* flush if incoming message level differs from those already in buffer */
if ( (cfg->levelflush) /* if different levels force a flush */
&& (cfg->bufpos > 0) /* and there is something in the buffer */
&& (cfg->level != L2_LEVEL_NONE) /* and a remembered level is known */
&& (level != cfg->level) /* and the levels really differ */)
{
downstream = NULL;
while (l2_channel_downstream(ch, &downstream) == L2_OK)
if ((rv = l2_channel_write(downstream, cfg->level, cfg->buf, cfg->bufpos)) != L2_OK)
return rv;
cfg->bufpos = 0;
cfg->level = L2_LEVEL_NONE;
}
/* finally write incoming message to channel buffer */
memcpy(cfg->buf+cfg->bufpos, buf, buf_size);
cfg->bufpos += buf_size;
cfg->level = level;
return L2_OK;
}
/* flush channel */
static l2_result_t hook_flush(l2_context_t *ctx, l2_channel_t *ch)
{
l2_ch_buffer_t *cfg = (l2_ch_buffer_t *)ctx->vp;
l2_channel_t *downstream;
l2_result_t rv;
/* write the buffer contents downstream */
TRACE("l2_ch_buffer hook_flush called\n");
if (cfg->bufpos > 0) {
downstream = NULL;
while (l2_channel_downstream(ch, &downstream) == L2_OK)
if ((rv = l2_channel_write(downstream, cfg->level, cfg->buf, cfg->bufpos)) != L2_OK)
return rv;
cfg->bufpos = 0;
cfg->level = L2_LEVEL_NONE; /* reset this->context->level */
}
/* reset the flush alarm timer to synchronize the buffer */
if ((cfg->bufinterval != 0) && (cfg->bufinterval != -1L))
if (reset_alarm(cfg))
return L2_ERR_SYS;
return L2_OK_PASS;
}
/* close channel */
static l2_result_t hook_close(l2_context_t *ctx, l2_channel_t *ch)
{
l2_ch_buffer_t *cfg = (l2_ch_buffer_t *)ctx->vp;
l2_channel_t *downstream;
l2_result_t rv;
if ((cfg->bufinterval != 0) && (cfg->bufinterval != -1L)) {
#if defined(HAVE_SETITIMER) && defined(HAVE_SYS_TIME_H)
if (setitimer(L2_BUFFER_TIMER, &cfg->valprev, 0)) /* restore timer */
return L2_ERR_SYS;
#else
alarm(0);
#endif
/* restore previous signal context if previously saved & replaced */
if (&cfg->sigalrm.sa_handler)
if (sigaction(SIGALRM, &cfg->sigalrm, 0) < 0)
rv = L2_ERR_SYS;
}
/* write pending data before closing down */
if (cfg->bufpos > 0) {
downstream = NULL;
while (l2_channel_downstream(ch, &downstream) == L2_OK)
if ((rv = l2_channel_write(downstream, cfg->level, cfg->buf, cfg->bufpos)) != L2_OK)
return rv;
cfg->bufpos = 0;
cfg->level = L2_LEVEL_NONE; /* reset this->context->level */
}
/* close channel buffer */
if (cfg->buf != NULL) {
free(cfg->buf);
cfg->buf = NULL;
}
return L2_OK_PASS;
}
/* destroy channel */
static l2_result_t hook_destroy(l2_context_t *ctx, l2_channel_t *ch)
{
l2_ch_buffer_t *cfg = (l2_ch_buffer_t *)ctx->vp;
/* destroy channel configuration */
if (cfg->buf != NULL)
free(cfg->buf);
free(cfg);
return L2_OK_PASS;
}
/* exported channel handler structure */
l2_handler_t l2_handler_buffer = {
"buffer",
L2_CHANNEL_FILTER,
hook_create,
hook_configure,
hook_open,
hook_write,
hook_flush,
hook_close,
hook_destroy
};
@
1.40
log
@Fix compile warnings related to sigaction()'s sa_handler.
@
text
@d3 3
a5 3
** Copyright (c) 2001-2004 Cable & Wireless
** Copyright (c) 2001-2004 The OSSP Project
** Copyright (c) 2001-2004 Ralf S. Engelschall
@
1.39
log
@Adjust copyright messages for new year 2005.
@
text
@d192 1
a192 1
locact.sa_handler = (void(*)())catchsignal;
@
1.38
log
@- remove trailing whitespaces
- adjust copyright messages
- consistently use "OSSP l2"
- consistently talk about "Flexible Logging"
- use standard OSSP ASCII-art
@
text
@d3 3
a5 3
** Copyright (c) 2001-2003 Cable & Wireless Deutschland GmbH
** Copyright (c) 2001-2003 The OSSP Project (http://www.ossp.org/)
** Copyright (c) 2001-2003 Ralf S. Engelschall
@
1.37
log
@polish for release
@
text
@d2 4
a5 3
** OSSP l2 - Logging Library
** Copyright (c) 2001-2002 The OSSP Project (http://www.ossp.org/)
** Copyright (c) 2001-2002 Cable & Wireless Deutschland (http://www.cw.com/de/)
d7 1
a7 1
** This file is part of OSSP L2, a flexible logging library which
d176 1
a176 1
if (cfg->bufsize < 0)
@
1.36
log
@bump copyright year
@
text
@d2 1
a2 1
** L2 - OSSP Logging Library
d7 1
a7 1
** can be found at http://www.ossp.org/pkg/l2/.
@
1.35
log
@Cleanup before introducing timer changes.
@
text
@d3 2
a4 2
** Copyright (c) 2001 The OSSP Project (http://www.ossp.org/)
** Copyright (c) 2001 Cable & Wireless Deutschland (http://www.cw.com/de/)
@
1.34
log
@Hell, I've seldom seen that it is needed to prepare and adjust such a
lot of subtle details of existing code in order to make a new feature
implementable in a straight-forward way. Anyway, here comes one more
preparation change for the forthcoming channel tree specification
parser:
- change l2_util_setparam() to take an l2_env_t parameter
which allows the function to report better error messages.
- completely rewrite l2_util_setparam() to support calls
l2_channel_configure(ch, "n1=v1,n2=v2,n3=v3")
and/or
l2_channel_configure(ch, "n1=%x,n2=%x,n3=%x", v1, v2, v3)
instead of
l2_channel_configure(ch, "n1,n2,n3", v1, v2, v3)
This is both a step forward to make the interface of
l2_channel_configure() more flexible (because one now can directly
inline values instead of having them to be passed explicitly) and
allows the spec parser not having to know the type (integer, floating
point or string) of a parameter (which is important if one wants the
parser to be independent of the implementing channel handlers).
@
text
@d242 6
a247 5
/* flush if level of incoming message differs from those already in buffer */
if ( (cfg->levelflush) /* if different levels force a flush */
&& (cfg->bufpos > 0) /* and there is something in the buffer */
&& (cfg->level != L2_LEVEL_NONE) /* and a remembered level is known */
&& (level != cfg->level) /* and the levels really differ */) {
@
1.33
log
@More preparations for forthcoming channel tree specification parser
(especially to allow the parser to determine the handler structure
from a handler name without introducing another and this way redundant
sub-API):
- add "char *name" to l2_handler_t in order to tag each
handler structure with the corresponding channel name
- add l2_env_handler() function to add handler to
l2_env_t objects. All l2_handler_xxxx are automatically
pre-configured there after l2_env_create().
- change l2_channel_create() to take a "const char *name"
(handler name) instead of the "l2_handler_t *h" (handler
pointer) to make the stuff consistent and more clear.
- adjust l2_test.c to reflect the changes.
@
text
@d163 1
d170 2
a171 1
rv = l2_util_setparams(pa, fmt, ap);
@
1.32
log
@be pedantic about syntax in order to be really portable
@
text
@d341 1
@
1.31
log
@Channel-Only Revamping Step 1:
allow multiple downstream channels in order to
approach the later tree-like channel-only structure.
@
text
@d50 1
a50 1
#if defined HAVE_SETITIMER && defined HAVE_SYS_TIME_H
d60 1
a60 1
#if defined HAVE_SETITIMER && defined HAVE_SYS_TIME_H
d94 1
a94 1
#if defined HAVE_SETITIMER && defined HAVE_SYS_TIME_H
d147 1
a147 1
#if defined HAVE_SETITIMER && defined HAVE_SYS_TIME_H
d295 1
a295 1
#if defined HAVE_SETITIMER && defined HAVE_SYS_TIME_H
@
1.30
log
@Bug fixes, correction of sys/type.h inclusion, rid of warning errors.
@
text
@a182 1
l2_channel_t *downstream = l2_channel_downstream(ch);
a183 1
l2_result_t rv;
d209 1
a209 5
/* optionally open downstream channel, too */
if ((rv = l2_channel_open(downstream)) != L2_OK)
return rv;
return L2_OK;
d217 1
a217 1
l2_channel_t *downstream = l2_channel_downstream(ch);
d223 4
a226 2
if ((rv = l2_channel_write(downstream, cfg->level, cfg->buf, cfg->bufpos)) != L2_OK)
return rv;
d231 7
a237 2
if (buf_size > cfg->bufsize)
return l2_channel_write(downstream, level, buf, buf_size);
d245 4
a248 2
if ((rv = l2_channel_write(downstream, cfg->level, cfg->buf, cfg->bufpos)) != L2_OK)
return rv;
d265 1
a265 1
l2_channel_t *downstream = l2_channel_downstream(ch);
d271 4
a274 2
if ((rv = l2_channel_write(downstream, cfg->level, cfg->buf, cfg->bufpos)) != L2_OK)
return rv;
d284 1
a284 5
/* optionally flush downstream channel, too */
if ((rv = l2_channel_flush(downstream)) != L2_OK)
return rv;
return L2_OK;
d291 1
a291 1
l2_channel_t *downstream = l2_channel_downstream(ch);
d309 4
a312 2
if ((rv = l2_channel_write(downstream, cfg->level, cfg->buf, cfg->bufpos)) != L2_OK)
return rv;
a316 4
/* optionally close downstream channel, too */
if ((rv = l2_channel_close(downstream)) != L2_OK)
return rv;
d323 1
a323 1
return L2_OK;
a329 2
l2_channel_t *downstream = l2_channel_downstream(ch);
l2_result_t rv;
d331 2
a332 2
/* if not already closed, close channel buffer now */
if (cfg->buf != NULL) {
a333 4
cfg->buf = NULL;
}
/* destroy channel configuration */
d336 1
a336 5
/* optionally destroy downstream channel, too */
if ((rv = l2_channel_destroy(downstream)) != L2_OK)
return rv;
return L2_OK;
@
1.29
log
@Fixed implicit inclusion of sys/time.h. Now it is included explicitly, and
solves a linux OS preprocessor problem found by Lawrence "Larry" Greenfield
.
@
text
@d37 1
a37 1
#ifdef HAVE_SETITIMER
d50 1
a50 1
#ifdef HAVE_SETITIMER
d60 1
a60 1
#ifdef HAVE_INET_SETITIMER
d70 3
a72 3
if ((getitimer(L2_BUFFER_TIMER, &testval) == 0) &&
((testval.it_value.tv_sec | testval.it_value.tv_usec |
testval.it_interval.tv_sec | testval.it_interval.tv_usec) == 0))
d77 1
d82 1
a82 1
uiAlarmed = alarm(cfg->bufinterval);
a85 1
assert(FALSE); /* ...and warn the user about problems */
d94 1
a94 1
#ifdef HAVE_INET_SETITIMER
a125 1
#ifndef HAVE_SETITIMER
a126 1
#endif
d147 1
a147 1
#ifdef HAVE_SETITIMER
d294 1
a294 1
#ifdef HAVE_INET_SETITIMER
@
1.28
log
@external feedback. I don't think hardcoding the include would be correct solution
@
text
@d31 1
a31 1
#include "l2_p.h" /* for TRACE() */
d34 6
a39 3
#include /* for alarm() and setitime() */
#include /* for use of sigaction() and SIGALRM */
//FIXME feedback from lmtp2nntp 1.1b2 tester Lawrence "Larry" Greenfield // "[...] on Linux, l2_ch_buffer.c needed a #include // [...]"
@
1.27
log
@get rid of compile warnings by moving code
@
text
@d36 1
@
1.26
log
@Implemented half-solution to occupied timer problem.
@
text
@d53 54
a174 60
}
/************************************************************
* set_alarm: Helper method to hook_open *
* Sets the VIRTUAL timer to preconfigured value in cfg *
************************************************************/
static int set_alarm(l2_ch_buffer_t *cfg)
{
#ifdef HAVE_INET_SETITIMER
struct itimerval valtest, valnew;
/* initialize auto vars before using them */
memset(&valnew, 0, sizeof(valnew));
valnew.it_interval.tv_sec = cfg->bufinterval;
valnew.it_interval.tv_usec = 0;
valnew.it_value.tv_sec = cfg->bufinterval;
valnew.it_value.tv_usec = 0;
if ((getitimer(L2_BUFFER_TIMER, &testval) == 0) &&
((testval.it_value.tv_sec | testval.it_value.tv_usec |
testval.it_interval.tv_sec | testval.it_interval.tv_usec) == 0))
return setitimer(L2_BUFFER_TIMER, &valnew, &cfg->valprev);
else {
cfg->bufinterval = -1L; /* mark this timer as broken */
assert(FALSE);
}
#else
unsigned int uiAlarmed = 0;
uiAlarmed = alarm(cfg->bufinterval);
if (uiAlarmed) { /* check if SIGALRM is occupied */
alarm(uiAlarmed); /* ...if so, then hack in the old value */
cfg->bufinterval = -1L; /* ...mark this timer as broken */
assert(FALSE); /* ...and warn the user about problems */
}
return 0;
#endif
}
/************************************************************
* reset_alarm: Helper method to hook_flush *
* Resets the VIRTUAL timer to preconfigured value in cfg *
************************************************************/
static int reset_alarm(l2_ch_buffer_t *cfg)
{
#ifdef HAVE_INET_SETITIMER
struct itimerval valnew;
/* initialize auto vars before using them */
memset(&valnew, 0, sizeof(valnew));
valnew.it_interval.tv_sec = cfg->bufinterval;
valnew.it_interval.tv_usec = 0;
valnew.it_value.tv_sec = cfg->bufinterval;
valnew.it_value.tv_usec = 0;
return setitimer(L2_BUFFER_TIMER, &valnew, 0);
#else
alarm(cfg->bufinterval);
return 0;
#endif
@
1.25
log
@Completed implementation of timer. Beware of scope problem - I have only
tested it, but not proven it correct.
@
text
@d44 1
a44 1
int bufinterval;
d114 3
d130 1
a130 1
struct itimerval valnew;
d139 8
a146 1
return setitimer(L2_BUFFER_TIMER, &valnew, &cfg->valprev);
d148 8
a155 1
alarm(cfg->bufinterval);
d191 1
a191 1
if (cfg->bufinterval != 0) {
d204 1
a204 1
if (set_alarm(cfg))
d279 1
a279 1
if (cfg->bufinterval != 0)
d297 1
a297 1
if (cfg->bufinterval != 0) {
@
1.24
log
@Make usage of setitimer(2) dependent on if it exists on the target system.
Quick hack, future fix will replace lost functionality by issuing a call to
alarm(3) instead.
@
text
@d56 2
a57 1
static l2_channel_t *ch = NULL;
d61 2
a62 1
ch = va_arg(ap, l2_channel_t *);
d68 3
d138 1
d161 1
d182 1
a182 1
catchsignal(0, ch);
d253 1
@
1.23
log
@Changed timer from VIRTUAL to REAL. Completed flush alarm mechanism which
seems to work, probably because we are not forking.
@
text
@d31 1
a31 1
#include "l2_p.h" /* for TRACE() */
d34 4
a37 2
#include /* has setitime() in standard unix functions */
#include /* for use of sigaction() and SIGALRM */
d46 1
d48 1
d86 1
d88 1
d121 1
d131 4
a134 1
return setitimer(ITIMER_REAL, &valnew, &cfg->valprev); /* set flush timer */
d143 1
d153 4
a156 1
return setitimer(ITIMER_REAL, &valnew, 0); /* reset flush timer */
d273 7
a279 2
setitimer(ITIMER_REAL, &cfg->valprev, 0); /* restore timer values */
/* restore previous signal context if previously saved & replaced */
@
1.22
log
@Added untested code to implement alarm exceptions in the buffer channel. The
buffer will auto-flush after a user specified timeout if it is even possible
to do this with a c-style exception handler.
@
text
@d51 9
a59 1
if (sig == SIGALRM)
d61 2
d124 1
a124 1
return setitimer(ITIMER_VIRTUAL, &valnew, &cfg->valprev); /* set flush timer */
d142 1
a142 1
return setitimer(ITIMER_VIRTUAL, &valnew, 0); /* reset flush timer */
d161 1
d259 1
a259 1
setitimer(ITIMER_VIRTUAL, &cfg->valprev, 0); /* restore timer values */
@
1.21
log
@1. make level flushing optional by introducing a "levelflush" parameter
which by default is off to make sure maximum throughput is achieved.
2. bugfix the write operation.
@
text
@d31 1
d34 2
d42 3
d49 6
d65 8
a72 5
cfg->buf = NULL;
cfg->bufpos = 0;
cfg->bufsize = 4096;
cfg->levelflush = 0;
cfg->level = L2_LEVEL_NONE;
d84 1
a84 1
l2_param_t pa[3];
d89 3
a91 2
L2_PARAM_SET(pa[1], levelflush, INT, &cfg->levelflush);
L2_PARAM_END(pa[2]);
d99 36
d140 1
d143 16
d228 5
d246 8
@
1.20
log
@Added new logic to buffer only until incoming message level changes.
@
text
@d36 1
a36 1
char *buf;
d39 1
d53 5
a57 4
cfg->buf = NULL;
cfg->bufpos = 0;
cfg->bufsize = 4096;
cfg->level = L2_LEVEL_NONE;
d69 1
a69 1
l2_param_t pa[2];
d73 3
a75 2
L2_PARAM_SET(pa[0], size, INT, &cfg->bufsize);
L2_PARAM_END(pa[1]);
d118 1
a118 1
cfg->level = L2_LEVEL_NONE; /* reset this->context->level */
d125 5
a129 3
/* flush if incoming message level differs from those already in buffer */
if ((level != cfg->level) && (cfg->level == L2_LEVEL_NONE))
{
d133 1
a133 1
cfg->level = level;
d139 1
@
1.19
log
@Corrected bufsize variable inconsistency and upgraded file descriptor handler
to new L2_LEVEL parameter design.
@
text
@d36 4
a39 3
char *buf;
int bufpos;
int bufsize;
d55 1
d112 1
a112 1
if ((rv = l2_channel_write(downstream, level, cfg->buf, cfg->bufpos)) != L2_OK)
d115 1
d122 10
a131 1
/* write message to channel buffer */
d146 5
a150 4
if (cfg->bufpos > 0) { /* !---------! */
if ((rv = l2_channel_write(downstream, L2_LEVEL_PANIC, cfg->buf, cfg->bufpos)) != L2_OK)
return rv; /* !! FIXME !! */
cfg->bufpos = 0; /* !---------! */
d168 5
a172 4
if (cfg->bufpos > 0) { /* !---------! */
if ((rv = l2_channel_write(downstream, L2_LEVEL_PANIC, cfg->buf, cfg->bufpos)) != L2_OK)
return rv; /* !! FIXME !! */
cfg->bufpos = 0; /* !---------! */
@
1.18
log
@fix channel destruction in case of channel stacks
@
text
@d100 2
a101 2
static l2_result_t hook_write(l2_context_t *ctx, l2_channel_t *ch,
const char *buf, size_t bufsize)
d107 1
a107 1
if (bufsize > (cfg->bufsize - cfg->bufpos)) {
d110 1
a110 1
if ((rv = l2_channel_write(downstream, cfg->buf, cfg->bufpos)) != L2_OK)
d115 2
a116 2
if (bufsize > cfg->bufsize)
return l2_channel_write(downstream, buf, bufsize);
d120 2
a121 2
memcpy(cfg->buf+cfg->bufpos, buf, bufsize);
cfg->bufpos += bufsize;
d134 4
a137 4
if (cfg->bufpos > 0) {
if ((rv = l2_channel_write(downstream, cfg->buf, cfg->bufpos)) != L2_OK)
return rv;
cfg->bufpos = 0;
d155 4
a158 4
if (cfg->bufpos > 0) {
if ((rv = l2_channel_write(downstream, cfg->buf, cfg->bufpos)) != L2_OK)
return rv;
cfg->bufpos = 0;
@
1.17
log
@Simplify channels again: The channel framework gurranties that the
handler context is available if the handler has set it, so there is
no need to perform an additional run-time check and try to return
L2_ERR_ARG.
@
text
@d178 2
d189 4
@
1.16
log
@Replace generic L2_ERROR with more granular L2_ERR_XXX and
make sure that we always check with "!= L2_OK".
@
text
@d64 1
a64 1
l2_ch_buffer_t *cfg;
a67 4
/* parameter checks */
if ((cfg = (l2_ch_buffer_t *)ctx->vp) == NULL)
return L2_ERR_ARG;
d74 1
d81 2
a82 2
l2_ch_buffer_t *cfg;
l2_channel_t *downstream;
a84 4
/* parameter checks */
if ((cfg = (l2_ch_buffer_t *)ctx->vp) == NULL)
return L2_ERR_ARG;
d93 2
a94 3
if ((downstream = l2_channel_downstream(ch)) != NULL)
if ((rv = l2_channel_open(downstream)) != L2_OK)
return rv;
d103 1
a104 1
l2_ch_buffer_t *cfg;
a106 4
/* parameter checks */
if ((cfg = (l2_ch_buffer_t *)ctx->vp) == NULL)
return L2_ERR_ARG;
d129 2
a130 2
l2_ch_buffer_t *cfg;
l2_channel_t *downstream;
a132 4
/* parameter checks */
if ((cfg = (l2_ch_buffer_t *)ctx->vp) == NULL)
return L2_ERR_ARG;
d135 2
a136 3
if ((downstream = l2_channel_downstream(ch)) != NULL)
if ((rv = l2_channel_write(downstream, cfg->buf, cfg->bufpos)) != L2_OK)
return rv;
d141 2
a142 3
if ((downstream = l2_channel_downstream(ch)) != NULL)
if ((rv = l2_channel_flush(downstream)) != L2_OK)
return rv;
d150 2
a151 2
l2_ch_buffer_t *cfg;
l2_channel_t *downstream;
d154 1
a154 5
/* parameter checks */
if ((cfg = (l2_ch_buffer_t *)ctx->vp) == NULL)
return L2_ERR_ARG;
/* write stale data before closing down */
d156 2
a157 3
if ((downstream = l2_channel_downstream(ch)) != NULL)
if ((rv = l2_channel_write(downstream, cfg->buf, cfg->bufpos)) != L2_OK)
return rv;
d162 2
a163 3
if ((downstream = l2_channel_downstream(ch)) != NULL)
if ((rv = l2_channel_close(downstream)) != L2_OK)
return rv;
d177 1
a177 5
l2_ch_buffer_t *cfg;
/* parameter checks */
if ((cfg = (l2_ch_buffer_t *)ctx->vp) == NULL)
return L2_ERR_ARG;
@
1.15
log
@Fix buffer channel: in case the buffer is full, the "write" operation
has to flush it instead of complaining, of course.
@
text
@d48 1
a48 1
return L2_ERROR;
d70 1
a70 1
return L2_ERROR;
d77 1
a77 1
return L2_ERROR;
d86 1
d90 1
a90 1
return L2_ERROR;
d95 1
a95 1
return L2_ERROR;
d101 2
a102 2
if (l2_channel_open(downstream) == L2_ERROR)
return L2_ERROR;
d117 1
a117 1
return L2_ERROR;
d143 1
d147 1
a147 1
return L2_ERROR;
d152 2
a153 2
if (l2_channel_write(downstream, cfg->buf, cfg->bufpos) == L2_ERROR)
return L2_ERROR;
d159 2
a160 2
if (l2_channel_flush(downstream) == L2_ERROR)
return L2_ERROR;
d170 1
d174 1
a174 1
return L2_ERROR;
d179 2
a180 2
if (l2_channel_write(downstream, cfg->buf, cfg->bufpos) == L2_ERROR)
return L2_ERROR;
d186 2
a187 2
if (l2_channel_close(downstream) == L2_ERROR)
return L2_ERROR;
d205 1
a205 1
return L2_ERROR;
@
1.14
log
@Be politically correct: channels are intended to be implemented also by
users, which have only access to the public API (l2.h), so do not even
try to use anything more in our own shipped channels.
@
text
@d110 1
d112 1
d117 12
a128 2
if (bufsize > (cfg->bufsize - cfg->bufpos))
return L2_ERROR; /* The buffer is too small */
@
1.13
log
@Be pedantically correct: handler hooks return "l2_result_t"
and not "int", although currently it is just an int/enum.
@
text
@a30 1
#include "l2_p.h"
@
1.12
log
@Revamp channel handler API:
Instead of passing the downstream channel to all channels we instead
provide a l2_channel_downstream() function and provide the current
channel. This way the handler API is prototype-wise fully orthogonal
with the channel API (which it implements) and we no longer pass
information to 2/3 of our (output) channels which is of no use there.
Additionally add a channel type field to l2_handler_t which allows a
handler to say what type of channel it implements (filter or output).
This information is now used in l2_channel_stack() to make sure that
one can only stack a filter channel on top of another channel. For
convinience reasons there is also a new l2_channel_type() function which
allows one to query the type of a particular channel.
@
text
@d43 1
a43 1
static int hook_create(l2_context_t *ctx, l2_channel_t *ch)
d63 1
a63 1
static int hook_configure(l2_context_t *ctx, l2_channel_t *ch, const char *fmt, va_list ap)
d83 1
a83 1
static int hook_open(l2_context_t *ctx, l2_channel_t *ch)
d108 1
a108 1
static int hook_write(l2_context_t *ctx, l2_channel_t *ch,
d127 1
a127 1
static int hook_flush(l2_context_t *ctx, l2_channel_t *ch)
d153 1
a153 1
static int hook_close(l2_context_t *ctx, l2_channel_t *ch)
d185 1
a185 1
static int hook_destroy(l2_context_t *ctx, l2_channel_t *ch)
@
1.11
log
@fix array sizes
@
text
@d43 1
a43 1
static int hook_create(l2_context_t *ctx)
d63 1
a63 1
static int hook_configure(l2_context_t *ctx, const char *fmt, va_list ap)
d83 1
a83 1
static int hook_open(l2_context_t *ctx, l2_channel_t *downstream)
d86 1
d100 1
a100 1
if (downstream != NULL)
d108 1
a108 1
static int hook_write(l2_context_t *ctx, l2_channel_t *downstream,
d127 1
a127 1
static int hook_flush(l2_context_t *ctx, l2_channel_t *downstream)
d130 1
d138 1
a138 1
if (downstream != NULL)
d145 1
a145 1
if (downstream != NULL)
d153 1
a153 1
static int hook_close(l2_context_t *ctx, l2_channel_t *downstream)
d156 1
d164 1
a164 1
if (downstream != NULL)
d171 1
a171 1
if (downstream != NULL)
d185 1
a185 1
static int hook_destroy(l2_context_t *ctx)
d207 1
@
1.10
log
@Wohhooooo! Here comes the underlying message formatting support:
1. renamed l2_channel_setparam() to l2_util_setparam() because it
is just a utility function and is not tied to any channel.
2. moved l2_util_setparam() to its own l2_ut_param.c source file.
3. added l2_ut_format.c which contains a slightly adjusted version
of Str's str_format() stuff under the name l2_util_format().
4. use l2_util_format() in l2_stream.c instead of vsnprintf()
and this way finally support l2_formatter_t callbacks.
5. cleanup adjustments to the l2_stream_formatter() API.
Let's rock...
@
text
@d66 1
a66 1
l2_param_t pa[3];
d75 1
a75 1
L2_PARAM_END(pa[2]);
@
1.9
log
@Buffer channel now flushes itself to the downstream channel before closing
itself due to a call to its close method.
@
text
@d76 1
a76 1
rv = l2_channel_setparams(pa, fmt, ap);
@
1.8
log
@Conforms to doc (mostly comments) standard set by l2_ch_file.c.
@
text
@d66 1
a66 1
l2_param_t pa[3];
d155 12
a170 4
/* parameter checks */
if ((cfg = (l2_ch_buffer_t *)ctx->vp) == NULL)
return L2_ERROR;
@
1.7
log
@Upgraded bzero(3) to memset(3).
@
text
@d35 1
d42 1
d47 1
d50 2
d55 2
d58 1
d62 1
d69 1
d72 2
d82 1
d87 1
d90 2
d97 2
d102 1
d106 1
d112 1
a114 1
d118 1
d125 1
d130 1
d134 1
a139 1
memset(cfg->buf, 0x5A, cfg->bufsize); /* Guard against improper usage */
d142 1
d146 1
d150 1
d155 1
d159 2
d163 2
d169 1
d173 1
d178 1
d181 3
a183 1
if (cfg->buf != NULL)
d185 4
d190 1
d194 1
@
1.6
log
@When buffer will overflow, it should fail first. Also, when buffer gets a
write message it should not pass it downstream. The buffer writes data further
downstream only when it is flushed (either by the user or implicitly.)
@
text
@d116 1
a116 1
bzero(cfg->buf, cfg->bufsize); /* Guard against improper usage */
@
1.5
log
@Fix more ossp.com references by replacing with the
correct domain name ossp.org.
@
text
@d95 2
a96 6
if (bufsize > (cfg->bufsize - cfg->bufpos)) {
if (downstream != NULL)
if (l2_channel_write(downstream, cfg->buf, cfg->bufpos) == L2_ERROR)
return L2_ERROR;
cfg->bufpos = 0;
}
d116 1
@
1.4
log
@o rename l2_error_t to l2_result_t
o introduce internal channel state for API robustness
@
text
@d7 1
a7 1
** can be found at http://www.ossp.com/pkg/l2/.
@
1.3
log
@Implement a first cut for a buffer channel (still untested).
@
text
@d58 1
a58 1
l2_error_t rv;
@
1.2
log
@Fill in channel handler template code.
@
text
@d33 8
d43 8
d56 12
a67 1
return L2_OK;
d70 1
a70 1
static int hook_open(l2_context_t *ctx, l2_channel_t *below)
d72 12
d87 2
a88 2
static int hook_write(l2_context_t *ctx, l2_channel_t *below,
const char *buf, size_t buf_size)
d90 15
d108 1
a108 1
static int hook_flush(l2_context_t *ctx, l2_channel_t *below)
d110 15
d128 1
a128 1
static int hook_close(l2_context_t *ctx, l2_channel_t *below)
d130 11
d146 7
@
1.1
log
@Initial revision
@
text
@d33 46
@
1.1.1.1
log
@L2 initial source tree
@
text
@@