blob: fdfb68d34fd9c2d2cee027c1849079233488843d [file] [log] [blame]
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <errno.h>
#ifdef WIN32
#define random rand /* replace POSIX random with Windows rand */
#include <winsock2.h> /* must always be included before ws2tcpip.h */
#include <ws2tcpip.h> /* for sockaddr_storage */
#include "winport.h"
#endif
#include "addrvec.h"
#define ADDRVEC_DEFAULT_GROW_AMOUNT 16
void addrvec_init(addrvec_t *avec)
{
assert(avec);
avec->next = 0;
avec->count = 0;
avec->capacity = 0;
avec->data = NULL;
}
void addrvec_free(addrvec_t *avec)
{
if (avec == NULL)
{
return;
}
avec->next = 0;
avec->count = 0;
avec->capacity = 0;
if (avec->data) {
free(avec->data);
avec->data = NULL;
}
}
int addrvec_alloc(addrvec_t *avec)
{
addrvec_init(avec);
return addrvec_grow_default(avec);
}
int addrvec_alloc_capacity(addrvec_t* avec, uint32_t capacity)
{
addrvec_init(avec);
return addrvec_grow(avec, capacity);
}
int addrvec_grow(addrvec_t *avec, uint32_t grow_amount)
{
unsigned int old_capacity = 0;
struct sockaddr_storage *old_data = NULL;
assert(avec);
if (grow_amount == 0)
{
return 0;
}
// Save off old data and capacity in case there is a realloc failure
old_capacity = avec->capacity;
old_data = avec->data;
avec->capacity += grow_amount;
avec->data = realloc(avec->data, sizeof(*avec->data) * avec->capacity);
if (avec->data == NULL)
{
avec->capacity = old_capacity;
avec->data = old_data;
errno = ENOMEM;
return 1;
}
return 0;
}
int addrvec_grow_default(addrvec_t *avec)
{
return addrvec_grow(avec, ADDRVEC_DEFAULT_GROW_AMOUNT);
}
static int addrvec_grow_if_full(addrvec_t *avec)
{
assert(avec);
if (avec->count == avec->capacity)
{
int rc = addrvec_grow_default(avec);
if (rc != 0)
{
return rc;
}
}
return 0;
}
int addrvec_contains(const addrvec_t *avec, const struct sockaddr_storage *addr)
{
uint32_t i = 0;
if (!avec || !addr)
{
return 0;
}
for (i = 0; i < avec->count; i++)
{
if(memcmp(&avec->data[i], addr, INET_ADDRSTRLEN) == 0)
return 1;
}
return 0;
}
int addrvec_append(addrvec_t *avec, const struct sockaddr_storage *addr)
{
int rc = 0;
assert(avec);
assert(addr);
rc = addrvec_grow_if_full(avec);
if (rc != 0)
{
return rc;
}
// Copy addrinfo into address list
memcpy(avec->data + avec->count, addr, sizeof(*addr));
++avec->count;
return 0;
}
int addrvec_append_addrinfo(addrvec_t *avec, const struct addrinfo *addrinfo)
{
int rc = 0;
assert(avec);
assert(addrinfo);
rc = addrvec_grow_if_full(avec);
if (rc != 0)
{
return rc;
}
// Copy addrinfo into address list
memcpy(avec->data + avec->count, addrinfo->ai_addr, addrinfo->ai_addrlen);
++avec->count;
return 0;
}
void addrvec_shuffle(addrvec_t *avec)
{
int i = 0;
for (i = avec->count - 1; i > 0; --i) {
long int j = random()%(i+1);
if (i != j) {
struct sockaddr_storage t = avec->data[i];
avec->data[i] = avec->data[j];
avec->data[j] = t;
}
}
}
int addrvec_hasnext(const addrvec_t *avec)
{
return avec->count > 0 && (avec->next < avec->count);
}
int addrvec_atend(const addrvec_t *avec)
{
return avec->count > 0 && avec->next >= avec->count;
}
void addrvec_next(addrvec_t *avec, struct sockaddr_storage *next)
{
int index;
// If we're at the end of the list, then reset index to start
if (addrvec_atend(avec)) {
avec->next = 0;
}
if (!addrvec_hasnext(avec)) {
if (next) {
memset(next, 0, sizeof(*next));
}
return;
}
index = avec->next++;
if (next) {
*next = avec->data[index];
}
}
void addrvec_peek(addrvec_t *avec, struct sockaddr_storage *next)
{
int index = avec->next;
if (avec->count == 0) {
memset(next, 0, sizeof(*next));
return;
}
if (addrvec_atend(avec)) {
index = 0;
}
*next = avec->data[index];
}
int addrvec_eq(const addrvec_t *a1, const addrvec_t *a2)
{
uint32_t i = 0;
if (a1->count != a2->count)
{
return 0;
}
for (i = 0; i < a1->count; ++i)
{
if (!addrvec_contains(a2, &a1->data[i]))
return 0;
}
return 1;
}