blob: 87faff089edeaeb11129a37baee2fcfd2313d76a [file] [log] [blame]
/*
* OpenVPN -- An application to securely tunnel IP networks
* over a single TCP/UDP port, with support for SSL/TLS-based
* session authentication and key exchange,
* packet encryption, packet authentication, and
* packet compression.
*
* Copyright (C) 2002-2018 OpenVPN Inc <sales@openvpn.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2
* as published by the Free Software Foundation.
*
* 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.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#elif defined(_MSC_VER)
#include "config-msvc.h"
#endif
#include "syshead.h"
#if P2MP
#include "buffer.h"
#include "error.h"
#include "integer.h"
#include "misc.h"
#include "mbuf.h"
#include "memdbg.h"
struct mbuf_set *
mbuf_init(unsigned int size)
{
struct mbuf_set *ret;
ALLOC_OBJ_CLEAR(ret, struct mbuf_set);
ret->capacity = adjust_power_of_2(size);
ALLOC_ARRAY(ret->array, struct mbuf_item, ret->capacity);
return ret;
}
void
mbuf_free(struct mbuf_set *ms)
{
if (ms)
{
int i;
for (i = 0; i < (int) ms->len; ++i)
{
struct mbuf_item *item = &ms->array[MBUF_INDEX(ms->head, i, ms->capacity)];
mbuf_free_buf(item->buffer);
}
free(ms->array);
free(ms);
}
}
struct mbuf_buffer *
mbuf_alloc_buf(const struct buffer *buf)
{
struct mbuf_buffer *ret;
ALLOC_OBJ(ret, struct mbuf_buffer);
ret->buf = clone_buf(buf);
ret->refcount = 1;
ret->flags = 0;
return ret;
}
void
mbuf_free_buf(struct mbuf_buffer *mb)
{
if (mb)
{
if (--mb->refcount <= 0)
{
free_buf(&mb->buf);
free(mb);
}
}
}
void
mbuf_add_item(struct mbuf_set *ms, const struct mbuf_item *item)
{
ASSERT(ms);
if (ms->len == ms->capacity)
{
struct mbuf_item rm;
ASSERT(mbuf_extract_item(ms, &rm));
mbuf_free_buf(rm.buffer);
msg(D_MULTI_DROPPED, "MBUF: mbuf packet dropped");
}
ASSERT(ms->len < ms->capacity);
ms->array[MBUF_INDEX(ms->head, ms->len, ms->capacity)] = *item;
if (++ms->len > ms->max_queued)
{
ms->max_queued = ms->len;
}
++item->buffer->refcount;
}
bool
mbuf_extract_item(struct mbuf_set *ms, struct mbuf_item *item)
{
bool ret = false;
if (ms)
{
while (ms->len)
{
*item = ms->array[ms->head];
ms->head = MBUF_INDEX(ms->head, 1, ms->capacity);
--ms->len;
if (item->instance) /* ignore dereferenced instances */
{
ret = true;
break;
}
}
}
return ret;
}
struct multi_instance *
mbuf_peek_dowork(struct mbuf_set *ms)
{
struct multi_instance *ret = NULL;
if (ms)
{
int i;
for (i = 0; i < (int) ms->len; ++i)
{
struct mbuf_item *item = &ms->array[MBUF_INDEX(ms->head, i, ms->capacity)];
if (item->instance)
{
ret = item->instance;
break;
}
}
}
return ret;
}
void
mbuf_dereference_instance(struct mbuf_set *ms, struct multi_instance *mi)
{
if (ms)
{
int i;
for (i = 0; i < (int) ms->len; ++i)
{
struct mbuf_item *item = &ms->array[MBUF_INDEX(ms->head, i, ms->capacity)];
if (item->instance == mi)
{
mbuf_free_buf(item->buffer);
item->buffer = NULL;
item->instance = NULL;
msg(D_MBUF, "MBUF: dereferenced queued packet");
}
}
}
}
#else /* if P2MP */
static void
dummy(void)
{
}
#endif /* P2MP */