#include <sys_defs.h>
#include <unistd.h>
#include <string.h>
#include <msg.h>
#include <vstring.h>
#include <mymalloc.h>
#include <events.h>
#include <scache.h>
typedef struct {
VSTRING *endp_label;
VSTRING *endp_prop;
int fd;
} SCACHE_SINGLE_ENDP;
typedef struct {
VSTRING *dest_label;
VSTRING *dest_prop;
VSTRING *endp_label;
} SCACHE_SINGLE_DEST;
typedef struct {
SCACHE scache[1];
SCACHE_SINGLE_ENDP endp;
SCACHE_SINGLE_DEST dest;
} SCACHE_SINGLE;
static void scache_single_expire_endp(int, void *);
static void scache_single_expire_dest(int, void *);
#define SCACHE_SINGLE_ENDP_BUSY(sp) (VSTRING_LEN(sp->endp.endp_label) > 0)
#define SCACHE_SINGLE_DEST_BUSY(sp) (VSTRING_LEN(sp->dest.dest_label) > 0)
#define STR(x) vstring_str(x)
static void scache_single_free_endp(SCACHE_SINGLE *sp)
{
const char *myname = "scache_single_free_endp";
if (msg_verbose)
msg_info("%s: %s", myname, STR(sp->endp.endp_label));
event_cancel_timer(scache_single_expire_endp, (void *) sp);
if (sp->endp.fd >= 0 && close(sp->endp.fd) < 0)
msg_warn("close session endpoint %s: %m", STR(sp->endp.endp_label));
VSTRING_RESET(sp->endp.endp_label);
VSTRING_TERMINATE(sp->endp.endp_label);
VSTRING_RESET(sp->endp.endp_prop);
VSTRING_TERMINATE(sp->endp.endp_prop);
sp->endp.fd = -1;
}
static void scache_single_expire_endp(int unused_event, void *context)
{
SCACHE_SINGLE *sp = (SCACHE_SINGLE *) context;
scache_single_free_endp(sp);
}
static void scache_single_save_endp(SCACHE *scache, int endp_ttl,
const char *endp_label,
const char *endp_prop, int fd)
{
SCACHE_SINGLE *sp = (SCACHE_SINGLE *) scache;
const char *myname = "scache_single_save_endp";
if (endp_ttl <= 0)
msg_panic("%s: bad endp_ttl: %d", myname, endp_ttl);
if (SCACHE_SINGLE_ENDP_BUSY(sp))
scache_single_free_endp(sp);
vstring_strcpy(sp->endp.endp_label, endp_label);
vstring_strcpy(sp->endp.endp_prop, endp_prop);
sp->endp.fd = fd;
event_request_timer(scache_single_expire_endp, (void *) sp, endp_ttl);
if (msg_verbose)
msg_info("%s: %s fd=%d", myname, endp_label, fd);
}
static int scache_single_find_endp(SCACHE *scache, const char *endp_label,
VSTRING *endp_prop)
{
SCACHE_SINGLE *sp = (SCACHE_SINGLE *) scache;
const char *myname = "scache_single_find_endp";
int fd;
if (!SCACHE_SINGLE_ENDP_BUSY(sp)) {
if (msg_verbose)
msg_info("%s: no endpoint cache: %s", myname, endp_label);
return (-1);
}
if (strcmp(STR(sp->endp.endp_label), endp_label) == 0) {
vstring_strcpy(endp_prop, STR(sp->endp.endp_prop));
fd = sp->endp.fd;
sp->endp.fd = -1;
scache_single_free_endp(sp);
if (msg_verbose)
msg_info("%s: found: %s fd=%d", myname, endp_label, fd);
return (fd);
}
if (msg_verbose)
msg_info("%s: not found: %s", myname, endp_label);
return (-1);
}
static void scache_single_free_dest(SCACHE_SINGLE *sp)
{
const char *myname = "scache_single_free_dest";
if (msg_verbose)
msg_info("%s: %s -> %s", myname, STR(sp->dest.dest_label),
STR(sp->dest.endp_label));
event_cancel_timer(scache_single_expire_dest, (void *) sp);
VSTRING_RESET(sp->dest.dest_label);
VSTRING_TERMINATE(sp->dest.dest_label);
VSTRING_RESET(sp->dest.dest_prop);
VSTRING_TERMINATE(sp->dest.dest_prop);
VSTRING_RESET(sp->dest.endp_label);
VSTRING_TERMINATE(sp->dest.endp_label);
}
static void scache_single_expire_dest(int unused_event, void *context)
{
SCACHE_SINGLE *sp = (SCACHE_SINGLE *) context;
scache_single_free_dest(sp);
}
static void scache_single_save_dest(SCACHE *scache, int dest_ttl,
const char *dest_label,
const char *dest_prop,
const char *endp_label)
{
SCACHE_SINGLE *sp = (SCACHE_SINGLE *) scache;
const char *myname = "scache_single_save_dest";
int refresh;
if (dest_ttl <= 0)
msg_panic("%s: bad dest_ttl: %d", myname, dest_ttl);
refresh =
(SCACHE_SINGLE_DEST_BUSY(sp)
&& strcmp(STR(sp->dest.dest_label), dest_label) == 0
&& strcmp(STR(sp->dest.dest_prop), dest_prop) == 0
&& strcmp(STR(sp->dest.endp_label), endp_label) == 0);
if (refresh == 0) {
vstring_strcpy(sp->dest.dest_label, dest_label);
vstring_strcpy(sp->dest.dest_prop, dest_prop);
vstring_strcpy(sp->dest.endp_label, endp_label);
}
event_request_timer(scache_single_expire_dest, (void *) sp, dest_ttl);
if (msg_verbose)
msg_info("%s: %s -> %s%s", myname, dest_label, endp_label,
refresh ? " (refreshed)" : "");
}
static int scache_single_find_dest(SCACHE *scache, const char *dest_label,
VSTRING *dest_prop, VSTRING *endp_prop)
{
SCACHE_SINGLE *sp = (SCACHE_SINGLE *) scache;
const char *myname = "scache_single_find_dest";
int fd;
if (!SCACHE_SINGLE_DEST_BUSY(sp)) {
if (msg_verbose)
msg_info("%s: no destination cache: %s", myname, dest_label);
return (-1);
}
if (strcmp(STR(sp->dest.dest_label), dest_label) == 0) {
if (msg_verbose)
msg_info("%s: found: %s", myname, dest_label);
if ((fd = scache_single_find_endp(scache, STR(sp->dest.endp_label), endp_prop)) >= 0) {
vstring_strcpy(dest_prop, STR(sp->dest.dest_prop));
return (fd);
}
}
if (msg_verbose)
msg_info("%s: not found: %s", myname, dest_label);
return (-1);
}
static void scache_single_size(SCACHE *scache, SCACHE_SIZE *size)
{
SCACHE_SINGLE *sp = (SCACHE_SINGLE *) scache;
size->dest_count = (!SCACHE_SINGLE_DEST_BUSY(sp) ? 0 : 1);
size->endp_count = (!SCACHE_SINGLE_ENDP_BUSY(sp) ? 0 : 1);
size->sess_count = (sp->endp.fd < 0 ? 0 : 1);
}
static void scache_single_free(SCACHE *scache)
{
SCACHE_SINGLE *sp = (SCACHE_SINGLE *) scache;
vstring_free(sp->endp.endp_label);
vstring_free(sp->endp.endp_prop);
if (sp->endp.fd >= 0)
close(sp->endp.fd);
vstring_free(sp->dest.dest_label);
vstring_free(sp->dest.dest_prop);
vstring_free(sp->dest.endp_label);
myfree((void *) sp);
}
SCACHE *scache_single_create(void)
{
SCACHE_SINGLE *sp = (SCACHE_SINGLE *) mymalloc(sizeof(*sp));
sp->scache->save_endp = scache_single_save_endp;
sp->scache->find_endp = scache_single_find_endp;
sp->scache->save_dest = scache_single_save_dest;
sp->scache->find_dest = scache_single_find_dest;
sp->scache->size = scache_single_size;
sp->scache->free = scache_single_free;
sp->endp.endp_label = vstring_alloc(10);
sp->endp.endp_prop = vstring_alloc(10);
sp->endp.fd = -1;
sp->dest.dest_label = vstring_alloc(10);
sp->dest.dest_prop = vstring_alloc(10);
sp->dest.endp_label = vstring_alloc(10);
return (sp->scache);
}