1/* -*- Mode: C; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2/*
3 *     Copyright 2013-2020 Couchbase, Inc.
4 *
5 *   Licensed under the Apache License, Version 2.0 (the "License");
6 *   you may not use this file except in compliance with the License.
7 *   You may obtain a copy of the License at
8 *
9 *       http://www.apache.org/licenses/LICENSE-2.0
10 *
11 *   Unless required by applicable law or agreed to in writing, software
12 *   distributed under the License is distributed on an "AS IS" BASIS,
13 *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 *   See the License for the specific language governing permissions and
15 *   limitations under the License.
16 */
17
18#ifndef LCB_HOSTLIST_H
19#define LCB_HOSTLIST_H
20
21#include "config.h"
22#include <libcouchbase/couchbase.h>
23
24#ifndef NI_MAXHOST
25#define NI_MAXHOST 1025
26#endif
27#ifndef NI_MAXSERV
28#define NI_MAXSERV 32
29#endif
30
31/**
32 * Structure representing a host. This contains the string representation
33 * of a host and a port.
34 */
35typedef struct lcb_host_st {
36    char host[NI_MAXHOST + 1];
37    char port[NI_MAXSERV + 1];
38    int ipv6;
39} lcb_host_t;
40
41#define LCB_HOST_FMT LCB_LOG_SPEC("%s%s%s:%s")
42#define LCB_HOST_ARG(__settings, __host)                                                                               \
43    ((__settings && __settings->log_redaction) ? LCB_LOG_SD_OTAG : ""), ((__host)->ipv6 ? "[" : ""), (__host)->host,   \
44        ((__host)->ipv6 ? "]" : ""), (__host)->port,                                                                   \
45        ((__settings && __settings->log_redaction) ? LCB_LOG_SD_CTAG : "")
46
47/**
48 * Structure representing a list of hosts. This has an internal iteration
49 * index which is used to cycle between 'good' and 'bad' hosts.
50 */
51#ifndef __cplusplus
52struct hostlist_st;
53typedef struct hostlist_st *hostlist_t;
54#else
55#include <vector>
56
57namespace lcb
58{
59struct Hostlist {
60    Hostlist() : ix(0) {}
61    ~Hostlist();
62
63    /**
64     * Adds a string to the hostlist. See lcb_host_parse for details.
65     * Note that if the host already exists (see 'lcb_host_equals') it will
66     * not be added
67     * @param s the string to parse
68     * @param len the length of the string
69     * @param deflport If `s` does not contain an explicit port, use this
70     *        port instead.
71     * @return LCB_ERR_INVALID_ARGUMENT if the host string is not valid
72     */
73    lcb_STATUS add(const char *s, long len, int deflport);
74    lcb_STATUS add(const char *s, int deflport)
75    {
76        return add(s, -1, deflport);
77    }
78    void add(const lcb_host_t &);
79
80    bool exists(const lcb_host_t &) const;
81    bool exists(const char *hostport) const;
82
83    /**
84     * Return the next host in the list.
85     * @param wrap If the internal iterator has reached its limit, this
86     * indicates whether it should be reset, or if it should return NULL
87     * @return a new host if available, or NULL if the list is empty or the
88     * iterator is finished.
89     */
90    lcb_host_t *next(bool wrap);
91    bool finished() const;
92
93    size_t size() const
94    {
95        return hosts.size();
96    }
97    bool empty() const
98    {
99        return hosts.empty();
100    }
101    Hostlist &assign(const Hostlist &other);
102
103    /** Clears the hostlist */
104    void clear()
105    {
106        hosts.clear();
107        reset_strlist();
108        ix = 0;
109    }
110
111    /** Randomize the hostlist by shuffling the order. */
112    void randomize();
113
114    /**
115     * String list handling functions. These are used to return the hostlist via
116     * the API where we return a char*[] terminated by a NULL pointer.
117     */
118
119    /** Ensure that the string list contains at least one entry */
120    void ensure_strlist();
121
122    /** Frees the current list of strings */
123    void reset_strlist();
124
125    const char *const *get_strlist()
126    {
127        ensure_strlist();
128        return &hoststrs[0];
129    }
130
131    unsigned int ix;
132    const lcb_host_t &operator[](size_t ix_) const
133    {
134        return hosts[ix_];
135    }
136
137    std::vector< lcb_host_t > hosts;
138    std::vector< const char * > hoststrs;
139};
140} // namespace lcb
141typedef lcb::Hostlist *hostlist_t;
142
143struct hostlist_st : lcb::Hostlist {
144    hostlist_st() : Hostlist() {}
145};
146#endif
147
148#ifdef __cplusplus
149extern "C" {
150#endif
151/**
152 * Parses a string into a hostlist
153 * @param host the target host to populate
154 * @param spec a string to parse. This may either be an IP/host or an
155 * IP:Port pair.
156 * @param speclen the length of the string. If this is -1 then it is assumed
157 * to be NUL-terminated and strlen will be used
158 * @param deflport If a port is not found in the spec, then this port will
159 * be used
160 *
161 * @return LCB_ERR_INVALID_ARGUMENT if the host format is invalid
162 */
163lcb_STATUS lcb_host_parse(lcb_host_t *host, const char *spec, int speclen, int deflport);
164
165/** Wrapper around lcb_host_parse() which accepts a NUL-terminated string
166 * @param host the host to populate
167 * @param spec a NUL-terminated string to parse
168 * @param deflport the default port to use if the `spec` does not contain a port
169 * @see lcb_host_parse()
170 */
171#define lcb_host_parsez(host, spec, deflport) lcb_host_parse(host, spec, -1, deflport)
172
173/**
174 * Compares two hosts for equality.
175 * @param a host to compare
176 * @param b other host to compare
177 * @return true if equal, false if different.
178 */
179int lcb_host_equals(const lcb_host_t *a, const lcb_host_t *b);
180
181#ifdef __cplusplus
182}
183#endif
184#endif
185