@@ -32,52 +32,64 @@ static int close(SOCKET sock)
3232namespace aoe {
3333
3434#if _WIN32
35- // process and throw error message. always throws
36- static void wsa_generic_error (const char *prefix, int code) noexcept (false )
35+ static std::string wsa_parse_error (const char *prefix=" " , int code=WSAGetLastError())
3736{
3837 std::string msg (prefix);
39- msg += " : " ;
4038
4139 switch (code) {
42- case WSANOTINITIALISED:
43- msg += " winsock not ready" ;
44- break ;
45- case WSAENETDOWN:
46- msg += " network subsystem error" ;
47- break ;
48- case WSAENOBUFS:
49- msg += " out of memory" ;
50- break ;
51- case WSAENOTSOCK:
52- msg += " invalid socket" ;
53- break ;
54- case WSAEOPNOTSUPP:
55- msg += " operation not supported" ;
56- break ;
57- default :
58- msg += " code " + std::to_string (code);
59- break ;
40+ case WSANOTINITIALISED:
41+ msg += " winsock not ready" ;
42+ break ;
43+ case WSAENETDOWN:
44+ msg += " network subsystem error" ;
45+ break ;
46+ case WSAEINPROGRESS:
47+ msg += " waiting for network to become ready" ;
48+ break ;
49+ case WSAENOBUFS:
50+ msg += " out of memory" ;
51+ break ;
52+ case WSAENOTSOCK:
53+ msg += " invalid socket" ;
54+ break ;
55+ case WSAEOPNOTSUPP:
56+ msg += " operation not supported" ;
57+ break ;
58+ case WSAEFAULT:
59+ msg += " argument address fault" ;
60+ break ;
61+ case WSAEACCES:
62+ msg += " access denied" ;
63+ break ;
64+ case WSAEADDRINUSE:
65+ msg += " socket address still in use" ;
66+ break ;
67+ case WSAEADDRNOTAVAIL:
68+ msg += " invalid address" ;
69+ break ;
70+ case WSAEINVAL:
71+ msg += " invalid state or invalid value specified" ;
72+ break ;
73+ default :
74+ msg += " unknown error code " + std::to_string (code);
75+ break ;
6076 }
6177
62- throw std::runtime_error (msg);
78+ return msg;
79+ }
80+
81+ // process and throw error message. always throws
82+ static void wsa_generic_error (const char *prefix, int code) noexcept (false )
83+ {
84+ throw std::runtime_error (wsa_parse_error (prefix, code));
6385}
6486
6587std::atomic<unsigned > initnet (0 );
6688
6789void set_nonblocking (SOCKET s, bool nonbl) {
6890 u_long arg = !!nonbl;
69- if (!ioctlsocket (s, FIONBIO, &arg))
70- return ;
71-
72- int r;
73-
74- switch (r = WSAGetLastError ()) {
75- case WSAEFAULT:
76- throw std::runtime_error (" wsa: argument address fault" );
77- default :
78- wsa_generic_error (" wsa: cannot change non-blocking mode" , r);
79- break ;
80- }
91+ if (ioctlsocket (s, FIONBIO, &arg))
92+ throw std::runtime_error (wsa_parse_error ());
8193}
8294
8395Net::Net () {
@@ -95,6 +107,8 @@ Net::Net() {
95107 throw std::runtime_error (" wsa: winsock blocked" );
96108 case WSAEPROCLIM:
97109 throw std::runtime_error (" wsa: winsock process limit reached" );
110+ case WSAEFAULT:
111+ throw std::runtime_error (" wsa: wsadata bogus pointer" );
98112 default :
99113 if (r)
100114 throw std::runtime_error (std::string (" wsa: winsock error code " ) + std::to_string (r));
@@ -108,27 +122,16 @@ Net::~Net() {
108122 // https://docs.microsoft.com/en-us/windows/win32/api/winsock/nf-winsock-wsacleanup
109123 int r = WSACleanup ();
110124
125+ if (r == 0 ) {
126+ --initnet;
127+ return ;
128+ }
129+
111130 if (r == SOCKET_ERROR)
112131 // https://docs.microsoft.com/en-us/windows/win32/api/winsock/nf-winsock-wsacleanup
113- r = WSAGetLastError ();
114-
115- switch (r) {
116- case WSANOTINITIALISED:
117- fprintf (stderr, " %s: winsock not initialised\n " , __func__);
118- break ;
119- case WSAENETDOWN:
120- fprintf (stderr, " %s: winsock failed\n " , __func__);
121- break ;
122- case WSAEINPROGRESS:
123- fprintf (stderr, " %s: winsock is blocked\n " , __func__);
124- break ;
125- default :
126- if (r)
127- fprintf (stderr, " %s: winsock error %d\n " , __func__, r);
128- else
129- --initnet;
130- break ;
131- }
132+ fprintf (stderr, " %s: %s\n " , __func__, wsa_parse_error (" " ).c_str ());
133+ else
134+ fprintf (stderr, " %s: unexpected error code %d\n " , __func__, r);
132135}
133136
134137TcpSocket::TcpSocket () : s((int )INVALID_SOCKET) {
@@ -137,7 +140,7 @@ TcpSocket::TcpSocket() : s((int)INVALID_SOCKET) {
137140 if ((sock = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP)) == INVALID_SOCKET)
138141 throw std::runtime_error (" socket failed" );
139142
140- s.store (( int ) sock);
143+ s.store (sock);
141144}
142145
143146TcpSocket::~TcpSocket () {
@@ -152,7 +155,7 @@ void TcpSocket::open() {
152155 throw std::runtime_error (" socket failed" );
153156
154157 closesocket (s);
155- s.store (( int ) sock);
158+ s.store (sock);
156159}
157160
158161void TcpSocket::close () {
@@ -172,48 +175,40 @@ void TcpSocket::bind(const char *address, uint16_t port) {
172175 const auto sock = s.load (std::memory_order_relaxed);
173176 sockaddr_in dst{ 0 };
174177
175- dst. sin_family = AF_INET;
176- dst.sin_addr . s_addr = inet_addr (address) ;
178+ int af = AF_INET;
179+ dst.sin_family = af ;
177180 dst.sin_port = htons (port);
178181
179- // https://docs.microsoft.com/en-us/windows/win32/api/winsock/nf-winsock-bind
180- int r = ::bind (sock, (const sockaddr *)&dst, sizeof dst);
181-
182- if (r == 0 )
183- return ;
184-
185- if (r != SOCKET_ERROR)
186- throw std::runtime_error (std::string (" wsa: bind failed: unknown return code " ) + std::to_string (r));
187-
188- int err = WSAGetLastError ();
189-
190- switch (err) {
191- case WSAEACCES:
192- throw std::runtime_error (" wsa: bind failed: access denied" );
193- case WSAEADDRINUSE:
194- throw std::runtime_error (" wsa: bind failed: socket address still in use" );
195- case WSAEADDRNOTAVAIL:
196- throw std::runtime_error (" wsa: bind failed: invalid address" );
197- case WSAEFAULT:
198- throw std::runtime_error (" wsa: bind failed: bad argument" );
199- case WSAEINPROGRESS:
200- throw std::runtime_error (" wsa: bind failed: in progress" );
201- case WSAEINVAL:
202- throw std::runtime_error (" wsa: bind failed: already bound" );
203- default :
204- wsa_generic_error (" wsa: bind failed" , err);
205- break ;
182+ int r = InetPton (af, address, &dst.sin_addr );
183+ if (r != 1 ) {
184+ if (r == 0 )
185+ throw SocketError (
186+ std::string (" wsa: InetPton: invalid address \" " ) + address + " \" " ,
187+ std::string (" Invalid address \" " ) + address + " \" "
188+ );
189+
190+ if (r != -1 )
191+ throw SocketError (
192+ std::string (" wsa: InetPton: unexpected error code " ) + std::to_string (r),
193+ std::string (" Unexpected error for address \" " ) + address + " \" "
194+ );
195+
196+ throw std::runtime_error (wsa_parse_error (" " , r));
206197 }
198+
199+ // https://docs.microsoft.com/en-us/windows/win32/api/winsock/nf-winsock-bind
200+ r = ::bind (sock, (const sockaddr*)&dst, sizeof dst);
201+ if (r != 0 )
202+ throw std::runtime_error (wsa_parse_error (" wsa: bind failed: " ));
207203}
208204
209205void TcpSocket::listen (int backlog) {
210206 if (backlog < 1 )
211207 throw std::runtime_error (" listen failed: backlog must be positive" );
212208
213- const auto sock = s.load (std::memory_order_relaxed);
209+ SOCKET sock = s.load (std::memory_order_relaxed);
214210 // https://docs.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-listen
215211 int r = ::listen (sock, backlog);
216-
217212 if (r == 0 )
218213 return ;
219214
@@ -243,15 +238,39 @@ void TcpSocket::listen(int backlog) {
243238}
244239
245240void TcpSocket::connect (const char *address, uint16_t port) {
246- const auto sock = s.load (std::memory_order_relaxed);
241+ SOCKET sock = s.load (std::memory_order_relaxed);
247242 sockaddr_in dst{ 0 };
248243
249- dst. sin_family = AF_INET;
250- dst.sin_addr . s_addr = inet_addr (address) ;
244+ int af = AF_INET;
245+ dst.sin_family = af ;
251246 dst.sin_port = htons (port);
252247
248+ int r = InetPton (af, address, &dst.sin_addr );
249+ if (r != 1 ) {
250+ if (r == 0 )
251+ throw SocketError (
252+ std::string (" wsa: connect failed: invalid address \" " ) + address + " \" " ,
253+ std::string (" Invalid IPv4 host address \" " ) + address + " \" " );
254+
255+ if (r != -1 )
256+ throw SocketError (
257+ std::string (" wsa: connect failed: unknown error code: " ) + std::to_string (r),
258+ std::string (" Unknown error " ) + std::to_string (r) + " has occurred" );
259+
260+ r = WSAGetLastError ();
261+
262+ switch (r) {
263+ case WSAEFAULT: // should we just abort?
264+ throw std::string (" wsa: connect failed: invalid address: The system detected an invalid pointer address in attempting to use a pointer argument in a call" );
265+ case WSAEAFNOSUPPORT: // should we just abort?
266+ throw std::string (" wsa: connect failed: invalid address: An address incompatible with the requested protocol was used" );
267+ default :
268+ throw std::runtime_error (std::string (" wsa: connect failed: invalid address: unknown error code: " ) + std::to_string (r));
269+ }
270+ }
271+
253272 // https://docs.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-connect
254- int r = ::connect (sock, (const sockaddr *)&dst, sizeof dst);
273+ r = ::connect (sock, (sockaddr*)&dst, sizeof dst);
255274
256275 if (r == 0 )
257276 return ;
0 commit comments