@@ -114,6 +114,7 @@ using socket_t = SOCKET;
114114
115115#include < arpa/inet.h>
116116#include < cstring>
117+ #include < ifaddrs.h>
117118#include < netdb.h>
118119#include < netinet/in.h>
119120#ifdef CPPHTTPLIB_USE_POLL
@@ -743,6 +744,8 @@ class Client {
743744
744745 void set_compress (bool on);
745746
747+ void set_interface (const char *intf);
748+
746749protected:
747750 bool process_request (Stream &strm, const Request &req, Response &res,
748751 bool last_connection, bool &connection_close);
@@ -758,6 +761,7 @@ class Client {
758761 std::string username_;
759762 std::string password_;
760763 bool compress_;
764+ std::string interface_;
761765
762766private:
763767 socket_t create_client_socket () const ;
@@ -1348,10 +1352,62 @@ inline bool is_connection_error() {
13481352#endif
13491353}
13501354
1355+ inline bool bind_ip_address (socket_t sock, const char *host) {
1356+ struct addrinfo hints;
1357+ struct addrinfo *result;
1358+
1359+ memset (&hints, 0 , sizeof (struct addrinfo ));
1360+ hints.ai_family = AF_UNSPEC;
1361+ hints.ai_socktype = SOCK_STREAM;
1362+ hints.ai_protocol = 0 ;
1363+
1364+ if (getaddrinfo (host, " 0" , &hints, &result)) { return false ; }
1365+
1366+ bool ret = false ;
1367+ for (auto rp = result; rp; rp = rp->ai_next ) {
1368+ const auto &ai = *rp;
1369+ if (!::bind (sock, ai.ai_addr , static_cast <int >(ai.ai_addrlen ))) {
1370+ ret = true ;
1371+ break ;
1372+ }
1373+ }
1374+
1375+ freeaddrinfo (result);
1376+ return ret;
1377+ }
1378+
1379+ inline std::string if2ip (const std::string &ifn) {
1380+ #ifndef _WIN32
1381+ struct ifaddrs *ifap;
1382+ getifaddrs (&ifap);
1383+ for (auto ifa = ifap; ifa; ifa = ifa->ifa_next ) {
1384+ if (ifa->ifa_addr && ifn == ifa->ifa_name ) {
1385+ if (ifa->ifa_addr ->sa_family == AF_INET) {
1386+ auto sa = reinterpret_cast <struct sockaddr_in *>(ifa->ifa_addr );
1387+ char buf[INET_ADDRSTRLEN];
1388+ if (inet_ntop (AF_INET, &sa->sin_addr , buf, INET_ADDRSTRLEN)) {
1389+ freeifaddrs (ifap);
1390+ return std::string (buf, INET_ADDRSTRLEN);
1391+ }
1392+ }
1393+ }
1394+ }
1395+ freeifaddrs (ifap);
1396+ #endif
1397+ return std::string ();
1398+ }
1399+
13511400inline socket_t create_client_socket (const char *host, int port,
1352- time_t timeout_sec) {
1401+ time_t timeout_sec,
1402+ const std::string &intf) {
13531403 return create_socket (
1354- host, port, [=](socket_t sock, struct addrinfo &ai) -> bool {
1404+ host, port, [&](socket_t sock, struct addrinfo &ai) -> bool {
1405+ if (!intf.empty ()) {
1406+ auto ip = if2ip (intf);
1407+ if (ip.empty ()) { ip = intf; }
1408+ if (!bind_ip_address (sock, ip.c_str ())) { return false ; }
1409+ }
1410+
13551411 set_nonblocking (sock, true );
13561412
13571413 auto ret = ::connect (sock, ai.ai_addr , static_cast <int >(ai.ai_addrlen ));
@@ -3312,7 +3368,8 @@ inline Client::~Client() {}
33123368inline bool Client::is_valid () const { return true ; }
33133369
33143370inline socket_t Client::create_client_socket () const {
3315- return detail::create_client_socket (host_.c_str (), port_, timeout_sec_);
3371+ return detail::create_client_socket (host_.c_str (), port_, timeout_sec_,
3372+ interface_);
33163373}
33173374
33183375inline bool Client::read_response_line (Stream &strm, Response &res) {
@@ -3942,6 +3999,10 @@ inline void Client::set_follow_location(bool on) { follow_location_ = on; }
39423999
39434000inline void Client::set_compress (bool on) { compress_ = on; }
39444001
4002+ inline void Client::set_interface (const char *intf) {
4003+ interface_ = intf;
4004+ }
4005+
39454006/*
39464007 * SSL Implementation
39474008 */
0 commit comments