simple-socket library 1.2.0
SocketUtils.cpp
Go to the documentation of this file.
1#include "SocketUtils.h"
2#include "SimpleSocket.h"
3
4#include <sys/socket.h>
5#include <sys/ioctl.h>
6#include <arpa/inet.h>
7#include <net/if.h>
8#include <net/if_arp.h>
9#include <netdb.h>
10#include <unistd.h>
11#include <cstdint>
12
13#include <cstring>
14#include <cstdlib>
15
16using namespace NET;
17
18namespace
19{
20 // needed because of strict aliasing rules
21 class sockaddr_ptr
22 {
23 public:
24 explicit sockaddr_ptr( const sockaddr* sa) : msa(*sa) {}
25 const sockaddr_in& operator*() const { return msi; }
26 const sockaddr_in* operator->() const { return &msi; }
27
28 private:
29 union { sockaddr msa; sockaddr_in msi; };
30 };
31
32 // use as temporary RAII socket
33 class temp_socket : public SimpleSocket
34 {
35 public:
36 temp_socket() : SimpleSocket( AF_INET, SOCK_DGRAM, 0) {}
37 };
38
39 // check and copy the name of the interface
40 void assign_ifreq( struct ifreq& ifr, std::string_view interface)
41 {
42 size_t len = interface.length();
43
44 if( len >= IF_NAMESIZE)
45 throw SocketException("Interface name is too long", false);
46
47 ifr.ifr_addr.sa_family = AF_INET;
48 std::memcpy( ifr.ifr_name, interface.data(), len);
49 ifr.ifr_name[len] = 0;
50 }
51}
52
53std::string NET::resolveHostname( const std::string& hostname)
54{
55 hostent* host = gethostbyname( hostname.c_str());
56 if( host == nullptr)
57 {
58 // strerror() will not work for gethostbyname()
59 throw SocketException("Failed to resolve address (gethostbyname)", false);
60 }
61
62 char ip[20];
63 auto addr = host->h_addr;
64 int len = sprintf(ip, "%d.%d.%d.%d", addr[0], addr[1], addr[2], addr[3]);
65 return std::string(ip, len);
66}
67
68uint16_t NET::resolveService( const std::string& service, const std::string& protocol)
69{
70 struct servent* serv;
71 if( protocol.empty())
72 serv = getservbyname( service.c_str(), nullptr);
73 else
74 serv = getservbyname( service.c_str(), protocol.c_str());
75
76 if(serv)
77 return ntohs( static_cast<uint16_t>(serv->s_port));
78 return 0;
79}
80
81/* This function does not understand interfaces with multiple addresses
82 * For example when using zeroconf (eth0, eth0:avahi) it would only list eth0
83 * In this case eth0 does not have an ip address yet and getInterfaceAddress("eth0") throws
84std::vector<std::string> NET::getNetworkInterfaces()
85{
86 std::vector<std::string> ret;
87 struct if_nameindex* index = if_nameindex();
88 if(index == nullptr) return ret;
89
90 for( int i = 0; (index[i].if_index != 0); ++i)
91 ret.push_back( std::string( index[i].if_name));
92
93 if_freenameindex(index);
94 return ret;
95}
96*/
97
98std::vector<std::string> NET::getNetworkInterfaces()
99{
100 std::vector<std::string> ret;
101 // maximum of number interfaces
102 char data[32 * sizeof(struct ifreq)];
103 struct ifconf conf;
104 struct ifreq *ifr;
105
106 conf.ifc_len = sizeof(data);
107 conf.ifc_buf = (caddr_t) data;
108
109 temp_socket sock;
110 if( ioctl( sock.nativeHandle(), SIOCGIFCONF, &conf) < 0)
111 throw SocketException("ioctl failed (getNetworkInterfaces)");
112
113 ifr = (struct ifreq*)data;
114 while( (char*)ifr < data+conf.ifc_len)
115 {
116 switch(ifr->ifr_addr.sa_family)
117 {
118 case AF_INET:
119 ret.emplace_back( ifr->ifr_name);
120 //printf("%s : %s\n", ifr->ifr_name, inet_ntop(ifr->ifr_addr.sa_family, &((struct sockaddr_in*)&ifr->ifr_addr)->sin_addr, addrbuf, sizeof(addrbuf)));
121 break;
122 #if 0
123 case AF_INET6:
124 printf("%s : %s\n", ifr->ifr_name, inet_ntop(ifr->ifr_addr.sa_family, &((struct sockaddr_in6*)&ifr->ifr_addr)->sin6_addr, addrbuf, sizeof(addrbuf)));
125 break;
126 #endif
127 default:
128 break;
129 }
130 ++ifr;
131 }
132 return ret;
133}
134
135std::string NET::getInterfaceAddress( std::string_view interface)
136{
137 struct ifreq ifr;
138 assign_ifreq( ifr, interface);
139
140 temp_socket sock;
141 if( ioctl( sock.nativeHandle(), SIOCGIFADDR, &ifr) < 0)
142 throw SocketException("ioctl failed (getInterfaceAddress)");
143
144 return inet_ntoa( sockaddr_ptr( &ifr.ifr_addr)->sin_addr);
145}
146
147void NET::setInterfaceAddress( std::string_view interface, std::string_view address)
148{
149 struct ifreq ifr;
150 assign_ifreq( ifr, interface);
151
152 std::string address_z(address);
153 inet_aton( address_z.c_str(), &(reinterpret_cast<sockaddr_in*>(&ifr.ifr_addr)->sin_addr));
154
155 temp_socket sock;
156 if( ioctl( sock.nativeHandle(), SIOCSIFADDR, &ifr) < 0)
157 throw SocketException("ioctl failed (setInterfaceAddress)");
158}
159
160std::string NET::getBroadcastAddress( std::string_view interface)
161{
162 struct ifreq ifr;
163 assign_ifreq( ifr, interface);
164
165 temp_socket sock;
166 if( ioctl( sock.nativeHandle(), SIOCGIFBRDADDR, &ifr) < 0)
167 throw SocketException("ioctl failed (getBroadcastAddress)");
168
169 return inet_ntoa( sockaddr_ptr( &ifr.ifr_broadaddr)->sin_addr);
170}
171
172void NET::setBroadcastAddress( std::string_view interface, std::string_view address)
173{
174 struct ifreq ifr;
175 assign_ifreq( ifr, interface);
176
177 std::string address_z(address);
178 inet_aton( address_z.c_str(), &(reinterpret_cast<sockaddr_in*>(&ifr.ifr_broadaddr)->sin_addr));
179
180 temp_socket sock;
181 if( ioctl( sock.nativeHandle(), SIOCSIFBRDADDR, &ifr) < 0)
182 throw SocketException("ioctl failed (setBroadcastAddress)");
183}
184
185std::string NET::getNetmask( std::string_view interface)
186{
187 struct ifreq ifr;
188 assign_ifreq( ifr, interface);
189
190 temp_socket sock;
191 if( ioctl( sock.nativeHandle(), SIOCGIFNETMASK, &ifr) < 0)
192 throw SocketException("ioctl failed (getNetmask)");
193
194 return inet_ntoa( sockaddr_ptr( &ifr.ifr_netmask)->sin_addr);
195}
196
197void NET::setNetmask( std::string_view interface, std::string_view address)
198{
199 struct ifreq ifr;
200 assign_ifreq( ifr, interface);
201
202 std::string address_z(address);
203 inet_aton( address_z.c_str(), &(reinterpret_cast<sockaddr_in*>(&ifr.ifr_netmask)->sin_addr));
204
205 temp_socket sock;
206 if( ioctl( sock.nativeHandle(), SIOCSIFNETMASK, &ifr) < 0)
207 throw SocketException("ioctl failed (setNetmask)");
208}
209
210std::string NET::getDestinationAddress( std::string_view interface)
211{
212 struct ifreq ifr;
213 assign_ifreq( ifr, interface);
214
215 temp_socket sock;
216 if( ioctl( sock.nativeHandle(), SIOCGIFDSTADDR, &ifr) < 0)
217 throw SocketException("ioctl failed (getDestinationAddress)");
218
219 return inet_ntoa( sockaddr_ptr( &ifr.ifr_dstaddr)->sin_addr);
220}
221
222void NET::setDestinationAddress( std::string_view interface, std::string_view address)
223{
224 struct ifreq ifr;
225 assign_ifreq( ifr, interface);
226
227 std::string address_z(address);
228 inet_aton( address_z.c_str(), &(reinterpret_cast<sockaddr_in*>(&ifr.ifr_dstaddr)->sin_addr));
229
230 temp_socket sock;
231 if( ioctl( sock.nativeHandle(), SIOCSIFDSTADDR, &ifr) < 0)
232 throw SocketException("ioctl failed (setDestinationAddress)");
233}
234
235int NET::getMTU( std::string_view interface)
236{
237 struct ifreq ifr;
238 assign_ifreq( ifr, interface);
239
240 temp_socket sock;
241 if( ioctl( sock.nativeHandle(), SIOCGIFMTU, &ifr) < 0)
242 throw SocketException("ioctl failed (getMTU)");
243
244 return ifr.ifr_mtu;
245}
246
247void NET::setMTU( std::string_view interface, int mtu)
248{
249 struct ifreq ifr;
250 assign_ifreq( ifr, interface);
251
252 ifr.ifr_mtu = mtu;
253
254 temp_socket sock;
255 if( ioctl( sock.nativeHandle(), SIOCSIFMTU, &ifr) < 0)
256 throw SocketException("ioctl failed (setMTU)");
257}
258
259std::string NET::getHardwareAddress( std::string_view interface)
260{
261 struct ifreq ifr;
262 assign_ifreq( ifr, interface);
263
264 temp_socket sock;
265 if( ioctl( sock.nativeHandle(), SIOCGIFHWADDR, &ifr) < 0)
266 throw SocketException("ioctl failed (getHardwareAddress)");
267
268 switch( ifr.ifr_hwaddr.sa_family) {
269 default:
270 throw SocketException("Invalid Hardware type (getHardwareAddress)");
271 break;
272 case ARPHRD_NETROM:
273 case ARPHRD_ETHER:
274 case ARPHRD_PPP:
275 case ARPHRD_EETHER:
276 case ARPHRD_IEEE802:
277 break;
278 }
279
280 char mac[20];
281 auto addr = reinterpret_cast<unsigned char*>( ifr.ifr_addr.sa_data);
282 int len = sprintf(mac, "%02x:%02x:%02x:%02x:%02x:%02x", addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]);
283 return std::string(mac, len);
284}
static const int len
Definition CANFrame.h:7
void setDestinationAddress(std::string_view interface, std::string_view address)
Set the IPv4 destination address of the given network interface.
std::string getDestinationAddress(std::string_view interface)
Return the IPv4 destination address of the given network interface.
std::string getHardwareAddress(std::string_view interface)
Return the MAC address of the given network interfaces.
std::string getInterfaceAddress(std::string_view interface)
Return the IPv4 address of the given network interface.
int getMTU(std::string_view interface)
Return the MTU (Maximum Transmission Unit) of the given network interface in bytes.
void setInterfaceAddress(std::string_view interface, std::string_view address)
Set the IPv4 address of the given network interface.
uint16_t resolveService(const std::string &service, const std::string &protocol="tcp")
std::vector< std::string > getNetworkInterfaces()
Return a list of available network interfaces.
std::string getBroadcastAddress(std::string_view interface)
Return the IPv4 broadcast address of the given network interface.
void setMTU(std::string_view interface, int mtu)
Set the MTU (Maximum Transmission Unit) of the given network interface in bytes.
std::string getNetmask(std::string_view interface)
Return the IPv4 netmask of the given network interface.
std::string resolveHostname(const std::string &hostname)
void setBroadcastAddress(std::string_view interface, std::string_view address)
Set the IPv4 broadcast address of the given network interface.
void setNetmask(std::string_view interface, std::string_view address)
Set the IPv4 netmask of the given network interface.
Signals a problem with the execution of a socket call.
A socket representing a basic communication endpoint.