blob: 76425b18495b527431fb29d213272a7efe467c53 [file] [log] [blame]
/*
* (C) 2006-2009 by Pablo Neira Ayuso <pablo@netfilter.org>
*
* 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 of the License, 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 "queue.h"
#include "event.h"
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
static LIST_HEAD(queue_list); /* list of existing queues */
static uint32_t qobjects_num; /* number of active queue objects */
struct queue *
queue_create(const char *name, int max_objects, unsigned int flags)
{
struct queue *b;
b = calloc(sizeof(struct queue), 1);
if (b == NULL)
return NULL;
b->max_elems = max_objects;
INIT_LIST_HEAD(&b->head);
b->flags = flags;
if (flags & QUEUE_F_EVFD) {
b->evfd = create_evfd();
if (b->evfd == NULL) {
free(b);
return NULL;
}
}
strncpy(b->name, name, QUEUE_NAMELEN);
b->name[QUEUE_NAMELEN-1]='\0';
list_add(&b->list, &queue_list);
return b;
}
void queue_destroy(struct queue *b)
{
list_del(&b->list);
if (b->flags & QUEUE_F_EVFD)
destroy_evfd(b->evfd);
free(b);
}
void queue_stats_show(int fd)
{
struct queue *this;
int size = 0;
char buf[512];
size += snprintf(buf+size, sizeof(buf),
"allocated queue nodes:\t\t%12u\n\n",
qobjects_num);
list_for_each_entry(this, &queue_list, list) {
size += snprintf(buf+size, sizeof(buf),
"queue %s:\n"
"current elements:\t\t%12u\n"
"maximum elements:\t\t%12u\n"
"not enough space errors:\t%12u\n\n",
this->name,
this->num_elems,
this->max_elems,
this->enospc_err);
}
send(fd, buf, size, 0);
}
void queue_node_init(struct queue_node *n, int type)
{
INIT_LIST_HEAD(&n->head);
n->type = type;
}
void *queue_node_data(struct queue_node *n)
{
return ((char *)n) + sizeof(struct queue_node);
}
struct queue_object *queue_object_new(int type, size_t size)
{
struct queue_object *obj;
obj = calloc(sizeof(struct queue_object) + size, 1);
if (obj == NULL)
return NULL;
obj->qnode.size = size;
queue_node_init(&obj->qnode, type);
qobjects_num++;
return obj;
}
void queue_object_free(struct queue_object *obj)
{
free(obj);
qobjects_num--;
}
int queue_add(struct queue *b, struct queue_node *n)
{
if (!list_empty(&n->head))
return 0;
if (b->num_elems >= b->max_elems) {
b->enospc_err++;
errno = ENOSPC;
return -1;
}
n->owner = b;
list_add_tail(&n->head, &b->head);
b->num_elems++;
if (b->evfd)
write_evfd(b->evfd);
return 1;
}
int queue_del(struct queue_node *n)
{
if (list_empty(&n->head))
return 0;
list_del_init(&n->head);
n->owner->num_elems--;
if (n->owner->evfd)
read_evfd(n->owner->evfd);
n->owner = NULL;
return 1;
}
struct queue_node *queue_del_head(struct queue *b)
{
struct queue_node *n = (struct queue_node *) b->head.next;
queue_del(n);
return n;
}
int queue_in(struct queue *b, struct queue_node *n)
{
return b == n->owner;
}
int queue_get_eventfd(struct queue *b)
{
return get_read_evfd(b->evfd);
}
void queue_iterate(struct queue *b,
const void *data,
int (*iterate)(struct queue_node *n, const void *data2))
{
struct list_head *i, *tmp;
struct queue_node *n;
list_for_each_safe(i, tmp, &b->head) {
n = (struct queue_node *) i;
if (iterate(n, data))
break;
}
}
unsigned int queue_len(const struct queue *b)
{
return b->num_elems;
}