/** * 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 #include #include #include #ifdef WIN32 #define random rand /* replace POSIX random with Windows rand */ #include /* must always be included before ws2tcpip.h */ #include /* 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 (avec->data[i].ss_family != addr->ss_family) continue; switch (addr->ss_family) { case AF_INET: if (memcmp(&((struct sockaddr_in*)&avec->data[i])->sin_addr, &((struct sockaddr_in*)addr)->sin_addr, sizeof(struct in_addr)) == 0) return 1; break; #ifdef AF_INET6 case AF_INET6: if (memcmp(&((struct sockaddr_in6*)&avec->data[i])->sin6_addr, &((struct sockaddr_in6*)addr)->sin6_addr, sizeof(struct in6_addr)) == 0) return 1; break; #endif default: break; } } 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; }