Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-04-17 08:35:03

0001 /*
0002  * Licensed to the Apache Software Foundation (ASF) under one
0003  * or more contributor license agreements. See the NOTICE file
0004  * distributed with this work for additional information
0005  * regarding copyright ownership. The ASF licenses this file
0006  * to you under the Apache License, Version 2.0 (the
0007  * "License"); you may not use this file except in compliance
0008  * with the License. You may obtain a copy of the License at
0009  *
0010  *   http://www.apache.org/licenses/LICENSE-2.0
0011  *
0012  * Unless required by applicable law or agreed to in writing,
0013  * software distributed under the License is distributed on an
0014  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
0015  * KIND, either express or implied. See the License for the
0016  * specific language governing permissions and limitations
0017  * under the License.
0018  */
0019 
0020 #ifndef _THRIFT_TRANSPORT_SOCKETUTILS_H_
0021 #define _THRIFT_TRANSPORT_SOCKETUTILS_H_ 1
0022 
0023 #include <memory>
0024 #include <string>
0025 #include <system_error>
0026 #include <vector>
0027 
0028 #include <sys/types.h>
0029 #ifdef HAVE_SYS_SOCKET_H
0030 #include <sys/socket.h>
0031 #endif
0032 #ifdef HAVE_NETDB_H
0033 #include <netdb.h>
0034 #endif
0035 
0036 #include <thrift/transport/PlatformSocket.h>
0037 
0038 namespace apache {
0039 namespace thrift {
0040 
0041 /**
0042  * A helper to resolve hostnames to struct addrinfo's -- and not leak memory.
0043  *
0044  * Use like this:
0045  *
0046  *   apache::thrift::AddressResolutionHelper addresses("localhost", "80");
0047  *
0048  *   for (auto addr : addresses.iterate()) {
0049  *      connect(sock, addr->ai_addr, addr->ai_addrlen);
0050  *      // ...
0051  *   }
0052  */
0053 struct AddressResolutionHelper {
0054 
0055 private:
0056   struct addrinfo_deleter {
0057     void operator()(addrinfo* addr) {
0058       ::freeaddrinfo(addr); // frees the whole list
0059     }
0060   };
0061 
0062 public:
0063   using PtrOwnedList = std::unique_ptr<addrinfo, addrinfo_deleter>;
0064 
0065   struct Iter : std::iterator<std::forward_iterator_tag, const addrinfo*> {
0066     value_type ptr = nullptr;
0067 
0068     Iter() = default;
0069     Iter(const addrinfo* head) : ptr(head) {}
0070 
0071     value_type operator*() const { return ptr; }
0072 
0073     bool operator==(const Iter& other) { return this->ptr == other.ptr; }
0074     bool operator!=(const Iter& other) { return this->ptr != other.ptr; }
0075 
0076     operator bool() { return this->ptr != nullptr; }
0077     bool operator!() { return this->ptr == nullptr; }
0078 
0079     Iter& operator++() {
0080       if (ptr == nullptr) {
0081         throw std::out_of_range("won't go pass end of linked list");
0082       }
0083       ptr = ptr->ai_next;
0084       return *this;
0085     }
0086     Iter operator++(int) {
0087       Iter tmp(*this);
0088       ++(*this);
0089       return tmp;
0090     }
0091   };
0092 
0093   struct gai_error : std::error_category {
0094     virtual const char* name() const noexcept override { return "getaddrinfo"; }
0095     virtual std::string message(int code) const override { return THRIFT_GAI_STRERROR(code); }
0096   };
0097 
0098 private:
0099   PtrOwnedList gai_results;
0100 
0101   addrinfo* query(const std::string& host, const std::string& port, int socktype, int flags) {
0102     addrinfo hints{};
0103     hints.ai_flags = flags;
0104     hints.ai_family = AF_UNSPEC;
0105     hints.ai_socktype = socktype;
0106 
0107     addrinfo* head;
0108     int ret = ::getaddrinfo(host.empty() ? NULL : host.c_str(), port.c_str(), &hints, &head);
0109     if (ret == 0) {
0110       return head;
0111 #ifdef _WIN32
0112     } else {
0113       throw std::system_error{THRIFT_GET_SOCKET_ERROR, std::system_category()};
0114 #else
0115     } else if (ret == EAI_SYSTEM) {
0116       throw std::system_error{THRIFT_GET_SOCKET_ERROR, std::system_category()};
0117     } else {
0118       throw std::system_error{ret, gai_error()};
0119 #endif
0120     }
0121   }
0122 
0123 public:
0124   /**
0125    * Constructor. May block. Throws errors.
0126    *
0127    * @param port Port number, or service name, as a string.
0128    * @param socktype Socket type, SOCK_STREAM or SOCK_DGRAM.
0129    * @param flags Standard getaddrinfo() flags.
0130    */
0131   AddressResolutionHelper(const std::string& host,
0132                           const std::string& port, // pass "25" or "smtp" for port 25
0133                           int socktype = SOCK_STREAM,
0134                           int flags = AI_V4MAPPED | AI_ADDRCONFIG)
0135     : gai_results(query(host, port, socktype, flags)) {}
0136 
0137   AddressResolutionHelper() = default;
0138 
0139   /**
0140    * Manual query. May block. Throws errors.
0141    *
0142    * @param port Port number, or service name, as a string.
0143    * @param socktype Socket type, SOCK_STREAM or SOCK_DGRAM.
0144    * @param flags Standard getaddrinfo() flags.
0145    */
0146   AddressResolutionHelper& resolve(const std::string& host,
0147                                    const std::string& port, // pass "25" or "smtp" for port 25
0148                                    int socktype = SOCK_STREAM,
0149                                    int flags = AI_V4MAPPED | AI_ADDRCONFIG) {
0150     gai_results.reset(query(host, port, socktype, flags));
0151     return *this;
0152   }
0153 
0154   /**
0155    * Return ForwardIterator to struct addrinfo* results.
0156    */
0157   Iter iterate() const { return Iter{gai_results.get()}; }
0158 };
0159 
0160 } // namespace thrift
0161 } // namespace apache
0162 
0163 #endif