simple-socket library 1.2.0
InternetSocket.cpp
Go to the documentation of this file.
1#include "InternetSocket.h"
2#include "TempFailure.h"
3
4#include <sys/socket.h>
5#include <arpa/inet.h>
6#include <poll.h>
7#include <fcntl.h>
8#include <cstring>
9
10using namespace NET;
11
12InternetSocket::InternetSocket( int type, int protocol)
13: SimpleSocket( INTERNET, type, protocol)
14{}
15
17: SimpleSocket(sockfd) {}
18
19void InternetSocket::connect( std::string_view foreignAddress, unsigned short foreignPort)
20{
21 sockaddr_in addr;
22 fillAddress( foreignAddress, foreignPort, addr);
23
24 if( ::connect( m_socket, (sockaddr*) &addr, sizeof(addr)) < 0)
25 throw SocketException("Connect failed (connect)");
26
27 m_peerDisconnected = false;
28}
29
30int InternetSocket::timedConnect( std::string_view foreignAddress, unsigned short foreignPort, int timeout)
31{
32 sockaddr_in addr;
33 fillAddress( foreignAddress, foreignPort, addr);
35 // Set O_NONBLOCK
36 int flags_before = ::fcntl( m_socket, F_GETFL, 0);
37 if( flags_before < 0)
38 throw SocketException("timedConnect failed (fcntl)");
39 ::fcntl( m_socket, F_SETFL, flags_before | O_NONBLOCK);
40
41 int ret = 0;
42 // Start connecting (asynchronously)
43 if( ::connect( m_socket, (sockaddr*) &addr, sizeof(addr)) == 0)
44 { ret = 1; goto exit; }
45
46 // Did connect return an unexpected error?
47 if( (errno != EWOULDBLOCK) && (errno != EINPROGRESS))
48 { ret = -1; goto exit; }
49
50 // Wait for the connection to complete.
51 struct pollfd poll;
52 poll.fd = m_socket;
53 poll.events = POLLOUT;
54
55 ret = TEMP_FAILURE_RETRY (::poll( &poll, 1, timeout));
56
57 if( ret < 0) goto exit;
58 if( ret == 0) // Did poll timeout?
59 {
60 errno = ETIMEDOUT;
61 }
62 if( ret > 0) // If poll succeeded, make sure there is no error
63 {
64 int error = 0; socklen_t len = sizeof(error);
65 int opt = ::getsockopt( m_socket, SOL_SOCKET, SO_ERROR, &error, &len);
66 if( opt == 0) errno = error;
67 if( error != 0) ret = -1;
68 }
69
70 exit:
71 // Restore original flags
72 ::fcntl( m_socket, F_SETFL, flags_before);
73
74 if( ret < 0)
75 throw SocketException("timedConnect failed (connect)");
76 if( ret > 0)
77 m_peerDisconnected = false;
78
79 return ret;
80}
81
82void InternetSocket::bind( unsigned short localPort /* = 0 */)
83{
84 sockaddr_in addr;
85 addr.sin_family = AF_INET;
86 addr.sin_addr.s_addr = INADDR_ANY;
87 addr.sin_port = htons(localPort);
88
89 if( ::bind( m_socket, (sockaddr*) &addr, sizeof(addr)) < 0)
90 throw SocketException("Set of local port failed (bind)");
91}
92
93void InternetSocket::bind( std::string_view localAddress, unsigned short localPort /* = 0 */)
94{
95 sockaddr_in addr;
96 fillAddress( localAddress, localPort, addr);
97
98 if( ::bind( m_socket, (sockaddr*) &addr, sizeof(addr)) < 0)
99 throw SocketException("Set of local address and port failed (bind)");
100}
101
103{
104 sockaddr_in addr;
105 socklen_t addr_len = sizeof(addr);
106
107 if( getsockname( m_socket, (sockaddr*) &addr, &addr_len) < 0)
108 throw SocketException("Fetch of local address failed (getsockname)");
109
110 return inet_ntoa( addr.sin_addr);
111}
112
113unsigned short InternetSocket::getLocalPort() const
114{
115 sockaddr_in addr;
116 socklen_t addr_len = sizeof(addr);
117
118 if( getsockname( m_socket, (sockaddr*) &addr, &addr_len) < 0)
119 throw SocketException("Fetch of local port failed (getsockname)");
120
121 return ntohs( addr.sin_port);
122}
123
125{
126 sockaddr_in addr;
127 socklen_t addr_len = sizeof(addr);
128
129 if( getpeername( m_socket, (sockaddr*) &addr, &addr_len) < 0)
130 throw SocketException("Fetch of foreign address failed (getpeername)");
131
132 return inet_ntoa( addr.sin_addr);
133}
134
135unsigned short InternetSocket::getForeignPort() const
136{
137 sockaddr_in addr;
138 socklen_t addr_len = sizeof(addr);
139
140 if( getpeername( m_socket, (sockaddr*) &addr, &addr_len) < 0)
141 throw SocketException("Fetch of foreign port failed (getpeername)");
142
143 return ntohs( addr.sin_port);
144}
145
146void InternetSocket::fillAddress( std::string_view address, unsigned short port, sockaddr_in& addr)
147{
148 const int IP_MAXSIZE = 20;
149 const int len = address.length();
150
151 // needed space is size plus null character
152 if( len >= IP_MAXSIZE)
153 throw SocketException("IPv4 address is too long", false);
154
155 addr.sin_family = AF_INET;
156 addr.sin_port = htons(port);
157
158 char buf[IP_MAXSIZE];
159 std::memcpy( buf, address.data(), len);
160 buf[len] = 0;
161
162 if( inet_aton( buf, &addr.sin_addr) == 0)
163 throw SocketException("Unable to parse IPv4 address");
164}
static const int len
#define TEMP_FAILURE_RETRY(expression)
Definition TempFailure.h:8
Definition CANFrame.h:7
void bind(unsigned short localPort=0)
unsigned short getLocalPort() const
unsigned short getForeignPort() const
InternetSocket(int sockfd)
create socket from a SocketHandle returned by an accept() call
int timedConnect(std::string_view foreignAddress, unsigned short foreignPort, int timeout)
establish a connection with the given foreign address and port
void connect(std::string_view foreignAddress, unsigned short foreignPort)
establish a connection with the given foreign address and port
std::string getLocalAddress() const
std::string getForeignAddress() const
static void fillAddress(std::string_view address, unsigned short port, sockaddr_in &addr)
int connect(const std::vector< std::string > &foreignAddresses, unsigned short foreignPort=0)
Signals a problem with the execution of a socket call.
SimpleSocket(int sockfd)
enables return of an accepted socket