@@ -114,6 +114,7 @@ using socket_t = SOCKET;
114
114
115
115
#include < arpa/inet.h>
116
116
#include < cstring>
117
+ #include < ifaddrs.h>
117
118
#include < netdb.h>
118
119
#include < netinet/in.h>
119
120
#ifdef CPPHTTPLIB_USE_POLL
@@ -743,6 +744,8 @@ class Client {
743
744
744
745
void set_compress (bool on);
745
746
747
+ void set_interface (const char *intf);
748
+
746
749
protected:
747
750
bool process_request (Stream &strm, const Request &req, Response &res,
748
751
bool last_connection, bool &connection_close);
@@ -758,6 +761,7 @@ class Client {
758
761
std::string username_;
759
762
std::string password_;
760
763
bool compress_;
764
+ std::string interface_;
761
765
762
766
private:
763
767
socket_t create_client_socket () const ;
@@ -1348,10 +1352,62 @@ inline bool is_connection_error() {
1348
1352
#endif
1349
1353
}
1350
1354
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
+
1351
1400
inline 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) {
1353
1403
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
+
1355
1411
set_nonblocking (sock, true );
1356
1412
1357
1413
auto ret = ::connect (sock, ai.ai_addr , static_cast <int >(ai.ai_addrlen ));
@@ -3312,7 +3368,8 @@ inline Client::~Client() {}
3312
3368
inline bool Client::is_valid () const { return true ; }
3313
3369
3314
3370
inline 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_);
3316
3373
}
3317
3374
3318
3375
inline bool Client::read_response_line (Stream &strm, Response &res) {
@@ -3942,6 +3999,10 @@ inline void Client::set_follow_location(bool on) { follow_location_ = on; }
3942
3999
3943
4000
inline void Client::set_compress (bool on) { compress_ = on; }
3944
4001
4002
+ inline void Client::set_interface (const char *intf) {
4003
+ interface_ = intf;
4004
+ }
4005
+
3945
4006
/*
3946
4007
* SSL Implementation
3947
4008
*/
0 commit comments